[Inventory] Cache the result of enumerating groups and host names
for `VariableManager._get_magic_variables()`. This saves a lot of time re-iterating the nearly always constant global list of groups and their members. Generate once and cache, and invalidate cache in case `add_host:` or `group_by:` are used.
This commit is contained in:
parent
28227546fa
commit
c23b11d212
4 changed files with 38 additions and 11 deletions
|
@ -25,7 +25,7 @@ import sys
|
||||||
import re
|
import re
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
from ansible.compat.six import string_types
|
from ansible.compat.six import string_types, iteritems
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
|
@ -63,11 +63,12 @@ class Inventory(object):
|
||||||
# caching to avoid repeated calculations, particularly with
|
# caching to avoid repeated calculations, particularly with
|
||||||
# external inventory scripts.
|
# external inventory scripts.
|
||||||
|
|
||||||
self._vars_per_host = {}
|
self._vars_per_host = {}
|
||||||
self._vars_per_group = {}
|
self._vars_per_group = {}
|
||||||
self._hosts_cache = {}
|
self._hosts_cache = {}
|
||||||
self._pattern_cache = {}
|
self._pattern_cache = {}
|
||||||
self._vars_plugins = []
|
self._group_dict_cache = {}
|
||||||
|
self._vars_plugins = []
|
||||||
|
|
||||||
self._basedir = self.basedir()
|
self._basedir = self.basedir()
|
||||||
|
|
||||||
|
@ -88,6 +89,7 @@ class Inventory(object):
|
||||||
# clear the cache here, which is only useful if more than
|
# clear the cache here, which is only useful if more than
|
||||||
# one Inventory objects are created when using the API directly
|
# one Inventory objects are created when using the API directly
|
||||||
self.clear_pattern_cache()
|
self.clear_pattern_cache()
|
||||||
|
self.clear_group_dict_cache()
|
||||||
|
|
||||||
self.parse_inventory(host_list)
|
self.parse_inventory(host_list)
|
||||||
|
|
||||||
|
@ -220,7 +222,7 @@ class Inventory(object):
|
||||||
hosts = [ h for h in hosts if h in subset ]
|
hosts = [ h for h in hosts if h in subset ]
|
||||||
|
|
||||||
# exclude hosts mentioned in any restriction (ex: failed hosts)
|
# exclude hosts mentioned in any restriction (ex: failed hosts)
|
||||||
if self._restriction is not None:
|
if self._restriction:
|
||||||
hosts = [ h for h in hosts if h.name in self._restriction ]
|
hosts = [ h for h in hosts if h.name in self._restriction ]
|
||||||
|
|
||||||
seen = set()
|
seen = set()
|
||||||
|
@ -502,6 +504,10 @@ class Inventory(object):
|
||||||
HOSTS_PATTERNS_CACHE = {}
|
HOSTS_PATTERNS_CACHE = {}
|
||||||
self._pattern_cache = {}
|
self._pattern_cache = {}
|
||||||
|
|
||||||
|
def clear_group_dict_cache(self):
|
||||||
|
''' called exclusively by the add_host and group_by plugins '''
|
||||||
|
self._group_dict_cache = {}
|
||||||
|
|
||||||
def groups_for_host(self, host):
|
def groups_for_host(self, host):
|
||||||
if host in self._hosts_cache:
|
if host in self._hosts_cache:
|
||||||
return self._hosts_cache[host].get_groups()
|
return self._hosts_cache[host].get_groups()
|
||||||
|
@ -568,6 +574,20 @@ class Inventory(object):
|
||||||
|
|
||||||
return vars
|
return vars
|
||||||
|
|
||||||
|
def get_group_dict(self):
|
||||||
|
"""
|
||||||
|
In get_vars() we merge a 'magic' dictionary 'groups' with group name
|
||||||
|
keys and hostname list values into every host variable set.
|
||||||
|
|
||||||
|
Cache the creation of this structure here
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not self._group_dict_cache:
|
||||||
|
for (group_name, group) in iteritems(self.groups):
|
||||||
|
self._group_dict_cache[group_name] = [h.name for h in group.get_hosts()]
|
||||||
|
|
||||||
|
return self._group_dict_cache
|
||||||
|
|
||||||
def get_vars(self, hostname, update_cached=False, vault_password=None):
|
def get_vars(self, hostname, update_cached=False, vault_password=None):
|
||||||
|
|
||||||
host = self.get_host(hostname)
|
host = self.get_host(hostname)
|
||||||
|
@ -829,6 +849,7 @@ class Inventory(object):
|
||||||
def refresh_inventory(self):
|
def refresh_inventory(self):
|
||||||
|
|
||||||
self.clear_pattern_cache()
|
self.clear_pattern_cache()
|
||||||
|
self.clear_group_dict_cache()
|
||||||
|
|
||||||
self._hosts_cache = {}
|
self._hosts_cache = {}
|
||||||
self._vars_per_host = {}
|
self._vars_per_host = {}
|
||||||
|
|
|
@ -475,6 +475,9 @@ class StrategyBase:
|
||||||
# patterns may have referenced the group
|
# patterns may have referenced the group
|
||||||
self._inventory.clear_pattern_cache()
|
self._inventory.clear_pattern_cache()
|
||||||
|
|
||||||
|
# clear cache of group dict, which is used in magic host variables
|
||||||
|
self._inventory.clear_group_dict_cache()
|
||||||
|
|
||||||
# also clear the hostvar cache entry for the given play, so that
|
# also clear the hostvar cache entry for the given play, so that
|
||||||
# the new hosts are available if hostvars are referenced
|
# the new hosts are available if hostvars are referenced
|
||||||
self._variable_manager.invalidate_hostvars_cache(play=iterator._play)
|
self._variable_manager.invalidate_hostvars_cache(play=iterator._play)
|
||||||
|
@ -495,6 +498,9 @@ class StrategyBase:
|
||||||
group_name = result_item.get('add_group')
|
group_name = result_item.get('add_group')
|
||||||
new_group = self._inventory.get_group(group_name)
|
new_group = self._inventory.get_group(group_name)
|
||||||
if not new_group:
|
if not new_group:
|
||||||
|
# clear cache of group dict, which is used in magic host variables
|
||||||
|
self._inventory.clear_group_dict_cache()
|
||||||
|
|
||||||
# create the new group and add it to inventory
|
# create the new group and add it to inventory
|
||||||
new_group = Group(name=group_name)
|
new_group = Group(name=group_name)
|
||||||
self._inventory.add_group(new_group)
|
self._inventory.add_group(new_group)
|
||||||
|
|
|
@ -393,10 +393,9 @@ class VariableManager:
|
||||||
if host:
|
if host:
|
||||||
variables['group_names'] = sorted([group.name for group in host.get_groups() if group.name != 'all'])
|
variables['group_names'] = sorted([group.name for group in host.get_groups() if group.name != 'all'])
|
||||||
|
|
||||||
if self._inventory is not None:
|
if self._inventory:
|
||||||
variables['groups'] = dict()
|
variables['groups'] = self._inventory.get_group_dict()
|
||||||
for (group_name, group) in iteritems(self._inventory.groups):
|
|
||||||
variables['groups'][group_name] = [h.name for h in group.get_hosts()]
|
|
||||||
if play:
|
if play:
|
||||||
variables['role_names'] = [r._role_name for r in play.roles]
|
variables['role_names'] = [r._role_name for r in play.roles]
|
||||||
|
|
||||||
|
|
|
@ -237,6 +237,7 @@ class TestStrategyBase(unittest.TestCase):
|
||||||
mock_inventory.get_host.side_effect = _get_host
|
mock_inventory.get_host.side_effect = _get_host
|
||||||
mock_inventory.get_group.side_effect = _get_group
|
mock_inventory.get_group.side_effect = _get_group
|
||||||
mock_inventory.clear_pattern_cache.return_value = None
|
mock_inventory.clear_pattern_cache.return_value = None
|
||||||
|
mock_inventory.clear_group_dict_cache.return_value = None
|
||||||
mock_inventory.get_host_vars.return_value = {}
|
mock_inventory.get_host_vars.return_value = {}
|
||||||
|
|
||||||
mock_var_mgr = MagicMock()
|
mock_var_mgr = MagicMock()
|
||||||
|
|
Loading…
Reference in a new issue