mirror of
https://github.com/ansible/awx.git
synced 2026-05-15 21:37:42 -02:30
Merge pull request #12728 from john-westcott-iv/ig_fallback
Adding prevent_instance_group_fallback
This commit is contained in:
@@ -1680,6 +1680,7 @@ class InventorySerializer(LabelsListMixin, BaseSerializerWithVariables):
|
|||||||
'total_inventory_sources',
|
'total_inventory_sources',
|
||||||
'inventory_sources_with_failures',
|
'inventory_sources_with_failures',
|
||||||
'pending_deletion',
|
'pending_deletion',
|
||||||
|
'prevent_instance_group_fallback',
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
@@ -2937,6 +2938,7 @@ class JobTemplateSerializer(JobTemplateMixin, UnifiedJobTemplateSerializer, JobO
|
|||||||
'job_slice_count',
|
'job_slice_count',
|
||||||
'webhook_service',
|
'webhook_service',
|
||||||
'webhook_credential',
|
'webhook_credential',
|
||||||
|
'prevent_instance_group_fallback',
|
||||||
)
|
)
|
||||||
read_only_fields = ('*', 'custom_virtualenv')
|
read_only_fields = ('*', 'custom_virtualenv')
|
||||||
|
|
||||||
|
|||||||
29
awx/main/migrations/0172_prevent_instance_fallback.py
Normal file
29
awx/main/migrations/0172_prevent_instance_fallback.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Generated by Django 3.2.13 on 2022-09-29 18:10
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('main', '0171_add_health_check_started'),
|
||||||
|
]
|
||||||
|
|
||||||
|
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.If this setting is enabled and you provided an empty list, the global instance groups will be applied.',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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.If this setting is enabled and you provided an empty list, the global instance groups will be applied.',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -228,15 +228,14 @@ class AdHocCommand(UnifiedJob, JobNotificationMixin):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def preferred_instance_groups(self):
|
def preferred_instance_groups(self):
|
||||||
if self.inventory is not None and self.inventory.organization is not None:
|
selected_groups = []
|
||||||
organization_groups = [x for x in self.inventory.organization.instance_groups.all()]
|
|
||||||
else:
|
|
||||||
organization_groups = []
|
|
||||||
if self.inventory is not None:
|
if self.inventory is not None:
|
||||||
inventory_groups = [x for x in self.inventory.instance_groups.all()]
|
for instance_group in self.inventory.instance_groups.all():
|
||||||
else:
|
selected_groups.append(instance_group)
|
||||||
inventory_groups = []
|
if not self.inventory.prevent_instance_group_fallback and self.inventory.organization is not None:
|
||||||
selected_groups = inventory_groups + organization_groups
|
for instance_group in self.inventory.organization.instance_groups.all():
|
||||||
|
selected_groups.append(instance_group)
|
||||||
|
|
||||||
if not selected_groups:
|
if not selected_groups:
|
||||||
return self.global_instance_groups
|
return self.global_instance_groups
|
||||||
return selected_groups
|
return selected_groups
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin, RelatedJobsMixin):
|
|||||||
an inventory source contains lists and hosts.
|
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 = [
|
KIND_CHOICES = [
|
||||||
('', _('Hosts have a direct link to this inventory.')),
|
('', _('Hosts have a direct link to this inventory.')),
|
||||||
('smart', _('Hosts for inventory generated using the host_filter property.')),
|
('smart', _('Hosts for inventory generated using the host_filter property.')),
|
||||||
@@ -175,6 +175,16 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin, RelatedJobsMixin):
|
|||||||
related_name='inventory_labels',
|
related_name='inventory_labels',
|
||||||
help_text=_('Labels associated with this inventory.'),
|
help_text=_('Labels associated with this inventory.'),
|
||||||
)
|
)
|
||||||
|
prevent_instance_group_fallback = 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."
|
||||||
|
"If this setting is enabled and you provided an empty list, the global instance "
|
||||||
|
"groups will be applied."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def get_absolute_url(self, request=None):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:inventory_detail', kwargs={'pk': self.pk}, request=request)
|
return reverse('api:inventory_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
@@ -1268,15 +1278,19 @@ class InventoryUpdate(UnifiedJob, InventorySourceOptions, JobNotificationMixin,
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def preferred_instance_groups(self):
|
def preferred_instance_groups(self):
|
||||||
if self.inventory_source.inventory is not None and self.inventory_source.inventory.organization is not None:
|
selected_groups = []
|
||||||
organization_groups = [x for x in self.inventory_source.inventory.organization.instance_groups.all()]
|
|
||||||
else:
|
|
||||||
organization_groups = []
|
|
||||||
if self.inventory_source.inventory is not None:
|
if self.inventory_source.inventory is not None:
|
||||||
inventory_groups = [x for x in self.inventory_source.inventory.instance_groups.all()]
|
# Add the inventory sources IG to the selected IGs first
|
||||||
else:
|
for instance_group in self.inventory_source.inventory.instance_groups.all():
|
||||||
inventory_groups = []
|
selected_groups.append(instance_group)
|
||||||
selected_groups = inventory_groups + organization_groups
|
# 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:
|
if not selected_groups:
|
||||||
return self.global_instance_groups
|
return self.global_instance_groups
|
||||||
return selected_groups
|
return selected_groups
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour
|
|||||||
playbook) to an inventory source with a given credential.
|
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']
|
FIELDS_TO_DISCARD_AT_COPY = ['vault_credential', 'credential']
|
||||||
SOFT_UNIQUE_TOGETHER = [('polymorphic_ctype', 'name', 'organization')]
|
SOFT_UNIQUE_TOGETHER = [('polymorphic_ctype', 'name', 'organization')]
|
||||||
|
|
||||||
@@ -274,6 +274,15 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour
|
|||||||
'admin_role',
|
'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."
|
||||||
|
"If this setting is enabled and you provided an empty list, the global instance "
|
||||||
|
"groups will be applied."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_unified_job_class(cls):
|
def _get_unified_job_class(cls):
|
||||||
@@ -797,19 +806,13 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin, TaskMana
|
|||||||
def preferred_instance_groups(self):
|
def preferred_instance_groups(self):
|
||||||
# If the user specified instance groups those will be handled by the unified_job.create_unified_job
|
# 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
|
# This function handles only the defaults for a template w/o user specification
|
||||||
if self.organization is not None:
|
selected_groups = []
|
||||||
organization_groups = [x for x in self.organization.instance_groups.all()]
|
for obj_type in ['job_template', 'inventory', 'organization']:
|
||||||
else:
|
if getattr(self, obj_type) is not None:
|
||||||
organization_groups = []
|
for instance_group in getattr(self, obj_type).instance_groups.all():
|
||||||
if self.inventory is not None:
|
selected_groups.append(instance_group)
|
||||||
inventory_groups = [x for x in self.inventory.instance_groups.all()]
|
if getattr(getattr(self, obj_type), 'prevent_instance_group_fallback', False):
|
||||||
else:
|
break
|
||||||
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
|
|
||||||
if not selected_groups:
|
if not selected_groups:
|
||||||
return self.global_instance_groups
|
return self.global_instance_groups
|
||||||
return selected_groups
|
return selected_groups
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ def test_job_template_copy(
|
|||||||
job_template_with_survey_passwords.inventory = inventory
|
job_template_with_survey_passwords.inventory = inventory
|
||||||
job_template_with_survey_passwords.labels.add(label)
|
job_template_with_survey_passwords.labels.add(label)
|
||||||
job_template_with_survey_passwords.instance_groups.add(ig)
|
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.save()
|
||||||
job_template_with_survey_passwords.credentials.add(credential)
|
job_template_with_survey_passwords.credentials.add(credential)
|
||||||
job_template_with_survey_passwords.credentials.add(machine_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.labels.get(pk=label.pk) == label
|
||||||
assert jt_copy.instance_groups.count() != 0
|
assert jt_copy.instance_groups.count() != 0
|
||||||
assert jt_copy.instance_groups.get(pk=ig.pk) == ig
|
assert jt_copy.instance_groups.get(pk=ig.pk) == ig
|
||||||
|
assert jt_copy.prevent_instance_group_fallback == True
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@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)
|
host = group_1_1.hosts.create(name='host', inventory=inventory)
|
||||||
group_2_1.hosts.add(host)
|
group_2_1.hosts.add(host)
|
||||||
inventory.admin_role.members.add(alice)
|
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
|
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)
|
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
|
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.organization == organization
|
||||||
assert inventory_copy.created_by == alice
|
assert inventory_copy.created_by == alice
|
||||||
assert inventory_copy.name == 'new inv name'
|
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_1_1_copy.parents.all()) == set()
|
||||||
assert set(group_2_1_copy.parents.all()) == set([group_1_1_copy])
|
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])
|
assert set(group_2_2_copy.parents.all()) == set([group_1_1_copy, group_2_1_copy])
|
||||||
|
|||||||
@@ -391,6 +391,8 @@ class TestInstanceGroupOrdering:
|
|||||||
assert ad_hoc.preferred_instance_groups == [ig_org]
|
assert ad_hoc.preferred_instance_groups == [ig_org]
|
||||||
inventory.instance_groups.add(ig_inv)
|
inventory.instance_groups.add(ig_inv)
|
||||||
assert ad_hoc.preferred_instance_groups == [ig_inv, ig_org]
|
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):
|
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)
|
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)
|
inventory_source.instance_groups.add(ig_tmp)
|
||||||
# API does not allow setting IGs on inventory source, so ignore those
|
# API does not allow setting IGs on inventory source, so ignore those
|
||||||
assert iu.preferred_instance_groups == [ig_inv, ig_org]
|
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):
|
def test_job_instance_groups(self, instance_group_factory, inventory, project, default_instance_group):
|
||||||
jt = JobTemplate.objects.create(inventory=inventory, project=project)
|
jt = JobTemplate.objects.create(inventory=inventory, project=project)
|
||||||
|
|||||||
@@ -2,7 +2,14 @@ import React, { useCallback, useEffect } from 'react';
|
|||||||
import { Link, useHistory } from 'react-router-dom';
|
import { Link, useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
import { t } from '@lingui/macro';
|
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 AlertModal from 'components/AlertModal';
|
||||||
import { CardBody, CardActionsRow } from 'components/Card';
|
import { CardBody, CardActionsRow } from 'components/Card';
|
||||||
import { DetailList, Detail, UserDateDetail } from 'components/DetailList';
|
import { DetailList, Detail, UserDateDetail } from 'components/DetailList';
|
||||||
@@ -50,9 +57,23 @@ function InventoryDetail({ inventory }) {
|
|||||||
const { organization, user_capabilities: userCapabilities } =
|
const { organization, user_capabilities: userCapabilities } =
|
||||||
inventory.summary_fields;
|
inventory.summary_fields;
|
||||||
|
|
||||||
|
const { prevent_instance_group_fallback } = inventory;
|
||||||
|
|
||||||
const deleteDetailsRequests =
|
const deleteDetailsRequests =
|
||||||
relatedResourceDeleteRequests.inventory(inventory);
|
relatedResourceDeleteRequests.inventory(inventory);
|
||||||
|
|
||||||
|
const renderOptionsField = prevent_instance_group_fallback;
|
||||||
|
|
||||||
|
const renderOptions = (
|
||||||
|
<TextList component={TextListVariants.ul}>
|
||||||
|
{prevent_instance_group_fallback && (
|
||||||
|
<TextListItem component={TextListItemVariants.li}>
|
||||||
|
{t`Prevent Instance Group Fallback`}
|
||||||
|
</TextListItem>
|
||||||
|
)}
|
||||||
|
</TextList>
|
||||||
|
);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <ContentLoading />;
|
return <ContentLoading />;
|
||||||
}
|
}
|
||||||
@@ -104,6 +125,22 @@ function InventoryDetail({ inventory }) {
|
|||||||
isEmpty={instanceGroups.length === 0}
|
isEmpty={instanceGroups.length === 0}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{prevent_instance_group_fallback && (
|
||||||
|
<Detail
|
||||||
|
label={t`Prevent Instance Group Fallback`}
|
||||||
|
dataCy="inv-detail-prevent-instnace-group-fallback"
|
||||||
|
helpText={helpText.preventInstanceGroupFallback}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{renderOptionsField && (
|
||||||
|
<Detail
|
||||||
|
fullWidth
|
||||||
|
label={t`Enabled Options`}
|
||||||
|
value={renderOptions}
|
||||||
|
dataCy="jt-detail-enabled-options"
|
||||||
|
helpText={helpText.enabledOptions}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{inventory.summary_fields.labels && (
|
{inventory.summary_fields.labels && (
|
||||||
<Detail
|
<Detail
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|||||||
@@ -191,6 +191,11 @@ const getInventoryHelpTextStrings = () => ({
|
|||||||
sourcePath: t`The inventory file
|
sourcePath: t`The inventory file
|
||||||
to be synced by this source. You can select from
|
to be synced by this source. You can select from
|
||||||
the dropdown or enter a file within the input.`,
|
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: (
|
||||||
|
<p>{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.`}</p>
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default getInventoryHelpTextStrings;
|
export default getInventoryHelpTextStrings;
|
||||||
|
|||||||
@@ -5,14 +5,21 @@ import { func, shape } from 'prop-types';
|
|||||||
import { Form, FormGroup } from '@patternfly/react-core';
|
import { Form, FormGroup } from '@patternfly/react-core';
|
||||||
import { VariablesField } from 'components/CodeEditor';
|
import { VariablesField } from 'components/CodeEditor';
|
||||||
import Popover from 'components/Popover';
|
import Popover from 'components/Popover';
|
||||||
import FormField, { FormSubmitError } from 'components/FormField';
|
import FormField, {
|
||||||
|
CheckboxField,
|
||||||
|
FormSubmitError,
|
||||||
|
} from 'components/FormField';
|
||||||
import FormActionGroup from 'components/FormActionGroup';
|
import FormActionGroup from 'components/FormActionGroup';
|
||||||
import { required } from 'util/validators';
|
import { required } from 'util/validators';
|
||||||
import LabelSelect from 'components/LabelSelect';
|
import LabelSelect from 'components/LabelSelect';
|
||||||
import InstanceGroupsLookup from 'components/Lookup/InstanceGroupsLookup';
|
import InstanceGroupsLookup from 'components/Lookup/InstanceGroupsLookup';
|
||||||
import OrganizationLookup from 'components/Lookup/OrganizationLookup';
|
import OrganizationLookup from 'components/Lookup/OrganizationLookup';
|
||||||
import ContentError from 'components/ContentError';
|
import ContentError from 'components/ContentError';
|
||||||
import { FormColumnLayout, FormFullWidthLayout } from 'components/FormLayout';
|
import {
|
||||||
|
FormColumnLayout,
|
||||||
|
FormFullWidthLayout,
|
||||||
|
FormCheckboxLayout,
|
||||||
|
} from 'components/FormLayout';
|
||||||
import getHelpText from './Inventory.helptext';
|
import getHelpText from './Inventory.helptext';
|
||||||
|
|
||||||
function InventoryFormFields({ inventory }) {
|
function InventoryFormFields({ inventory }) {
|
||||||
@@ -84,6 +91,16 @@ function InventoryFormFields({ inventory }) {
|
|||||||
createText={t`Create`}
|
createText={t`Create`}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
<FormGroup fieldId="inventory-option-checkboxes" label={t`Options`}>
|
||||||
|
<FormCheckboxLayout>
|
||||||
|
<CheckboxField
|
||||||
|
id="option-prevent-instance-group-fallback"
|
||||||
|
name="prevent_instance_group_fallback"
|
||||||
|
label={t`Prevent Instance Group Fallback`}
|
||||||
|
tooltip={helpText.preventInstanceGroupFallback}
|
||||||
|
/>
|
||||||
|
</FormCheckboxLayout>
|
||||||
|
</FormGroup>
|
||||||
<VariablesField
|
<VariablesField
|
||||||
tooltip={helpText.variables()}
|
tooltip={helpText.variables()}
|
||||||
id="inventory-variables"
|
id="inventory-variables"
|
||||||
@@ -112,6 +129,8 @@ function InventoryForm({
|
|||||||
null,
|
null,
|
||||||
instanceGroups: instanceGroups || [],
|
instanceGroups: instanceGroups || [],
|
||||||
labels: inventory?.summary_fields?.labels?.results || [],
|
labels: inventory?.summary_fields?.labels?.results || [],
|
||||||
|
prevent_instance_group_fallback:
|
||||||
|
inventory.prevent_instance_group_fallback || false,
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Formik
|
<Formik
|
||||||
|
|||||||
@@ -3,77 +3,77 @@
|
|||||||
"type": "inventory",
|
"type": "inventory",
|
||||||
"url": "/api/v2/inventories/1/",
|
"url": "/api/v2/inventories/1/",
|
||||||
"related": {
|
"related": {
|
||||||
"named_url": "/api/v2/inventories/Mike's Inventory++Default/",
|
"named_url": "/api/v2/inventories/Mike's Inventory++Default/",
|
||||||
"created_by": "/api/v2/users/1/",
|
"created_by": "/api/v2/users/1/",
|
||||||
"modified_by": "/api/v2/users/1/",
|
"modified_by": "/api/v2/users/1/",
|
||||||
"hosts": "/api/v2/inventories/1/hosts/",
|
"hosts": "/api/v2/inventories/1/hosts/",
|
||||||
"groups": "/api/v2/inventories/1/groups/",
|
"groups": "/api/v2/inventories/1/groups/",
|
||||||
"root_groups": "/api/v2/inventories/1/root_groups/",
|
"root_groups": "/api/v2/inventories/1/root_groups/",
|
||||||
"variable_data": "/api/v2/inventories/1/variable_data/",
|
"variable_data": "/api/v2/inventories/1/variable_data/",
|
||||||
"script": "/api/v2/inventories/1/script/",
|
"script": "/api/v2/inventories/1/script/",
|
||||||
"tree": "/api/v2/inventories/1/tree/",
|
"tree": "/api/v2/inventories/1/tree/",
|
||||||
"inventory_sources": "/api/v2/inventories/1/inventory_sources/",
|
"inventory_sources": "/api/v2/inventories/1/inventory_sources/",
|
||||||
"update_inventory_sources": "/api/v2/inventories/1/update_inventory_sources/",
|
"update_inventory_sources": "/api/v2/inventories/1/update_inventory_sources/",
|
||||||
"activity_stream": "/api/v2/inventories/1/activity_stream/",
|
"activity_stream": "/api/v2/inventories/1/activity_stream/",
|
||||||
"job_templates": "/api/v2/inventories/1/job_templates/",
|
"job_templates": "/api/v2/inventories/1/job_templates/",
|
||||||
"ad_hoc_commands": "/api/v2/inventories/1/ad_hoc_commands/",
|
"ad_hoc_commands": "/api/v2/inventories/1/ad_hoc_commands/",
|
||||||
"access_list": "/api/v2/inventories/1/access_list/",
|
"access_list": "/api/v2/inventories/1/access_list/",
|
||||||
"object_roles": "/api/v2/inventories/1/object_roles/",
|
"object_roles": "/api/v2/inventories/1/object_roles/",
|
||||||
"instance_groups": "/api/v2/inventories/1/instance_groups/",
|
"instance_groups": "/api/v2/inventories/1/instance_groups/",
|
||||||
"copy": "/api/v2/inventories/1/copy/",
|
"copy": "/api/v2/inventories/1/copy/",
|
||||||
"organization": "/api/v2/organizations/1/"
|
"organization": "/api/v2/organizations/1/"
|
||||||
},
|
},
|
||||||
"summary_fields": {
|
"summary_fields": {
|
||||||
"organization": {
|
"organization": {
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"name": "Default",
|
"name": "Default",
|
||||||
"description": ""
|
"description": ""
|
||||||
|
},
|
||||||
|
"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 inventory",
|
||||||
|
"name": "Admin",
|
||||||
|
"id": 19
|
||||||
},
|
},
|
||||||
"created_by": {
|
"update_role": {
|
||||||
"id": 1,
|
"description": "May update the inventory",
|
||||||
"username": "admin",
|
"name": "Update",
|
||||||
"first_name": "",
|
"id": 20
|
||||||
"last_name": ""
|
|
||||||
},
|
},
|
||||||
"modified_by": {
|
"adhoc_role": {
|
||||||
"id": 1,
|
"description": "May run ad hoc commands on the inventory",
|
||||||
"username": "admin",
|
"name": "Ad Hoc",
|
||||||
"first_name": "",
|
"id": 21
|
||||||
"last_name": ""
|
|
||||||
},
|
},
|
||||||
"object_roles": {
|
"use_role": {
|
||||||
"admin_role": {
|
"description": "Can use the inventory in a job template",
|
||||||
"description": "Can manage all aspects of the inventory",
|
"name": "Use",
|
||||||
"name": "Admin",
|
"id": 22
|
||||||
"id": 19
|
|
||||||
},
|
|
||||||
"update_role": {
|
|
||||||
"description": "May update the inventory",
|
|
||||||
"name": "Update",
|
|
||||||
"id": 20
|
|
||||||
},
|
|
||||||
"adhoc_role": {
|
|
||||||
"description": "May run ad hoc commands on the inventory",
|
|
||||||
"name": "Ad Hoc",
|
|
||||||
"id": 21
|
|
||||||
},
|
|
||||||
"use_role": {
|
|
||||||
"description": "Can use the inventory in a job template",
|
|
||||||
"name": "Use",
|
|
||||||
"id": 22
|
|
||||||
},
|
|
||||||
"read_role": {
|
|
||||||
"description": "May view settings for the inventory",
|
|
||||||
"name": "Read",
|
|
||||||
"id": 23
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"user_capabilities": {
|
"read_role": {
|
||||||
"edit": true,
|
"description": "May view settings for the inventory",
|
||||||
"delete": true,
|
"name": "Read",
|
||||||
"copy": true,
|
"id": 23
|
||||||
"adhoc": true
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"user_capabilities": {
|
||||||
|
"edit": true,
|
||||||
|
"delete": true,
|
||||||
|
"copy": true,
|
||||||
|
"adhoc": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"created": "2019-10-04T14:28:04.765571Z",
|
"created": "2019-10-04T14:28:04.765571Z",
|
||||||
"modified": "2019-10-04T14:28:04.765594Z",
|
"modified": "2019-10-04T14:28:04.765594Z",
|
||||||
@@ -91,5 +91,6 @@
|
|||||||
"has_inventory_sources": false,
|
"has_inventory_sources": false,
|
||||||
"total_inventory_sources": 0,
|
"total_inventory_sources": 0,
|
||||||
"inventory_sources_with_failures": 0,
|
"inventory_sources_with_failures": 0,
|
||||||
"pending_deletion": false
|
"pending_deletion": false,
|
||||||
}
|
"prevent_instance_group_fallback": false
|
||||||
|
}
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ const jobTemplateData = {
|
|||||||
limit: '',
|
limit: '',
|
||||||
name: '',
|
name: '',
|
||||||
playbook: '',
|
playbook: '',
|
||||||
|
prevent_instance_group_fallback: false,
|
||||||
project: { id: 1, summary_fields: { organization: { id: 1 } } },
|
project: { id: 1, summary_fields: { organization: { id: 1 } } },
|
||||||
scm_branch: '',
|
scm_branch: '',
|
||||||
skip_tags: '',
|
skip_tags: '',
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ function JobTemplateDetail({ template }) {
|
|||||||
webhook_service,
|
webhook_service,
|
||||||
related: { webhook_receiver },
|
related: { webhook_receiver },
|
||||||
webhook_key,
|
webhook_key,
|
||||||
|
prevent_instance_group_fallback,
|
||||||
custom_virtualenv,
|
custom_virtualenv,
|
||||||
} = template;
|
} = template;
|
||||||
const { id: templateId } = useParams();
|
const { id: templateId } = useParams();
|
||||||
@@ -111,7 +112,8 @@ function JobTemplateDetail({ template }) {
|
|||||||
host_config_key ||
|
host_config_key ||
|
||||||
allow_simultaneous ||
|
allow_simultaneous ||
|
||||||
use_fact_cache ||
|
use_fact_cache ||
|
||||||
webhook_service;
|
webhook_service ||
|
||||||
|
prevent_instance_group_fallback;
|
||||||
|
|
||||||
const renderOptions = (
|
const renderOptions = (
|
||||||
<TextList component={TextListVariants.ul}>
|
<TextList component={TextListVariants.ul}>
|
||||||
@@ -140,6 +142,11 @@ function JobTemplateDetail({ template }) {
|
|||||||
{t`Webhooks`}
|
{t`Webhooks`}
|
||||||
</TextListItem>
|
</TextListItem>
|
||||||
)}
|
)}
|
||||||
|
{prevent_instance_group_fallback && (
|
||||||
|
<TextListItem component={TextListItemVariants.li}>
|
||||||
|
{t`Prevent Instance Group Fallback`}
|
||||||
|
</TextListItem>
|
||||||
|
)}
|
||||||
</TextList>
|
</TextList>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -335,6 +342,13 @@ function JobTemplateDetail({ template }) {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{prevent_instance_group_fallback && (
|
||||||
|
<Detail
|
||||||
|
label={t`Prevent Instance Group Fallback`}
|
||||||
|
dataCy="jt-detail-prevent-instnace-group-fallback"
|
||||||
|
helpText={helpText.preventInstanceGroupFallback}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<UserDateDetail
|
<UserDateDetail
|
||||||
label={t`Created`}
|
label={t`Created`}
|
||||||
date={created}
|
date={created}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ const mockJobTemplate = {
|
|||||||
limit: '',
|
limit: '',
|
||||||
name: 'Foo',
|
name: 'Foo',
|
||||||
playbook: 'Baz',
|
playbook: 'Baz',
|
||||||
|
prevent_instance_group_fallback: false,
|
||||||
project: 3,
|
project: 3,
|
||||||
scm_branch: '',
|
scm_branch: '',
|
||||||
skip_tags: '',
|
skip_tags: '',
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ const jtHelpTextStrings = () => ({
|
|||||||
privilegeEscalation: t`If enabled, run this playbook as an administrator.`,
|
privilegeEscalation: t`If enabled, run this playbook as an administrator.`,
|
||||||
enableWebhook: t`Enable webhook for this template.`,
|
enableWebhook: t`Enable webhook for this template.`,
|
||||||
concurrentJobs: t`If enabled, simultaneous runs of this job template will be allowed.`,
|
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.
|
||||||
|
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.`,
|
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: (
|
enabledOptions: (
|
||||||
<>
|
<>
|
||||||
@@ -38,6 +40,7 @@ const jtHelpTextStrings = () => ({
|
|||||||
<p>{t`Privilege escalation: If enabled, run this playbook as an administrator.`}</p>
|
<p>{t`Privilege escalation: If enabled, run this playbook as an administrator.`}</p>
|
||||||
<p>{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.`}</p>
|
<p>{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.`}</p>
|
||||||
<p>{t`Webhooks: Enable webhook for this template.`}</p>
|
<p>{t`Webhooks: Enable webhook for this template.`}</p>
|
||||||
|
<p>{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.`}</p>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
forks: (
|
forks: (
|
||||||
|
|||||||
@@ -597,6 +597,12 @@ function JobTemplateForm({
|
|||||||
label={t`Enable Fact Storage`}
|
label={t`Enable Fact Storage`}
|
||||||
tooltip={helpText.enableFactStorage}
|
tooltip={helpText.enableFactStorage}
|
||||||
/>
|
/>
|
||||||
|
<CheckboxField
|
||||||
|
id="option-prevent-instance-group-fallback"
|
||||||
|
name="prevent_instance_group_fallback"
|
||||||
|
label={t`Prevent Instance Group Fallback`}
|
||||||
|
tooltip={helpText.preventInstanceGroupFallback}
|
||||||
|
/>
|
||||||
</FormCheckboxLayout>
|
</FormCheckboxLayout>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</FormFullWidthLayout>
|
</FormFullWidthLayout>
|
||||||
@@ -731,6 +737,8 @@ const FormikApp = withFormik({
|
|||||||
limit: template.limit || '',
|
limit: template.limit || '',
|
||||||
name: template.name || '',
|
name: template.name || '',
|
||||||
playbook: template.playbook || '',
|
playbook: template.playbook || '',
|
||||||
|
prevent_instance_group_fallback:
|
||||||
|
template.prevent_instance_group_fallback || false,
|
||||||
project: summary_fields?.project || projectValues || null,
|
project: summary_fields?.project || projectValues || null,
|
||||||
scm_branch: template.scm_branch || '',
|
scm_branch: template.scm_branch || '',
|
||||||
skip_tags: template.skip_tags || '',
|
skip_tags: template.skip_tags || '',
|
||||||
|
|||||||
@@ -1,194 +1,199 @@
|
|||||||
{
|
{
|
||||||
"id": 7,
|
"id": 7,
|
||||||
"type": "job_template",
|
"type": "job_template",
|
||||||
"url": "/api/v2/job_templates/7/",
|
"url": "/api/v2/job_templates/7/",
|
||||||
"related": {
|
"related": {
|
||||||
"named_url": "/api/v2/job_templates/Mike's JT/",
|
"named_url": "/api/v2/job_templates/Mike's JT/",
|
||||||
"created_by": "/api/v2/users/1/",
|
"created_by": "/api/v2/users/1/",
|
||||||
"modified_by": "/api/v2/users/1/",
|
"modified_by": "/api/v2/users/1/",
|
||||||
"labels": "/api/v2/job_templates/7/labels/",
|
"labels": "/api/v2/job_templates/7/labels/",
|
||||||
"inventory": "/api/v2/inventories/1/",
|
"inventory": "/api/v2/inventories/1/",
|
||||||
"project": "/api/v2/projects/6/",
|
"project": "/api/v2/projects/6/",
|
||||||
"credentials": "/api/v2/job_templates/7/credentials/",
|
"credentials": "/api/v2/job_templates/7/credentials/",
|
||||||
"last_job": "/api/v2/jobs/12/",
|
"last_job": "/api/v2/jobs/12/",
|
||||||
"jobs": "/api/v2/job_templates/7/jobs/",
|
"jobs": "/api/v2/job_templates/7/jobs/",
|
||||||
"schedules": "/api/v2/job_templates/7/schedules/",
|
"schedules": "/api/v2/job_templates/7/schedules/",
|
||||||
"activity_stream": "/api/v2/job_templates/7/activity_stream/",
|
"activity_stream": "/api/v2/job_templates/7/activity_stream/",
|
||||||
"launch": "/api/v2/job_templates/7/launch/",
|
"launch": "/api/v2/job_templates/7/launch/",
|
||||||
"notification_templates_started": "/api/v2/job_templates/7/notification_templates_started/",
|
"notification_templates_started": "/api/v2/job_templates/7/notification_templates_started/",
|
||||||
"notification_templates_success": "/api/v2/job_templates/7/notification_templates_success/",
|
"notification_templates_success": "/api/v2/job_templates/7/notification_templates_success/",
|
||||||
"notification_templates_error": "/api/v2/job_templates/7/notification_templates_error/",
|
"notification_templates_error": "/api/v2/job_templates/7/notification_templates_error/",
|
||||||
"access_list": "/api/v2/job_templates/7/access_list/",
|
"access_list": "/api/v2/job_templates/7/access_list/",
|
||||||
"survey_spec": "/api/v2/job_templates/7/survey_spec/",
|
"survey_spec": "/api/v2/job_templates/7/survey_spec/",
|
||||||
"object_roles": "/api/v2/job_templates/7/object_roles/",
|
"object_roles": "/api/v2/job_templates/7/object_roles/",
|
||||||
"instance_groups": "/api/v2/job_templates/7/instance_groups/",
|
"instance_groups": "/api/v2/job_templates/7/instance_groups/",
|
||||||
"slice_workflow_jobs": "/api/v2/job_templates/7/slice_workflow_jobs/",
|
"slice_workflow_jobs": "/api/v2/job_templates/7/slice_workflow_jobs/",
|
||||||
"copy": "/api/v2/job_templates/7/copy/",
|
"copy": "/api/v2/job_templates/7/copy/",
|
||||||
"webhook_receiver": "/api/v2/job_templates/7/github/",
|
"webhook_receiver": "/api/v2/job_templates/7/github/",
|
||||||
"webhook_key": "/api/v2/job_templates/7/webhook_key/"
|
"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": {
|
"project": {
|
||||||
"inventory": {
|
"id": 6,
|
||||||
"id": 1,
|
"name": "Mike's Project",
|
||||||
"name": "Mike's Inventory",
|
"description": "",
|
||||||
"description": "",
|
"status": "successful",
|
||||||
"has_active_failures": false,
|
"scm_type": "git"
|
||||||
"total_hosts": 1,
|
},
|
||||||
"hosts_with_active_failures": 0,
|
"last_job": {
|
||||||
"total_groups": 0,
|
"id": 12,
|
||||||
"groups_with_active_failures": 0,
|
"name": "Mike's JT",
|
||||||
"has_inventory_sources": false,
|
"description": "",
|
||||||
"total_inventory_sources": 0,
|
"finished": "2019-10-01T14:34:35.142483Z",
|
||||||
"inventory_sources_with_failures": 0,
|
"status": "successful",
|
||||||
"organization_id": 1,
|
"failed": false
|
||||||
"kind": ""
|
},
|
||||||
},
|
"last_update": {
|
||||||
"project": {
|
"id": 12,
|
||||||
"id": 6,
|
"name": "Mike's JT",
|
||||||
"name": "Mike's Project",
|
"description": "",
|
||||||
"description": "",
|
"status": "successful",
|
||||||
"status": "successful",
|
"failed": false
|
||||||
"scm_type": "git"
|
},
|
||||||
},
|
"created_by": {
|
||||||
"last_job": {
|
"id": 1,
|
||||||
"id": 12,
|
"username": "admin",
|
||||||
"name": "Mike's JT",
|
"first_name": "",
|
||||||
"description": "",
|
"last_name": ""
|
||||||
"finished": "2019-10-01T14:34:35.142483Z",
|
},
|
||||||
"status": "successful",
|
"modified_by": {
|
||||||
"failed": false
|
"id": 1,
|
||||||
},
|
"username": "admin",
|
||||||
"last_update": {
|
"first_name": "",
|
||||||
"id": 12,
|
"last_name": ""
|
||||||
"name": "Mike's JT",
|
},
|
||||||
"description": "",
|
"object_roles": {
|
||||||
"status": "successful",
|
"admin_role": {
|
||||||
"failed": false
|
"description": "Can manage all aspects of the job template",
|
||||||
},
|
"name": "Admin",
|
||||||
"created_by": {
|
"id": 24
|
||||||
"id": 1,
|
},
|
||||||
"username": "admin",
|
"execute_role": {
|
||||||
"first_name": "",
|
"description": "May run the job template",
|
||||||
"last_name": ""
|
"name": "Execute",
|
||||||
},
|
"id": 25
|
||||||
"modified_by": {
|
},
|
||||||
"id": 1,
|
"read_role": {
|
||||||
"username": "admin",
|
"description": "May view settings for the job template",
|
||||||
"first_name": "",
|
"name": "Read",
|
||||||
"last_name": ""
|
"id": 26
|
||||||
},
|
}
|
||||||
"object_roles": {
|
},
|
||||||
"admin_role": {
|
"user_capabilities": {
|
||||||
"description": "Can manage all aspects of the job template",
|
"edit": true,
|
||||||
"name": "Admin",
|
"delete": true,
|
||||||
"id": 24
|
"start": true,
|
||||||
},
|
"schedule": true,
|
||||||
"execute_role": {
|
"copy": true
|
||||||
"description": "May run the job template",
|
},
|
||||||
"name": "Execute",
|
"labels": {
|
||||||
"id": 25
|
"count": 1,
|
||||||
},
|
"results": [
|
||||||
"read_role": {
|
{
|
||||||
"description": "May view settings for the job template",
|
"id": 91,
|
||||||
"name": "Read",
|
"name": "L_91o2"
|
||||||
"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"
|
|
||||||
}
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"created": "2019-09-30T16:18:34.564820Z",
|
"survey": {
|
||||||
"modified": "2019-10-01T14:47:31.818431Z",
|
"title": "",
|
||||||
"name": "Mike's JT",
|
"description": ""
|
||||||
"description": "",
|
},
|
||||||
"job_type": "run",
|
"recent_jobs": [
|
||||||
"inventory": 1,
|
{
|
||||||
"project": 6,
|
"id": 12,
|
||||||
"playbook": "ping.yml",
|
"status": "successful",
|
||||||
"scm_branch": "Foo branch",
|
"finished": "2019-10-01T14:34:35.142483Z",
|
||||||
"forks": 0,
|
"type": "job"
|
||||||
"limit": "",
|
}
|
||||||
"verbosity": 0,
|
],
|
||||||
"extra_vars": "",
|
"credentials": [
|
||||||
"job_tags": "T_100,T_200",
|
{
|
||||||
"force_handlers": false,
|
"id": 1,
|
||||||
"skip_tags": "S_100,S_200",
|
"kind": "ssh",
|
||||||
"start_at_task": "",
|
"name": "Credential 1"
|
||||||
"timeout": 0,
|
},
|
||||||
"use_fact_cache": true,
|
{
|
||||||
"last_job_run": "2019-10-01T14:34:35.142483Z",
|
"id": 2,
|
||||||
"last_job_failed": false,
|
"kind": "awx",
|
||||||
"next_job_run": null,
|
"name": "Credential 2"
|
||||||
"status": "successful",
|
}
|
||||||
"host_config_key": "",
|
],
|
||||||
"ask_scm_branch_on_launch": false,
|
"webhook_credential": {
|
||||||
"ask_diff_mode_on_launch": false,
|
"id": "1",
|
||||||
"ask_variables_on_launch": false,
|
"name": "Webhook Credential"
|
||||||
"ask_limit_on_launch": false,
|
},
|
||||||
"ask_tags_on_launch": false,
|
"execution_environment": {
|
||||||
"ask_skip_tags_on_launch": false,
|
"id": 1,
|
||||||
"ask_job_type_on_launch": false,
|
"name": "Default EE",
|
||||||
"ask_verbosity_on_launch": false,
|
"description": "",
|
||||||
"ask_inventory_on_launch": false,
|
"image": "quay.io/ansible/awx-ee"
|
||||||
"ask_credential_on_launch": false,
|
},
|
||||||
"survey_enabled": true,
|
"resolved_environment": {
|
||||||
"become_enabled": false,
|
"id": 1,
|
||||||
"diff_mode": false,
|
"name": "Default EE",
|
||||||
"allow_simultaneous": false,
|
"description": "",
|
||||||
"custom_virtualenv": null,
|
"image": "quay.io/ansible/awx-ee"
|
||||||
"job_slice_count": 1,
|
}
|
||||||
"webhook_credential": 1,
|
},
|
||||||
"webhook_key": "asertdyuhjkhgfd234567kjgfds",
|
"created": "2019-09-30T16:18:34.564820Z",
|
||||||
"webhook_service": "github",
|
"modified": "2019-10-01T14:47:31.818431Z",
|
||||||
"execution_environment": 1
|
"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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,10 @@ options:
|
|||||||
- list of Instance Groups for this Organization to run on.
|
- list of Instance Groups for this Organization to run on.
|
||||||
type: list
|
type: list
|
||||||
elements: str
|
elements: str
|
||||||
|
prevent_instance_group_fallback:
|
||||||
|
description:
|
||||||
|
- Prevent falling back to instance groups set on the organization
|
||||||
|
type: bool
|
||||||
state:
|
state:
|
||||||
description:
|
description:
|
||||||
- Desired state of the resource.
|
- Desired state of the resource.
|
||||||
@@ -111,6 +115,7 @@ def main():
|
|||||||
kind=dict(choices=['', 'smart'], default=''),
|
kind=dict(choices=['', 'smart'], default=''),
|
||||||
host_filter=dict(),
|
host_filter=dict(),
|
||||||
instance_groups=dict(type="list", elements='str'),
|
instance_groups=dict(type="list", elements='str'),
|
||||||
|
prevent_instance_group_fallback=dict(type='bool'),
|
||||||
state=dict(choices=['present', 'absent'], default='present'),
|
state=dict(choices=['present', 'absent'], default='present'),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -127,6 +132,7 @@ def main():
|
|||||||
state = module.params.get('state')
|
state = module.params.get('state')
|
||||||
kind = module.params.get('kind')
|
kind = module.params.get('kind')
|
||||||
host_filter = module.params.get('host_filter')
|
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)
|
# 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)
|
org_id = module.resolve_name_to_id('organizations', organization)
|
||||||
@@ -157,6 +163,8 @@ def main():
|
|||||||
'kind': kind,
|
'kind': kind,
|
||||||
'host_filter': host_filter,
|
'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:
|
if description is not None:
|
||||||
inventory_fields['description'] = description
|
inventory_fields['description'] = description
|
||||||
if variables is not None:
|
if variables is not None:
|
||||||
|
|||||||
@@ -315,6 +315,10 @@ options:
|
|||||||
- list of notifications to send on error
|
- list of notifications to send on error
|
||||||
type: list
|
type: list
|
||||||
elements: str
|
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
|
extends_documentation_fragment: awx.awx.auth
|
||||||
|
|
||||||
@@ -441,6 +445,7 @@ def main():
|
|||||||
notification_templates_started=dict(type="list", elements='str'),
|
notification_templates_started=dict(type="list", elements='str'),
|
||||||
notification_templates_success=dict(type="list", elements='str'),
|
notification_templates_success=dict(type="list", elements='str'),
|
||||||
notification_templates_error=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'),
|
state=dict(choices=['present', 'absent'], default='present'),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -539,6 +544,7 @@ def main():
|
|||||||
'custom_virtualenv',
|
'custom_virtualenv',
|
||||||
'job_slice_count',
|
'job_slice_count',
|
||||||
'webhook_service',
|
'webhook_service',
|
||||||
|
'prevent_instance_group_fallback',
|
||||||
):
|
):
|
||||||
field_val = module.params.get(field_name)
|
field_val = module.params.get(field_name)
|
||||||
if field_val is not None:
|
if field_val is not None:
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class Inventory(HasCopy, HasCreate, HasInstanceGroups, HasVariables, base.Base):
|
|||||||
organization=organization.id,
|
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)
|
update_payload(payload, optional_fields, kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ class JobTemplate(HasCopy, HasCreate, HasInstanceGroups, HasNotifications, HasSu
|
|||||||
'webhook_service',
|
'webhook_service',
|
||||||
'webhook_credential',
|
'webhook_credential',
|
||||||
'scm_branch',
|
'scm_branch',
|
||||||
|
'prevent_instance_group_fallback',
|
||||||
)
|
)
|
||||||
|
|
||||||
update_payload(payload, optional_fields, kwargs)
|
update_payload(payload, optional_fields, kwargs)
|
||||||
|
|||||||
Reference in New Issue
Block a user