From 31c2e1a45084a9cd031c2d428e5cae9f6de48520 Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Wed, 7 Dec 2022 14:09:36 -0500 Subject: [PATCH 01/13] Only allow promote and stage to run on the awx repo --- .github/workflows/promote.yml | 1 + .github/workflows/stage.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml index 820494d303..594b213e49 100644 --- a/.github/workflows/promote.yml +++ b/.github/workflows/promote.yml @@ -10,6 +10,7 @@ on: jobs: promote: + if: github.repository == 'ansible/awx' runs-on: ubuntu-latest steps: - name: Checkout awx diff --git a/.github/workflows/stage.yml b/.github/workflows/stage.yml index 042b6b7b0d..192f307d50 100644 --- a/.github/workflows/stage.yml +++ b/.github/workflows/stage.yml @@ -21,6 +21,7 @@ on: jobs: stage: + if: github.repository == 'ansible/awx' runs-on: ubuntu-latest permissions: packages: write From e2cee10767c36b659a5e26431a8f7fbf21a1c955 Mon Sep 17 00:00:00 2001 From: John Westcott IV <32551173+john-westcott-iv@users.noreply.github.com> Date: Thu, 8 Dec 2022 16:34:13 -0500 Subject: [PATCH 02/13] Update .github/workflows/promote.yml Co-authored-by: Shane McDonald --- .github/workflows/promote.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml index 594b213e49..45dec2b283 100644 --- a/.github/workflows/promote.yml +++ b/.github/workflows/promote.yml @@ -10,7 +10,7 @@ on: jobs: promote: - if: github.repository == 'ansible/awx' + if: endsWith(github.repository, '/awx') runs-on: ubuntu-latest steps: - name: Checkout awx From 5d96ee084d787e18354b4eaa0fa8eec818090ad2 Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Thu, 8 Dec 2022 16:36:04 -0500 Subject: [PATCH 03/13] Adding endswith(awx) to stage --- .github/workflows/stage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stage.yml b/.github/workflows/stage.yml index 192f307d50..1e28952e0f 100644 --- a/.github/workflows/stage.yml +++ b/.github/workflows/stage.yml @@ -21,7 +21,7 @@ on: jobs: stage: - if: github.repository == 'ansible/awx' + if: endsWith(github.repository, '/awx') runs-on: ubuntu-latest permissions: packages: write From fd6605932a4d8c30bf4308cb06dca5197ae73eb4 Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Tue, 24 Jan 2023 12:02:49 -0500 Subject: [PATCH 04/13] Adding exception if unable to find the controler plane ee --- awx/main/utils/execution_environments.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/awx/main/utils/execution_environments.py b/awx/main/utils/execution_environments.py index 02e6a8b701..7b197287b3 100644 --- a/awx/main/utils/execution_environments.py +++ b/awx/main/utils/execution_environments.py @@ -1,4 +1,5 @@ import os +import logging from pathlib import Path from django.conf import settings @@ -6,8 +7,15 @@ from django.conf import settings from awx.main.models.execution_environments import ExecutionEnvironment +logger = logging.getLogger(__name__) + + def get_control_plane_execution_environment(): - return ExecutionEnvironment.objects.filter(organization=None, managed=True).first() + ee = ExecutionEnvironment.objects.filter(organization=None, managed=True).first() + if ee == None: + logger.error('Failed to find control plane ee, there are no managed EEs without organizations') + raise RuntimeError("Failed to find default control plane EE") + return ee def get_default_execution_environment(): From eb9431ee1f8433bdb479919fafa6493c935fb8c9 Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Tue, 24 Jan 2023 12:03:10 -0500 Subject: [PATCH 05/13] Fixing hard coded project --- awx/main/tasks/jobs.py | 2 +- awx/main/tests/unit/test_tasks.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/awx/main/tasks/jobs.py b/awx/main/tasks/jobs.py index a726a418c0..d453a2364b 100644 --- a/awx/main/tasks/jobs.py +++ b/awx/main/tasks/jobs.py @@ -311,7 +311,7 @@ class BaseTask(object): env['AWX_PRIVATE_DATA_DIR'] = private_data_dir if self.instance.execution_environment is None: - raise RuntimeError('The project could not sync because there is no Execution Environment.') + raise RuntimeError(f'The {self.model.__name__} could not run because there is no Execution Environment.') return env diff --git a/awx/main/tests/unit/test_tasks.py b/awx/main/tests/unit/test_tasks.py index 9a59e091d1..c3d472deb6 100644 --- a/awx/main/tests/unit/test_tasks.py +++ b/awx/main/tests/unit/test_tasks.py @@ -1972,7 +1972,7 @@ def test_project_update_no_ee(mock_me): with pytest.raises(RuntimeError) as e: task.build_env(job, {}) - assert 'The project could not sync because there is no Execution Environment' in str(e.value) + assert 'The ProjectUpdate could not run because there is no Execution Environment' in str(e.value) @pytest.mark.parametrize( From 26a888547d5ee2a9fce17bf1548f2dc52fd7627b Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Tue, 14 Feb 2023 14:49:58 -0500 Subject: [PATCH 06/13] Fixing variable with duplicate name which was causing errors with LDAP team addition --- awx/sso/backends.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/awx/sso/backends.py b/awx/sso/backends.py index c55f24e7de..3cc605e0aa 100644 --- a/awx/sso/backends.py +++ b/awx/sso/backends.py @@ -385,10 +385,10 @@ def on_populate_user(sender, **kwargs): logger.warning('LDAP user {} has {} > max {} characters'.format(user.username, field, max_len)) org_map = getattr(backend.settings, 'ORGANIZATION_MAP', {}) - team_map = getattr(backend.settings, 'TEAM_MAP', {}) + team_map_settings = getattr(backend.settings, 'TEAM_MAP', {}) orgs_list = list(org_map.keys()) team_map = {} - for team_name, team_opts in team_map.items(): + for team_name, team_opts in team_map_settings.items(): if not team_opts.get('organization', None): # You can't save the LDAP config in the UI w/o an org (or '' or null as the org) so if we somehow got this condition its an error logger.error("Team named {} in LDAP team map settings is invalid due to missing organization".format(team_name)) @@ -416,7 +416,7 @@ def on_populate_user(sender, **kwargs): # Compute in memory what the state is of the different LDAP teams desired_team_states = {} - for team_name, team_opts in team_map.items(): + for team_name, team_opts in team_map_settings.items(): if 'organization' not in team_opts: continue users_opts = team_opts.get('users', None) From 7f50679e68eb90ef2886fd02af02454d3fc62951 Mon Sep 17 00:00:00 2001 From: Alan Rominger Date: Wed, 15 Feb 2023 14:54:46 -0500 Subject: [PATCH 07/13] Do not create setting with invalid value in data migration (#13576) * Do not create setting with invalid value in data migration * Add test for conf app data migration --- awx/conf/migrations/_ldap_group_type.py | 9 +++++-- awx/conf/tests/functional/test_migrations.py | 25 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 awx/conf/tests/functional/test_migrations.py diff --git a/awx/conf/migrations/_ldap_group_type.py b/awx/conf/migrations/_ldap_group_type.py index b6580f8cae..378f934342 100644 --- a/awx/conf/migrations/_ldap_group_type.py +++ b/awx/conf/migrations/_ldap_group_type.py @@ -1,7 +1,11 @@ import inspect from django.conf import settings -from django.utils.timezone import now + +import logging + + +logger = logging.getLogger('awx.conf.migrations') def fill_ldap_group_type_params(apps, schema_editor): @@ -15,7 +19,7 @@ def fill_ldap_group_type_params(apps, schema_editor): entry = qs[0] group_type_params = entry.value else: - entry = Setting(key='AUTH_LDAP_GROUP_TYPE_PARAMS', value=group_type_params, created=now(), modified=now()) + return # for new installs we prefer to use the default value init_attrs = set(inspect.getfullargspec(group_type.__init__).args[1:]) for k in list(group_type_params.keys()): @@ -23,4 +27,5 @@ def fill_ldap_group_type_params(apps, schema_editor): del group_type_params[k] entry.value = group_type_params + logger.warning(f'Migration updating AUTH_LDAP_GROUP_TYPE_PARAMS with value {entry.value}') entry.save() diff --git a/awx/conf/tests/functional/test_migrations.py b/awx/conf/tests/functional/test_migrations.py new file mode 100644 index 0000000000..d3fddb292b --- /dev/null +++ b/awx/conf/tests/functional/test_migrations.py @@ -0,0 +1,25 @@ +import pytest + +from awx.conf.migrations._ldap_group_type import fill_ldap_group_type_params +from awx.conf.models import Setting + +from django.apps import apps + + +@pytest.mark.django_db +def test_fill_group_type_params_no_op(): + fill_ldap_group_type_params(apps, 'dont-use-me') + assert Setting.objects.count() == 0 + + +@pytest.mark.django_db +def test_keep_old_setting_with_default_value(): + Setting.objects.create(key='AUTH_LDAP_GROUP_TYPE', value={'name_attr': 'cn', 'member_attr': 'member'}) + fill_ldap_group_type_params(apps, 'dont-use-me') + assert Setting.objects.count() == 1 + s = Setting.objects.first() + assert s.value == {'name_attr': 'cn', 'member_attr': 'member'} + + +# NOTE: would be good to test the removal of attributes by migration +# but this requires fighting with the validator and is not done here From fb2647ff7bfcf29a60f1cb439c8aa10b19cb6da6 Mon Sep 17 00:00:00 2001 From: Gabe Muniz Date: Fri, 17 Feb 2023 14:17:18 -0500 Subject: [PATCH 08/13] changing the signature of workflowapprovallist included workflow approval as a read only endpoint to pass collection tests --- awx/api/views/__init__.py | 2 +- awx_collection/test/awx/test_completeness.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/awx/api/views/__init__.py b/awx/api/views/__init__.py index e81a6ebbde..609e88e155 100644 --- a/awx/api/views/__init__.py +++ b/awx/api/views/__init__.py @@ -4288,7 +4288,7 @@ class WorkflowApprovalTemplateJobsList(SubListAPIView): parent_key = 'workflow_approval_template' -class WorkflowApprovalList(ListCreateAPIView): +class WorkflowApprovalList(ListAPIView): model = models.WorkflowApproval serializer_class = serializers.WorkflowApprovalListSerializer diff --git a/awx_collection/test/awx/test_completeness.py b/awx_collection/test/awx/test_completeness.py index 43e225e4b8..451c1a61d3 100644 --- a/awx_collection/test/awx/test_completeness.py +++ b/awx_collection/test/awx/test_completeness.py @@ -16,7 +16,7 @@ import glob # Normally a read-only endpoint should not have a module (i.e. /api/v2/me) but sometimes we reuse a name # For example, we have a role module but /api/v2/roles is a read only endpoint. # This list indicates which read-only endpoints have associated modules with them. -read_only_endpoints_with_modules = ['settings', 'role', 'project_update'] +read_only_endpoints_with_modules = ['settings', 'role', 'project_update', 'workflow_approval'] # If a module should not be created for an endpoint and the endpoint is not read-only add it here # THINK HARD ABOUT DOING THIS From b5f240ce700a2f12e3ca888fb11bf71b6936c0cd Mon Sep 17 00:00:00 2001 From: Alan Rominger Date: Fri, 17 Feb 2023 15:10:59 -0500 Subject: [PATCH 09/13] Add integration test and docs for workflow_approval module --- .../plugins/modules/workflow_approval.py | 12 +++- .../targets/workflow_approval/tasks/main.yml | 57 +++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 awx_collection/tests/integration/targets/workflow_approval/tasks/main.yml diff --git a/awx_collection/plugins/modules/workflow_approval.py b/awx_collection/plugins/modules/workflow_approval.py index bb8c24dfb8..dd81eeb93c 100644 --- a/awx_collection/plugins/modules/workflow_approval.py +++ b/awx_collection/plugins/modules/workflow_approval.py @@ -57,7 +57,15 @@ extends_documentation_fragment: awx.awx.auth EXAMPLES = """ -- name: Launch a workflow with a timeout of 10 seconds +- name: Create a workflow approval node + workflow_job_template_node: + identifier: approval_test + approval_node: + name: approval_jt_name + timeout: 900 + workflow: "Test Workflow" + +- name: Launch the workflow with a timeout of 10 seconds workflow_launch: workflow_template: "Test Workflow" wait: False @@ -66,7 +74,7 @@ EXAMPLES = """ - name: Wait for approval node to activate and approve workflow_approval: workflow_job_id: "{{ workflow.id }}" - name: Approve Me + name: approval_jt_name interval: 10 timeout: 20 action: deny diff --git a/awx_collection/tests/integration/targets/workflow_approval/tasks/main.yml b/awx_collection/tests/integration/targets/workflow_approval/tasks/main.yml new file mode 100644 index 0000000000..eaf1b3bf8d --- /dev/null +++ b/awx_collection/tests/integration/targets/workflow_approval/tasks/main.yml @@ -0,0 +1,57 @@ +--- +- name: Generate a random string for names + set_fact: + test_id: "{{ lookup('password', '/dev/null chars=ascii_letters length=16') }}" + test_prefix: AWX-Collection-tests-workflow_approval + +- name: Generate random names for test objects + set_fact: + org_name: "{{ test_prefix }}-org-{{ test_id }}" + approval_node_name: "{{ test_prefix }}-node-{{ test_id }}" + wfjt_name: "{{ test_prefix }}-wfjt-{{ test_id }}" + +- block: + - name: Create a new organization for test isolation + organization: + name: "{{ org_name }}" + + - name: Create a workflow job template + workflow_job_template: + name: "{{ wfjt_name }}" + organization: "{{ org_name }}" + + - name: Create approval node + workflow_job_template_node: + identifier: approval_test + approval_node: + name: "{{ approval_node_name }}" # Referenced later on + timeout: 900 + workflow: "{{ wfjt_name }}" + + # Launch and approve the workflow + - name: Launch the workflow + workflow_launch: + workflow_template: "{{ wfjt_name }}" + wait: False + register: workflow_job + + - name: Wait for approval node to activate and approve + workflow_approval: + workflow_job_id: "{{ workflow_job.id }}" + name: "{{ approval_node_name }}" + interval: 10 + timeout: 20 + action: approve + register: result + + - assert: + that: + - "result is changed" + - "result is not failed" + + always: + - name: Delete the workflow job template + workflow_job_template: + name: "{{ wfjt_name }}" + state: absent + ignore_errors: True From fe3aa6ce2bd64d33faab41dd4636379416a51821 Mon Sep 17 00:00:00 2001 From: sean-m-sullivan Date: Thu, 16 Feb 2023 21:26:41 -0500 Subject: [PATCH 10/13] fix inventory prompt on launch for workflow nodes --- .../plugins/modules/workflow_job_template.py | 35 ++++++++++++++++--- .../workflow_job_template/tasks/main.yml | 5 +++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/awx_collection/plugins/modules/workflow_job_template.py b/awx_collection/plugins/modules/workflow_job_template.py index 41c5b66573..19954877b7 100644 --- a/awx_collection/plugins/modules/workflow_job_template.py +++ b/awx_collection/plugins/modules/workflow_job_template.py @@ -183,7 +183,21 @@ options: inventory: description: - Inventory applied as a prompt, if job template prompts for inventory - type: str + type: dict + suboptions: + name: + description: + - Name Inventory to be applied to job as launch-time prompts. + type: str + organization: + description: + - Name of key for use in model for organizational reference + type: dict + suboptions: + name: + description: + - The organization of the credentials exists in. + type: str scm_branch: description: - SCM branch applied as a prompt, if job template prompts for SCM branch @@ -544,6 +558,10 @@ EXAMPLES = ''' type: job_template execution_environment: name: My EE + inventory: + name: Test inventory + organization: + name: Default related: credentials: - name: cyberark @@ -613,10 +631,6 @@ def create_workflow_nodes(module, response, workflow_nodes, workflow_id): if workflow_node['unified_job_template']['type'] != 'workflow_approval': module.fail_json(msg="Unable to Find unified_job_template: {0}".format(search_fields)) - inventory = workflow_node.get('inventory') - if inventory: - workflow_node_fields['inventory'] = module.resolve_name_to_id('inventories', inventory) - # Lookup Values for other fields for field_name in ( @@ -645,6 +659,17 @@ def create_workflow_nodes(module, response, workflow_nodes, workflow_id): 'execution_environments', name_or_id=workflow_node['execution_environment']['name'] )['id'] + # Two lookup methods are used based on a fix added in 21.11.0, and the awx export model + if 'inventory' in workflow_node: + if 'name' in workflow_node['inventory']: + inv_lookup_data = {} + if 'organization' in workflow_node['inventory']: + inv_lookup_data['organization'] = module.resolve_name_to_id('organizations', workflow_node['inventory']['organization']['name']) + workflow_node_fields['inventory'] = module.get_one( + 'inventories', name_or_id=workflow_node['inventory']['name'], data=inv_lookup_data)['id'] + else: + workflow_node_fields['inventory'] = module.get_one('inventories', name_or_id=workflow_node['inventory'])['id'] + # Set Search fields search_fields['workflow_job_template'] = workflow_node_fields['workflow_job_template'] = workflow_id diff --git a/awx_collection/tests/integration/targets/workflow_job_template/tasks/main.yml b/awx_collection/tests/integration/targets/workflow_job_template/tasks/main.yml index 1477193e6c..e5f3366cd3 100644 --- a/awx_collection/tests/integration/targets/workflow_job_template/tasks/main.yml +++ b/awx_collection/tests/integration/targets/workflow_job_template/tasks/main.yml @@ -493,6 +493,7 @@ workflow_job_template: name: "copy_{{ wfjt_name }}" organization: Default + ask_inventory_on_launch: true survey_spec: name: Basic Survey description: Basic Survey @@ -737,6 +738,10 @@ timeout: 23 execution_environment: name: "{{ ee1 }}" + inventory: + name: Test inventory + organization: + name: Default related: credentials: - name: "{{ scm_cred_name }}" From 6d3f39fe92cf860ff490cfe0af127c7c9187a7cb Mon Sep 17 00:00:00 2001 From: Alan Rominger Date: Tue, 21 Feb 2023 13:34:29 -0500 Subject: [PATCH 11/13] Give proper 401 code to user not logged in --- awx/api/generics.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/awx/api/generics.py b/awx/api/generics.py index 7d21d74ee6..361506c605 100644 --- a/awx/api/generics.py +++ b/awx/api/generics.py @@ -28,7 +28,7 @@ from rest_framework import generics from rest_framework.response import Response from rest_framework import status from rest_framework import views -from rest_framework.permissions import AllowAny +from rest_framework.permissions import IsAuthenticated from rest_framework.renderers import StaticHTMLRenderer from rest_framework.negotiation import DefaultContentNegotiation @@ -822,7 +822,7 @@ def trigger_delayed_deep_copy(*args, **kwargs): class CopyAPIView(GenericAPIView): serializer_class = CopySerializer - permission_classes = (AllowAny,) + permission_classes = (IsAuthenticated,) copy_return_serializer_class = None new_in_330 = True new_in_api_v2 = True From 3a303875bb4f697269397e6d3cc9c8a379c40bf5 Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Wed, 22 Feb 2023 16:18:53 -0500 Subject: [PATCH 12/13] update kind development environment instruction --- docs/development/kind.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/development/kind.md b/docs/development/kind.md index 820abae182..d3a11cc4cd 100644 --- a/docs/development/kind.md +++ b/docs/development/kind.md @@ -75,7 +75,8 @@ In the root of awx-operator: -e image_version=devel \ -e image_pull_policy=Always \ -e service_type=nodeport \ - -e namespace=awx + -e namespace=awx \ + -e nodeport_port=30080 ``` Check the operator with the following commands: From 019e6a52fe6699e4bf34c36931b739430c37b190 Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Tue, 7 Feb 2023 09:51:05 -0500 Subject: [PATCH 13/13] Update project_update playbook to be compliant with ansible-lint --- awx/playbooks/project_update.yml | 189 ++++++++++++++++--------------- 1 file changed, 99 insertions(+), 90 deletions(-) diff --git a/awx/playbooks/project_update.yml b/awx/playbooks/project_update.yml index 2067e76043..7334547f97 100644 --- a/awx/playbooks/project_update.yml +++ b/awx/playbooks/project_update.yml @@ -25,42 +25,47 @@ connection: local name: Update source tree if necessary tasks: - - - name: delete project directory before update - command: "find -delete" # volume mounted, cannot delete folder itself + - name: Delete project directory before update + ansible.builtin.shell: set -o pipefail && find . -delete -print | head -2 # volume mounted, cannot delete folder itself + register: reg + changed_when: reg.stdout_lines | length > 1 args: chdir: "{{ project_path }}" tags: - delete - - block: - - name: update project using git - git: - dest: "{{project_path|quote}}" - repo: "{{scm_url}}" - version: "{{scm_branch|quote}}" - refspec: "{{scm_refspec|default(omit)}}" - force: "{{scm_clean}}" - track_submodules: "{{scm_track_submodules|default(omit)}}" - accept_hostkey: "{{scm_accept_hostkey|default(omit)}}" + - name: Update project using git + tags: + - update_git + block: + - name: Update project using git + ansible.builtin.git: + dest: "{{ project_path | quote }}" + repo: "{{ scm_url }}" + version: "{{ scm_branch | quote }}" + refspec: "{{ scm_refspec | default(omit) }}" + force: "{{ scm_clean }}" + track_submodules: "{{ scm_track_submodules | default(omit) }}" + accept_hostkey: "{{ scm_accept_hostkey | default(omit) }}" register: git_result - name: Set the git repository version - set_fact: + ansible.builtin.set_fact: scm_version: "{{ git_result['after'] }}" when: "'after' in git_result" - tags: - - update_git - - block: - - name: update project using svn - subversion: - dest: "{{project_path|quote}}" - repo: "{{scm_url|quote}}" - revision: "{{scm_branch|quote}}" - force: "{{scm_clean}}" - username: "{{scm_username|default(omit)}}" - password: "{{scm_password|default(omit)}}" + - name: Update project using svn + tags: + - update_svn + block: + - name: Update project using svn + ansible.builtin.subversion: + dest: "{{ project_path | quote }}" + repo: "{{ scm_url | quote }}" + revision: "{{ scm_branch | quote }}" + force: "{{ scm_clean }}" + username: "{{ scm_username | default(omit) }}" + password: "{{ scm_password | default(omit) }}" # must be in_place because folder pre-existing, because it is mounted in_place: true environment: @@ -68,85 +73,90 @@ register: svn_result - name: Set the svn repository version - set_fact: + ansible.builtin.set_fact: scm_version: "{{ svn_result['after'] }}" when: "'after' in svn_result" - - name: parse subversion version string properly - set_fact: - scm_version: "{{scm_version|regex_replace('^.*Revision: ([0-9]+).*$', '\\1')}}" - tags: - - update_svn + - name: Parse subversion version string properly + ansible.builtin.set_fact: + scm_version: "{{ scm_version | regex_replace('^.*Revision: ([0-9]+).*$', '\\1') }}" - - block: + + - name: Project update for Insights + tags: + - update_insights + block: - name: Ensure the project directory is present - file: - dest: "{{project_path|quote}}" + ansible.builtin.file: + dest: "{{ project_path | quote }}" state: directory + mode: '0755' - name: Fetch Insights Playbook(s) insights: - insights_url: "{{insights_url}}" - username: "{{scm_username}}" - password: "{{scm_password}}" - project_path: "{{project_path}}" - awx_license_type: "{{awx_license_type}}" - awx_version: "{{awx_version}}" + insights_url: "{{ insights_url }}" + username: "{{ scm_username }}" + password: "{{ scm_password }}" + project_path: "{{ project_path }}" + awx_license_type: "{{ awx_license_type }}" + awx_version: "{{ awx_version }}" register: results - name: Save Insights Version - set_fact: - scm_version: "{{results.version}}" + ansible.builtin.set_fact: + scm_version: "{{ results.version }}" when: results is defined - tags: - - update_insights - - block: + + - name: Update project using archive + tags: + - update_archive + block: - name: Ensure the project archive directory is present - file: - dest: "{{ project_path|quote }}/.archive" + ansible.builtin.file: + dest: "{{ project_path | quote }}/.archive" state: directory + mode: '0755' - name: Get archive from url - get_url: - url: "{{ scm_url|quote }}" - dest: "{{ project_path|quote }}/.archive/" - url_username: "{{ scm_username|default(omit) }}" - url_password: "{{ scm_password|default(omit) }}" + ansible.builtin.get_url: + url: "{{ scm_url | quote }}" + dest: "{{ project_path | quote }}/.archive/" + url_username: "{{ scm_username | default(omit) }}" + url_password: "{{ scm_password | default(omit) }}" force_basic_auth: true + mode: '0755' register: get_archive - name: Unpack archive project_archive: src: "{{ get_archive.dest }}" - project_path: "{{ project_path|quote }}" + project_path: "{{ project_path | quote }}" force: "{{ scm_clean }}" when: get_archive.changed or scm_clean register: unarchived - name: Find previous archives - find: - paths: "{{ project_path|quote }}/.archive/" + ansible.builtin.find: + paths: "{{ project_path | quote }}/.archive/" excludes: - - "{{ get_archive.dest|basename }}" + - "{{ get_archive.dest | basename }}" when: unarchived.changed register: previous_archive - name: Remove previous archives - file: + ansible.builtin.file: path: "{{ item.path }}" state: absent loop: "{{ previous_archive.files }}" - when: previous_archive.files|default([]) + when: previous_archive.files | default([]) - name: Set scm_version to archive sha1 checksum - set_fact: + ansible.builtin.set_fact: scm_version: "{{ get_archive.checksum_src }}" - tags: - - update_archive - name: Repository Version - debug: + ansible.builtin.debug: msg: "Repository Version {{ scm_version }}" tags: - update_git @@ -183,60 +193,59 @@ additional_collections_env: # These environment variables are used for installing collections, in addition to galaxy_task_env # setting the collections paths silences warnings - ANSIBLE_COLLECTIONS_PATHS: "{{projects_root}}/.__awx_cache/{{local_path}}/stage/requirements_collections" + ANSIBLE_COLLECTIONS_PATHS: "{{ projects_root }}/.__awx_cache/{{ local_path }}/stage/requirements_collections" # Put the local tmp directory in same volume as collection destination # otherwise, files cannot be moved accross volumes and will cause error - ANSIBLE_LOCAL_TEMP: "{{projects_root}}/.__awx_cache/{{local_path}}/stage/tmp" + ANSIBLE_LOCAL_TEMP: "{{ projects_root }}/.__awx_cache/{{ local_path }}/stage/tmp" tasks: - - name: Check content sync settings - block: - - debug: - msg: > - Collection and role syncing disabled. Check the AWX_ROLES_ENABLED and - AWX_COLLECTIONS_ENABLED settings and Galaxy credentials on the project's organization. - - - meta: end_play - - when: not roles_enabled|bool and not collections_enabled|bool + when: not roles_enabled | bool and not collections_enabled | bool tags: - install_roles - install_collections + block: + - name: Warn about disabled content sync + ansible.builtin.debug: + msg: > + Collection and role syncing disabled. Check the AWX_ROLES_ENABLED and + AWX_COLLECTIONS_ENABLED settings and Galaxy credentials on the project's organization. + - name: End play due to disabled content sync + ansible.builtin.meta: end_play - - name: fetch galaxy roles from requirements.(yml/yaml) - command: > + - name: Fetch galaxy roles from requirements.(yml/yaml) + ansible.builtin.command: > ansible-galaxy role install -r {{ item }} - --roles-path {{projects_root}}/.__awx_cache/{{local_path}}/stage/requirements_roles + --roles-path {{ projects_root }}/.__awx_cache/{{ local_path }}/stage/requirements_roles {{ ' -' + 'v' * ansible_verbosity if ansible_verbosity else '' }} args: - chdir: "{{project_path|quote}}" + chdir: "{{ project_path | quote }}" register: galaxy_result with_fileglob: - - "{{project_path|quote}}/roles/requirements.yaml" - - "{{project_path|quote}}/roles/requirements.yml" + - "{{ project_path | quote }}/roles/requirements.yaml" + - "{{ project_path | quote }}/roles/requirements.yml" changed_when: "'was installed successfully' in galaxy_result.stdout" environment: "{{ galaxy_task_env }}" - when: roles_enabled|bool + when: roles_enabled | bool tags: - install_roles - - name: fetch galaxy collections from collections/requirements.(yml/yaml) - command: > + - name: Fetch galaxy collections from collections/requirements.(yml/yaml) + ansible.builtin.command: > ansible-galaxy collection install -r {{ item }} - --collections-path {{projects_root}}/.__awx_cache/{{local_path}}/stage/requirements_collections + --collections-path {{ projects_root }}/.__awx_cache/{{ local_path }}/stage/requirements_collections {{ ' -' + 'v' * ansible_verbosity if ansible_verbosity else '' }} args: - chdir: "{{project_path|quote}}" + chdir: "{{ project_path | quote }}" register: galaxy_collection_result with_fileglob: - - "{{project_path|quote}}/collections/requirements.yaml" - - "{{project_path|quote}}/collections/requirements.yml" - - "{{project_path|quote}}/requirements.yaml" - - "{{project_path|quote}}/requirements.yml" + - "{{ project_path | quote }}/collections/requirements.yaml" + - "{{ project_path | quote }}/collections/requirements.yml" + - "{{ project_path | quote }}/requirements.yaml" + - "{{ project_path | quote }}/requirements.yml" changed_when: "'Installing ' in galaxy_collection_result.stdout" environment: "{{ additional_collections_env | combine(galaxy_task_env) }}" when: - "ansible_version.full is version_compare('2.9', '>=')" - - collections_enabled|bool + - collections_enabled | bool tags: - install_collections