diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:55:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:55:41 +0000 |
commit | 634758cfc77dff535c5e9e17cc99c6ba19e965b1 (patch) | |
tree | bb1c1a6bbff7abf9ed2d0e3b888480e70f0f109a /lib/ansible/vars/plugins.py | |
parent | Adding upstream version 2.14.13. (diff) | |
download | ansible-core-634758cfc77dff535c5e9e17cc99c6ba19e965b1.tar.xz ansible-core-634758cfc77dff535c5e9e17cc99c6ba19e965b1.zip |
Adding upstream version 2.16.5.upstream/2.16.5
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib/ansible/vars/plugins.py')
-rw-r--r-- | lib/ansible/vars/plugins.py | 112 |
1 files changed, 61 insertions, 51 deletions
diff --git a/lib/ansible/vars/plugins.py b/lib/ansible/vars/plugins.py index 303052b..c234350 100644 --- a/lib/ansible/vars/plugins.py +++ b/lib/ansible/vars/plugins.py @@ -1,33 +1,48 @@ # Copyright (c) 2018 Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import os +from functools import lru_cache + from ansible import constants as C from ansible.errors import AnsibleError -from ansible.inventory.host import Host -from ansible.module_utils._text import to_bytes +from ansible.inventory.group import InventoryObjectType from ansible.plugins.loader import vars_loader -from ansible.utils.collection_loader import AnsibleCollectionRef from ansible.utils.display import Display from ansible.utils.vars import combine_vars display = Display() +def _prime_vars_loader(): + # find 3rd party legacy vars plugins once, and look them up by name subsequently + list(vars_loader.all(class_only=True)) + for plugin_name in C.VARIABLE_PLUGINS_ENABLED: + if not plugin_name: + continue + vars_loader.get(plugin_name) + + def get_plugin_vars(loader, plugin, path, entities): data = {} try: data = plugin.get_vars(loader, path, entities) except AttributeError: + if hasattr(plugin, 'get_host_vars') or hasattr(plugin, 'get_group_vars'): + display.deprecated( + f"The vars plugin {plugin.ansible_name} from {plugin._original_path} is relying " + "on the deprecated entrypoints 'get_host_vars' and 'get_group_vars'. " + "This plugin should be updated to inherit from BaseVarsPlugin and define " + "a 'get_vars' method as the main entrypoint instead.", + version="2.20", + ) try: for entity in entities: - if isinstance(entity, Host): + if entity.base_type is InventoryObjectType.HOST: data |= plugin.get_host_vars(entity.name) else: data |= plugin.get_group_vars(entity.name) @@ -39,59 +54,53 @@ def get_plugin_vars(loader, plugin, path, entities): return data -def get_vars_from_path(loader, path, entities, stage): +# optimized for stateless plugins; non-stateless plugin instances will fall out quickly +@lru_cache(maxsize=10) +def _plugin_should_run(plugin, stage): + # if a plugin-specific setting has not been provided, use the global setting + # older/non shipped plugins that don't support the plugin-specific setting should also use the global setting + allowed_stages = None + + try: + allowed_stages = plugin.get_option('stage') + except (AttributeError, KeyError): + pass + + if allowed_stages: + return allowed_stages in ('all', stage) + # plugin didn't declare a preference; consult global config + config_stage_override = C.RUN_VARS_PLUGINS + if config_stage_override == 'demand' and stage == 'inventory': + return False + elif config_stage_override == 'start' and stage == 'task': + return False + return True + + +def get_vars_from_path(loader, path, entities, stage): data = {} + if vars_loader._paths is None: + # cache has been reset, reload all() + _prime_vars_loader() - vars_plugin_list = list(vars_loader.all()) - for plugin_name in C.VARIABLE_PLUGINS_ENABLED: - if AnsibleCollectionRef.is_valid_fqcr(plugin_name): - vars_plugin = vars_loader.get(plugin_name) - if vars_plugin is None: - # Error if there's no play directory or the name is wrong? - continue - if vars_plugin not in vars_plugin_list: - vars_plugin_list.append(vars_plugin) - - for plugin in vars_plugin_list: - # legacy plugins always run by default, but they can set REQUIRES_ENABLED=True to opt out. - - builtin_or_legacy = plugin.ansible_name.startswith('ansible.builtin.') or '.' not in plugin.ansible_name - - # builtin is supposed to have REQUIRES_ENABLED=True, the following is for legacy plugins... - needs_enabled = not builtin_or_legacy - if hasattr(plugin, 'REQUIRES_ENABLED'): - needs_enabled = plugin.REQUIRES_ENABLED - elif hasattr(plugin, 'REQUIRES_WHITELIST'): - display.deprecated("The VarsModule class variable 'REQUIRES_WHITELIST' is deprecated. " - "Use 'REQUIRES_ENABLED' instead.", version=2.18) - needs_enabled = plugin.REQUIRES_WHITELIST - - # A collection plugin was enabled to get to this point because vars_loader.all() does not include collection plugins. + for plugin_name in vars_loader._plugin_instance_cache: + if (plugin := vars_loader.get(plugin_name)) is None: + continue + + collection = '.' in plugin.ansible_name and not plugin.ansible_name.startswith('ansible.builtin.') # Warn if a collection plugin has REQUIRES_ENABLED because it has no effect. - if not builtin_or_legacy and (hasattr(plugin, 'REQUIRES_ENABLED') or hasattr(plugin, 'REQUIRES_WHITELIST')): + if collection and (hasattr(plugin, 'REQUIRES_ENABLED') or hasattr(plugin, 'REQUIRES_WHITELIST')): display.warning( "Vars plugins in collections must be enabled to be loaded, REQUIRES_ENABLED is not supported. " "This should be removed from the plugin %s." % plugin.ansible_name ) - elif builtin_or_legacy and needs_enabled and not plugin.matches_name(C.VARIABLE_PLUGINS_ENABLED): - continue - - has_stage = hasattr(plugin, 'get_option') and plugin.has_option('stage') - - # if a plugin-specific setting has not been provided, use the global setting - # older/non shipped plugins that don't support the plugin-specific setting should also use the global setting - use_global = (has_stage and plugin.get_option('stage') is None) or not has_stage - if use_global: - if C.RUN_VARS_PLUGINS == 'demand' and stage == 'inventory': - continue - elif C.RUN_VARS_PLUGINS == 'start' and stage == 'task': - continue - elif has_stage and plugin.get_option('stage') not in ('all', stage): + if not _plugin_should_run(plugin, stage): continue - data = combine_vars(data, get_plugin_vars(loader, plugin, path, entities)) + if (new_vars := get_plugin_vars(loader, plugin, path, entities)) != {}: + data = combine_vars(data, new_vars) return data @@ -105,10 +114,11 @@ def get_vars_from_inventory_sources(loader, sources, entities, stage): continue if ',' in path and not os.path.exists(path): # skip host lists continue - elif not os.path.isdir(to_bytes(path)): + elif not os.path.isdir(path): # always pass the directory of the inventory source file path = os.path.dirname(path) - data = combine_vars(data, get_vars_from_path(loader, path, entities, stage)) + if (new_vars := get_vars_from_path(loader, path, entities, stage)) != {}: + data = combine_vars(data, new_vars) return data |