mirror of
https://github.com/ansible/awx.git
synced 2026-04-10 20:49:24 -02:30
Switch to using extra_vars for survey variables, fix up some unit tests
related to that and some issues with system jobs
This commit is contained in:
@@ -1486,13 +1486,14 @@ class JobTemplateLaunch(GenericAPIView):
|
|||||||
request_data = {}
|
request_data = {}
|
||||||
else:
|
else:
|
||||||
request_data = request.DATA
|
request_data = request.DATA
|
||||||
validation_errors = obj.survey_variable_validation(request_data)
|
if 'extra_vars' in request_data:
|
||||||
if validation_errors:
|
validation_errors = obj.survey_variable_validation(request_data['extra_vars'])
|
||||||
return Response(dict(errors=validation_errors),
|
if validation_errors:
|
||||||
status=status.HTTP_400_BAD_REQUEST)
|
return Response(dict(errors=validation_errors),
|
||||||
|
status=status.HTTP_400_BAD_REQUEST)
|
||||||
if obj.credential is None and ('credential' not in request.DATA and 'credential_id' not in request.DATA):
|
if obj.credential is None and ('credential' not in request.DATA and 'credential_id' not in request.DATA):
|
||||||
return Response(dict(errors="Credential not provided"), status=status.HTTP_400_BAD_REQUEST)
|
return Response(dict(errors="Credential not provided"), status=status.HTTP_400_BAD_REQUEST)
|
||||||
new_job = obj.create_unified_job(**request.DATA)
|
new_job = obj.create_unified_job()
|
||||||
result = new_job.signal_start(**request.DATA)
|
result = new_job.signal_start(**request.DATA)
|
||||||
if not result:
|
if not result:
|
||||||
data = dict(passwords_needed_to_start=new_job.passwords_needed_to_start)
|
data = dict(passwords_needed_to_start=new_job.passwords_needed_to_start)
|
||||||
@@ -1773,7 +1774,8 @@ class SystemJobTemplateLaunch(GenericAPIView):
|
|||||||
extra_vars = {}
|
extra_vars = {}
|
||||||
else:
|
else:
|
||||||
extra_vars = {}
|
extra_vars = {}
|
||||||
result = new_job.signal_start(**extra_vars)
|
ev = {'extra_vars': extra_vars}
|
||||||
|
result = new_job.signal_start(**ev)
|
||||||
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_202_ACCEPTED)
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,10 @@ class VarsDictProperty(object):
|
|||||||
def __get__(self, obj, type=None):
|
def __get__(self, obj, type=None):
|
||||||
if obj is None:
|
if obj is None:
|
||||||
return self
|
return self
|
||||||
v = getattr(obj, self.field).encode('utf-8')
|
v = getattr(obj, self.field)
|
||||||
|
if hasattr(v, 'items'):
|
||||||
|
return v
|
||||||
|
v = v.encode('utf-8')
|
||||||
d = None
|
d = None
|
||||||
try:
|
try:
|
||||||
d = json.loads(v.strip() or '{}')
|
d = json.loads(v.strip() or '{}')
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ class JobTemplate(UnifiedJobTemplate, JobOptions):
|
|||||||
def _get_unified_job_field_names(cls):
|
def _get_unified_job_field_names(cls):
|
||||||
return ['name', 'description', 'job_type', 'inventory', 'project',
|
return ['name', 'description', 'job_type', 'inventory', 'project',
|
||||||
'playbook', 'credential', 'cloud_credential', 'forks', 'schedule',
|
'playbook', 'credential', 'cloud_credential', 'forks', 'schedule',
|
||||||
'limit', 'verbosity', 'extra_vars', 'job_tags', 'launch_type',
|
'limit', 'verbosity', 'job_tags', 'extra_vars', 'launch_type',
|
||||||
'force_handlers', 'skip_tags', 'start_at_task']
|
'force_handlers', 'skip_tags', 'start_at_task']
|
||||||
|
|
||||||
def create_job(self, **kwargs):
|
def create_job(self, **kwargs):
|
||||||
@@ -949,7 +949,7 @@ class SystemJobTemplate(UnifiedJobTemplate, SystemJobOptions):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_unified_job_field_names(cls):
|
def _get_unified_job_field_names(cls):
|
||||||
return ['name', 'description', 'job_type']
|
return ['name', 'description', 'job_type', 'extra_vars']
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('api:system_job_template_detail', args=(self.pk,))
|
return reverse('api:system_job_template_detail', args=(self.pk,))
|
||||||
|
|||||||
@@ -306,7 +306,10 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique):
|
|||||||
value = value.id
|
value = value.id
|
||||||
create_kwargs[id_field_name] = value
|
create_kwargs[id_field_name] = value
|
||||||
elif field_name in kwargs:
|
elif field_name in kwargs:
|
||||||
create_kwargs[field_name] = kwargs[field_name]
|
if field_name == 'extra_vars' and type(kwargs[field_name]) == dict:
|
||||||
|
create_kwargs[field_name] = json.dumps(kwargs['extra_vars'])
|
||||||
|
else:
|
||||||
|
create_kwargs[field_name] = kwargs[field_name]
|
||||||
elif hasattr(self, field_name):
|
elif hasattr(self, field_name):
|
||||||
create_kwargs[field_name] = getattr(self, field_name)
|
create_kwargs[field_name] = getattr(self, field_name)
|
||||||
kwargs = self._update_unified_job_kwargs(**create_kwargs)
|
kwargs = self._update_unified_job_kwargs(**create_kwargs)
|
||||||
@@ -692,9 +695,10 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique
|
|||||||
self.job_explanation = u'Missing needed fields: %s.' % missing_fields
|
self.job_explanation = u'Missing needed fields: %s.' % missing_fields
|
||||||
self.save(update_fields=['job_explanation'])
|
self.save(update_fields=['job_explanation'])
|
||||||
return False
|
return False
|
||||||
extra_data = dict([(field, kwargs[field]) for field in kwargs
|
#extra_data = dict([(field, kwargs[field]) for field in kwargs
|
||||||
if field not in needed])
|
# if field not in needed])
|
||||||
self.handle_extra_data(extra_data)
|
if 'extra_vars' in kwargs:
|
||||||
|
self.handle_extra_data(kwargs['extra_vars'])
|
||||||
task_class().apply_async((self.pk,), opts, link_error=error_callback)
|
task_class().apply_async((self.pk,), opts, link_error=error_callback)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -715,9 +719,8 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique
|
|||||||
opts = dict([(field, kwargs.get(field, '')) for field in needed])
|
opts = dict([(field, kwargs.get(field, '')) for field in needed])
|
||||||
if not all(opts.values()):
|
if not all(opts.values()):
|
||||||
return False
|
return False
|
||||||
extra_data = dict([(field, kwargs[field]) for field in kwargs
|
if 'extra_vars' in kwargs:
|
||||||
if field not in needed])
|
self.handle_extra_data(kwargs['extra_vars'])
|
||||||
self.handle_extra_data(extra_data)
|
|
||||||
|
|
||||||
# Save the pending status, and inform the SocketIO listener.
|
# Save the pending status, and inform the SocketIO listener.
|
||||||
self.update_fields(start_args=json.dumps(kwargs), status='pending')
|
self.update_fields(start_args=json.dumps(kwargs), status='pending')
|
||||||
|
|||||||
@@ -968,7 +968,7 @@ class JobTemplateTest(BaseJobTestMixin, django.test.TestCase):
|
|||||||
launch_url = reverse('api:job_template_launch', args=(new_jt_id,))
|
launch_url = reverse('api:job_template_launch', args=(new_jt_id,))
|
||||||
response = self.get(launch_url)
|
response = self.get(launch_url)
|
||||||
self.assertTrue('favorite_color' in response['variables_needed_to_start'])
|
self.assertTrue('favorite_color' in response['variables_needed_to_start'])
|
||||||
response = self.post(launch_url, dict(favorite_color="green"), expect=202)
|
response = self.post(launch_url, dict(extra_vars=dict(favorite_color="green")), expect=202)
|
||||||
job = Job.objects.get(pk=response["job"])
|
job = Job.objects.get(pk=response["job"])
|
||||||
job_extra = json.loads(job.extra_vars)
|
job_extra = json.loads(job.extra_vars)
|
||||||
self.assertTrue("favorite_color" in job_extra)
|
self.assertTrue("favorite_color" in job_extra)
|
||||||
@@ -983,43 +983,43 @@ class JobTemplateTest(BaseJobTestMixin, django.test.TestCase):
|
|||||||
response = self.post(url, json.loads(TEST_SURVEY_REQUIREMENTS), expect=200)
|
response = self.post(url, json.loads(TEST_SURVEY_REQUIREMENTS), expect=200)
|
||||||
launch_url = reverse('api:job_template_launch', args=(new_jt_id,))
|
launch_url = reverse('api:job_template_launch', args=(new_jt_id,))
|
||||||
# Just the required answer should work
|
# Just the required answer should work
|
||||||
self.post(launch_url, dict(reqd_answer="foo"), expect=202)
|
self.post(launch_url, dict(extra_vars=dict(reqd_answer="foo")), expect=202)
|
||||||
# Short answer but requires a long answer
|
# Short answer but requires a long answer
|
||||||
self.post(launch_url, dict(long_answer='a', reqd_answer="foo"), expect=400)
|
self.post(launch_url, dict(extra_vars=dict(long_answer='a', reqd_answer="foo")), expect=400)
|
||||||
# Long answer but requires a short answer
|
# Long answer but requires a short answer
|
||||||
self.post(launch_url, dict(short_answer='thisissomelongtext', reqd_answer="foo"), expect=400)
|
self.post(launch_url, dict(extra_vars=dict(short_answer='thisissomelongtext', reqd_answer="foo")), expect=400)
|
||||||
# Long answer but missing required answer
|
# Long answer but missing required answer
|
||||||
self.post(launch_url, dict(long_answer='thisissomelongtext'), expect=400)
|
self.post(launch_url, dict(extra_vars=dict(long_answer='thisissomelongtext')), expect=400)
|
||||||
# Integer that's not big enough
|
# Integer that's not big enough
|
||||||
self.post(launch_url, dict(int_answer=0, reqd_answer="foo"), expect=400)
|
self.post(launch_url, dict(extra_vars=dict(int_answer=0, reqd_answer="foo")), expect=400)
|
||||||
# Integer that's too big
|
# Integer that's too big
|
||||||
self.post(launch_url, dict(int_answer=10, reqd_answer="foo"), expect=400)
|
self.post(launch_url, dict(extra_vars=dict(int_answer=10, reqd_answer="foo")), expect=400)
|
||||||
# Integer that's just riiiiight
|
# Integer that's just riiiiight
|
||||||
self.post(launch_url, dict(int_answer=3, reqd_answer="foo"), expect=202)
|
self.post(launch_url, dict(extra_vars=dict(int_answer=3, reqd_answer="foo")), expect=202)
|
||||||
# Integer bigger than min with no max defined
|
# Integer bigger than min with no max defined
|
||||||
self.post(launch_url, dict(int_answer_no_max=3, reqd_answer="foo"), expect=202)
|
self.post(launch_url, dict(extra_vars=dict(int_answer_no_max=3, reqd_answer="foo")), expect=202)
|
||||||
# Integer answer that's the wrong type
|
# Integer answer that's the wrong type
|
||||||
self.post(launch_url, dict(int_answer="test", reqd_answer="foo"), expect=400)
|
self.post(launch_url, dict(extra_vars=dict(int_answer="test", reqd_answer="foo")), expect=400)
|
||||||
# Float that's too big
|
# Float that's too big
|
||||||
self.post(launch_url, dict(float_answer=10.5, reqd_answer="foo"), expect=400)
|
self.post(launch_url, dict(extra_vars=dict(float_answer=10.5, reqd_answer="foo")), expect=400)
|
||||||
# Float that's too small
|
# Float that's too small
|
||||||
self.post(launch_url, dict(float_answer=1.995, reqd_answer="foo"), expect=400)
|
self.post(launch_url, dict(extra_vars=dict(float_answer=1.995, reqd_answer="foo")), expect=400)
|
||||||
# float that's just riiiiight
|
# float that's just riiiiight
|
||||||
self.post(launch_url, dict(float_answer=2.01, reqd_answer="foo"), expect=202)
|
self.post(launch_url, dict(extra_vars=dict(float_answer=2.01, reqd_answer="foo")), expect=202)
|
||||||
# float answer that's the wrong type
|
# float answer that's the wrong type
|
||||||
self.post(launch_url, dict(float_answer="test", reqd_answer="foo"), expect=400)
|
self.post(launch_url, dict(extra_vars=dict(float_answer="test", reqd_answer="foo")), expect=400)
|
||||||
# Wrong choice in single choice
|
# Wrong choice in single choice
|
||||||
self.post(launch_url, dict(reqd_answer="foo", single_choice="three"), expect=400)
|
self.post(launch_url, dict(extra_vars=dict(reqd_answer="foo", single_choice="three")), expect=400)
|
||||||
# Wrong choice in multi choice
|
# Wrong choice in multi choice
|
||||||
self.post(launch_url, dict(reqd_answer="foo", multi_choice=["four"]), expect=400)
|
self.post(launch_url, dict(extra_vars=dict(reqd_answer="foo", multi_choice=["four"])), expect=400)
|
||||||
# Wrong type for multi choicen
|
# Wrong type for multi choicen
|
||||||
self.post(launch_url, dict(reqd_answer="foo", multi_choice="two"), expect=400)
|
self.post(launch_url, dict(extra_vars=dict(reqd_answer="foo", multi_choice="two")), expect=400)
|
||||||
# Right choice in single choice
|
# Right choice in single choice
|
||||||
self.post(launch_url, dict(reqd_answer="foo", single_choice="two"), expect=202)
|
self.post(launch_url, dict(extra_vars=dict(reqd_answer="foo", single_choice="two")), expect=202)
|
||||||
# Right choices in multi choice
|
# Right choices in multi choice
|
||||||
self.post(launch_url, dict(reqd_answer="foo", multi_choice=["one", "two"]), expect=202)
|
self.post(launch_url, dict(extra_vars=dict(reqd_answer="foo", multi_choice=["one", "two"])), expect=202)
|
||||||
# Nested json
|
# Nested json
|
||||||
self.post(launch_url, dict(json_answer=dict(test="val", num=1), reqd_answer="foo"), expect=202)
|
self.post(launch_url, dict(extra_vars=dict(json_answer=dict(test="val", num=1), reqd_answer="foo")), expect=202)
|
||||||
|
|
||||||
def test_launch_job_template(self):
|
def test_launch_job_template(self):
|
||||||
url = reverse('api:job_template_list')
|
url = reverse('api:job_template_list')
|
||||||
|
|||||||
Reference in New Issue
Block a user