diff options
Diffstat (limited to 'lib/ansible/vars/manager.py')
-rw-r--r-- | lib/ansible/vars/manager.py | 92 |
1 files changed, 68 insertions, 24 deletions
diff --git a/lib/ansible/vars/manager.py b/lib/ansible/vars/manager.py index a09704e0..8282190e 100644 --- a/lib/ansible/vars/manager.py +++ b/lib/ansible/vars/manager.py @@ -32,7 +32,7 @@ from ansible import constants as C from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleFileNotFound, AnsibleAssertionError, AnsibleTemplateError from ansible.inventory.host import Host from ansible.inventory.helpers import sort_groups, get_group_vars -from ansible.module_utils._text import to_text +from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.six import text_type, string_types from ansible.plugins.loader import lookup_loader from ansible.vars.fact_cache import FactCache @@ -139,7 +139,7 @@ class VariableManager: def set_inventory(self, inventory): self._inventory = inventory - def get_vars(self, play=None, host=None, task=None, include_hostvars=True, include_delegate_to=True, use_cache=True, + def get_vars(self, play=None, host=None, task=None, include_hostvars=True, include_delegate_to=False, use_cache=True, _hosts=None, _hosts_all=None, stage='task'): ''' Returns the variables, with optional "context" given via the parameters @@ -172,7 +172,6 @@ class VariableManager: host=host, task=task, include_hostvars=include_hostvars, - include_delegate_to=include_delegate_to, _hosts=_hosts, _hosts_all=_hosts_all, ) @@ -185,6 +184,9 @@ class VariableManager: See notes in the VarsWithSources docstring for caveats and limitations of the source tracking ''' + if new_data == {}: + return data + if C.DEFAULT_DEBUG: # Populate var sources dict for key in new_data: @@ -197,11 +199,10 @@ class VariableManager: basedirs = [self._loader.get_basedir()] if play: - # first we compile any vars specified in defaults/main.yml - # for all roles within the specified play - for role in play.get_roles(): - all_vars = _combine_and_track(all_vars, role.get_default_vars(), "role '%s' defaults" % role.name) - + # get role defaults (lowest precedence) + for role in play.roles: + if role.public: + all_vars = _combine_and_track(all_vars, role.get_default_vars(), "role '%s' defaults" % role.name) if task: # set basedirs if C.PLAYBOOK_VARS_ROOT == 'all': # should be default @@ -215,9 +216,9 @@ class VariableManager: # if we have a task in this context, and that task has a role, make # sure it sees its defaults above any other roles, as we previously # (v1) made sure each task had a copy of its roles default vars + # TODO: investigate why we need play or include_role check? if task._role is not None and (play or task.action in C._ACTION_INCLUDE_ROLE): - all_vars = _combine_and_track(all_vars, task._role.get_default_vars(dep_chain=task.get_dep_chain()), - "role '%s' defaults" % task._role.name) + all_vars = _combine_and_track(all_vars, task._role.get_default_vars(dep_chain=task.get_dep_chain()), "role '%s' defaults" % task._role.name) if host: # THE 'all' group and the rest of groups for a host, used below @@ -383,19 +384,18 @@ class VariableManager: raise AnsibleParserError("Error while reading vars files - please supply a list of file names. " "Got '%s' of type %s" % (vars_files, type(vars_files))) - # By default, we now merge in all vars from all roles in the play, - # unless the user has disabled this via a config option - if not C.DEFAULT_PRIVATE_ROLE_VARS: - for role in play.get_roles(): - all_vars = _combine_and_track(all_vars, role.get_vars(include_params=False), "role '%s' vars" % role.name) + # We now merge in all exported vars from all roles in the play (very high precedence) + for role in play.roles: + if role.public: + all_vars = _combine_and_track(all_vars, role.get_vars(include_params=False, only_exports=True), "role '%s' exported vars" % role.name) # next, we merge in the vars from the role, which will specifically # follow the role dependency chain, and then we merge in the tasks # vars (which will look at parent blocks/task includes) if task: if task._role: - all_vars = _combine_and_track(all_vars, task._role.get_vars(task.get_dep_chain(), include_params=False), - "role '%s' vars" % task._role.name) + all_vars = _combine_and_track(all_vars, task._role.get_vars(task.get_dep_chain(), include_params=False, only_exports=False), + "role '%s' all vars" % task._role.name) all_vars = _combine_and_track(all_vars, task.get_vars(), "task vars") # next, we merge in the vars cache (include vars) and nonpersistent @@ -408,12 +408,11 @@ class VariableManager: # next, we merge in role params and task include params if task: - if task._role: - all_vars = _combine_and_track(all_vars, task._role.get_role_params(task.get_dep_chain()), "role '%s' params" % task._role.name) - # special case for include tasks, where the include params # may be specified in the vars field for the task, which should # have higher precedence than the vars/np facts above + if task._role: + all_vars = _combine_and_track(all_vars, task._role.get_role_params(task.get_dep_chain()), "role params") all_vars = _combine_and_track(all_vars, task.get_include_params(), "include params") # extra vars @@ -444,7 +443,7 @@ class VariableManager: else: return all_vars - def _get_magic_variables(self, play, host, task, include_hostvars, include_delegate_to, _hosts=None, _hosts_all=None): + def _get_magic_variables(self, play, host, task, include_hostvars, _hosts=None, _hosts_all=None): ''' Returns a dictionary of so-called "magic" variables in Ansible, which are special variables we set internally for use. @@ -456,9 +455,8 @@ class VariableManager: variables['ansible_config_file'] = C.CONFIG_FILE if play: - # This is a list of all role names of all dependencies for all roles for this play + # using role_cache as play.roles only has 'public' roles for vars exporting dependency_role_names = list({d.get_name() for r in play.roles for d in r.get_all_dependencies()}) - # This is a list of all role names of all roles for this play play_role_names = [r.get_name() for r in play.roles] # ansible_role_names includes all role names, dependent or directly referenced by the play @@ -470,7 +468,7 @@ class VariableManager: # dependencies that are also explicitly named as roles are included in this list variables['ansible_dependent_role_names'] = dependency_role_names - # DEPRECATED: role_names should be deprecated in favor of ansible_role_names or ansible_play_role_names + # TODO: data tagging!!! DEPRECATED: role_names should be deprecated in favor of ansible_ prefixed ones variables['role_names'] = variables['ansible_play_role_names'] variables['ansible_play_name'] = play.get_name() @@ -516,6 +514,47 @@ class VariableManager: return variables + def get_delegated_vars_and_hostname(self, templar, task, variables): + """Get the delegated_vars for an individual task invocation, which may be be in the context + of an individual loop iteration. + + Not used directly be VariableManager, but used primarily within TaskExecutor + """ + delegated_vars = {} + delegated_host_name = None + if task.delegate_to: + delegated_host_name = templar.template(task.delegate_to, fail_on_undefined=False) + + # no need to do work if omitted + if delegated_host_name != self._omit_token: + + if not delegated_host_name: + raise AnsibleError('Empty hostname produced from delegate_to: "%s"' % task.delegate_to) + + delegated_host = self._inventory.get_host(delegated_host_name) + if delegated_host is None: + for h in self._inventory.get_hosts(ignore_limits=True, ignore_restrictions=True): + # check if the address matches, or if both the delegated_to host + # and the current host are in the list of localhost aliases + if h.address == delegated_host_name: + delegated_host = h + break + else: + delegated_host = Host(name=delegated_host_name) + + delegated_vars['ansible_delegated_vars'] = { + delegated_host_name: self.get_vars( + play=task.get_play(), + host=delegated_host, + task=task, + include_delegate_to=False, + include_hostvars=True, + ) + } + delegated_vars['ansible_delegated_vars'][delegated_host_name]['inventory_hostname'] = variables.get('inventory_hostname') + + return delegated_vars, delegated_host_name + def _get_delegated_vars(self, play, task, existing_variables): # This method has a lot of code copied from ``TaskExecutor._get_loop_items`` # if this is failing, and ``TaskExecutor._get_loop_items`` is not @@ -527,6 +566,11 @@ class VariableManager: # This "task" is not a Task, so we need to skip it return {}, None + display.deprecated( + 'Getting delegated variables via get_vars is no longer used, and is handled within the TaskExecutor.', + version='2.18', + ) + # we unfortunately need to template the delegate_to field here, # as we're fetching vars before post_validate has been called on # the task that has been passed in |