move credential to prompt-for mechanism

This commit is contained in:
AlanCoding
2016-04-11 15:39:06 -04:00
parent 0dff851f62
commit b0bbeb2ca8
12 changed files with 108 additions and 51 deletions

View File

@@ -1675,7 +1675,7 @@ class JobTemplateSerializer(UnifiedJobTemplateSerializer, JobOptionsSerializer):
model = JobTemplate model = JobTemplate
fields = ('*', 'host_config_key', 'ask_variables_on_launch', 'ask_limit_on_launch', fields = ('*', 'host_config_key', 'ask_variables_on_launch', 'ask_limit_on_launch',
'ask_tags_on_launch', 'ask_job_type_on_launch', 'ask_inventory_on_launch', 'ask_tags_on_launch', 'ask_job_type_on_launch', 'ask_inventory_on_launch',
'survey_enabled', 'become_enabled') 'ask_credential_on_launch', 'survey_enabled', 'become_enabled')
def get_related(self, obj): def get_related(self, obj):
res = super(JobTemplateSerializer, self).get_related(obj) res = super(JobTemplateSerializer, self).get_related(obj)
@@ -2104,6 +2104,7 @@ class JobLaunchSerializer(BaseSerializer):
can_start_without_user_input = serializers.BooleanField(read_only=True) can_start_without_user_input = serializers.BooleanField(read_only=True)
variables_needed_to_start = serializers.ReadOnlyField() variables_needed_to_start = serializers.ReadOnlyField()
credential_needed_to_start = serializers.SerializerMethodField() credential_needed_to_start = serializers.SerializerMethodField()
inventory_needed_to_start = serializers.SerializerMethodField()
survey_enabled = serializers.SerializerMethodField() survey_enabled = serializers.SerializerMethodField()
extra_vars = VerbatimField(required=False, write_only=True) extra_vars = VerbatimField(required=False, write_only=True)
@@ -2111,13 +2112,13 @@ class JobLaunchSerializer(BaseSerializer):
model = JobTemplate model = JobTemplate
fields = ('can_start_without_user_input', 'passwords_needed_to_start', fields = ('can_start_without_user_input', 'passwords_needed_to_start',
'extra_vars', 'limit', 'job_tags', 'skip_tags', 'job_type', 'inventory', 'extra_vars', 'limit', 'job_tags', 'skip_tags', 'job_type', 'inventory',
'ask_variables_on_launch', 'ask_tags_on_launch', 'ask_job_type_on_launch', 'credential', 'ask_variables_on_launch', 'ask_tags_on_launch',
'ask_inventory_on_launch', 'ask_limit_on_launch', 'ask_job_type_on_launch', 'ask_inventory_on_launch', 'ask_limit_on_launch',
'survey_enabled', 'variables_needed_to_start', 'survey_enabled', 'variables_needed_to_start',
'credential', 'credential_needed_to_start',) 'credential_needed_to_start', 'inventory_needed_to_start',)
read_only_fields = ('ask_variables_on_launch', 'ask_limit_on_launch', read_only_fields = ('ask_variables_on_launch', 'ask_limit_on_launch',
'ask_tags_on_launch', 'ask_job_type_on_launch', 'ask_tags_on_launch', 'ask_job_type_on_launch',
'ask_inventory_on_launch') 'ask_inventory_on_launch', 'ask_credential_on_launch')
extra_kwargs = { extra_kwargs = {
'credential': {'write_only': True,}, 'credential': {'write_only': True,},
'limit': {'write_only': True,}, 'limit': {'write_only': True,},
@@ -2130,6 +2131,9 @@ class JobLaunchSerializer(BaseSerializer):
def get_credential_needed_to_start(self, obj): def get_credential_needed_to_start(self, obj):
return not (obj and obj.credential) return not (obj and obj.credential)
def get_inventory_needed_to_start(self, obj):
return not (obj and obj.inventory)
def get_survey_enabled(self, obj): def get_survey_enabled(self, obj):
if obj: if obj:
return obj.survey_enabled and 'spec' in obj.survey_spec return obj.survey_enabled and 'spec' in obj.survey_spec
@@ -2140,10 +2144,8 @@ class JobLaunchSerializer(BaseSerializer):
obj = self.context.get('obj') obj = self.context.get('obj')
data = self.context.get('data') data = self.context.get('data')
if obj and obj.credential is not None: if (not obj.ask_credential_on_launch) or (not attrs.get('credential', None)):
# force job template to override runtime credential, if present
credential = obj.credential credential = obj.credential
attrs.pop('credential', None)
else: else:
credential = attrs.get('credential', None) credential = attrs.get('credential', None)
if not credential: if not credential:
@@ -2191,6 +2193,7 @@ class JobLaunchSerializer(BaseSerializer):
JT_job_tags = obj.job_tags JT_job_tags = obj.job_tags
JT_skip_tags = obj.skip_tags JT_skip_tags = obj.skip_tags
JT_inventory = obj.inventory JT_inventory = obj.inventory
JT_credential = obj.credential
attrs = super(JobLaunchSerializer, self).validate(attrs) attrs = super(JobLaunchSerializer, self).validate(attrs)
obj.extra_vars = JT_extra_vars obj.extra_vars = JT_extra_vars
obj.limit = JT_limit obj.limit = JT_limit
@@ -2198,6 +2201,7 @@ class JobLaunchSerializer(BaseSerializer):
obj.skip_tags = JT_skip_tags obj.skip_tags = JT_skip_tags
obj.job_tags = JT_job_tags obj.job_tags = JT_job_tags
obj.inventory = JT_inventory obj.inventory = JT_inventory
obj.credential = JT_credential
return attrs return attrs
class NotifierSerializer(BaseSerializer): class NotifierSerializer(BaseSerializer):

View File

@@ -6,6 +6,16 @@ The response will include the following fields:
* `ask_variables_on_launch`: Flag indicating whether the job_template is * `ask_variables_on_launch`: Flag indicating whether the job_template is
configured to prompt for variables upon launch (boolean, read-only) configured to prompt for variables upon launch (boolean, read-only)
* `ask_tags_on_launch`: Flag indicating whether the job_template is
configured to prompt for tags upon launch (boolean, read-only)
* `ask_job_type_on_launch`: Flag indicating whether the job_template is
configured to prompt for job_type upon launch (boolean, read-only)
* `ask_limit_on_launch`: Flag indicating whether the job_template is
configured to prompt for limit upon launch (boolean, read-only)
* `ask_inventory_on_launch`: Flag indicating whether the job_template is
configured to prompt for limit upon launch (boolean, read-only)
* `ask_credential_on_launch`: Flag indicating whether the job_template is
configured to prompt for limit upon launch (boolean, read-only)
* `can_start_without_user_input`: Flag indicating if the job_template can be * `can_start_without_user_input`: Flag indicating if the job_template can be
launched without user-input (boolean, read-only) launched without user-input (boolean, read-only)
* `passwords_needed_to_start`: Password names required to launch the * `passwords_needed_to_start`: Password names required to launch the
@@ -17,13 +27,19 @@ The response will include the following fields:
* `credential_needed_to_start`: Flag indicating the presence of a credential * `credential_needed_to_start`: Flag indicating the presence of a credential
associated with the job template. If not then one should be supplied when associated with the job template. If not then one should be supplied when
launching the job (boolean, read-only) launching the job (boolean, read-only)
* `inventory_needed_to_start`: Flag indicating the presence of an inventory
associated with the job template. If not then one should be supplied when
launching the job (boolean, read-only)
Make a POST request to this resource to launch the job_template. If any Make a POST request to this resource to launch the job_template. If any
passwords or extra variables (extra_vars) are required, they must be passed passwords, inventory, or extra variables (extra_vars) are required, they must
via POST data, with extra_vars given as a YAML or JSON string and escaped be passed via POST data, with extra_vars given as a YAML or JSON string and
parentheses. If `credential_needed_to_start` is `True` then the `credential` escaped parentheses. If `credential_needed_to_start` is `True` then the
field is required as well. `credential` field is required and if the `inventory_needed_to_start` is
`True` then the `inventory` is required as well.
If successful, the response status code will be 202. If any required passwords If successful, the response status code will be 201. If any required passwords
are not provided, a 400 status code will be returned. If the job cannot be are not provided, a 400 status code will be returned. If the job cannot be
launched, a 405 status code will be returned. launched, a 405 status code will be returned. If the provided credential or
inventory are not allowed to be used by the user, then a 403 status code will
be returned.

View File

@@ -2086,10 +2086,6 @@ class JobTemplateLaunch(RetrieveAPIView, GenericAPIView):
if obj: if obj:
for p in obj.passwords_needed_to_start: for p in obj.passwords_needed_to_start:
data[p] = u'' data[p] = u''
if obj.credential:
data.pop('credential', None)
else:
data['credential'] = None
for v in obj.variables_needed_to_start: for v in obj.variables_needed_to_start:
extra_vars.setdefault(v, u'') extra_vars.setdefault(v, u'')
ask_for_vars_dict = obj._ask_for_vars_dict() ask_for_vars_dict = obj._ask_for_vars_dict()
@@ -2098,12 +2094,8 @@ class JobTemplateLaunch(RetrieveAPIView, GenericAPIView):
data.pop(field, None) data.pop(field, None)
elif field == 'extra_vars': elif field == 'extra_vars':
data[field] = extra_vars data[field] = extra_vars
elif field == 'inventory': elif field == 'inventory' or field == 'credential':
inv_obj = getattr(obj, field) data[field] = getattrd(obj, "%s.%s" % (field, 'id'), None)
if inv_obj in ('', None):
data[field] = None
else:
data[field] = inv_obj.id
else: else:
data[field] = getattr(obj, field) data[field] = getattr(obj, field)
return data return data
@@ -2123,22 +2115,19 @@ class JobTemplateLaunch(RetrieveAPIView, GenericAPIView):
if not serializer.is_valid(): if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# At this point, a credential is gauranteed to exist at serializer.instance.credential
if not request.user.can_access(Credential, 'read', serializer.instance.credential):
raise PermissionDenied()
kv = {
'credential': serializer.instance.credential.pk,
}
prompted_fields, ignored_fields = obj._accept_or_ignore_job_kwargs(**request.data) prompted_fields, ignored_fields = obj._accept_or_ignore_job_kwargs(**request.data)
if 'inventory' in prompted_fields: if 'credential' in prompted_fields and prompted_fields['credential'] != getattrd(obj, 'credential.pk', None):
new_credential = Credential.objects.get(pk=prompted_fields['credential'])
if not request.user.can_access(Credential, 'read', new_credential):
raise PermissionDenied()
if 'inventory' in prompted_fields and prompted_fields['inventory'] != getattrd(obj, 'inventory.pk', None):
new_inventory = Inventory.objects.get(pk=prompted_fields['inventory']) new_inventory = Inventory.objects.get(pk=prompted_fields['inventory'])
if not request.user.can_access(Inventory, 'read', new_inventory): if not request.user.can_access(Inventory, 'read', new_inventory):
raise PermissionDenied() raise PermissionDenied()
kv.update(prompted_fields) kv = prompted_fields
kv.update(passwords) kv.update(passwords)
new_job = obj.create_unified_job(**kv) new_job = obj.create_unified_job(**kv)
@@ -2435,7 +2424,7 @@ class JobTemplateCallback(GenericAPIView):
# Return the location of the new job. # Return the location of the new job.
headers = {'Location': job.get_absolute_url()} headers = {'Location': job.get_absolute_url()}
return Response(status=status.HTTP_202_ACCEPTED, headers=headers) return Response(status=status.HTTP_201_CREATED, headers=headers)
class JobTemplateJobsList(SubListCreateAPIView): class JobTemplateJobsList(SubListCreateAPIView):
@@ -2483,7 +2472,7 @@ class SystemJobTemplateLaunch(GenericAPIView):
new_job = obj.create_unified_job(**request.data) new_job = obj.create_unified_job(**request.data)
new_job.signal_start(**request.data) new_job.signal_start(**request.data)
data = dict(system_job=new_job.id) data = dict(system_job=new_job.id)
return Response(data, status=status.HTTP_202_ACCEPTED) return Response(data, status=status.HTTP_201_CREATED)
class SystemJobTemplateSchedulesList(SubListCreateAttachDetachAPIView): class SystemJobTemplateSchedulesList(SubListCreateAttachDetachAPIView):

View File

@@ -9,7 +9,7 @@ from django.conf import settings
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('main', '0013_v300_label_changes'), ('main', '0014_v300_invsource_cred'),
] ]
operations = [ operations = [
@@ -23,6 +23,11 @@ class Migration(migrations.Migration):
name='ask_inventory_on_launch', name='ask_inventory_on_launch',
field=models.BooleanField(default=False), field=models.BooleanField(default=False),
), ),
migrations.AddField(
model_name='jobtemplate',
name='ask_credential_on_launch',
field=models.BooleanField(default=False),
),
migrations.AddField( migrations.AddField(
model_name='jobtemplate', model_name='jobtemplate',
name='ask_job_type_on_launch', name='ask_job_type_on_launch',

View File

@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from awx.main.migrations import _ask_for_variables as ask_for_variables
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('main', '0015_v300_prompting_changes'),
]
operations = [
migrations.RunPython(ask_for_variables.migrate_credential),
]

View File

@@ -0,0 +1,9 @@
def migrate_credential(apps, schema_editor):
'''If credential is not currently present, set ask_for_credential_on_launch
equal to True, and otherwise leave it as the default False value.
'''
JobTemplate = apps.get_model('main', 'JobTemplate')
for jt in JobTemplate.objects.iterator():
if jt.credential is None:
jt.ask_credential_on_launch = True
jt.save()

View File

@@ -212,6 +212,10 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, ResourceMixin):
blank=True, blank=True,
default=False, default=False,
) )
ask_credential_on_launch = models.BooleanField(
blank=True,
default=False,
)
survey_enabled = models.BooleanField( survey_enabled = models.BooleanField(
default=False, default=False,
@@ -256,6 +260,8 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, ResourceMixin):
raise ValidationError('Scan jobs must be assigned a fixed inventory') raise ValidationError('Scan jobs must be assigned a fixed inventory')
if (not self.ask_inventory_on_launch) and self.inventory is None: if (not self.ask_inventory_on_launch) and self.inventory is None:
raise ValidationError('Job Template must either have an inventory or allow prompting for inventory') raise ValidationError('Job Template must either have an inventory or allow prompting for inventory')
if (not self.ask_credential_on_launch) and self.credential is None:
raise ValidationError('Job Template must either have a credential or allow prompting for credential')
return super(JobTemplate, self).clean() return super(JobTemplate, self).clean()
def create_job(self, **kwargs): def create_job(self, **kwargs):
@@ -396,7 +402,8 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, ResourceMixin):
job_tags=self.ask_tags_on_launch, job_tags=self.ask_tags_on_launch,
skip_tags=self.ask_tags_on_launch, skip_tags=self.ask_tags_on_launch,
job_type=self.ask_job_type_on_launch, job_type=self.ask_job_type_on_launch,
inventory=self.ask_inventory_on_launch inventory=self.ask_inventory_on_launch,
credential=self.ask_credential_on_launch
) )
def _accept_or_ignore_job_kwargs(self, **kwargs): def _accept_or_ignore_job_kwargs(self, **kwargs):

