From 45212394ca9b03197849026ab11ef5f9343a7bf7 Mon Sep 17 00:00:00 2001 From: James Cammarata Date: Thu, 22 Jan 2015 22:45:25 -0500 Subject: [PATCH] Adding in hostvars to v2 and getting more integration tests working --- v2/ansible/executor/task_executor.py | 5 +++ v2/ansible/inventory/__init__.py | 4 +-- v2/ansible/modules/core | 2 +- v2/ansible/playbook/__init__.py | 1 + v2/ansible/playbook/playbook_include.py | 5 +++ v2/ansible/template/vars.py | 3 +- v2/ansible/vars/__init__.py | 25 ++++++++++--- v2/ansible/vars/hostvars.py | 47 +++++++++++++++++++++++++ v2/bin/ansible-playbook | 1 + 9 files changed, 85 insertions(+), 8 deletions(-) create mode 100644 v2/ansible/vars/hostvars.py diff --git a/v2/ansible/executor/task_executor.py b/v2/ansible/executor/task_executor.py index 677f95f1c46..5bd9d51842e 100644 --- a/v2/ansible/executor/task_executor.py +++ b/v2/ansible/executor/task_executor.py @@ -186,6 +186,11 @@ class TaskExecutor: # Now we do final validation on the task, which sets all fields to their final values self._task.post_validate(variables) + # And filter out any fields which were set to default(omit), and got the omit token value + omit_token = variables.get('omit') + if omit_token is not None: + self._task.args = dict(filter(lambda x: x[1] != omit_token, self._task.args.iteritems())) + # Read some values from the task, so that we can modify them if need be retries = self._task.retries if retries <= 0: diff --git a/v2/ansible/inventory/__init__.py b/v2/ansible/inventory/__init__.py index 0c43133b928..56c8c7ced03 100644 --- a/v2/ansible/inventory/__init__.py +++ b/v2/ansible/inventory/__init__.py @@ -455,12 +455,12 @@ class Inventory(object): return vars - def get_variables(self, hostname, update_cached=False, vault_password=None): + def get_vars(self, hostname, update_cached=False, vault_password=None): host = self.get_host(hostname) if not host: raise Exception("host not found: %s" % hostname) - return host.get_variables() + return host.get_vars() def get_host_variables(self, hostname, update_cached=False, vault_password=None): diff --git a/v2/ansible/modules/core b/v2/ansible/modules/core index 1dca8126628..8ba8f5ef4d9 160000 --- a/v2/ansible/modules/core +++ b/v2/ansible/modules/core @@ -1 +1 @@ -Subproject commit 1dca81266289f365765b004ab8c0c62ee9d3467e +Subproject commit 8ba8f5ef4d9361a03a690a0a71a28f3c56ce5bfb diff --git a/v2/ansible/playbook/__init__.py b/v2/ansible/playbook/__init__.py index 2ebce0be3db..8ecdadc878f 100644 --- a/v2/ansible/playbook/__init__.py +++ b/v2/ansible/playbook/__init__.py @@ -25,6 +25,7 @@ from ansible.errors import AnsibleError, AnsibleParserError from ansible.parsing import DataLoader from ansible.playbook.attribute import Attribute, FieldAttribute from ansible.playbook.play import Play +from ansible.playbook.playbook_include import PlaybookInclude from ansible.plugins import push_basedir diff --git a/v2/ansible/playbook/playbook_include.py b/v2/ansible/playbook/playbook_include.py index ae8ccff5952..2eb1c17e4f4 100644 --- a/v2/ansible/playbook/playbook_include.py +++ b/v2/ansible/playbook/playbook_include.py @@ -18,3 +18,8 @@ # Make coding more python3-ish from __future__ import (absolute_import, division, print_function) __metaclass__ = type + +from ansible.playbook.base import Base + +class PlaybookInclude(Base): + pass diff --git a/v2/ansible/template/vars.py b/v2/ansible/template/vars.py index 029f9e50a55..3c0bb61ecb0 100644 --- a/v2/ansible/template/vars.py +++ b/v2/ansible/template/vars.py @@ -71,7 +71,8 @@ class AnsibleJ2Vars: # HostVars is special, return it as-is, as is the special variable # 'vars', which contains the vars structure - if isinstance(variable, dict) and varname == "vars": # or isinstance(var, HostVars): + from ansible.vars.hostvars import HostVars + if isinstance(variable, dict) and varname == "vars" or isinstance(variable, HostVars): return variable else: return self._templar.template(variable) diff --git a/v2/ansible/vars/__init__.py b/v2/ansible/vars/__init__.py index 16a3e32e612..cbd4d11fb96 100644 --- a/v2/ansible/vars/__init__.py +++ b/v2/ansible/vars/__init__.py @@ -23,11 +23,16 @@ import os from collections import defaultdict +try: + from hashlib import sha1 +except ImportError: + from sha import sha as sha1 + from ansible.parsing import DataLoader from ansible.plugins.cache import FactCache from ansible.template import Templar - from ansible.utils.debug import debug +from ansible.vars.hostvars import HostVars CACHED_VARS = dict() @@ -40,6 +45,9 @@ class VariableManager: self._extra_vars = defaultdict(dict) self._host_vars_files = defaultdict(dict) self._group_vars_files = defaultdict(dict) + self._inventory = None + + self._omit_token = '__omit_place_holder__%s' % sha1(os.urandom(64)).hexdigest() def _get_cache_entry(self, play=None, host=None, task=None): play_id = "NONE" @@ -66,6 +74,9 @@ class VariableManager: assert isinstance(value, dict) self._extra_vars = value.copy() + def set_inventory(self, inventory): + self._inventory = inventory + def _merge_dicts(self, a, b): ''' Recursively merges dict b into a, so that keys @@ -177,8 +188,15 @@ class VariableManager: all_vars = self._merge_dicts(all_vars, self._extra_vars) - # FIXME: we need to move the special variables from the old runner - # inject into here (HostVars?, groups, etc.) + # FIXME: make sure all special vars are here + # Finally, we create special vars + + if host and self._inventory is not None: + hostvars = HostVars(vars_manager=self, inventory=self._inventory, loader=loader) + all_vars['hostvars'] = hostvars + + # the 'omit' value alows params to be left out if the variable they are based on is undefined + all_vars['omit'] = self._omit_token CACHED_VARS[cache_entry] = all_vars @@ -229,7 +247,6 @@ class VariableManager: (name, data) = self._load_inventory_file(path, loader) self._group_vars_files[name] = data - def set_host_facts(self, host, facts): ''' Sets or updates the given facts for a host in the fact cache. diff --git a/v2/ansible/vars/hostvars.py b/v2/ansible/vars/hostvars.py new file mode 100644 index 00000000000..45b3340229d --- /dev/null +++ b/v2/ansible/vars/hostvars.py @@ -0,0 +1,47 @@ +# (c) 2012-2014, Michael DeHaan +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from ansible.template import Templar + +__all__ = ['HostVars'] + +class HostVars(dict): + ''' A special view of vars_cache that adds values from the inventory when needed. ''' + + def __init__(self, vars_manager, inventory, loader): + self._vars_manager = vars_manager + self._inventory = inventory + self._loader = loader + self._lookup = {} + + #self.update(vars_cache) + + def __getitem__(self, host_name): + + if host_name not in self._lookup: + host = self._inventory.get_host(host_name) + result = self._vars_manager.get_vars(loader=self._loader, host=host) + #result.update(self._vars_cache.get(host, {})) + #templar = Templar(variables=self._vars_cache, loader=self._loader) + #self._lookup[host] = templar.template(result) + self._lookup[host_name] = result + return self._lookup[host_name] + diff --git a/v2/bin/ansible-playbook b/v2/bin/ansible-playbook index a67864edecf..fe8c0861dc2 100755 --- a/v2/bin/ansible-playbook +++ b/v2/bin/ansible-playbook @@ -139,6 +139,7 @@ def main(args): # create the inventory, and filter it based on the subset specified (if any) inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=options.inventory) + variable_manager.set_inventory(inventory) # Note: slightly wrong, this is written so that implicit localhost # (which is not returned in list_hosts()) is taken into account for