Set HostVars._variable_manager's attrs (#65508)

When HostVars are part of the data that goes through (de)serialization
when being passed from a worker process to the main process, its
variable manager reference loses some of its attributes due to the
implementation of __getstate__ and __setstate__ (perf utilization).
Since HostVars already has those attributes, use __setstate__ to assign
them.

Fixes #65365
This commit is contained in:
Martin Krizek 2020-01-22 11:57:09 +01:00 committed by ansibot
parent 0c4f167b82
commit ec371eb227
6 changed files with 29 additions and 1 deletions

View file

@ -0,0 +1,2 @@
bugfixes:
- Fix traceback when printing ``HostVars`` on native Jinja2 (https://github.com/ansible/ansible/issues/65365)

View file

@ -49,7 +49,6 @@ class HostVars(Mapping):
''' A special view of vars_cache that adds values from the inventory when needed. ''' ''' A special view of vars_cache that adds values from the inventory when needed. '''
def __init__(self, inventory, variable_manager, loader): def __init__(self, inventory, variable_manager, loader):
self._lookup = dict()
self._inventory = inventory self._inventory = inventory
self._loader = loader self._loader = loader
self._variable_manager = variable_manager self._variable_manager = variable_manager
@ -77,6 +76,19 @@ class HostVars(Mapping):
return self._variable_manager.get_vars(host=host, include_hostvars=False) return self._variable_manager.get_vars(host=host, include_hostvars=False)
def __setstate__(self, state):
self.__dict__.update(state)
# Methods __getstate__ and __setstate__ of VariableManager do not
# preserve _loader and _hostvars attributes to improve pickle
# performance and memory utilization. Since HostVars holds values
# of those attributes already, assign them if needed.
if self._variable_manager._loader is None:
self._variable_manager._loader = self._loader
if self._variable_manager._hostvars is None:
self._variable_manager._hostvars = self
def __getitem__(self, host_name): def __getitem__(self, host_name):
data = self.raw_get(host_name) data = self.raw_get(host_name)
if isinstance(data, AnsibleUndefined): if isinstance(data, AnsibleUndefined):

View file

@ -133,6 +133,8 @@ class VariableManager:
self._inventory = data.get('inventory', None) self._inventory = data.get('inventory', None)
self._options_vars = data.get('options_vars', dict()) self._options_vars = data.get('options_vars', dict())
self.safe_basedir = data.get('safe_basedir', False) self.safe_basedir = data.get('safe_basedir', False)
self._loader = None
self._hostvars = None
@property @property
def extra_vars(self): def extra_vars(self):

View file

@ -4,3 +4,4 @@ set -eux
ANSIBLE_JINJA2_NATIVE=1 ansible-playbook -i inventory.jinja2_native_types runtests.yml -v "$@" ANSIBLE_JINJA2_NATIVE=1 ansible-playbook -i inventory.jinja2_native_types runtests.yml -v "$@"
ANSIBLE_JINJA2_NATIVE=1 ansible-playbook -i inventory.jinja2_native_types --vault-password-file test_vault_pass test_vault.yml -v "$@" ANSIBLE_JINJA2_NATIVE=1 ansible-playbook -i inventory.jinja2_native_types --vault-password-file test_vault_pass test_vault.yml -v "$@"
ANSIBLE_JINJA2_NATIVE=1 ansible-playbook -i inventory.jinja2_native_types test_hostvars.yml -v "$@"

View file

@ -0,0 +1,10 @@
- hosts: host1
gather_facts: no
tasks:
- name: Print vars
debug:
var: vars
- name: Print hostvars
debug:
var: hostvars