View File

@@ -352,6 +352,7 @@ class BaseTestMixin(QueueTestMixin, MockCommonlySlowTestMixin):
'host_config_key': settings.SYSTEM_UUID, 'host_config_key': settings.SYSTEM_UUID,
'created_by': created_by, 'created_by': created_by,
'playbook': playbook, 'playbook': playbook,
'ask_credential_on_launch': True,
} }
opts.update(kwargs) opts.update(kwargs)
return JobTemplate.objects.create(**opts) return JobTemplate.objects.create(**opts)

View File

@@ -37,6 +37,7 @@ def job_template_prompts(project, inventory, machine_credential):
ask_job_type_on_launch=on_off, ask_job_type_on_launch=on_off,
ask_inventory_on_launch=on_off, ask_inventory_on_launch=on_off,
ask_limit_on_launch=on_off, ask_limit_on_launch=on_off,
ask_credential_on_launch=on_off,
) )
return rf return rf
@@ -59,12 +60,14 @@ def test_job_ignore_unprompted_vars(runtime_data, job_template_prompts, post, us
assert job_obj.job_type == job_template_saved.job_type assert job_obj.job_type == job_template_saved.job_type
assert job_obj.inventory.pk == job_template_saved.inventory.pk assert job_obj.inventory.pk == job_template_saved.inventory.pk
assert job_obj.job_tags == job_template_saved.job_tags assert job_obj.job_tags == job_template_saved.job_tags
assert job_obj.credential.pk == job_template_saved.credential.pk
# Check that response tells us what things were ignored # Check that response tells us what things were ignored
assert 'job_launch_var' in response.data['ignored_fields']['extra_vars'] assert 'job_launch_var' in response.data['ignored_fields']['extra_vars']
assert 'job_type' in response.data['ignored_fields'] assert 'job_type' in response.data['ignored_fields']
assert 'limit' in response.data['ignored_fields'] assert 'limit' in response.data['ignored_fields']
assert 'inventory' in response.data['ignored_fields'] assert 'inventory' in response.data['ignored_fields']
assert 'credential' in response.data['ignored_fields']
assert 'job_tags' in response.data['ignored_fields'] assert 'job_tags' in response.data['ignored_fields']
assert 'skip_tags' in response.data['ignored_fields'] assert 'skip_tags' in response.data['ignored_fields']
@@ -89,6 +92,7 @@ def test_job_accept_prompted_vars(runtime_data, job_template_prompts, post, user
assert job_obj.limit == runtime_data['limit'] assert job_obj.limit == runtime_data['limit']
assert job_obj.job_type == runtime_data['job_type'] assert job_obj.job_type == runtime_data['job_type']
assert job_obj.inventory.pk == runtime_data['inventory'] assert job_obj.inventory.pk == runtime_data['inventory']
assert job_obj.credential.pk == runtime_data['credential']
assert job_obj.job_tags == runtime_data['job_tags'] assert job_obj.job_tags == runtime_data['job_tags']
@pytest.mark.django_db @pytest.mark.django_db
@@ -99,11 +103,12 @@ def test_job_reject_invalid_prompted_vars(runtime_data, job_template_prompts, po
response = post( response = post(
reverse('api:job_template_launch', args=[job_template.pk]), reverse('api:job_template_launch', args=[job_template.pk]),
dict(job_type='foobicate', # foobicate is not a valid job type dict(job_type='foobicate', # foobicate is not a valid job type
inventory=87865), user('admin', True)) inventory=87865, credential=48474), user('admin', True))
assert response.status_code == 400 assert response.status_code == 400
assert response.data['job_type'] == [u'"foobicate" is not a valid choice.'] assert response.data['job_type'] == [u'"foobicate" is not a valid choice.']
assert response.data['inventory'] == [u'Invalid pk "87865" - object does not exist.'] assert response.data['inventory'] == [u'Invalid pk "87865" - object does not exist.']
assert response.data['credential'] == [u'Invalid pk "48474" - object does not exist.']
@pytest.mark.django_db @pytest.mark.django_db
@pytest.mark.job_runtime_vars @pytest.mark.job_runtime_vars
@@ -189,7 +194,7 @@ def test_job_relaunch_prompted_vars(runtime_data, job_template_prompts, post, us
@pytest.mark.django_db @pytest.mark.django_db
def test_job_launch_JT_with_validation(machine_credential, deploy_jobtemplate): def test_job_launch_JT_with_validation(machine_credential, deploy_jobtemplate):
deploy_jobtemplate.extra_vars = '{"job_template_var": 3}' deploy_jobtemplate.extra_vars = '{"job_template_var": 3}'
deploy_jobtemplate.credential = None deploy_jobtemplate.ask_credential_on_launch = True
deploy_jobtemplate.save() deploy_jobtemplate.save()
kv = dict(extra_vars={"job_launch_var": 4}, credential=machine_credential.id) kv = dict(extra_vars={"job_launch_var": 4}, credential=machine_credential.id)

View File

@@ -503,6 +503,7 @@ class BaseJobTestMixin(BaseTestMixin):
playbook=self.proj_dev.playbooks[0], playbook=self.proj_dev.playbooks[0],
host_config_key=uuid.uuid4().hex, host_config_key=uuid.uuid4().hex,
created_by=self.user_sue, created_by=self.user_sue,
ask_credential_on_launch=True,
) )
# self.job_eng_run = self.jt_eng_run.create_job( # self.job_eng_run = self.jt_eng_run.create_job(
# created_by=self.user_sue, # created_by=self.user_sue,

View File

@@ -28,6 +28,7 @@ class JobTemplateLaunchTest(BaseJobTestMixin, django.test.TransactionTestCase):
credential = self.cred_sue.pk, credential = self.cred_sue.pk,
playbook = self.proj_dev.playbooks[0], playbook = self.proj_dev.playbooks[0],
ask_variables_on_launch = True, ask_variables_on_launch = True,
ask_credential_on_launch = True,
) )
self.data_no_cred = dict( self.data_no_cred = dict(
name = 'launched job template no credential', name = 'launched job template no credential',
@@ -35,6 +36,8 @@ class JobTemplateLaunchTest(BaseJobTestMixin, django.test.TransactionTestCase):
inventory = self.inv_eng.pk, inventory = self.inv_eng.pk,
project = self.proj_dev.pk, project = self.proj_dev.pk,
playbook = self.proj_dev.playbooks[0], playbook = self.proj_dev.playbooks[0],
ask_credential_on_launch = True,
ask_variables_on_launch = True,
) )
self.data_cred_ask = dict(self.data) self.data_cred_ask = dict(self.data)
self.data_cred_ask['name'] = 'launched job templated with ask passwords' self.data_cred_ask['name'] = 'launched job templated with ask passwords'
@@ -112,21 +115,21 @@ class JobTemplateLaunchTest(BaseJobTestMixin, django.test.TransactionTestCase):
self.assertEqual(j.status, 'new') self.assertEqual(j.status, 'new')
self.assertEqual(j.credential.pk, self.cred_doug.pk) self.assertEqual(j.credential.pk, self.cred_doug.pk)
def test_credential_override_reject(self): def test_credential_override(self):
# Explicit, credential # Explicit, credential
with self.current_user(self.user_sue): with self.current_user(self.user_sue):
response = self.post(self.launch_url, {'credential': self.cred_doug.pk}, expect=201) response = self.post(self.launch_url, {'credential': self.cred_doug.pk}, expect=201)
j = Job.objects.get(pk=response['job']) j = Job.objects.get(pk=response['job'])
self.assertEqual(j.status, 'new') self.assertEqual(j.status, 'new')
self.assertEqual(j.credential.pk, self.cred_sue.pk) self.assertEqual(j.credential.pk, self.cred_doug.pk)
def test_credential_override_via_credential_id_reject(self): def test_credential_override_via_credential_id(self):
# Explicit, credential # Explicit, credential
with self.current_user(self.user_sue): with self.current_user(self.user_sue):
response = self.post(self.launch_url, {'credential_id': self.cred_doug.pk}, expect=201) response = self.post(self.launch_url, {'credential_id': self.cred_doug.pk}, expect=201)
j = Job.objects.get(pk=response['job']) j = Job.objects.get(pk=response['job'])
self.assertEqual(j.status, 'new') self.assertEqual(j.status, 'new')
self.assertEqual(j.credential.pk, self.cred_sue.pk) self.assertEqual(j.credential.pk, self.cred_doug.pk)
def test_bad_credential_launch_fail(self): def test_bad_credential_launch_fail(self):
# Can't launch a job template without a credential defined (or if we # Can't launch a job template without a credential defined (or if we
@@ -192,6 +195,7 @@ class JobTemplateLaunchPasswordsTest(BaseJobTestMixin, django.test.TransactionTe
project = self.proj_dev.pk, project = self.proj_dev.pk,
credential = self.cred_sue_ask.pk, credential = self.cred_sue_ask.pk,
playbook = self.proj_dev.playbooks[0], playbook = self.proj_dev.playbooks[0],
ask_credential_on_launch = True,
) )
with self.current_user(self.user_sue): with self.current_user(self.user_sue):

