diff --git a/changelogs/fragments/object_diff.yml b/changelogs/fragments/object_diff.yml new file mode 100644 index 000000000..6a9ca2996 --- /dev/null +++ b/changelogs/fragments/object_diff.yml @@ -0,0 +1,5 @@ +--- +bugfixes: + - Added more attributes to be expanded and used by the comparison + - Fixed lintering issues +... diff --git a/plugins/lookup/controller_object_diff.py b/plugins/lookup/controller_object_diff.py index e894b7f1c..b9926cea1 100644 --- a/plugins/lookup/controller_object_diff.py +++ b/plugins/lookup/controller_object_diff.py @@ -89,11 +89,11 @@ returned: on successful differential """ -from ansible.plugins.lookup import LookupBase +import copy from ansible.errors import AnsibleError, AnsibleLookupError from ansible.module_utils._text import to_native +from ansible.plugins.lookup import LookupBase from ansible.utils.display import Display -import copy class LookupModule(LookupBase): @@ -114,6 +114,13 @@ def create_present_list(self, compare_list): return compare_list + def map_item(self, item, new_attribute_name, attribute_value, dupitems): + new_item = copy.deepcopy(item) + new_item.update({new_attribute_name: attribute_value}) + for dupitem in [dupitem for dupitem in dupitems if dupitem in new_item]: + new_item.pop(dupitem) + return new_item + def run(self, terms, variables=None, **kwargs): self.set_options(direct=kwargs) @@ -179,7 +186,12 @@ def run(self, terms, variables=None, **kwargs): api_list_reduced = copy.deepcopy(api_list) elif api_list[0]["type"] == "instance_group": compare_list_reduced = [{key: item[key] for key in keys_to_keep} for item in compare_list] - api_list_reduced = [{key: item[key] for key in api_keys_to_keep} for item in api_list if item["summary_fields"]["user_capabilities"]["delete"]] + api_list_reduced = [ + {key: item[key] for key in api_keys_to_keep} + for item in api_list + if (item["summary_fields"] and item["summary_fields"]["user_capabilities"]["delete"]) + ] + else: compare_list_reduced = [{key: item[key] for key in keys_to_keep} for item in compare_list] api_list_reduced = [{key: item[key] for key in api_keys_to_keep} for item in api_list] @@ -196,7 +208,7 @@ def run(self, terms, variables=None, **kwargs): item.pop("summary_fields") elif api_list[0]["type"] == "credential": for item in api_list_reduced: - item.update({"organization": item["summary_fields"]["organization"]["name"]}) + item.update({"organization": item["summary_fields"]["organization"]["name"] if item["summary_fields"]["organization"] else ""}) item.update({"credential_type": item["summary_fields"]["credential_type"]["name"]}) item.pop("summary_fields") elif api_list[0]["type"] == "workflow_job_template_node": @@ -225,43 +237,57 @@ def run(self, terms, variables=None, **kwargs): list_to_extend = [] list_to_remove = [] for item in compare_list_reduced: - target_teams_expanded = False - job_templates_expanded = False - workflows_expanded = False + expanded = False + dupitems = [ + "target_team", + "target_teams", + "job_template", + "job_templates", + "workflow", + "workflows", + "inventory", + "inventories", + "project", + "projects", + "credential", + "credentials", + ] + if "target_team" in item: + list_to_extend.append(self.map_item(item, "team", item["target_team"], dupitems)) + expanded = True if "target_teams" in item: for team in item["target_teams"]: - new_item = copy.deepcopy(item) - new_item.update({"team": team}) - new_item.pop("target_teams") - if "job_templates" in new_item: - new_item.pop("job_templates") - if "workflows" in new_item: - new_item.pop("workflows") - list_to_extend.append(new_item) - target_teams_expanded = True + list_to_extend.append(self.map_item(item, "team", team, dupitems)) + expanded = True + if "job_template" in item: + list_to_extend.append(self.map_item(item, "job_template", item["job_template"], dupitems)) + expanded = True if "job_templates" in item: for job_template in item["job_templates"]: - new_item = copy.deepcopy(item) - new_item.update({"job_template": job_template}) - new_item.pop("job_templates") - if "target_teams" in new_item: - new_item.pop("target_teams") - if "workflows" in new_item: - new_item.pop("workflows") - list_to_extend.append(new_item) - job_templates_expanded = True + list_to_extend.append(self.map_item(item, "job_template", job_template, dupitems)) + expanded = True + if "workflow" in item: + list_to_extend.append(self.map_item(item, "workflow_job_template", item["workflow"], dupitems)) + expanded = True if "workflows" in item: for workflow in item["workflows"]: - new_item = copy.deepcopy(item) - new_item.update({"workflow_job_template": workflow}) - new_item.pop("workflows") - if "target_teams" in new_item: - new_item.pop("target_teams") - if "job_templates" in new_item: - new_item.pop("job_templates") - list_to_extend.append(new_item) - workflows_expanded = True - if target_teams_expanded or job_templates_expanded or workflows_expanded: + list_to_extend.append(self.map_item(item, "workflow_job_template", workflow, dupitems)) + expanded = True + if "inventory" in item: + list_to_extend.append(self.map_item(item, "inventory", item["inventory"], dupitems)) + expanded = True + if "inventories" in item: + for inventory in item["inventories"]: + list_to_extend.append(self.map_item(item, "inventory", inventory, dupitems)) + expanded = True + if "project" in item: + list_to_extend.append(self.map_item(item, "project", item["project"], dupitems)) + expanded = True + if "projects" in item: + for project in item["projects"]: + list_to_extend.append(self.map_item(item, "project", project, dupitems)) + expanded = True + if expanded: list_to_remove.append(item) for item in list_to_remove: compare_list_reduced.remove(item) @@ -295,7 +321,8 @@ def run(self, terms, variables=None, **kwargs): item.update({"state": "absent"}) # Combine Lists if self.get_option("with_present"): - compare_list = self.create_present_list(compare_list) + for item in compare_list_reduced: + item.update({"state": "present"}) compare_list.extend(difference) # Return Compare list with difference attached difference = compare_list @@ -308,4 +335,4 @@ def run(self, terms, variables=None, **kwargs): for item in difference_to_remove: difference.remove(item) - return difference + return [difference] diff --git a/roles/applications/tasks/main.yml b/roles/applications/tasks/main.yml index 3ea5f8b07..cc56dfad2 100644 --- a/roles/applications/tasks/main.yml +++ b/roles/applications/tasks/main.yml @@ -5,11 +5,11 @@ name: "{{ __application_item.name | mandatory }}" new_name: "{{ __application_item.new_name | default(omit, true) }}" organization: "{{ __application_item.organization | mandatory }}" - description: "{{ __application_item.description | default(( '' if controller_configuration_applications_enforce_defaults else omit), true) }}" + description: "{{ __application_item.description | default(('' if controller_configuration_applications_enforce_defaults else omit), true) }}" authorization_grant_type: "{{ __application_item.authorization_grant_type | default('password') }}" client_type: "{{ __application_item.client_type | default('public') }}" redirect_uris: "{{ __application_item.redirect_uris | default([]) }}" - skip_authorization: "{{ __application_item.skip_authorization | default(( false if controller_configuration_applications_enforce_defaults else omit), true) }}" + skip_authorization: "{{ __application_item.skip_authorization | default((false if controller_configuration_applications_enforce_defaults else omit), true) }}" state: "{{ __application_item.state | default(controller_state | default('present')) }}" # Role specific options diff --git a/roles/credential_input_sources/tasks/main.yml b/roles/credential_input_sources/tasks/main.yml index bb4ab20b8..c0d93c211 100644 --- a/roles/credential_input_sources/tasks/main.yml +++ b/roles/credential_input_sources/tasks/main.yml @@ -4,8 +4,8 @@ target_credential: "{{ __cred_input_src_item.target_credential | mandatory }}" input_field_name: "{{ __cred_input_src_item.input_field_name | mandatory }}" source_credential: "{{ __cred_input_src_item.source_credential | default(omit, true) }}" - description: "{{ __cred_input_src_item.description | default(( '' if controller_configuration_credential_input_sources_enforce_defaults else omit), true) }}" - metadata: "{{ __cred_input_src_item.metadata | default(( {} if controller_configuration_credential_input_sources_enforce_defaults else omit), true) }}" + description: "{{ __cred_input_src_item.description | default(('' if controller_configuration_credential_input_sources_enforce_defaults else omit), true) }}" + metadata: "{{ __cred_input_src_item.metadata | default(({} if controller_configuration_credential_input_sources_enforce_defaults else omit), true) }}" state: "{{ __cred_input_src_item.state | default(controller_state | default('present')) }}" # Role specific options diff --git a/roles/credential_types/tasks/main.yml b/roles/credential_types/tasks/main.yml index 31174461e..53535c4d1 100644 --- a/roles/credential_types/tasks/main.yml +++ b/roles/credential_types/tasks/main.yml @@ -3,9 +3,9 @@ credential_type: name: "{{ __controller_credential_type_item.name | mandatory }}" new_name: "{{ __controller_credential_type_item.new_name | default(omit, true) }}" - description: "{{ __controller_credential_type_item.description | default(( '' if controller_configuration_credential_types_enforce_defaults else omit), true) }}" - injectors: "{{ __controller_credential_type_item.injectors | default(( {} if controller_configuration_credential_types_enforce_defaults else omit), true) | regex_replace('[ ]{2,}', '') }}" - inputs: "{{ __controller_credential_type_item.inputs | default(( {} if controller_configuration_credential_types_enforce_defaults else omit), true) }}" + description: "{{ __controller_credential_type_item.description | default(('' if controller_configuration_credential_types_enforce_defaults else omit), true) }}" + injectors: "{{ __controller_credential_type_item.injectors | default(({} if controller_configuration_credential_types_enforce_defaults else omit), true) | regex_replace('[ ]{2,}', '') }}" + inputs: "{{ __controller_credential_type_item.inputs | default(({} if controller_configuration_credential_types_enforce_defaults else omit), true) }}" kind: "{{ __controller_credential_type_item.kind | default('cloud') }}" state: "{{ __controller_credential_type_item.state | default(controller_state | default('present')) }}" diff --git a/roles/credentials/tasks/main.yml b/roles/credentials/tasks/main.yml index 576997301..108fc691d 100644 --- a/roles/credentials/tasks/main.yml +++ b/roles/credentials/tasks/main.yml @@ -4,13 +4,13 @@ name: "{{ __controller_credentials_item.name | mandatory }}" new_name: "{{ __controller_credentials_item.new_name | default(omit, true) }}" copy_from: "{{ __controller_credentials_item.copy_from | default(omit, true) }}" - description: "{{ __controller_credentials_item.description | default(( '' if controller_configuration_credentials_enforce_defaults else omit), true) }}" - organization: "{{ __controller_credentials_item.organization.name | default(__controller_credentials_item.organization | default(( '' if controller_configuration_credentials_enforce_defaults else omit), true)) }}" + description: "{{ __controller_credentials_item.description | default(('' if controller_configuration_credentials_enforce_defaults else omit), true) }}" + organization: "{{ __controller_credentials_item.organization.name | default(__controller_credentials_item.organization | default(('' if controller_configuration_credentials_enforce_defaults else omit), true)) }}" credential_type: "{{ __controller_credentials_item.credential_type.name | default(__controller_credentials_item.credential_type | mandatory ) }}" - inputs: "{{ __controller_credentials_item.inputs | default(( {} if controller_configuration_credentials_enforce_defaults else omit), true) }}" - user: "{{ __controller_credentials_item.user.username | default(__controller_credentials_item.user | default(( '' if controller_configuration_credentials_enforce_defaults else omit), true)) }}" - team: "{{ __controller_credentials_item.team.name | default(__controller_credentials_item.team | default(( '' if controller_configuration_credentials_enforce_defaults else omit), true)) }}" - update_secrets: "{{ __controller_credentials_item.update_secrets | default( true if controller_configuration_credentials_enforce_defaults else omit) }}" + inputs: "{{ __controller_credentials_item.inputs | default(({} if controller_configuration_credentials_enforce_defaults else omit), true) }}" + user: "{{ __controller_credentials_item.user.username | default(__controller_credentials_item.user | default(('' if controller_configuration_credentials_enforce_defaults else omit), true)) }}" + team: "{{ __controller_credentials_item.team.name | default(__controller_credentials_item.team | default(('' if controller_configuration_credentials_enforce_defaults else omit), true)) }}" + update_secrets: "{{ __controller_credentials_item.update_secrets | default(true if controller_configuration_credentials_enforce_defaults else omit) }}" state: "{{ __controller_credentials_item.state | default(controller_state | default('present')) }}" # Role specific options diff --git a/roles/filetree_create/tasks/all.yml b/roles/filetree_create/tasks/all.yml index 8f9e6148b..d00f00e67 100644 --- a/roles/filetree_create/tasks/all.yml +++ b/roles/filetree_create/tasks/all.yml @@ -25,7 +25,7 @@ msg: "The organization {{ organization_filter }} has the ID {{ organization_id }}" - name: Include tasks (block) - when: "['all', 'labels', 'applications', 'instance_groups', 'settings', 'inventory', 'credentials', 'credential_types', 'notification_templates', 'users', 'teams', 'organizations', 'projects', 'execution_environments', 'job_templates', 'workflow_job_templates', 'workflow_job_template_nodes', 'schedules'] | intersect(input_tag) | length > 0" + when: "['all', 'labels', 'applications', 'instance_groups', 'settings', 'inventory', 'credentials', 'credential_types', 'notification_templates', 'users', 'teams', 'roles', 'organizations', 'projects', 'execution_environments', 'job_templates', 'workflow_job_templates', 'workflow_job_template_nodes', 'schedules'] | intersect(input_tag) | length > 0" block: - name: "Export Inventories and related Groups and Hosts" ansible.builtin.include_tasks: "inventory.yml" @@ -41,10 +41,10 @@ when: "'notification_templates' in input_tag or 'all' in input_tag" - name: "Export Users" ansible.builtin.include_tasks: "users.yml" - when: "'users' in input_tag or 'all' in input_tag" + when: "'users' in input_tag or 'roles' in input_tag or 'all' in input_tag" - name: "Export Teams" ansible.builtin.include_tasks: "teams.yml" - when: "'teams' in input_tag or 'all' in input_tag" + when: "'teams' in input_tag or 'roles' in input_tag or 'all' in input_tag" - name: "Export Organizations" ansible.builtin.include_tasks: "organizations.yml" when: "'organizations' in input_tag or 'all' in input_tag" diff --git a/roles/filetree_create/tasks/users.yml b/roles/filetree_create/tasks/users.yml index dc1e0de13..26d6bd538 100644 --- a/roles/filetree_create/tasks/users.yml +++ b/roles/filetree_create/tasks/users.yml @@ -9,7 +9,7 @@ - name: "Add the users the Organizations information" # noqa jinja[spacing] ansible.builtin.set_fact: - current_users: "{{ (current_users | default([])) + [user_lookvar_item | combine({'organizations': user_lookvar_item_organizations})] }}" + current_users: "{{ (current_users | default([])) + [user_lookvar_item | combine({'organizations': user_lookvar_item_organizations if (user_lookvar_item_organizations | length > 1) else ['ORGANIZATIONLESS']})] }}" vars: user_lookvar_item_organizations: "{{ query(controller_api_plugin, user_lookvar_item.related.organizations, host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs, diff --git a/roles/filetree_create/templates/current_credentials.j2 b/roles/filetree_create/templates/current_credentials.j2 index e9aeed9d9..1eed4841c 100644 --- a/roles/filetree_create/templates/current_credentials.j2 +++ b/roles/filetree_create/templates/current_credentials.j2 @@ -5,6 +5,8 @@ controller_credentials: credential_type: "{{ current_credentials_asset_value.summary_fields.credential_type.name }}" {% if current_credentials_asset_value.organization is defined and current_credentials_asset_value.organization is not none %} organization: "{{ current_credentials_asset_value.summary_fields.organization.name }}" +{% else %} + organization: "ORGANIZATIONLESS" {% endif %} inputs: {{ current_credentials_asset_value.inputs | to_nice_yaml(indent=2) | indent(width=6, first=True) | replace("$encrypted$", "\'\'") }} diff --git a/roles/object_diff/tasks/applications.yml b/roles/object_diff/tasks/applications.yml index 9651143dc..ad337a871 100644 --- a/roles/object_diff/tasks/applications.yml +++ b/roles/object_diff/tasks/applications.yml @@ -9,17 +9,17 @@ - name: "Get the API list of all Applications in Organization {{ orgs }}" ansible.builtin.set_fact: __controller_api_applications: "{{ query(controller_api_plugin, 'applications', - query_params={'organization': __controller_organization_id.id}, - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs, - return_all=true, max_objects=query_controller_api_max_objects) - }}" + query_params={'organization': __controller_organization_id.id}, + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs, + return_all=true, max_objects=query_controller_api_max_objects) + }}" - name: "Find the difference of Application between what is on the Controller versus CasC on SCM" ansible.builtin.set_fact: __applications_difference: "{{ query(controller_role_plugin, - api_list=__controller_api_applications, compare_list=controller_applications, - with_present=include_present_state, set_absent=true) - }}" + api_list=__controller_api_applications, compare_list=controller_applications, + with_present=include_present_state, set_absent=true) | flatten + }}" - name: "Set application's list to be configured" ansible.builtin.set_fact: diff --git a/roles/object_diff/tasks/credential_types.yml b/roles/object_diff/tasks/credential_types.yml index bae39645b..8b42e43de 100644 --- a/roles/object_diff/tasks/credential_types.yml +++ b/roles/object_diff/tasks/credential_types.yml @@ -23,8 +23,9 @@ - name: "Find the difference of Credential Types between what is on the Controller versus CasC on SCM" ansible.builtin.set_fact: __credential_types_difference: "{{ query(controller_role_plugin, - api_list=__controller_api_credential_types, compare_list=controller_credential_types, - with_present=include_present_state, set_absent=true) }}" + api_list=__controller_api_credential_types, compare_list=controller_credential_types, + with_present=include_present_state, set_absent=true) | flatten + }}" - name: "Set credential's list to be configured" ansible.builtin.set_fact: diff --git a/roles/object_diff/tasks/credentials.yml b/roles/object_diff/tasks/credentials.yml index fba26423a..8929bf44e 100644 --- a/roles/object_diff/tasks/credentials.yml +++ b/roles/object_diff/tasks/credentials.yml @@ -20,8 +20,8 @@ - name: "Find the difference of Credentials between what is on the Controller versus CasC on SCM" ansible.builtin.set_fact: __credentials_difference: "{{ query(controller_role_plugin, - api_list=__controller_api_credentials, compare_list=controller_credentials, - with_present=include_present_state, set_absent=true) + api_list=__controller_api_credentials, compare_list=controller_credentials, + with_present=include_present_state, set_absent=true) | flatten }}" - name: "Set credential's list to be configured" diff --git a/roles/object_diff/tasks/execution_environments.yml b/roles/object_diff/tasks/execution_environments.yml index 13dec4a9e..b6e0fb686 100644 --- a/roles/object_diff/tasks/execution_environments.yml +++ b/roles/object_diff/tasks/execution_environments.yml @@ -1,27 +1,30 @@ --- -- name: Get the organization ID - ansible.builtin.set_fact: - __controller_organization_id: "{{ lookup(controller_api_plugin, 'organizations', - query_params={'name': orgs}, - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) - }}" +- name: "Block to be executed only when connected against an AAP instance (not Tower)" + when: is_aap + block: + - name: Get the organization ID + ansible.builtin.set_fact: + __controller_organization_id: "{{ lookup(controller_api_plugin, 'organizations', + query_params={'name': orgs}, + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) + }}" -- name: "Get the API list of all Execution Environments in Organization {{ orgs }}" - ansible.builtin.set_fact: - __controller_api_execution_environments: "{{ query(controller_api_plugin, 'execution_environments', - query_params={'organization': __controller_organization_id.id}, - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs, - return_all=true, max_objects=query_controller_api_max_objects) - }}" + - name: "Get the API list of all Execution Environments in Organization {{ orgs }}" + ansible.builtin.set_fact: + __controller_api_execution_environments: "{{ query(controller_api_plugin, 'execution_environments', + query_params={'organization': __controller_organization_id.id}, + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs, + return_all=true, max_objects=query_controller_api_max_objects) + }}" -- name: "Find the difference of Execution Environment between what is on the Controller versus CasC on SCM" - ansible.builtin.set_fact: - __execution_environments_difference: "{{ query(controller_role_plugin, - api_list=__controller_api_execution_environments, compare_list=controller_execution_environments, - with_present=include_present_state, set_absent=true) - }}" + - name: "Find the difference of Execution Environment between what is on the Controller versus CasC on SCM" + ansible.builtin.set_fact: + __execution_environments_difference: "{{ query(controller_role_plugin, + api_list=__controller_api_execution_environments, compare_list=controller_execution_environments, + with_present=include_present_state, set_absent=true) | flatten + }}" -- name: "Set execution_environment's list to be configured" - ansible.builtin.set_fact: - controller_execution_environments: "{{ __execution_environments_difference }}" + - name: "Set execution_environment's list to be configured" + ansible.builtin.set_fact: + controller_execution_environments: "{{ __execution_environments_difference }}" ... diff --git a/roles/object_diff/tasks/groups.yml b/roles/object_diff/tasks/groups.yml index 9847179e7..81fd8041d 100644 --- a/roles/object_diff/tasks/groups.yml +++ b/roles/object_diff/tasks/groups.yml @@ -39,7 +39,7 @@ __groups_difference: "{{ query(controller_role_plugin, query_params={'summary_fields.inventory.organization_id': controller_organization_id.id}, api_list=__controller_api_groups, compare_list=controller_groups, - with_present=include_present_state, set_absent=true) + with_present=include_present_state, set_absent=true) | flatten }}" - name: "Set the inventory key at the correct place" diff --git a/roles/object_diff/tasks/hosts.yml b/roles/object_diff/tasks/hosts.yml index d5e9e4c6b..31d898c7d 100644 --- a/roles/object_diff/tasks/hosts.yml +++ b/roles/object_diff/tasks/hosts.yml @@ -39,7 +39,7 @@ __hosts_difference: "{{ query(controller_role_plugin, query_params={'summary_fields.inventory.organization_id': controller_organization_id.id}, api_list=__controller_api_hosts, compare_list=controller_hosts, - with_present=include_present_state, set_absent=true) + with_present=include_present_state, set_absent=true) | flatten }}" - name: "Set the inventory key at the correct place" diff --git a/roles/object_diff/tasks/instance_groups.yml b/roles/object_diff/tasks/instance_groups.yml index b1ff4ba26..cad212783 100644 --- a/roles/object_diff/tasks/instance_groups.yml +++ b/roles/object_diff/tasks/instance_groups.yml @@ -2,7 +2,7 @@ - name: "Get the current controller user to determine if it is super-admin" ansible.builtin.set_fact: __controller_api_current_user_check_is_admin: "{{ lookup(controller_api_plugin, 'me', - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) }}" - name: "Instance Group differences (block)" @@ -12,18 +12,18 @@ - name: "Get the API list of all instance_groups" ansible.builtin.set_fact: __controller_api_instance_groups: "{{ query(controller_api_plugin, 'instance_groups', - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs, - return_all=true, max_objects=query_controller_api_max_objects) - }}" + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs, + return_all=true, max_objects=query_controller_api_max_objects) + }}" - name: "Find the difference of Instance Groups between what is on the Controller versus CasC on SCM" ansible.builtin.set_fact: __instance_groups_difference: "{{ query(controller_role_plugin, - api_list=__controller_api_instance_groups, - compare_list=controller_instance_groups, - with_present=include_present_state, - set_absent=true) - }}" + api_list=__controller_api_instance_groups, + compare_list=controller_instance_groups, + with_present=include_present_state, + set_absent=true) | flatten + }}" - name: "Sets the difference of Instance Groups between what is on the Controller versus CasC on SCM" ansible.builtin.set_fact: diff --git a/roles/object_diff/tasks/inventories.yml b/roles/object_diff/tasks/inventories.yml index b1307428f..e407bf36b 100644 --- a/roles/object_diff/tasks/inventories.yml +++ b/roles/object_diff/tasks/inventories.yml @@ -19,8 +19,8 @@ - name: "Find the difference of Inventories between what is on the Controller versus CasC on SCM" ansible.builtin.set_fact: __inventories_difference: "{{ query(controller_role_plugin, - api_list=__controller_api_inventories, compare_list=controller_inventories, - with_present=include_present_state, set_absent=true) + api_list=__controller_api_inventories, compare_list=controller_inventories, + with_present=include_present_state, set_absent=true) | flatten }}" - name: "Set inventores' list to be configured" diff --git a/roles/object_diff/tasks/inventory_sources.yml b/roles/object_diff/tasks/inventory_sources.yml index 44cf6ef0b..f1cde6c25 100644 --- a/roles/object_diff/tasks/inventory_sources.yml +++ b/roles/object_diff/tasks/inventory_sources.yml @@ -19,9 +19,9 @@ - name: "Find the difference of Inventory Sources between what is on the Controller versus CasC on SCM" ansible.builtin.set_fact: __inventory_sources_difference: "{{ query(controller_role_plugin, - api_list=__controller_api_inventory_sources, - compare_list=controller_inventory_sources, - with_present=include_present_state, set_absent=true) + api_list=__controller_api_inventory_sources, + compare_list=controller_inventory_sources, + with_present=include_present_state, set_absent=true) | flatten }}" - name: "Set inventory_sources' list to be configured" diff --git a/roles/object_diff/tasks/job_templates.yml b/roles/object_diff/tasks/job_templates.yml index 00eeb351b..84b8fc577 100644 --- a/roles/object_diff/tasks/job_templates.yml +++ b/roles/object_diff/tasks/job_templates.yml @@ -2,8 +2,8 @@ - name: Get the organization ID ansible.builtin.set_fact: __controller_organization_id: "{{ lookup(controller_api_plugin, 'organizations', - query_params={'name': orgs}, - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) + query_params={'name': orgs}, + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) }}" no_log: "{{ controller_configuration_object_diff_secure_logging }}" @@ -19,8 +19,8 @@ - name: "Find the difference of Job Templates between what is on the Controller versus CasC on SCM" ansible.builtin.set_fact: __job_templates_difference: "{{ query(controller_role_plugin, - api_list=__controller_api_job_templates, compare_list=controller_templates, - with_present=include_present_state, set_absent=true) + api_list=__controller_api_job_templates, compare_list=controller_templates, + with_present=include_present_state, set_absent=true) | flatten }}" - name: "Set job_template's list to be configured" diff --git a/roles/object_diff/tasks/main.yml b/roles/object_diff/tasks/main.yml index 12d316a54..1ffcb7f84 100644 --- a/roles/object_diff/tasks/main.yml +++ b/roles/object_diff/tasks/main.yml @@ -64,7 +64,8 @@ args: apply: tags: "{{ __task_diff.tags }}" - tags: always + tags: + - always loop: "{{ controller_configuration_object_diff_tasks }}" loop_control: loop_var: __task_diff diff --git a/roles/object_diff/tasks/notification_templates.yml b/roles/object_diff/tasks/notification_templates.yml index 9af7122a5..4308c6fd0 100644 --- a/roles/object_diff/tasks/notification_templates.yml +++ b/roles/object_diff/tasks/notification_templates.yml @@ -2,24 +2,24 @@ - name: Get the organization ID ansible.builtin.set_fact: __controller_organization_id: "{{ lookup(controller_api_plugin, 'organizations', - query_params={'name': orgs}, - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) + query_params={'name': orgs}, + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) }}" - name: "Get the API list of all Notification Templates in Organization {{ orgs }}" ansible.builtin.set_fact: __controller_api_notification_templates: "{{ query(controller_api_plugin, 'notification_templates', - query_params={'organization': __controller_organization_id.id}, - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs, - return_all=true, max_objects=query_controller_api_max_objects) - }}" + query_params={'organization': __controller_organization_id.id}, + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs, + return_all=true, max_objects=query_controller_api_max_objects) + }}" - name: "Find the difference of Notification Template between what is on the Controller versus CasC on SCM" ansible.builtin.set_fact: __notification_templates_difference: "{{ query(controller_role_plugin, - api_list=__controller_api_notification_templates, compare_list=controller_notifications, - with_present=include_present_state, set_absent=true) - }}" + api_list=__controller_api_notification_templates, compare_list=controller_notifications, + with_present=include_present_state, set_absent=true) | flatten + }}" - name: "Set notification_template's list to be configured" ansible.builtin.set_fact: diff --git a/roles/object_diff/tasks/organizations.yml b/roles/object_diff/tasks/organizations.yml index 3da346712..7497eb81e 100644 --- a/roles/object_diff/tasks/organizations.yml +++ b/roles/object_diff/tasks/organizations.yml @@ -21,8 +21,8 @@ - name: "Find the difference of Organizations between what is on the Controller versus curated list." ansible.builtin.set_fact: __organizations_difference: "{{ query(controller_role_plugin, - api_list=__controller_api_organizations, compare_list=controller_organizations, - with_present=include_present_state, set_absent=true) + api_list=__controller_api_organizations, compare_list=controller_organizations, + with_present=include_present_state, set_absent=true) | flatten }}" - name: "Set list __list_empty_orgs when protect_not_empty_orgs" diff --git a/roles/object_diff/tasks/projects.yml b/roles/object_diff/tasks/projects.yml index cc48a8b60..b9e338055 100644 --- a/roles/object_diff/tasks/projects.yml +++ b/roles/object_diff/tasks/projects.yml @@ -2,25 +2,25 @@ - name: Get the organization ID ansible.builtin.set_fact: __controller_organization_id: "{{ lookup(controller_api_plugin, 'organizations', - query_params={'name': orgs}, - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) + query_params={'name': orgs}, + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) }}" no_log: "{{ controller_configuration_object_diff_secure_logging }}" - name: "Get the API list of all Projects in Organization {{ orgs }}" ansible.builtin.set_fact: __controller_api_projects: "{{ query(controller_api_plugin, 'projects', - query_params={'organization': __controller_organization_id.id}, - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs, - return_all=true, max_objects=query_controller_api_max_objects) + query_params={'organization': __controller_organization_id.id}, + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs, + return_all=true, max_objects=query_controller_api_max_objects) }}" no_log: "{{ controller_configuration_object_diff_secure_logging }}" - name: "Find the difference of Project between what is on the Controller versus CasC on SCM" ansible.builtin.set_fact: __projects_difference: "{{ query(controller_role_plugin, - api_list=__controller_api_projects, compare_list=controller_projects, - with_present=include_present_state, set_absent=true) + api_list=__controller_api_projects, compare_list=controller_projects, + with_present=include_present_state, set_absent=true) | flatten }}" - name: "Set project's list to be configured" diff --git a/roles/object_diff/tasks/roles.yml b/roles/object_diff/tasks/roles.yml index ba706b62b..cf77f7f91 100644 --- a/roles/object_diff/tasks/roles.yml +++ b/roles/object_diff/tasks/roles.yml @@ -2,13 +2,17 @@ - name: "Get the current controller user to determine if it is super-admin" ansible.builtin.set_fact: __controller_api_current_user_check_is_admin: "{{ lookup(controller_api_plugin, 'me', - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) }}" no_log: "{{ controller_configuration_object_diff_secure_logging }}" + tags: + - always - name: "Role differences (block)" when: - __controller_api_current_user_check_is_admin.is_superuser + tags: + - always block: - name: "Get the API list of all roles" # noqa jinja[spacing] @@ -53,8 +57,8 @@ - name: "Find the difference of Roles between what is on the Controller versus CasC on SCM" ansible.builtin.set_fact: __roles_difference: "{{ query(controller_role_plugin, - api_list=__full_controller_api_roles, compare_list=controller_roles, - with_present=include_present_state, set_absent=true) + api_list=__full_controller_api_roles, compare_list=controller_roles, + with_present=include_present_state, set_absent=true) | flatten }}" - name: "Sets differences between Roles what is on the Controller versus CasC on SCM" diff --git a/roles/object_diff/tasks/schedules.yml b/roles/object_diff/tasks/schedules.yml index 7eb2dc271..8deffd283 100644 --- a/roles/object_diff/tasks/schedules.yml +++ b/roles/object_diff/tasks/schedules.yml @@ -2,8 +2,8 @@ - name: Get the organization ID ansible.builtin.set_fact: __controller_organization_id: "{{ lookup(controller_api_plugin, 'organizations', - query_params={'name': orgs}, - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) + query_params={'name': orgs}, + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) }}" - name: "Get the API list of all WF and Job Templates in Organization {{ orgs }}" @@ -14,10 +14,10 @@ return_all=true, max_objects=query_controller_api_max_objects) }}" __controller_api_workflow_job_templates: "{{ query(controller_api_plugin, 'workflow_job_templates', - query_params={'organization': __controller_organization_id.id}, - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs, - return_all=true, max_objects=query_controller_api_max_objects) - }}" + query_params={'organization': __controller_organization_id.id}, + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs, + return_all=true, max_objects=query_controller_api_max_objects) + }}" - name: "Get WF and JT IDs" # noqa jinja[spacing] @@ -27,9 +27,9 @@ - name: "Get the API list of all Schedules" ansible.builtin.set_fact: __controller_api_schedules_prefilter: "{{ query(controller_api_plugin, 'schedules', - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs, - return_all=true, max_objects=query_controller_api_max_objects) - }}" + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs, + return_all=true, max_objects=query_controller_api_max_objects) + }}" - name: "Get the API list of all Schedules in Organization {{ orgs }}" ansible.builtin.set_fact: @@ -39,8 +39,8 @@ ansible.builtin.set_fact: __schedules_difference: "{{ query(controller_role_plugin, api_list=__controller_api_schedules, compare_list=controller_schedules, - with_present=include_present_state, set_absent=true) - }}" + with_present=include_present_state, set_absent=true) | flatten + }}" - name: "Set schedule's list to be configured" ansible.builtin.set_fact: diff --git a/roles/object_diff/tasks/teams.yml b/roles/object_diff/tasks/teams.yml index 36221d368..70a7d5b5f 100644 --- a/roles/object_diff/tasks/teams.yml +++ b/roles/object_diff/tasks/teams.yml @@ -2,7 +2,7 @@ - name: "Get the current controller user to determine if it is super-admin" ansible.builtin.set_fact: __controller_api_current_user_check_is_admin: "{{ lookup(controller_api_plugin, 'me', - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) }}" no_log: "{{ controller_configuration_object_diff_secure_logging }}" @@ -13,8 +13,8 @@ - name: Get the organization ID ansible.builtin.set_fact: __controller_organization_id: "{{ lookup(controller_api_plugin, 'organizations', - query_params={'name': orgs}, - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) + query_params={'name': orgs}, + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) }}" no_log: "{{ controller_configuration_object_diff_secure_logging }}" @@ -30,10 +30,10 @@ - name: "Find the difference of Teams between what is on the Controller versus CasC on SCM" ansible.builtin.set_fact: __teams_difference: "{{ query(controller_role_plugin, - api_list=__controller_api_teams, - compare_list=controller_teams, - with_present=include_present_state, - set_absent=true) + api_list=__controller_api_teams, + compare_list=controller_teams, + with_present=include_present_state, + set_absent=true) | flatten }}" - name: "Sets the difference of Teams between what is on the Controller versus CasC on SCM" diff --git a/roles/object_diff/tasks/user_accounts.yml b/roles/object_diff/tasks/user_accounts.yml index e4dc4ef27..b8109dd66 100644 --- a/roles/object_diff/tasks/user_accounts.yml +++ b/roles/object_diff/tasks/user_accounts.yml @@ -3,7 +3,7 @@ - name: "Get the current controller user to determine if it is super-admin" ansible.builtin.set_fact: __controller_api_current_user_check_is_admin: "{{ lookup(controller_api_plugin, 'me', - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) }}" no_log: "{{ controller_configuration_object_diff_secure_logging }}" @@ -36,8 +36,8 @@ - name: "Find the difference of User Accounts between what is on the Controller versus CasC on SCM" ansible.builtin.set_fact: __user_accounts_difference: "{{ query(controller_role_plugin, - api_list=__controller_api_user_accounts, compare_list=controller_user_accounts, - with_present=include_present_state, set_absent=true) + api_list=__controller_api_user_accounts, compare_list=controller_user_accounts, + with_present=include_present_state, set_absent=true) | flatten }}" no_log: "{{ controller_configuration_object_diff_secure_logging }}" diff --git a/roles/object_diff/tasks/workflow_job_templates.yml b/roles/object_diff/tasks/workflow_job_templates.yml index 2609e9ba0..cf7f05ffa 100644 --- a/roles/object_diff/tasks/workflow_job_templates.yml +++ b/roles/object_diff/tasks/workflow_job_templates.yml @@ -2,26 +2,26 @@ - name: Get the organization ID ansible.builtin.set_fact: __controller_organization_id: "{{ lookup(controller_api_plugin, 'organizations', - query_params={'name': orgs}, - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) + query_params={'name': orgs}, + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs) }}" no_log: "{{ controller_configuration_object_diff_secure_logging }}" - name: "Get the API list of all Workflow Job Templates" ansible.builtin.set_fact: __controller_api_workflow_job_templates: "{{ query(controller_api_plugin, 'workflow_job_templates', - query_params={'organization': __controller_organization_id.id}, - host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs, - return_all=true, max_objects=query_controller_api_max_objects) + query_params={'organization': __controller_organization_id.id}, + host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs, + return_all=true, max_objects=query_controller_api_max_objects) }}" no_log: "{{ controller_configuration_object_diff_secure_logging }}" - name: "Find the difference of Workflow Job Templates between what is on the Controller versus CasC on SCM" ansible.builtin.set_fact: __workflow_job_templates_difference: "{{ query(controller_role_plugin, - api_list=__controller_api_workflow_job_templates, - compare_list=controller_workflows, - with_present=include_present_state, set_absent=true) + api_list=__controller_api_workflow_job_templates, + compare_list=controller_workflows, + with_present=include_present_state, set_absent=true) | flatten }}" - name: "Set job_template's list to be configured" diff --git a/roles/object_diff/tests/.gitignore b/roles/object_diff/tests/.gitignore new file mode 100644 index 000000000..9bcaba703 --- /dev/null +++ b/roles/object_diff/tests/.gitignore @@ -0,0 +1,3 @@ +collections +.vault_password_file +vault.yml diff --git a/roles/object_diff/tests/drop_diff.yml b/roles/object_diff/tests/drop_diff.yml index d76a29a71..46e371e7c 100644 --- a/roles/object_diff/tests/drop_diff.yml +++ b/roles/object_diff/tests/drop_diff.yml @@ -40,6 +40,7 @@ controller_configuration_dispatcher_roles: - {role: workflow_job_templates, var: controller_workflows, tags: workflow_job_templates} - {role: job_templates, var: controller_templates, tags: job_templates} + - {role: roles, var: controller_roles, tags: roles} - {role: teams, var: controller_teams, tags: teams} - {role: users, var: controller_user_accounts, tags: users} - {role: groups, var: controller_groups, tags: inventories} @@ -62,4 +63,6 @@ validate_certs: "{{ controller_validate_certs }}" status_code: 204 when: controller_oauthtoken_url is defined + tags: + - always ... diff --git a/roles/object_diff/tests/object_diff.yml b/roles/object_diff/tests/object_diff.yml index b6cd9efa7..bd2089c66 100644 --- a/roles/object_diff/tests/object_diff.yml +++ b/roles/object_diff/tests/object_diff.yml @@ -46,4 +46,6 @@ validate_certs: "{{ controller_validate_certs }}" status_code: 204 when: controller_oauthtoken_url is defined + tags: + - always ... diff --git a/tests/configs/differential_items.yml b/tests/configs/differential_items.yml index 217603386..770b8854c 100644 --- a/tests/configs/differential_items.yml +++ b/tests/configs/differential_items.yml @@ -45,20 +45,20 @@ differential_items: organization: Default scm_type: git scm_url: https://github.com/ansible/tower-example.git - state: present + # state: present - description: ansible-examples name: Test Inventory source project organization: Default scm_type: git scm_url: https://github.com/ansible/ansible-examples.git - state: present + # state: present - credential: gitlab-personal-access-token for satqe_auto_droid description: ansible-examples name: Test Inventory source project with credential organization: Default scm_type: git scm_url: https://github.com/ansible/ansible-examples.git - state: present + # state: present wait: false - description: Test Project 1 name: Test Project @@ -67,7 +67,7 @@ differential_items: scm_clean: true scm_type: git scm_url: https://github.com/ansible/tower-example.git - state: present + # state: present - name: Demo Project organization: Default state: absent @@ -77,6 +77,9 @@ differential_items: - name: "cyberark" credential_type: CyberArk Central Credential Provider Lookup organization: Default + - name: Demo Credential + organization: Default + credential_type: "Machine" expected_test_result: - name: gitlab organization: Default diff --git a/tests/configure_controller.yml b/tests/configure_controller.yml index 9d59e1d85..31d52fdbc 100644 --- a/tests/configure_controller.yml +++ b/tests/configure_controller.yml @@ -48,7 +48,7 @@ - name: Wait for Controller to come up ansible.builtin.uri: - url: "https://{{ controller_hostname }}/api/v2/ping" + url: "https://{{ controller_hostname }}/api/v2/ping/" status_code: 200 validate_certs: "{{ controller_validate_certs }}" register: result diff --git a/tests/tasks/differential.yml b/tests/tasks/differential.yml index 5fd698c7c..b48b9f0d4 100644 --- a/tests/tasks/differential.yml +++ b/tests/tasks/differential.yml @@ -5,7 +5,7 @@ - name: "Find the difference between what is on the Controller versus curated list of {{ differential_item.name }}" ansible.builtin.set_fact: - set_absent_diff: "{{ query('controller_object_diff', api_list=controller_api_results, compare_list=differential_item.differential_test_items, with_present=differential_item.with_present) }}" + set_absent_diff: "{{ query('controller_object_diff', api_list=controller_api_results, compare_list=differential_item.differential_test_items, with_present=differential_item.with_present) | flatten }}" - name: Display set_absent_diff ansible.builtin.debug: @@ -18,7 +18,7 @@ - name: "Assert that the expected results match for {{ differential_item.name }}" ansible.builtin.assert: that: - - set_absent_diff == differential_item.expected_test_result + - set_absent_diff == differential_item.expected_test_result - name: Run differential applications ansible.builtin.include_role: