Merge remote-tracking branch 'tower/release_3.2.2' into devel

This commit is contained in:
Matthew Jones
2017-12-13 12:25:47 -05:00
144 changed files with 9292 additions and 9012 deletions

View File

@@ -1,6 +1,6 @@
# Python
import json
from copy import copy
from copy import copy, deepcopy
# Django
from django.db import models
@@ -14,6 +14,7 @@ from awx.main.models.rbac import (
Role, RoleAncestorEntry, get_roles_on_resource
)
from awx.main.utils import parse_yaml_or_json
from awx.main.utils.encryption import decrypt_value, get_encryption_key
from awx.main.fields import JSONField, AskForField
@@ -141,21 +142,27 @@ class SurveyJobTemplateMixin(models.Model):
else:
runtime_extra_vars = {}
# Overwrite with job template extra vars with survey default vars
# Overwrite job template extra vars with survey default vars
if self.survey_enabled and 'spec' in self.survey_spec:
for survey_element in self.survey_spec.get("spec", []):
default = survey_element.get('default')
variable_key = survey_element.get('variable')
if survey_element.get('type') == 'password':
if variable_key in runtime_extra_vars and default:
if variable_key in runtime_extra_vars:
kw_value = runtime_extra_vars[variable_key]
if kw_value.startswith('$encrypted$') and kw_value != default:
runtime_extra_vars[variable_key] = default
if kw_value == '$encrypted$':
runtime_extra_vars.pop(variable_key)
if default is not None:
data = {variable_key: default}
errors = self._survey_element_validation(survey_element, data)
decrypted_default = default
if (
survey_element['type'] == "password" and
isinstance(decrypted_default, basestring) and
decrypted_default.startswith('$encrypted$')
):
decrypted_default = decrypt_value(get_encryption_key('value', pk=None), decrypted_default)
errors = self._survey_element_validation(survey_element, {variable_key: decrypted_default})
if not errors:
survey_defaults[variable_key] = default
extra_vars.update(survey_defaults)
@@ -167,7 +174,20 @@ class SurveyJobTemplateMixin(models.Model):
return create_kwargs
def _survey_element_validation(self, survey_element, data):
# Don't apply validation to the `$encrypted$` placeholder; the decrypted
# default (if any) will be validated against instead
errors = []
if (survey_element['type'] == "password"):
password_value = data.get(survey_element['variable'])
if (
isinstance(password_value, basestring) and
password_value == '$encrypted$'
):
if survey_element.get('default') is None and survey_element['required']:
errors.append("'%s' value missing" % survey_element['variable'])
return errors
if survey_element['variable'] not in data and survey_element['required']:
errors.append("'%s' value missing" % survey_element['variable'])
elif survey_element['type'] in ["textarea", "text", "password"]:
@@ -272,6 +292,40 @@ class SurveyJobTemplateMixin(models.Model):
return (accepted, rejected, errors)
@staticmethod
def pivot_spec(spec):
'''
Utility method that will return a dictionary keyed off variable names
'''
pivoted = {}
for element_data in spec.get('spec', []):
if 'variable' in element_data:
pivoted[element_data['variable']] = element_data
return pivoted
def survey_variable_validation(self, data):
errors = []
if not self.survey_enabled:
return errors
if 'name' not in self.survey_spec:
errors.append("'name' missing from survey spec.")
if 'description' not in self.survey_spec:
errors.append("'description' missing from survey spec.")
for survey_element in self.survey_spec.get("spec", []):
errors += self._survey_element_validation(survey_element, data)
return errors
def display_survey_spec(self):
'''
Hide encrypted default passwords in survey specs
'''
survey_spec = deepcopy(self.survey_spec) if self.survey_spec else {}
for field in survey_spec.get('spec', []):
if field.get('type') == 'password':
if 'default' in field and field['default']:
field['default'] = '$encrypted$'
return survey_spec
class SurveyJobMixin(models.Model):
class Meta:
@@ -296,6 +350,20 @@ class SurveyJobMixin(models.Model):
else:
return self.extra_vars
def decrypted_extra_vars(self):
'''
Decrypts fields marked as passwords in survey.
'''
if self.survey_passwords:
extra_vars = json.loads(self.extra_vars)
for key in self.survey_passwords:
value = extra_vars.get(key)
if value and isinstance(value, basestring) and value.startswith('$encrypted$'):
extra_vars[key] = decrypt_value(get_encryption_key('value', pk=None), value)
return json.dumps(extra_vars)
else:
return self.extra_vars
class TaskManagerUnifiedJobMixin(models.Model):
class Meta:
@@ -312,6 +380,9 @@ class TaskManagerJobMixin(TaskManagerUnifiedJobMixin):
class Meta:
abstract = True
def get_jobs_fail_chain(self):
return [self.project_update] if self.project_update else []
def dependent_jobs_finished(self):
for j in self.dependent_jobs.all():
if j.status in ['pending', 'waiting', 'running']: