# 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 import os 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.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 get_plugin_vars(loader, plugin, path, entities): data = {} try: data = plugin.get_vars(loader, path, entities) except AttributeError: try: for entity in entities: if isinstance(entity, Host): data |= plugin.get_host_vars(entity.name) else: data |= plugin.get_group_vars(entity.name) except AttributeError: if hasattr(plugin, 'run'): raise AnsibleError("Cannot use v1 type vars plugin %s from %s" % (plugin._load_name, plugin._original_path)) else: raise AnsibleError("Invalid vars plugin %s from %s" % (plugin._load_name, plugin._original_path)) return data def get_vars_from_path(loader, path, entities, stage): data = {} 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. # 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')): 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): continue data = combine_vars(data, get_plugin_vars(loader, plugin, path, entities)) return data def get_vars_from_inventory_sources(loader, sources, entities, stage): data = {} for path in sources: if path is None: continue if ',' in path and not os.path.exists(path): # skip host lists continue elif not os.path.isdir(to_bytes(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)) return data