1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
#
# 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 <http://www.gnu.org/licenses/>.
from __future__ import annotations
from collections.abc import Mapping
from ansible import constants as C
from ansible.template import Templar, AnsibleUndefined
__all__ = ['HostVars', 'HostVarsVars']
# Note -- this is a Mapping, not a MutableMapping
class HostVars(Mapping):
''' A special view of vars_cache that adds values from the inventory when needed. '''
def __init__(self, inventory, variable_manager, loader):
self._inventory = inventory
self._loader = loader
self._variable_manager = variable_manager
variable_manager._hostvars = self
def set_variable_manager(self, variable_manager):
self._variable_manager = variable_manager
variable_manager._hostvars = self
def set_inventory(self, inventory):
self._inventory = inventory
def _find_host(self, host_name):
# does not use inventory.hosts so it can create localhost on demand
return self._inventory.get_host(host_name)
def raw_get(self, host_name):
'''
Similar to __getitem__, however the returned data is not run through
the templating engine to expand variables in the hostvars.
'''
host = self._find_host(host_name)
if host is None:
return AnsibleUndefined(name="hostvars['%s']" % host_name)
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):
data = self.raw_get(host_name)
if isinstance(data, AnsibleUndefined):
return data
return HostVarsVars(data, loader=self._loader)
def set_host_variable(self, host, varname, value):
self._variable_manager.set_host_variable(host, varname, value)
def set_nonpersistent_facts(self, host, facts):
self._variable_manager.set_nonpersistent_facts(host, facts)
def set_host_facts(self, host, facts):
self._variable_manager.set_host_facts(host, facts)
def __contains__(self, host_name):
# does not use inventory.hosts so it can create localhost on demand
return self._find_host(host_name) is not None
def __iter__(self):
yield from self._inventory.hosts
def __len__(self):
return len(self._inventory.hosts)
def __repr__(self):
out = {}
for host in self._inventory.hosts:
out[host] = self.get(host)
return repr(out)
def __deepcopy__(self, memo):
# We do not need to deepcopy because HostVars is immutable,
# however we have to implement the method so we can deepcopy
# variables' dicts that contain HostVars.
return self
class HostVarsVars(Mapping):
def __init__(self, variables, loader):
self._vars = variables
self._loader = loader
# NOTE: this only has access to the host's own vars,
# so templates that depend on vars in other scopes will not work.
self._templar = Templar(variables=self._vars, loader=self._loader)
def __getitem__(self, var):
return self._templar.template(self._vars[var], fail_on_undefined=False, static_vars=C.INTERNAL_STATIC_VARS)
def __contains__(self, var):
return (var in self._vars)
def __iter__(self):
yield from self._vars.keys()
def __len__(self):
return len(self._vars.keys())
def __repr__(self):
return repr(self._templar.template(self._vars, fail_on_undefined=False, static_vars=C.INTERNAL_STATIC_VARS))
|