diff --git a/changelogs/fragments/vm_fix.yml b/changelogs/fragments/vm_fix.yml new file mode 100644 index 00000000000..f247cce3383 --- /dev/null +++ b/changelogs/fragments/vm_fix.yml @@ -0,0 +1,2 @@ +bugfixes: + - fix issue with incorrect dict update in vars manager diff --git a/lib/ansible/plugins/cache/__init__.py b/lib/ansible/plugins/cache/__init__.py index 7991a8bc763..ef1d9d5013e 100644 --- a/lib/ansible/plugins/cache/__init__.py +++ b/lib/ansible/plugins/cache/__init__.py @@ -292,10 +292,18 @@ class FactCache(MutableMapping): """ Flush the fact cache of all keys. """ self._plugin.flush() - def update(self, key, value): - host_cache = self._plugin.get(key) - host_cache.update(value) - self._plugin.set(key, host_cache) + def update(self, host_facts): + """ We override the normal update to ensure we always use the 'setter' method """ + for key in host_facts: + try: + host_cache = self._plugin.get(key) + if host_cache: + host_cache.update(host_facts[key]) + else: + host_cache = host_facts[key] + self._plugin.set(key, host_cache) + except KeyError: + self._plugin.set(key, host_facts[key]) class InventoryFileCacheModule(BaseFileCacheModule): @@ -314,7 +322,7 @@ class InventoryFileCacheModule(BaseFileCacheModule): def validate_cache_connection(self): try: super(InventoryFileCacheModule, self).validate_cache_connection() - except AnsibleError as e: + except AnsibleError: cache_connection_set = False else: cache_connection_set = True diff --git a/lib/ansible/vars/manager.py b/lib/ansible/vars/manager.py index ec5d581ef50..84658e2827f 100644 --- a/lib/ansible/vars/manager.py +++ b/lib/ansible/vars/manager.py @@ -625,8 +625,7 @@ class VariableManager: ''' Clears the facts for a host ''' - if hostname in self._fact_cache: - del self._fact_cache[hostname] + self._fact_cache.pop(hostname, None) def set_host_facts(self, host, facts): ''' @@ -636,13 +635,16 @@ class VariableManager: if not isinstance(facts, dict): raise AnsibleAssertionError("the type of 'facts' to set for host_facts should be a dict but is a %s" % type(facts)) - if host.name not in self._fact_cache: - self._fact_cache[host.name] = facts - else: + try: try: + # this is a cache plugin, not a dictionary + self._fact_cache.update({host.name: facts}) + except TypeError: + # this is here for backwards compatibilty for the time cache plugins were not 'dict compatible' self._fact_cache.update(host.name, facts) - except KeyError: - self._fact_cache[host.name] = facts + display.deprecated("Your configured fact cache plugin is using a deprecated form of the 'update' method", version="2.12") + except KeyError: + self._fact_cache[host.name] = facts def set_nonpersistent_facts(self, host, facts): ''' @@ -652,13 +654,10 @@ class VariableManager: if not isinstance(facts, dict): raise AnsibleAssertionError("the type of 'facts' to set for nonpersistent_facts should be a dict but is a %s" % type(facts)) - if host.name not in self._nonpersistent_fact_cache: + try: + self._nonpersistent_fact_cache[host.name].update(facts) + except KeyError: self._nonpersistent_fact_cache[host.name] = facts - else: - try: - self._nonpersistent_fact_cache[host.name].update(facts) - except KeyError: - self._nonpersistent_fact_cache[host.name] = facts def set_host_variable(self, host, varname, value): '''