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:
Matthew Jones 2014-12-17 16:04:25 -05:00
parent 6e3cd5bc54
commit d4879506c2
5 changed files with 44 additions and 36 deletions

View File

@ -1486,13 +1486,14 @@ class JobTemplateLaunch(GenericAPIView):
request_data = {}
else:
request_data = request.DATA
validation_errors = obj.survey_variable_validation(request_data)
if validation_errors:
return Response(dict(errors=validation_errors),
status=status.HTTP_400_BAD_REQUEST)
if 'extra_vars' in request_data:
validation_errors = obj.survey_variable_validation(request_data['extra_vars'])
if validation_errors:
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):
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)
if not result:
data = dict(passwords_needed_to_start=new_job.passwords_needed_to_start)
@ -1773,7 +1774,8 @@ class SystemJobTemplateLaunch(GenericAPIView):
extra_vars = {}
else:
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)
return Response(data, status=status.HTTP_202_ACCEPTED)

View File

@ -78,7 +78,10 @@ class VarsDictProperty(object):
def __get__(self, obj, type=None):
if obj is None:
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
try:
d = json.loads(v.strip() or '{}')

View File

@ -195,7 +195,7 @@ class JobTemplate(UnifiedJobTemplate, JobOptions):
def _get_unified_job_field_names(cls):
return ['name', 'description', 'job_type', 'inventory', 'project',
'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']
def create_job(self, **kwargs):
@ -949,7 +949,7 @@ class SystemJobTemplate(UnifiedJobTemplate, SystemJobOptions):
@classmethod
def _get_unified_job_field_names(cls):
return ['name', 'description', 'job_type']
return ['name', 'description', 'job_type', 'extra_vars']
def get_absolute_url(self):
return reverse('api:system_job_template_detail', args=(self.pk,))

View File

@ -306,7 +306,10 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique):
value = value.id
create_kwargs[id_field_name] = value
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):
create_kwargs[field_name] = getattr(self, field_name)
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.save(update_fields=['job_explanation'])
return False
extra_data = dict([(field, kwargs[field]) for field in kwargs
if field not in needed])
self.handle_extra_data(extra_data)
#extra_data = dict([(field, kwargs[field]) for field in kwargs
# if field not in needed])
if 'extra_vars' in kwargs:
self.handle_extra_data(kwargs['extra_vars'])
task_class().apply_async((self.pk,), opts, link_error=error_callback)
return True
@ -715,9 +719,8 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique
opts = dict([(field, kwargs.get(field, '')) for field in needed])
if not all(opts.values()):
return False
extra_data = dict([(field, kwargs[field]) for field in kwargs
if field not in needed])
self.handle_extra_data(extra_data)
if 'extra_vars' in kwargs:
self.handle_extra_data(kwargs['extra_vars'])
# Save the pending status, and inform the SocketIO listener.
self.update_fields(start_args=json.dumps(kwargs), status='pending')

View File

@ -968,7 +968,7 @@ class JobTemplateTest(BaseJobTestMixin, django.test.TestCase):
launch_url = reverse('api:job_template_launch', args=(new_jt_id,))
response = self.get(launch_url)
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_extra = json.loads(job.extra_vars)
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)
launch_url = reverse('api:job_template_launch', args=(new_jt_id,))
# 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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):
url = reverse('api:job_template_list')