View File

@@ -798,7 +798,7 @@ class JobTemplateCallbackTest(BaseJobTestMixin, django.test.LiveServerTestCase):
self.assertEqual(jobs_qs.count(), 0) self.assertEqual(jobs_qs.count(), 0)
# Create the job itself. # Create the job itself.
result = self.post(url, data, expect=202, remote_addr=host_ip) result = self.post(url, data, expect=201, remote_addr=host_ip)
# Establish that we got back what we expect, and made the changes # Establish that we got back what we expect, and made the changes
# that we expect. # that we expect.
@@ -813,7 +813,7 @@ class JobTemplateCallbackTest(BaseJobTestMixin, django.test.LiveServerTestCase):
self.assertEqual(job.hosts.all()[0], host) self.assertEqual(job.hosts.all()[0], host)
# Create the job itself using URL-encoded form data instead of JSON. # Create the job itself using URL-encoded form data instead of JSON.
result = self.post(url, data, expect=202, remote_addr=host_ip, data_type='form') result = self.post(url, data, expect=201, remote_addr=host_ip, data_type='form')
# Establish that we got back what we expect, and made the changes # Establish that we got back what we expect, and made the changes
# that we expect. # that we expect.
@@ -829,7 +829,7 @@ class JobTemplateCallbackTest(BaseJobTestMixin, django.test.LiveServerTestCase):
# Run the callback job again with extra vars and verify their presence # Run the callback job again with extra vars and verify their presence
data.update(dict(extra_vars=dict(key="value"))) data.update(dict(extra_vars=dict(key="value")))
result = self.post(url, data, expect=202, remote_addr=host_ip) result = self.post(url, data, expect=201, remote_addr=host_ip)
jobs_qs = job_template.jobs.filter(launch_type='callback').order_by('-pk') jobs_qs = job_template.jobs.filter(launch_type='callback').order_by('-pk')
job = jobs_qs[0] job = jobs_qs[0]
self.assertTrue("key" in job.extra_vars) self.assertTrue("key" in job.extra_vars)
@@ -878,7 +878,7 @@ class JobTemplateCallbackTest(BaseJobTestMixin, django.test.LiveServerTestCase):
break break
self.assertTrue(host) self.assertTrue(host)
self.assertEqual(jobs_qs.count(), 3) self.assertEqual(jobs_qs.count(), 3)
self.post(url, data, expect=202, remote_addr=host_ip) self.post(url, data, expect=201, remote_addr=host_ip)
self.assertEqual(jobs_qs.count(), 4) self.assertEqual(jobs_qs.count(), 4)
job = jobs_qs[0] job = jobs_qs[0]
self.assertEqual(job.launch_type, 'callback') self.assertEqual(job.launch_type, 'callback')
@@ -903,7 +903,7 @@ class JobTemplateCallbackTest(BaseJobTestMixin, django.test.LiveServerTestCase):
break break
self.assertTrue(host) self.assertTrue(host)
self.assertEqual(jobs_qs.count(), 4) self.assertEqual(jobs_qs.count(), 4)
self.post(url, data, expect=202, remote_addr=host_ip) self.post(url, data, expect=201, remote_addr=host_ip)
self.assertEqual(jobs_qs.count(), 5) self.assertEqual(jobs_qs.count(), 5)
job = jobs_qs[0] job = jobs_qs[0]
self.assertEqual(job.launch_type, 'callback') self.assertEqual(job.launch_type, 'callback')
@@ -917,7 +917,7 @@ class JobTemplateCallbackTest(BaseJobTestMixin, django.test.LiveServerTestCase):
host = host_qs[0] host = host_qs[0]
host_ip = host.variables_dict['ansible_ssh_host'] host_ip = host.variables_dict['ansible_ssh_host']
self.assertEqual(jobs_qs.count(), 5) self.assertEqual(jobs_qs.count(), 5)
self.post(url, data, expect=202, remote_addr=host_ip) self.post(url, data, expect=201, remote_addr=host_ip)
self.assertEqual(jobs_qs.count(), 6) self.assertEqual(jobs_qs.count(), 6)
job = jobs_qs[0] job = jobs_qs[0]
self.assertEqual(job.launch_type, 'callback') self.assertEqual(job.launch_type, 'callback')
@@ -951,7 +951,7 @@ class JobTemplateCallbackTest(BaseJobTestMixin, django.test.LiveServerTestCase):
break break
self.assertTrue(host) self.assertTrue(host)
self.assertEqual(jobs_qs.count(), 6) self.assertEqual(jobs_qs.count(), 6)
self.post(url, data, expect=202, remote_addr=host_ip) self.post(url, data, expect=201, remote_addr=host_ip)
self.assertEqual(jobs_qs.count(), 7) self.assertEqual(jobs_qs.count(), 7)
job = jobs_qs[0] job = jobs_qs[0]
self.assertEqual(job.launch_type, 'callback') self.assertEqual(job.launch_type, 'callback')