From bbd08cd0e29fb73d8cb97df525c46c5e9a99e5bd Mon Sep 17 00:00:00 2001 From: James Cammarata Date: Mon, 26 Jan 2015 23:41:02 -0600 Subject: [PATCH] Fixing more v2 issues with integration tests --- v2/ansible/executor/playbook_executor.py | 5 ++- v2/ansible/parsing/__init__.py | 3 ++ v2/ansible/playbook/role/__init__.py | 17 +++++++-- v2/ansible/plugins/callback/default.py | 4 +-- v2/ansible/plugins/strategies/__init__.py | 5 +-- v2/ansible/vars/__init__.py | 43 +++++++++++++++-------- v2/bin/ansible-playbook | 6 ++-- 7 files changed, 58 insertions(+), 25 deletions(-) diff --git a/v2/ansible/executor/playbook_executor.py b/v2/ansible/executor/playbook_executor.py index 5a5f86e7eb..88ec05b9e8 100644 --- a/v2/ansible/executor/playbook_executor.py +++ b/v2/ansible/executor/playbook_executor.py @@ -70,7 +70,10 @@ class PlaybookExecutor: for batch in self._get_serialized_batches(new_play): if len(batch) == 0: - raise AnsibleError("No hosts matched the list specified in the play", obj=play._ds) + self._tqm._callback.playbook_on_play_start(new_play.name) + self._tqm._callback.playbook_on_no_hosts_matched() + result = 0 + break # restrict the inventory to the hosts in the serialized batch self._inventory.restrict_to_hosts(batch) # and run it... diff --git a/v2/ansible/parsing/__init__.py b/v2/ansible/parsing/__init__.py index 861ab57acd..82679ad9e8 100644 --- a/v2/ansible/parsing/__init__.py +++ b/v2/ansible/parsing/__init__.py @@ -66,6 +66,7 @@ class DataLoader(): a JSON or YAML string. ''' + #print("in load, data is: %s (%s)" % (data, type(data))) try: # we first try to load this data as JSON return json.loads(data) @@ -108,6 +109,8 @@ class DataLoader(): def _safe_load(self, stream, file_name=None): ''' Implements yaml.safe_load(), except using our custom loader class. ''' + #print("stream is: %s" % stream) + #print("file name is: %s" % file_name) loader = AnsibleLoader(stream, file_name) try: return loader.get_single_data() diff --git a/v2/ansible/playbook/role/__init__.py b/v2/ansible/playbook/role/__init__.py index afe4a1c48a..ae083e5f92 100644 --- a/v2/ansible/playbook/role/__init__.py +++ b/v2/ansible/playbook/role/__init__.py @@ -39,8 +39,20 @@ from ansible.plugins import module_loader from ansible.utils.vars import combine_vars -__all__ = ['Role', 'ROLE_CACHE'] +__all__ = ['Role', 'ROLE_CACHE', 'hash_params'] +# FIXME: this should be a utility function, but can't be a member of +# the role due to the fact that it would require the use of self +# in a static method. This is also used in the base class for +# strategies (ansible/plugins/strategies/__init__.py) +def hash_params(params): + s = set() + for k,v in params.iteritems(): + if isinstance(v, dict): + s.update((k, hash_params(v))) + else: + s.update((k, v)) + return frozenset(s) # The role cache is used to prevent re-loading roles, which # may already exist. Keys into this cache are the SHA1 hash @@ -84,7 +96,8 @@ class Role(Base, Conditional, Taggable): # specified for a role as the key and the Role() object itself. # We use frozenset to make the dictionary hashable. - hashed_params = frozenset(role_include.get_role_params().iteritems()) + #hashed_params = frozenset(role_include.get_role_params().iteritems()) + hashed_params = hash_params(role_include.get_role_params()) if role_include.role in ROLE_CACHE: for (entry, role_obj) in ROLE_CACHE[role_include.role].iteritems(): if hashed_params == entry: diff --git a/v2/ansible/plugins/callback/default.py b/v2/ansible/plugins/callback/default.py index 9ae156931b..091def9427 100644 --- a/v2/ansible/plugins/callback/default.py +++ b/v2/ansible/plugins/callback/default.py @@ -57,7 +57,7 @@ class CallbackModule(CallbackBase): msg = "ok: [%s]" % result._host.get_name() color = 'green' - if self._display._verbosity > 0 or 'verbose_always' in result._result: + if (self._display._verbosity > 0 or 'verbose_always' in result._result) and result._task.action != 'setup': indent = None if 'verbose_always' in result._result: indent = 4 @@ -97,7 +97,7 @@ class CallbackModule(CallbackBase): pass def playbook_on_no_hosts_matched(self): - pass + self._display.display("skipping: no hosts matched", color='cyan') def playbook_on_no_hosts_remaining(self): self._print_banner("NO MORE HOSTS LEFT") diff --git a/v2/ansible/plugins/strategies/__init__.py b/v2/ansible/plugins/strategies/__init__.py index 1e25a84d10..b8ae6ffa85 100644 --- a/v2/ansible/plugins/strategies/__init__.py +++ b/v2/ansible/plugins/strategies/__init__.py @@ -28,7 +28,7 @@ from ansible.inventory.host import Host from ansible.inventory.group import Group from ansible.playbook.helpers import compile_block_list -from ansible.playbook.role import ROLE_CACHE +from ansible.playbook.role import ROLE_CACHE, hash_params from ansible.plugins import module_loader from ansible.utils.debug import debug @@ -149,7 +149,8 @@ class StrategyBase: # lookup the role in the ROLE_CACHE to make sure we're dealing # with the correct object and mark it as executed for (entry, role_obj) in ROLE_CACHE[task_result._task._role._role_name].iteritems(): - hashed_entry = frozenset(task_result._task._role._role_params.iteritems()) + #hashed_entry = frozenset(task_result._task._role._role_params.iteritems()) + hashed_entry = hash_params(task_result._task._role._role_params) if entry == hashed_entry : role_obj._had_task_run = True diff --git a/v2/ansible/vars/__init__.py b/v2/ansible/vars/__init__.py index cbd4d11fb9..ac03199c97 100644 --- a/v2/ansible/vars/__init__.py +++ b/v2/ansible/vars/__init__.py @@ -28,6 +28,7 @@ try: except ImportError: from sha import sha as sha1 +from ansible import constants as C from ansible.parsing import DataLoader from ansible.plugins.cache import FactCache from ansible.template import Templar @@ -77,6 +78,20 @@ class VariableManager: def set_inventory(self, inventory): self._inventory = inventory + def _combine_vars(self, a, b): + ''' + Combines dictionaries of variables, based on the hash behavior + ''' + + # FIXME: do we need this from utils, or should it just + # be merged into this definition? + #_validate_both_dicts(a, b) + + if C.DEFAULT_HASH_BEHAVIOUR == "merge": + return self._merge_dicts(a, b) + else: + return dict(a.items() + b.items()) + def _merge_dicts(self, a, b): ''' Recursively merges dict b into a, so that keys @@ -135,7 +150,7 @@ class VariableManager: # 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 = self._merge_dicts(all_vars, role.get_default_vars()) + all_vars = self._combine_vars(all_vars, role.get_default_vars()) if host: # next, if a host is specified, we load any vars from group_vars @@ -144,49 +159,49 @@ class VariableManager: # we merge in the special 'all' group_vars first, if they exist if 'all' in self._group_vars_files: - all_vars = self._merge_dicts(all_vars, self._group_vars_files['all']) + all_vars = self._combine_vars(all_vars, self._group_vars_files['all']) for group in host.get_groups(): group_name = group.get_name() - all_vars = self._merge_dicts(all_vars, group.get_vars()) + all_vars = self._combine_vars(all_vars, group.get_vars()) if group_name in self._group_vars_files and group_name != 'all': - all_vars = self._merge_dicts(all_vars, self._group_vars_files[group_name]) + all_vars = self._combine_vars(all_vars, self._group_vars_files[group_name]) host_name = host.get_name() if host_name in self._host_vars_files: - all_vars = self._merge_dicts(all_vars, self._host_vars_files[host_name]) + all_vars = self._combine_vars(all_vars, self._host_vars_files[host_name]) # then we merge in vars specified for this host - all_vars = self._merge_dicts(all_vars, host.get_vars()) + all_vars = self._combine_vars(all_vars, host.get_vars()) # next comes the facts cache and the vars cache, respectively - all_vars = self._merge_dicts(all_vars, self._fact_cache.get(host.get_name(), dict())) + all_vars = self._combine_vars(all_vars, self._fact_cache.get(host.get_name(), dict())) if play: - all_vars = self._merge_dicts(all_vars, play.get_vars()) + all_vars = self._combine_vars(all_vars, play.get_vars()) templar = Templar(loader=loader, variables=all_vars) for vars_file in play.get_vars_files(): try: vars_file = templar.template(vars_file) data = loader.load_from_file(vars_file) - all_vars = self._merge_dicts(all_vars, data) + all_vars = self._combine_vars(all_vars, data) except: # FIXME: get_vars should probably be taking a flag to determine # whether or not vars files errors should be fatal at this # stage, or just base it on whether a host was specified? pass for role in play.get_roles(): - all_vars = self._merge_dicts(all_vars, role.get_vars()) + all_vars = self._combine_vars(all_vars, role.get_vars()) if host: - all_vars = self._merge_dicts(all_vars, self._vars_cache.get(host.get_name(), dict())) + all_vars = self._combine_vars(all_vars, self._vars_cache.get(host.get_name(), dict())) if task: if task._role: - all_vars = self._merge_dicts(all_vars, task._role.get_vars()) - all_vars = self._merge_dicts(all_vars, task.get_vars()) + all_vars = self._combine_vars(all_vars, task._role.get_vars()) + all_vars = self._combine_vars(all_vars, task.get_vars()) - all_vars = self._merge_dicts(all_vars, self._extra_vars) + all_vars = self._combine_vars(all_vars, self._extra_vars) # FIXME: make sure all special vars are here # Finally, we create special vars diff --git a/v2/bin/ansible-playbook b/v2/bin/ansible-playbook index fe8c0861dc..543a66dd82 100755 --- a/v2/bin/ansible-playbook +++ b/v2/bin/ansible-playbook @@ -108,15 +108,13 @@ def main(args): if extra_vars_opt.startswith("@"): # Argument is a YAML file (JSON is a subset of YAML) data = loader.load_from_file(extra_vars_opt[1:]) - extra_vars = combine_vars(extra_vars, data) elif extra_vars_opt and extra_vars_opt[0] in '[{': # Arguments as YAML - data = loader.load(extra_vars) - extra_vars = combine_vars(extra_vars, data) + data = loader.load(extra_vars_opt) else: # Arguments as Key-value data = parse_kv(extra_vars_opt) - extra_vars = combine_vars(extra_vars, data) + extra_vars = combine_vars(extra_vars, data) # FIXME: this should be moved inside the playbook executor code only_tags = options.tags.split(",")