diff --git a/lib/ansible/playbook/base.py b/lib/ansible/playbook/base.py index 62af94dd740..56c42fc0ee6 100644 --- a/lib/ansible/playbook/base.py +++ b/lib/ansible/playbook/base.py @@ -36,9 +36,8 @@ from ansible.parsing import DataLoader from ansible.playbook.attribute import Attribute, FieldAttribute from ansible.template import Templar from ansible.utils.boolean import boolean - from ansible.utils.debug import debug - +from ansible.utils.vars import combine_vars from ansible.template import template class Base: @@ -48,6 +47,9 @@ class Base: _port = FieldAttribute(isa='int') _remote_user = FieldAttribute(isa='string') + # variables + _vars = FieldAttribute(isa='dict', default=dict()) + # flags and misc. settings _environment = FieldAttribute(isa='list', default=[]) _no_log = FieldAttribute(isa='bool', default=False) @@ -351,6 +353,30 @@ class Base: # restore the UUID field setattr(self, '_uuid', data.get('uuid')) + def _load_vars(self, attr, ds): + ''' + Vars in a play can be specified either as a dictionary directly, or + as a list of dictionaries. If the later, this method will turn the + list into a single dictionary. + ''' + + try: + if isinstance(ds, dict): + return ds + elif isinstance(ds, list): + all_vars = dict() + for item in ds: + if not isinstance(item, dict): + raise ValueError + all_vars = combine_vars(all_vars, item) + return all_vars + elif ds is None: + return {} + else: + raise ValueError + except ValueError: + raise AnsibleParserError("Vars in a %s must be specified as a dictionary, or a list of dictionaries" % self.__class__.__name__, obj=ds) + def _extend_value(self, value, new_value): ''' Will extend the value given with new_value (and will turn both diff --git a/lib/ansible/playbook/block.py b/lib/ansible/playbook/block.py index 7bba9f325c3..c6afe5ba96c 100644 --- a/lib/ansible/playbook/block.py +++ b/lib/ansible/playbook/block.py @@ -53,7 +53,7 @@ class Block(Base, Become, Conditional, Taggable): of a role or task include which does, so return those if present. ''' - all_vars = dict() + all_vars = self.vars.copy() if self._role: all_vars.update(self._role.get_vars(self._dep_chain)) diff --git a/lib/ansible/playbook/play.py b/lib/ansible/playbook/play.py index 000a280a569..7b3a862911b 100644 --- a/lib/ansible/playbook/play.py +++ b/lib/ansible/playbook/play.py @@ -32,8 +32,6 @@ from ansible.playbook.role import Role from ansible.playbook.taggable import Taggable from ansible.playbook.task import Task -from ansible.utils.vars import combine_vars - __all__ = ['Play'] @@ -64,7 +62,6 @@ class Play(Base, Taggable, Become): _name = FieldAttribute(isa='string', default='') # Variable Attributes - _vars = FieldAttribute(isa='dict', default=dict()) _vars_files = FieldAttribute(isa='list', default=[]) _vars_prompt = FieldAttribute(isa='list', default=[]) _vault_password = FieldAttribute(isa='string') @@ -150,30 +147,6 @@ class Play(Base, Taggable, Become): return ds - def _load_vars(self, attr, ds): - ''' - Vars in a play can be specified either as a dictionary directly, or - as a list of dictionaries. If the later, this method will turn the - list into a single dictionary. - ''' - - try: - if isinstance(ds, dict): - return ds - elif isinstance(ds, list): - all_vars = dict() - for item in ds: - if not isinstance(item, dict): - raise ValueError - all_vars = combine_vars(all_vars, item) - return all_vars - elif ds is None: - return {} - else: - raise ValueError - except ValueError: - raise AnsibleParserError("Vars in a playbook must be specified as a dictionary, or a list of dictionaries", obj=ds) - def _load_tasks(self, attr, ds): ''' Loads a list of blocks from a list which may be mixed tasks/blocks. diff --git a/lib/ansible/playbook/task.py b/lib/ansible/playbook/task.py index 5ae056f604f..7d45506e2d8 100644 --- a/lib/ansible/playbook/task.py +++ b/lib/ansible/playbook/task.py @@ -78,7 +78,6 @@ class Task(Base, Conditional, Taggable, Become): _retries = FieldAttribute(isa='int', default=1) _run_once = FieldAttribute(isa='bool') _until = FieldAttribute(isa='list') # ? - _vars = FieldAttribute(isa='dict', default=dict()) def __init__(self, block=None, role=None, task_include=None): ''' constructors a task, without the Task.load classmethod, it will be pretty blank ''' @@ -166,9 +165,9 @@ class Task(Base, Conditional, Taggable, Become): # be adding things to them below (special handling for includes). # When that deprecated feature is removed, this can be too. if 'vars' in ds: - if not isinstance(ds['vars'], dict): - raise AnsibleError("vars specified on a task must be a dictionary (got a %s)" % type(ds['vars']), obj=new_ds) - new_ds['vars'] = ds.pop('vars') + # _load_vars is defined in Base, and is used to load a dictionary + # or list of dictionaries in a standard way + new_ds['vars'] = self._load_vars(None, ds.pop('vars')) else: new_ds['vars'] = dict() diff --git a/lib/ansible/plugins/strategies/__init__.py b/lib/ansible/plugins/strategies/__init__.py index 83ddd1d2c36..b6a6e7e305c 100644 --- a/lib/ansible/plugins/strategies/__init__.py +++ b/lib/ansible/plugins/strategies/__init__.py @@ -412,7 +412,7 @@ class StrategyBase: # set the vars for this task from those specified as params to the include for b in block_list: - b.vars = included_file._args.copy() + b.vars.update(included_file._args.copy()) return block_list