Adjust field loading order for vars and tweak post_validate exclusion logic

FieldAttributes will now by default not be post_validated unless a flag
is set on them in the class, as a large number of fields are really there
simply to be inherited by Task/PlayContext and shouldn't be templated too
early.

The other (unrelated to the base issue) in #12084 is also fixed here, where
the roles field is loaded before vars/vars_files, meaning there are no vars
yet loaded in the play when the templating occurs.

Fixes #12084
pull/12152/head
James Cammarata 9 years ago
parent ee7f7a82a8
commit 0859ba7726

@ -21,7 +21,7 @@ __metaclass__ = type
class Attribute:
def __init__(self, isa=None, private=False, default=None, required=False, listof=None, priority=0):
def __init__(self, isa=None, private=False, default=None, required=False, listof=None, priority=0, always_post_validate=False):
self.isa = isa
self.private = private
@ -29,6 +29,7 @@ class Attribute:
self.required = required
self.listof = listof
self.priority = priority
self.always_post_validate = always_post_validate
def __cmp__(self, other):
return cmp(other.priority, self.priority)

@ -48,7 +48,7 @@ class Base:
_remote_user = FieldAttribute(isa='string')
# variables
_vars = FieldAttribute(isa='dict', default=dict())
_vars = FieldAttribute(isa='dict', default=dict(), priority=100)
# flags and misc. settings
_environment = FieldAttribute(isa='list')
@ -266,6 +266,11 @@ class Base:
continue
else:
raise AnsibleParserError("the field '%s' is required but was not set" % name)
elif not attribute.always_post_validate and self.__class__.__name__ not in ('Task', 'PlayContext'):
# Intermediate objects like Play() won't have their fields validated by
# default, as their values are often inherited by other objects and validated
# later, so we don't want them to fail out early
continue
try:
# Run the post-validator if present. These methods are responsible for

@ -52,22 +52,22 @@ class Play(Base, Taggable, Become):
# Connection-Related Attributes
# TODO: generalize connection
_accelerate = FieldAttribute(isa='bool', default=False)
_accelerate_ipv6 = FieldAttribute(isa='bool', default=False)
_accelerate_port = FieldAttribute(isa='int', default=5099) # should be alias of port
_accelerate = FieldAttribute(isa='bool', default=False, always_post_validate=True)
_accelerate_ipv6 = FieldAttribute(isa='bool', default=False, always_post_validate=True)
_accelerate_port = FieldAttribute(isa='int', default=5099, always_post_validate=True)
# Connection
_gather_facts = FieldAttribute(isa='bool', default=None)
_hosts = FieldAttribute(isa='list', default=[], required=True, listof=string_types)
_name = FieldAttribute(isa='string', default='')
_gather_facts = FieldAttribute(isa='bool', default=None, always_post_validate=True)
_hosts = FieldAttribute(isa='list', default=[], required=True, listof=string_types, always_post_validate=True)
_name = FieldAttribute(isa='string', default='', always_post_validate=True)
# Variable Attributes
_vars_files = FieldAttribute(isa='list', default=[])
_vars_prompt = FieldAttribute(isa='list', default=[])
_vault_password = FieldAttribute(isa='string')
_vars_files = FieldAttribute(isa='list', default=[], priority=99)
_vars_prompt = FieldAttribute(isa='list', default=[], always_post_validate=True)
_vault_password = FieldAttribute(isa='string', always_post_validate=True)
# Role Attributes
_roles = FieldAttribute(isa='list', default=[], priority=100)
_roles = FieldAttribute(isa='list', default=[], priority=90)
# Block (Task) Lists Attributes
_handlers = FieldAttribute(isa='list', default=[])
@ -76,11 +76,11 @@ class Play(Base, Taggable, Become):
_tasks = FieldAttribute(isa='list', default=[])
# Flag/Setting Attributes
_any_errors_fatal = FieldAttribute(isa='bool', default=False)
_force_handlers = FieldAttribute(isa='bool')
_max_fail_percentage = FieldAttribute(isa='percent')
_serial = FieldAttribute(isa='int', default=0)
_strategy = FieldAttribute(isa='string', default='linear')
_any_errors_fatal = FieldAttribute(isa='bool', default=False, always_post_validate=True)
_force_handlers = FieldAttribute(isa='bool', always_post_validate=True)
_max_fail_percentage = FieldAttribute(isa='percent', always_post_validate=True)
_serial = FieldAttribute(isa='int', default=0, always_post_validate=True)
_strategy = FieldAttribute(isa='string', default='linear', always_post_validate=True)
# =================================================================================
@ -191,28 +191,6 @@ class Play(Base, Taggable, Become):
roles.append(Role.load(ri, play=self))
return roles
def _post_validate_vars(self, attr, value, templar):
'''
Override post validation of vars on the play, as we don't want to
template these too early.
'''
return value
def _post_validate_vars_files(self, attr, value, templar):
'''
Override post validation of vars_files on the play, as we don't want to
template these too early.
'''
return value
# disable validation on various fields which will be validated later in other objects
def _post_validate_become(self, attr, value, templar):
return value
def _post_validate_become_user(self, attr, value, templar):
return value
def _post_validate_become_method(self, attr, value, templar):
return value
# FIXME: post_validation needs to ensure that become/su/sudo have only 1 set
def _compile_roles(self):

@ -119,7 +119,7 @@ class RoleDefinition(Base, Become, Conditional, Taggable):
# if we have the required datastructures, and if the role_name
# contains a variable, try and template it now
if self._play and self._variable_manager:
if self._variable_manager:
all_vars = self._variable_manager.get_vars(loader=self._loader, play=self._play)
templar = Templar(loader=self._loader, variables=all_vars)
if templar._contains_vars(role_name):

Loading…
Cancel
Save