From 0983bd8dc048431924421156fedd389bb6d047f9 Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Tue, 23 Aug 2022 14:13:06 -0400 Subject: [PATCH 01/14] Adding prevent_instance_group_fallback --- awx/api/serializers.py | 2 + awx/main/models/inventory.py | 7 + awx/main/models/jobs.py | 28 +- .../Inventory/shared/Inventory.helptext.js | 1 + .../screens/Inventory/shared/InventoryForm.js | 13 +- .../Inventory/shared/data.inventory.json | 133 +++--- .../Template/shared/JobTemplate.helptext.js | 2 + .../Template/shared/JobTemplateForm.js | 8 + .../Template/shared/data.job_template.json | 383 +++++++++--------- 9 files changed, 308 insertions(+), 269 deletions(-) diff --git a/awx/api/serializers.py b/awx/api/serializers.py index eaad921eb2..d5bb2cfe6b 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -1680,6 +1680,7 @@ class InventorySerializer(LabelsListMixin, BaseSerializerWithVariables): 'total_inventory_sources', 'inventory_sources_with_failures', 'pending_deletion', + 'prevent_instance_group_fallback', ) def get_related(self, obj): @@ -2937,6 +2938,7 @@ class JobTemplateSerializer(JobTemplateMixin, UnifiedJobTemplateSerializer, JobO 'job_slice_count', 'webhook_service', 'webhook_credential', + 'prevent_instance_group_fallback', ) read_only_fields = ('*', 'custom_virtualenv') diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 4a90ad5bad..8c9a9e6256 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -175,6 +175,13 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin, RelatedJobsMixin): related_name='inventory_labels', help_text=_('Labels associated with this inventory.'), ) + prevent_instance_group_fallback = models.BooleanField( + default=False, + help_text=( + "If enabled, the job template will prevent adding any inventory or organization " + "instance groups to the list of preferred instances groups to run on." + ), + ) def get_absolute_url(self, request=None): return reverse('api:inventory_detail', kwargs={'pk': self.pk}, request=request) diff --git a/awx/main/models/jobs.py b/awx/main/models/jobs.py index b954c76e35..a9c6cf6907 100644 --- a/awx/main/models/jobs.py +++ b/awx/main/models/jobs.py @@ -274,6 +274,13 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour 'admin_role', ], ) + prevent_instance_group_fallback = models.BooleanField( + default=False, + help_text=( + "If enabled, the job template will prevent adding any inventory or organization " + "instance groups to the list of preferred instances groups to run on." + ), + ) @classmethod def _get_unified_job_class(cls): @@ -797,19 +804,14 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin, TaskMana def preferred_instance_groups(self): # If the user specified instance groups those will be handled by the unified_job.create_unified_job # This function handles only the defaults for a template w/o user specification - if self.organization is not None: - organization_groups = [x for x in self.organization.instance_groups.all()] - else: - organization_groups = [] - if self.inventory is not None: - inventory_groups = [x for x in self.inventory.instance_groups.all()] - else: - inventory_groups = [] - if self.job_template is not None: - template_groups = [x for x in self.job_template.instance_groups.all()] - else: - template_groups = [] - selected_groups = template_groups + inventory_groups + organization_groups + selected_groups = [] + for obj_type in ['job_template', 'inventory', 'organization']: + if getattr(self, obj_type) is not None: + for instance_group in getattr(self, obj_type).instance_groups.all(): + selected_groups.append(instance_group) + if getattr(getattr(self, obj_type), 'prevent_instance_group_fallback', False): + logger.error("Breaking in preferred instance group at {}".format(obj_type)) + break if not selected_groups: return self.global_instance_groups return selected_groups diff --git a/awx/ui/src/screens/Inventory/shared/Inventory.helptext.js b/awx/ui/src/screens/Inventory/shared/Inventory.helptext.js index 19636128f0..564add096d 100644 --- a/awx/ui/src/screens/Inventory/shared/Inventory.helptext.js +++ b/awx/ui/src/screens/Inventory/shared/Inventory.helptext.js @@ -191,6 +191,7 @@ const getInventoryHelpTextStrings = () => ({ sourcePath: t`The inventory file to be synced by this source. You can select from the dropdown or enter a file within the input.`, + preventInstanceGroupFallback: t`If enabled, the job template will prevent adding any inventory or organization instance groups to the list of preferred instances groups to run on.`, }); export default getInventoryHelpTextStrings; diff --git a/awx/ui/src/screens/Inventory/shared/InventoryForm.js b/awx/ui/src/screens/Inventory/shared/InventoryForm.js index e29ffcdfa6..30c166c73d 100644 --- a/awx/ui/src/screens/Inventory/shared/InventoryForm.js +++ b/awx/ui/src/screens/Inventory/shared/InventoryForm.js @@ -5,7 +5,10 @@ import { func, shape } from 'prop-types'; import { Form, FormGroup } from '@patternfly/react-core'; import { VariablesField } from 'components/CodeEditor'; import Popover from 'components/Popover'; -import FormField, { FormSubmitError } from 'components/FormField'; +import FormField, { + CheckboxField, + FormSubmitError, +} from 'components/FormField'; import FormActionGroup from 'components/FormActionGroup'; import { required } from 'util/validators'; import LabelSelect from 'components/LabelSelect'; @@ -71,6 +74,12 @@ function InventoryFormFields({ inventory }) { }} fieldName="instanceGroups" /> + ({ privilegeEscalation: t`If enabled, run this playbook as an administrator.`, enableWebhook: t`Enable webhook for this template.`, concurrentJobs: t`If enabled, simultaneous runs of this job template will be allowed.`, + preventInstanceGroupFallback: t`If enabled, the job template will prevent adding any inventory or organization instance groups to the list of preferred instances groups to run on.`, enableFactStorage: t`If enabled, this will store gathered facts so they can be viewed at the host level. Facts are persisted and injected into the fact cache at runtime.`, enabledOptions: ( <> @@ -38,6 +39,7 @@ const jtHelpTextStrings = () => ({

{t`Privilege escalation: If enabled, run this playbook as an administrator.`}

{t`Provisioning callbacks: Enables creation of a provisioning callback URL. Using the URL a host can contact Ansible AWX and request a configuration update using this job template.`}

{t`Webhooks: Enable webhook for this template.`}

+

{t`Prevent Instance Group Fallback: If enabled, the job template will prevent adding any inventory or organization instance groups to the list of preferred instances groups to run on.`}

), forks: ( diff --git a/awx/ui/src/screens/Template/shared/JobTemplateForm.js b/awx/ui/src/screens/Template/shared/JobTemplateForm.js index a82aaa8ad3..7621601e9e 100644 --- a/awx/ui/src/screens/Template/shared/JobTemplateForm.js +++ b/awx/ui/src/screens/Template/shared/JobTemplateForm.js @@ -597,6 +597,12 @@ function JobTemplateForm({ label={t`Enable Fact Storage`} tooltip={helpText.enableFactStorage} /> +
@@ -731,6 +737,8 @@ const FormikApp = withFormik({ limit: template.limit || '', name: template.name || '', playbook: template.playbook || '', + prevent_instance_group_fallback: + template.prevent_instance_group_fallback || false, project: summary_fields?.project || projectValues || null, scm_branch: template.scm_branch || '', skip_tags: template.skip_tags || '', diff --git a/awx/ui/src/screens/Template/shared/data.job_template.json b/awx/ui/src/screens/Template/shared/data.job_template.json index 4d4eb77af1..3c57d0143c 100644 --- a/awx/ui/src/screens/Template/shared/data.job_template.json +++ b/awx/ui/src/screens/Template/shared/data.job_template.json @@ -1,194 +1,199 @@ { - "id": 7, - "type": "job_template", - "url": "/api/v2/job_templates/7/", - "related": { - "named_url": "/api/v2/job_templates/Mike's JT/", - "created_by": "/api/v2/users/1/", - "modified_by": "/api/v2/users/1/", - "labels": "/api/v2/job_templates/7/labels/", - "inventory": "/api/v2/inventories/1/", - "project": "/api/v2/projects/6/", - "credentials": "/api/v2/job_templates/7/credentials/", - "last_job": "/api/v2/jobs/12/", - "jobs": "/api/v2/job_templates/7/jobs/", - "schedules": "/api/v2/job_templates/7/schedules/", - "activity_stream": "/api/v2/job_templates/7/activity_stream/", - "launch": "/api/v2/job_templates/7/launch/", - "notification_templates_started": "/api/v2/job_templates/7/notification_templates_started/", - "notification_templates_success": "/api/v2/job_templates/7/notification_templates_success/", - "notification_templates_error": "/api/v2/job_templates/7/notification_templates_error/", - "access_list": "/api/v2/job_templates/7/access_list/", - "survey_spec": "/api/v2/job_templates/7/survey_spec/", - "object_roles": "/api/v2/job_templates/7/object_roles/", - "instance_groups": "/api/v2/job_templates/7/instance_groups/", - "slice_workflow_jobs": "/api/v2/job_templates/7/slice_workflow_jobs/", - "copy": "/api/v2/job_templates/7/copy/", - "webhook_receiver": "/api/v2/job_templates/7/github/", - "webhook_key": "/api/v2/job_templates/7/webhook_key/" + "id": 7, + "type": "job_template", + "url": "/api/v2/job_templates/7/", + "related": { + "named_url": "/api/v2/job_templates/Mike's JT/", + "created_by": "/api/v2/users/1/", + "modified_by": "/api/v2/users/1/", + "labels": "/api/v2/job_templates/7/labels/", + "inventory": "/api/v2/inventories/1/", + "project": "/api/v2/projects/6/", + "credentials": "/api/v2/job_templates/7/credentials/", + "last_job": "/api/v2/jobs/12/", + "jobs": "/api/v2/job_templates/7/jobs/", + "schedules": "/api/v2/job_templates/7/schedules/", + "activity_stream": "/api/v2/job_templates/7/activity_stream/", + "launch": "/api/v2/job_templates/7/launch/", + "notification_templates_started": "/api/v2/job_templates/7/notification_templates_started/", + "notification_templates_success": "/api/v2/job_templates/7/notification_templates_success/", + "notification_templates_error": "/api/v2/job_templates/7/notification_templates_error/", + "access_list": "/api/v2/job_templates/7/access_list/", + "survey_spec": "/api/v2/job_templates/7/survey_spec/", + "object_roles": "/api/v2/job_templates/7/object_roles/", + "instance_groups": "/api/v2/job_templates/7/instance_groups/", + "slice_workflow_jobs": "/api/v2/job_templates/7/slice_workflow_jobs/", + "copy": "/api/v2/job_templates/7/copy/", + "webhook_receiver": "/api/v2/job_templates/7/github/", + "webhook_key": "/api/v2/job_templates/7/webhook_key/" + }, + "summary_fields": { + "inventory": { + "id": 1, + "name": "Mike's Inventory", + "description": "", + "has_active_failures": false, + "total_hosts": 1, + "hosts_with_active_failures": 0, + "total_groups": 0, + "groups_with_active_failures": 0, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "organization_id": 1, + "kind": "" }, - "summary_fields": { - "inventory": { - "id": 1, - "name": "Mike's Inventory", - "description": "", - "has_active_failures": false, - "total_hosts": 1, - "hosts_with_active_failures": 0, - "total_groups": 0, - "groups_with_active_failures": 0, - "has_inventory_sources": false, - "total_inventory_sources": 0, - "inventory_sources_with_failures": 0, - "organization_id": 1, - "kind": "" - }, - "project": { - "id": 6, - "name": "Mike's Project", - "description": "", - "status": "successful", - "scm_type": "git" - }, - "last_job": { - "id": 12, - "name": "Mike's JT", - "description": "", - "finished": "2019-10-01T14:34:35.142483Z", - "status": "successful", - "failed": false - }, - "last_update": { - "id": 12, - "name": "Mike's JT", - "description": "", - "status": "successful", - "failed": false - }, - "created_by": { - "id": 1, - "username": "admin", - "first_name": "", - "last_name": "" - }, - "modified_by": { - "id": 1, - "username": "admin", - "first_name": "", - "last_name": "" - }, - "object_roles": { - "admin_role": { - "description": "Can manage all aspects of the job template", - "name": "Admin", - "id": 24 - }, - "execute_role": { - "description": "May run the job template", - "name": "Execute", - "id": 25 - }, - "read_role": { - "description": "May view settings for the job template", - "name": "Read", - "id": 26 - } - }, - "user_capabilities": { - "edit": true, - "delete": true, - "start": true, - "schedule": true, - "copy": true - }, - "labels": { - "count": 1, - "results": [{ - "id": 91, - "name": "L_91o2" - }] - }, - "survey": { - "title": "", - "description": "" - }, - "recent_jobs": [{ - "id": 12, - "status": "successful", - "finished": "2019-10-01T14:34:35.142483Z", - "type": "job" - }], - "credentials": [{ - "id": 1, - "kind": "ssh", - "name": "Credential 1" - }, - { - "id": 2, - "kind": "awx", - "name": "Credential 2" - } - ], - "webhook_credential": { - "id": "1", - "name": "Webhook Credential" - - }, - "execution_environment": { - "id": 1, - "name": "Default EE", - "description": "", - "image": "quay.io/ansible/awx-ee" - }, - "resolved_environment": { - "id": 1, - "name": "Default EE", - "description": "", - "image": "quay.io/ansible/awx-ee" + "project": { + "id": 6, + "name": "Mike's Project", + "description": "", + "status": "successful", + "scm_type": "git" + }, + "last_job": { + "id": 12, + "name": "Mike's JT", + "description": "", + "finished": "2019-10-01T14:34:35.142483Z", + "status": "successful", + "failed": false + }, + "last_update": { + "id": 12, + "name": "Mike's JT", + "description": "", + "status": "successful", + "failed": false + }, + "created_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "modified_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "object_roles": { + "admin_role": { + "description": "Can manage all aspects of the job template", + "name": "Admin", + "id": 24 + }, + "execute_role": { + "description": "May run the job template", + "name": "Execute", + "id": 25 + }, + "read_role": { + "description": "May view settings for the job template", + "name": "Read", + "id": 26 + } + }, + "user_capabilities": { + "edit": true, + "delete": true, + "start": true, + "schedule": true, + "copy": true + }, + "labels": { + "count": 1, + "results": [ + { + "id": 91, + "name": "L_91o2" } + ] }, - "created": "2019-09-30T16:18:34.564820Z", - "modified": "2019-10-01T14:47:31.818431Z", - "name": "Mike's JT", - "description": "", - "job_type": "run", - "inventory": 1, - "project": 6, - "playbook": "ping.yml", - "scm_branch": "Foo branch", - "forks": 0, - "limit": "", - "verbosity": 0, - "extra_vars": "", - "job_tags": "T_100,T_200", - "force_handlers": false, - "skip_tags": "S_100,S_200", - "start_at_task": "", - "timeout": 0, - "use_fact_cache": true, - "last_job_run": "2019-10-01T14:34:35.142483Z", - "last_job_failed": false, - "next_job_run": null, - "status": "successful", - "host_config_key": "", - "ask_scm_branch_on_launch": false, - "ask_diff_mode_on_launch": false, - "ask_variables_on_launch": false, - "ask_limit_on_launch": false, - "ask_tags_on_launch": false, - "ask_skip_tags_on_launch": false, - "ask_job_type_on_launch": false, - "ask_verbosity_on_launch": false, - "ask_inventory_on_launch": false, - "ask_credential_on_launch": false, - "survey_enabled": true, - "become_enabled": false, - "diff_mode": false, - "allow_simultaneous": false, - "custom_virtualenv": null, - "job_slice_count": 1, - "webhook_credential": 1, - "webhook_key": "asertdyuhjkhgfd234567kjgfds", - "webhook_service": "github", - "execution_environment": 1 + "survey": { + "title": "", + "description": "" + }, + "recent_jobs": [ + { + "id": 12, + "status": "successful", + "finished": "2019-10-01T14:34:35.142483Z", + "type": "job" + } + ], + "credentials": [ + { + "id": 1, + "kind": "ssh", + "name": "Credential 1" + }, + { + "id": 2, + "kind": "awx", + "name": "Credential 2" + } + ], + "webhook_credential": { + "id": "1", + "name": "Webhook Credential" + }, + "execution_environment": { + "id": 1, + "name": "Default EE", + "description": "", + "image": "quay.io/ansible/awx-ee" + }, + "resolved_environment": { + "id": 1, + "name": "Default EE", + "description": "", + "image": "quay.io/ansible/awx-ee" + } + }, + "created": "2019-09-30T16:18:34.564820Z", + "modified": "2019-10-01T14:47:31.818431Z", + "name": "Mike's JT", + "description": "", + "job_type": "run", + "inventory": 1, + "project": 6, + "playbook": "ping.yml", + "scm_branch": "Foo branch", + "forks": 0, + "limit": "", + "verbosity": 0, + "extra_vars": "", + "job_tags": "T_100,T_200", + "force_handlers": false, + "skip_tags": "S_100,S_200", + "start_at_task": "", + "timeout": 0, + "use_fact_cache": true, + "last_job_run": "2019-10-01T14:34:35.142483Z", + "last_job_failed": false, + "next_job_run": null, + "status": "successful", + "host_config_key": "", + "ask_scm_branch_on_launch": false, + "ask_diff_mode_on_launch": false, + "ask_variables_on_launch": false, + "ask_limit_on_launch": false, + "ask_tags_on_launch": false, + "ask_skip_tags_on_launch": false, + "ask_job_type_on_launch": false, + "ask_verbosity_on_launch": false, + "ask_inventory_on_launch": false, + "ask_credential_on_launch": false, + "survey_enabled": true, + "become_enabled": false, + "diff_mode": false, + "allow_simultaneous": false, + "custom_virtualenv": null, + "job_slice_count": 1, + "webhook_credential": 1, + "webhook_key": "asertdyuhjkhgfd234567kjgfds", + "webhook_service": "github", + "execution_environment": 1, + "prevent_instance_group_fallback": false } From a85268f74a4b20726ce95503b9b0c6239df148d9 Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Fri, 9 Sep 2022 12:18:31 -0400 Subject: [PATCH 02/14] Fixing inventoy help text --- awx/main/models/inventory.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 8c9a9e6256..fdf3272f99 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -178,8 +178,9 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin, RelatedJobsMixin): prevent_instance_group_fallback = models.BooleanField( default=False, help_text=( - "If enabled, the job template will prevent adding any inventory or organization " - "instance groups to the list of preferred instances groups to run on." + "If enabled, the inventory will prevent adding any organization " + "instance groups to the list of preferred instances groups to run " + "associated job templates on." ), ) From 0f675cd37557dbf698af41b2a9788710265bde88 Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Fri, 9 Sep 2022 12:33:08 -0400 Subject: [PATCH 03/14] Updating modules for prevent_instance_group_fallback --- .../0168_prevent_instance_fallback.py | 29 +++++++++++++++++++ awx_collection/plugins/modules/inventory.py | 8 +++++ .../plugins/modules/job_template.py | 6 ++++ 3 files changed, 43 insertions(+) create mode 100644 awx/main/migrations/0168_prevent_instance_fallback.py diff --git a/awx/main/migrations/0168_prevent_instance_fallback.py b/awx/main/migrations/0168_prevent_instance_fallback.py new file mode 100644 index 0000000000..a041582d2c --- /dev/null +++ b/awx/main/migrations/0168_prevent_instance_fallback.py @@ -0,0 +1,29 @@ +# Generated by Django 3.2.13 on 2022-09-09 17:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0167_project_signature_validation_credential'), + ] + + operations = [ + migrations.AddField( + model_name='inventory', + name='prevent_instance_group_fallback', + field=models.BooleanField( + default=False, + help_text='If enabled, the inventory will prevent adding any organization instance groups to the list of preferred instances groups to run associated job templates on.', + ), + ), + migrations.AddField( + model_name='jobtemplate', + name='prevent_instance_group_fallback', + field=models.BooleanField( + default=False, + help_text='If enabled, the job template will prevent adding any inventory or organization instance groups to the list of preferred instances groups to run on.', + ), + ), + ] diff --git a/awx_collection/plugins/modules/inventory.py b/awx_collection/plugins/modules/inventory.py index f04e94c533..b4784f5260 100644 --- a/awx_collection/plugins/modules/inventory.py +++ b/awx_collection/plugins/modules/inventory.py @@ -66,6 +66,10 @@ options: - list of Instance Groups for this Organization to run on. type: list elements: str + prevent_instance_group_fallback: + description: + - Prevent falling back to instance groups set on the organization + type: bool state: description: - Desired state of the resource. @@ -111,6 +115,7 @@ def main(): kind=dict(choices=['', 'smart'], default=''), host_filter=dict(), instance_groups=dict(type="list", elements='str'), + prevent_instance_group_fallback=dict(type='bool'), state=dict(choices=['present', 'absent'], default='present'), ) @@ -127,6 +132,7 @@ def main(): state = module.params.get('state') kind = module.params.get('kind') host_filter = module.params.get('host_filter') + prevent_instance_group_fallback = module.params.get('prevent_instance_group_fallback') # Attempt to look up the related items the user specified (these will fail the module if not found) org_id = module.resolve_name_to_id('organizations', organization) @@ -157,6 +163,8 @@ def main(): 'kind': kind, 'host_filter': host_filter, } + if prevent_instance_group_fallback is not None: + inventory_fields['prevent_instance_group_fallback'] = prevent_instance_group_fallback if description is not None: inventory_fields['description'] = description if variables is not None: diff --git a/awx_collection/plugins/modules/job_template.py b/awx_collection/plugins/modules/job_template.py index 5a7e9b6e25..2a8408e2a4 100644 --- a/awx_collection/plugins/modules/job_template.py +++ b/awx_collection/plugins/modules/job_template.py @@ -315,6 +315,10 @@ options: - list of notifications to send on error type: list elements: str + prevent_instance_group_fallback: + description: + - Prevent falling back to instance groups set on the associated inventory or organization + type: bool extends_documentation_fragment: awx.awx.auth @@ -441,6 +445,7 @@ def main(): notification_templates_started=dict(type="list", elements='str'), notification_templates_success=dict(type="list", elements='str'), notification_templates_error=dict(type="list", elements='str'), + prevent_instance_group_fallback=dict(type="bool"), state=dict(choices=['present', 'absent'], default='present'), ) @@ -539,6 +544,7 @@ def main(): 'custom_virtualenv', 'job_slice_count', 'webhook_service', + 'prevent_instance_group_fallback', ): field_val = module.params.get(field_name) if field_val is not None: From e5fd42c4dac510c6346fea210bcf033a97d9ddec Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Mon, 12 Sep 2022 10:00:53 -0400 Subject: [PATCH 04/14] Removing debug message and adding help details about empty groups --- awx/main/models/inventory.py | 2 ++ awx/main/models/jobs.py | 3 ++- awx/ui/src/screens/Inventory/shared/Inventory.helptext.js | 3 ++- awx/ui/src/screens/Template/shared/JobTemplate.helptext.js | 3 ++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index fdf3272f99..30e50db1ea 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -181,6 +181,8 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin, RelatedJobsMixin): "If enabled, the inventory will prevent adding any organization " "instance groups to the list of preferred instances groups to run " "associated job templates on." + "If this setting is enabled and you provided an empty list, the global instance " + "groups will be applied." ), ) diff --git a/awx/main/models/jobs.py b/awx/main/models/jobs.py index a9c6cf6907..f5c5941914 100644 --- a/awx/main/models/jobs.py +++ b/awx/main/models/jobs.py @@ -279,6 +279,8 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour help_text=( "If enabled, the job template will prevent adding any inventory or organization " "instance groups to the list of preferred instances groups to run on." + "If this setting is enabled and you provided an empty list, the global instance " + "groups will be applied." ), ) @@ -810,7 +812,6 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin, TaskMana for instance_group in getattr(self, obj_type).instance_groups.all(): selected_groups.append(instance_group) if getattr(getattr(self, obj_type), 'prevent_instance_group_fallback', False): - logger.error("Breaking in preferred instance group at {}".format(obj_type)) break if not selected_groups: return self.global_instance_groups diff --git a/awx/ui/src/screens/Inventory/shared/Inventory.helptext.js b/awx/ui/src/screens/Inventory/shared/Inventory.helptext.js index 564add096d..43b231bfd6 100644 --- a/awx/ui/src/screens/Inventory/shared/Inventory.helptext.js +++ b/awx/ui/src/screens/Inventory/shared/Inventory.helptext.js @@ -191,7 +191,8 @@ const getInventoryHelpTextStrings = () => ({ sourcePath: t`The inventory file to be synced by this source. You can select from the dropdown or enter a file within the input.`, - preventInstanceGroupFallback: t`If enabled, the job template will prevent adding any inventory or organization instance groups to the list of preferred instances groups to run on.`, + preventInstanceGroupFallback: t`If enabled, the inventory will prevent adding any organization instance groups to the list of preferred instances groups to run associated job templates on. + Note: If this setting is enabled and you provided an empty list, the global instance groups will be applied.`, }); export default getInventoryHelpTextStrings; diff --git a/awx/ui/src/screens/Template/shared/JobTemplate.helptext.js b/awx/ui/src/screens/Template/shared/JobTemplate.helptext.js index b68ba02204..8aa8b48db3 100644 --- a/awx/ui/src/screens/Template/shared/JobTemplate.helptext.js +++ b/awx/ui/src/screens/Template/shared/JobTemplate.helptext.js @@ -30,7 +30,8 @@ const jtHelpTextStrings = () => ({ privilegeEscalation: t`If enabled, run this playbook as an administrator.`, enableWebhook: t`Enable webhook for this template.`, concurrentJobs: t`If enabled, simultaneous runs of this job template will be allowed.`, - preventInstanceGroupFallback: t`If enabled, the job template will prevent adding any inventory or organization instance groups to the list of preferred instances groups to run on.`, + preventInstanceGroupFallback: t`If enabled, the job template will prevent adding any inventory or organization instance groups to the list of preferred instances groups to run on. + Note: If this setting is enabled and you provided an empty list, the global instance groups will be applied.`, enableFactStorage: t`If enabled, this will store gathered facts so they can be viewed at the host level. Facts are persisted and injected into the fact cache at runtime.`, enabledOptions: ( <> From 6415671d93118865291c21fb39aa045f15f770e6 Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Mon, 12 Sep 2022 10:09:05 -0400 Subject: [PATCH 05/14] Creating options (like job template) on inventory screen --- .../screens/Inventory/shared/InventoryForm.js | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/awx/ui/src/screens/Inventory/shared/InventoryForm.js b/awx/ui/src/screens/Inventory/shared/InventoryForm.js index 30c166c73d..49c91fa73b 100644 --- a/awx/ui/src/screens/Inventory/shared/InventoryForm.js +++ b/awx/ui/src/screens/Inventory/shared/InventoryForm.js @@ -15,7 +15,11 @@ import LabelSelect from 'components/LabelSelect'; import InstanceGroupsLookup from 'components/Lookup/InstanceGroupsLookup'; import OrganizationLookup from 'components/Lookup/OrganizationLookup'; import ContentError from 'components/ContentError'; -import { FormColumnLayout, FormFullWidthLayout } from 'components/FormLayout'; +import { + FormColumnLayout, + FormFullWidthLayout, + FormCheckboxLayout, +} from 'components/FormLayout'; import getHelpText from './Inventory.helptext'; function InventoryFormFields({ inventory }) { @@ -74,12 +78,6 @@ function InventoryFormFields({ inventory }) { }} fieldName="instanceGroups" /> - + + + + + Date: Mon, 12 Sep 2022 12:12:03 -0400 Subject: [PATCH 06/14] Updating migration file --- awx/main/migrations/0168_prevent_instance_fallback.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/awx/main/migrations/0168_prevent_instance_fallback.py b/awx/main/migrations/0168_prevent_instance_fallback.py index a041582d2c..a38aea2dfe 100644 --- a/awx/main/migrations/0168_prevent_instance_fallback.py +++ b/awx/main/migrations/0168_prevent_instance_fallback.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.13 on 2022-09-09 17:03 +# Generated by Django 3.2.13 on 2022-09-12 16:11 from django.db import migrations, models @@ -15,7 +15,7 @@ class Migration(migrations.Migration): name='prevent_instance_group_fallback', field=models.BooleanField( default=False, - help_text='If enabled, the inventory will prevent adding any organization instance groups to the list of preferred instances groups to run associated job templates on.', + help_text='If enabled, the inventory will prevent adding any organization instance groups to the list of preferred instances groups to run associated job templates on.If this setting is enabled and you provided an empty list, the global instance groups will be applied.', ), ), migrations.AddField( @@ -23,7 +23,7 @@ class Migration(migrations.Migration): name='prevent_instance_group_fallback', field=models.BooleanField( default=False, - help_text='If enabled, the job template will prevent adding any inventory or organization instance groups to the list of preferred instances groups to run on.', + help_text='If enabled, the job template will prevent adding any inventory or organization instance groups to the list of preferred instances groups to run on.If this setting is enabled and you provided an empty list, the global instance groups will be applied.', ), ), ] From 5ba0bf3a64cf76e30acb8a3bd4a54a2dd19974e2 Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Mon, 12 Sep 2022 12:39:28 -0400 Subject: [PATCH 07/14] Fixing UI tests --- .../src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.js | 1 + .../src/screens/Template/JobTemplateEdit/JobTemplateEdit.test.js | 1 + 2 files changed, 2 insertions(+) diff --git a/awx/ui/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.js b/awx/ui/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.js index 9fffccbb33..3fd63394dc 100644 --- a/awx/ui/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.js +++ b/awx/ui/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.js @@ -55,6 +55,7 @@ const jobTemplateData = { limit: '', name: '', playbook: '', + prevent_instance_group_fallback: false, project: { id: 1, summary_fields: { organization: { id: 1 } } }, scm_branch: '', skip_tags: '', diff --git a/awx/ui/src/screens/Template/JobTemplateEdit/JobTemplateEdit.test.js b/awx/ui/src/screens/Template/JobTemplateEdit/JobTemplateEdit.test.js index 2ada0105d5..cb64051cc9 100644 --- a/awx/ui/src/screens/Template/JobTemplateEdit/JobTemplateEdit.test.js +++ b/awx/ui/src/screens/Template/JobTemplateEdit/JobTemplateEdit.test.js @@ -68,6 +68,7 @@ const mockJobTemplate = { limit: '', name: 'Foo', playbook: 'Baz', + prevent_instance_group_fallback: false, project: 3, scm_branch: '', skip_tags: '', From 420b3c8b84e0e4598d8797f8f5f7b7046ccebd92 Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Fri, 16 Sep 2022 06:13:48 -0400 Subject: [PATCH 08/14] Adding prevent instance group fallback to inventory and jt defail screens --- .../InventoryDetail/InventoryDetail.js | 40 ++++++++++++++++++- .../Inventory/shared/Inventory.helptext.js | 5 +++ .../JobTemplateDetail/JobTemplateDetail.js | 16 +++++++- 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/awx/ui/src/screens/Inventory/InventoryDetail/InventoryDetail.js b/awx/ui/src/screens/Inventory/InventoryDetail/InventoryDetail.js index b25630cb89..0ad2398a3a 100644 --- a/awx/ui/src/screens/Inventory/InventoryDetail/InventoryDetail.js +++ b/awx/ui/src/screens/Inventory/InventoryDetail/InventoryDetail.js @@ -2,7 +2,14 @@ import React, { useCallback, useEffect } from 'react'; import { Link, useHistory } from 'react-router-dom'; import { t } from '@lingui/macro'; -import { Button, Chip } from '@patternfly/react-core'; +import { + Button, + Chip, + TextList, + TextListItem, + TextListItemVariants, + TextListVariants, +} from '@patternfly/react-core'; import AlertModal from 'components/AlertModal'; import { CardBody, CardActionsRow } from 'components/Card'; import { DetailList, Detail, UserDateDetail } from 'components/DetailList'; @@ -50,9 +57,24 @@ function InventoryDetail({ inventory }) { const { organization, user_capabilities: userCapabilities } = inventory.summary_fields; + const prevent_instance_group_fallback = + inventory.prevent_instance_group_fallback; + const deleteDetailsRequests = relatedResourceDeleteRequests.inventory(inventory); + const renderOptionsField = prevent_instance_group_fallback; + + const renderOptions = ( + + {prevent_instance_group_fallback && ( + + {t`Prevent Instance Group Fallback`} + + )} + + ); + if (isLoading) { return ; } @@ -104,6 +126,22 @@ function InventoryDetail({ inventory }) { isEmpty={instanceGroups.length === 0} /> )} + {prevent_instance_group_fallback && ( + + )} + {renderOptionsField && ( + + )} {inventory.summary_fields.labels && ( ({ the dropdown or enter a file within the input.`, preventInstanceGroupFallback: t`If enabled, the inventory will prevent adding any organization instance groups to the list of preferred instances groups to run associated job templates on. Note: If this setting is enabled and you provided an empty list, the global instance groups will be applied.`, + enabledOptions: ( + <> +

{t`Prevent Instance Group Fallback: If enabled, the inventory will prevent adding any organization instance groups to the list of preferred instances groups to run associated job templates on.`}

+ + ), }); export default getInventoryHelpTextStrings; diff --git a/awx/ui/src/screens/Template/JobTemplateDetail/JobTemplateDetail.js b/awx/ui/src/screens/Template/JobTemplateDetail/JobTemplateDetail.js index 22506185d6..dd5fdc837a 100644 --- a/awx/ui/src/screens/Template/JobTemplateDetail/JobTemplateDetail.js +++ b/awx/ui/src/screens/Template/JobTemplateDetail/JobTemplateDetail.js @@ -63,6 +63,7 @@ function JobTemplateDetail({ template }) { webhook_service, related: { webhook_receiver }, webhook_key, + prevent_instance_group_fallback, custom_virtualenv, } = template; const { id: templateId } = useParams(); @@ -111,7 +112,8 @@ function JobTemplateDetail({ template }) { host_config_key || allow_simultaneous || use_fact_cache || - webhook_service; + webhook_service || + prevent_instance_group_fallback; const renderOptions = ( @@ -140,6 +142,11 @@ function JobTemplateDetail({ template }) { {t`Webhooks`} )} + {prevent_instance_group_fallback && ( + + {t`Prevent Instance Group Fallback`} + + )} ); @@ -335,6 +342,13 @@ function JobTemplateDetail({ template }) { } /> )} + {prevent_instance_group_fallback && ( + + )} Date: Fri, 16 Sep 2022 06:44:43 -0400 Subject: [PATCH 09/14] Fixing warnings from rebase --- .../src/screens/Inventory/InventoryDetail/InventoryDetail.js | 3 +-- awx/ui/src/screens/Inventory/shared/Inventory.helptext.js | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/awx/ui/src/screens/Inventory/InventoryDetail/InventoryDetail.js b/awx/ui/src/screens/Inventory/InventoryDetail/InventoryDetail.js index 0ad2398a3a..6944707a6d 100644 --- a/awx/ui/src/screens/Inventory/InventoryDetail/InventoryDetail.js +++ b/awx/ui/src/screens/Inventory/InventoryDetail/InventoryDetail.js @@ -57,8 +57,7 @@ function InventoryDetail({ inventory }) { const { organization, user_capabilities: userCapabilities } = inventory.summary_fields; - const prevent_instance_group_fallback = - inventory.prevent_instance_group_fallback; + const { prevent_instance_group_fallback } = inventory; const deleteDetailsRequests = relatedResourceDeleteRequests.inventory(inventory); diff --git a/awx/ui/src/screens/Inventory/shared/Inventory.helptext.js b/awx/ui/src/screens/Inventory/shared/Inventory.helptext.js index 26370b2853..685a47f01a 100644 --- a/awx/ui/src/screens/Inventory/shared/Inventory.helptext.js +++ b/awx/ui/src/screens/Inventory/shared/Inventory.helptext.js @@ -194,9 +194,7 @@ const getInventoryHelpTextStrings = () => ({ preventInstanceGroupFallback: t`If enabled, the inventory will prevent adding any organization instance groups to the list of preferred instances groups to run associated job templates on. Note: If this setting is enabled and you provided an empty list, the global instance groups will be applied.`, enabledOptions: ( - <> -

{t`Prevent Instance Group Fallback: If enabled, the inventory will prevent adding any organization instance groups to the list of preferred instances groups to run associated job templates on.`}

- +

{t`Prevent Instance Group Fallback: If enabled, the inventory will prevent adding any organization instance groups to the list of preferred instances groups to run associated job templates on.`}

), }); From 84d00722b9333c3942529e6c78f931cac8bb1f23 Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Mon, 26 Sep 2022 13:52:42 -0400 Subject: [PATCH 10/14] Add prevent_instance_group_fallback to awxkit --- awxkit/awxkit/api/pages/inventory.py | 2 +- awxkit/awxkit/api/pages/job_templates.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/awxkit/awxkit/api/pages/inventory.py b/awxkit/awxkit/api/pages/inventory.py index 33c84f2aa2..8431f15965 100644 --- a/awxkit/awxkit/api/pages/inventory.py +++ b/awxkit/awxkit/api/pages/inventory.py @@ -59,7 +59,7 @@ class Inventory(HasCopy, HasCreate, HasInstanceGroups, HasVariables, base.Base): organization=organization.id, ) - optional_fields = ('host_filter', 'kind', 'variables') + optional_fields = ('host_filter', 'kind', 'variables', 'prevent_instance_group_fallback') update_payload(payload, optional_fields, kwargs) diff --git a/awxkit/awxkit/api/pages/job_templates.py b/awxkit/awxkit/api/pages/job_templates.py index 46862d9f2b..5378059843 100644 --- a/awxkit/awxkit/api/pages/job_templates.py +++ b/awxkit/awxkit/api/pages/job_templates.py @@ -79,6 +79,7 @@ class JobTemplate(HasCopy, HasCreate, HasInstanceGroups, HasNotifications, HasSu 'webhook_service', 'webhook_credential', 'scm_branch', + 'prevent_instance_group_fallback', ) update_payload(payload, optional_fields, kwargs) From e6518a1d1c1fb69647664b71952b371d48586d43 Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Mon, 26 Sep 2022 13:53:01 -0400 Subject: [PATCH 11/14] Updating the migration id --- ...instance_fallback.py => 0171_prevent_instance_fallback.py} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename awx/main/migrations/{0168_prevent_instance_fallback.py => 0171_prevent_instance_fallback.py} (90%) diff --git a/awx/main/migrations/0168_prevent_instance_fallback.py b/awx/main/migrations/0171_prevent_instance_fallback.py similarity index 90% rename from awx/main/migrations/0168_prevent_instance_fallback.py rename to awx/main/migrations/0171_prevent_instance_fallback.py index a38aea2dfe..ef74da931c 100644 --- a/awx/main/migrations/0168_prevent_instance_fallback.py +++ b/awx/main/migrations/0171_prevent_instance_fallback.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.13 on 2022-09-12 16:11 +# Generated by Django 3.2.13 on 2022-09-26 17:34 from django.db import migrations, models @@ -6,7 +6,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('main', '0167_project_signature_validation_credential'), + ('main', '0170_node_and_link_state'), ] operations = [ From 2d756959d3ab486694785a2b12798432a5ea5b20 Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Mon, 26 Sep 2022 16:41:32 -0400 Subject: [PATCH 12/14] Altering prefered_instance_groups for ad_hoc_commands and inventory objects --- awx/main/models/ad_hoc_commands.py | 15 +++++++-------- awx/main/models/inventory.py | 20 ++++++++++++-------- awx/main/tests/functional/test_instances.py | 4 ++++ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/awx/main/models/ad_hoc_commands.py b/awx/main/models/ad_hoc_commands.py index 7543162080..dfb5993e3a 100644 --- a/awx/main/models/ad_hoc_commands.py +++ b/awx/main/models/ad_hoc_commands.py @@ -228,15 +228,14 @@ class AdHocCommand(UnifiedJob, JobNotificationMixin): @property def preferred_instance_groups(self): - if self.inventory is not None and self.inventory.organization is not None: - organization_groups = [x for x in self.inventory.organization.instance_groups.all()] - else: - organization_groups = [] + selected_groups = [] if self.inventory is not None: - inventory_groups = [x for x in self.inventory.instance_groups.all()] - else: - inventory_groups = [] - selected_groups = inventory_groups + organization_groups + for instance_group in self.inventory.instance_groups.all(): + selected_groups.append(instance_group) + if not getattr(self.inventory, 'prevent_instance_group_fallback', False) and self.inventory.organization is not None: + for instance_group in self.inventory.organization.instance_groups.all(): + selected_groups.append(instance_group) + if not selected_groups: return self.global_instance_groups return selected_groups diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 30e50db1ea..f56bd17f4f 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -1278,15 +1278,19 @@ class InventoryUpdate(UnifiedJob, InventorySourceOptions, JobNotificationMixin, @property def preferred_instance_groups(self): - if self.inventory_source.inventory is not None and self.inventory_source.inventory.organization is not None: - organization_groups = [x for x in self.inventory_source.inventory.organization.instance_groups.all()] - else: - organization_groups = [] + selected_groups = [] if self.inventory_source.inventory is not None: - inventory_groups = [x for x in self.inventory_source.inventory.instance_groups.all()] - else: - inventory_groups = [] - selected_groups = inventory_groups + organization_groups + # Add the inventory sources IG to the selected IGs first + for instance_group in self.inventory_source.inventory.instance_groups.all(): + selected_groups.append(instance_group) + # If the inventory allows for fallback and we have an organization then also append the orgs IGs to the end of the list + if ( + not getattr(self.inventory_source.inventory, 'prevent_instance_group_fallback', False) + and self.inventory_source.inventory.organization is not None + ): + for instance_group in self.inventory_source.inventory.organization.instance_groups.all(): + selected_groups.append(instance_group) + if not selected_groups: return self.global_instance_groups return selected_groups diff --git a/awx/main/tests/functional/test_instances.py b/awx/main/tests/functional/test_instances.py index e704de8971..8ce6524d38 100644 --- a/awx/main/tests/functional/test_instances.py +++ b/awx/main/tests/functional/test_instances.py @@ -391,6 +391,8 @@ class TestInstanceGroupOrdering: assert ad_hoc.preferred_instance_groups == [ig_org] inventory.instance_groups.add(ig_inv) assert ad_hoc.preferred_instance_groups == [ig_inv, ig_org] + inventory.prevent_instance_group_fallback = True + assert ad_hoc.preferred_instance_groups == [ig_inv] def test_inventory_update_instance_groups(self, instance_group_factory, inventory_source, default_instance_group): iu = InventoryUpdate.objects.create(inventory_source=inventory_source, source=inventory_source.source) @@ -404,6 +406,8 @@ class TestInstanceGroupOrdering: inventory_source.instance_groups.add(ig_tmp) # API does not allow setting IGs on inventory source, so ignore those assert iu.preferred_instance_groups == [ig_inv, ig_org] + inventory_source.inventory.prevent_instance_group_fallback = True + assert iu.preferred_instance_groups == [ig_inv] def test_job_instance_groups(self, instance_group_factory, inventory, project, default_instance_group): jt = JobTemplate.objects.create(inventory=inventory, project=project) From 2dcc7ec7493883ce9dbc3b0c51761fdec767cee1 Mon Sep 17 00:00:00 2001 From: Sarabraj Singh Date: Wed, 28 Sep 2022 10:53:17 -0400 Subject: [PATCH 13/14] implementing Alan's recommendations for ig_fallback --- awx/main/models/ad_hoc_commands.py | 2 +- awx/main/models/inventory.py | 2 +- awx/main/models/jobs.py | 2 +- awx/main/tests/functional/test_copy.py | 5 +++++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/awx/main/models/ad_hoc_commands.py b/awx/main/models/ad_hoc_commands.py index dfb5993e3a..3b71119031 100644 --- a/awx/main/models/ad_hoc_commands.py +++ b/awx/main/models/ad_hoc_commands.py @@ -232,7 +232,7 @@ class AdHocCommand(UnifiedJob, JobNotificationMixin): if self.inventory is not None: for instance_group in self.inventory.instance_groups.all(): selected_groups.append(instance_group) - if not getattr(self.inventory, 'prevent_instance_group_fallback', False) and self.inventory.organization is not None: + if not self.inventory.prevent_instance_group_fallback and self.inventory.organization is not None: for instance_group in self.inventory.organization.instance_groups.all(): selected_groups.append(instance_group) diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index f56bd17f4f..54c7d3e2b1 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -63,7 +63,7 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin, RelatedJobsMixin): an inventory source contains lists and hosts. """ - FIELDS_TO_PRESERVE_AT_COPY = ['hosts', 'groups', 'instance_groups'] + FIELDS_TO_PRESERVE_AT_COPY = ['hosts', 'groups', 'instance_groups', 'prevent_instance_group_fallback'] KIND_CHOICES = [ ('', _('Hosts have a direct link to this inventory.')), ('smart', _('Hosts for inventory generated using the host_filter property.')), diff --git a/awx/main/models/jobs.py b/awx/main/models/jobs.py index f5c5941914..a84a5a67eb 100644 --- a/awx/main/models/jobs.py +++ b/awx/main/models/jobs.py @@ -203,7 +203,7 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour playbook) to an inventory source with a given credential. """ - FIELDS_TO_PRESERVE_AT_COPY = ['labels', 'instance_groups', 'credentials', 'survey_spec'] + FIELDS_TO_PRESERVE_AT_COPY = ['labels', 'instance_groups', 'credentials', 'survey_spec', 'prevent_instance_group_fallback'] FIELDS_TO_DISCARD_AT_COPY = ['vault_credential', 'credential'] SOFT_UNIQUE_TOGETHER = [('polymorphic_ctype', 'name', 'organization')] diff --git a/awx/main/tests/functional/test_copy.py b/awx/main/tests/functional/test_copy.py index 9be8d6574c..0574f9ccbd 100644 --- a/awx/main/tests/functional/test_copy.py +++ b/awx/main/tests/functional/test_copy.py @@ -19,6 +19,7 @@ def test_job_template_copy( job_template_with_survey_passwords.inventory = inventory job_template_with_survey_passwords.labels.add(label) job_template_with_survey_passwords.instance_groups.add(ig) + job_template_with_survey_passwords.prevent_instance_group_fallback = True job_template_with_survey_passwords.save() job_template_with_survey_passwords.credentials.add(credential) job_template_with_survey_passwords.credentials.add(machine_credential) @@ -65,6 +66,7 @@ def test_job_template_copy( assert jt_copy.labels.get(pk=label.pk) == label assert jt_copy.instance_groups.count() != 0 assert jt_copy.instance_groups.get(pk=ig.pk) == ig + assert jt_copy.prevent_instance_group_fallback == True @pytest.mark.django_db @@ -95,6 +97,8 @@ def test_inventory_copy(inventory, group_factory, post, get, alice, organization host = group_1_1.hosts.create(name='host', inventory=inventory) group_2_1.hosts.add(host) inventory.admin_role.members.add(alice) + inventory.prevent_instance_group_fallback = True + inventory.save() assert get(reverse('api:inventory_copy', kwargs={'pk': inventory.pk}), alice, expect=200).data['can_copy'] is False inventory.organization.admin_role.members.add(alice) assert get(reverse('api:inventory_copy', kwargs={'pk': inventory.pk}), alice, expect=200).data['can_copy'] is True @@ -110,6 +114,7 @@ def test_inventory_copy(inventory, group_factory, post, get, alice, organization assert inventory_copy.organization == organization assert inventory_copy.created_by == alice assert inventory_copy.name == 'new inv name' + assert inventory_copy.prevent_instance_group_fallback == True assert set(group_1_1_copy.parents.all()) == set() assert set(group_2_1_copy.parents.all()) == set([group_1_1_copy]) assert set(group_2_2_copy.parents.all()) == set([group_1_1_copy, group_2_1_copy]) From d1588b94b0bc4a388582ebb4b3560f8cd1850de5 Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Thu, 29 Sep 2022 14:20:49 -0400 Subject: [PATCH 14/14] Updating migration file again --- ...instance_fallback.py => 0172_prevent_instance_fallback.py} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename awx/main/migrations/{0171_prevent_instance_fallback.py => 0172_prevent_instance_fallback.py} (91%) diff --git a/awx/main/migrations/0171_prevent_instance_fallback.py b/awx/main/migrations/0172_prevent_instance_fallback.py similarity index 91% rename from awx/main/migrations/0171_prevent_instance_fallback.py rename to awx/main/migrations/0172_prevent_instance_fallback.py index ef74da931c..aeb3ad3ebb 100644 --- a/awx/main/migrations/0171_prevent_instance_fallback.py +++ b/awx/main/migrations/0172_prevent_instance_fallback.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.13 on 2022-09-26 17:34 +# Generated by Django 3.2.13 on 2022-09-29 18:10 from django.db import migrations, models @@ -6,7 +6,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('main', '0170_node_and_link_state'), + ('main', '0171_add_health_check_started'), ] operations = [