Enable autoloading of inventory plugins (#32709)

* Automatically loads and executes an inventory plugin specified by a standard YAML inventory config file containing a `plugin` key at its root.
* Moved inventory PluginLoader to a shared global instance.
This commit is contained in:
Matt Davis 2017-11-09 16:38:34 -08:00 committed by ansibot
parent abc4210a33
commit 5ff36c3423
5 changed files with 67 additions and 5 deletions

View file

@ -29,7 +29,7 @@ from ansible.module_utils._text import to_native
from ansible.module_utils.six import string_types from ansible.module_utils.six import string_types
from ansible.parsing.yaml.dumper import AnsibleDumper from ansible.parsing.yaml.dumper import AnsibleDumper
from ansible.plugins.loader import module_loader, action_loader, lookup_loader, callback_loader, cache_loader, \ from ansible.plugins.loader import module_loader, action_loader, lookup_loader, callback_loader, cache_loader, \
vars_loader, connection_loader, strategy_loader, PluginLoader vars_loader, connection_loader, strategy_loader, inventory_loader
from ansible.utils import plugin_docs from ansible.utils import plugin_docs
try: try:
from __main__ import display from __main__ import display
@ -97,7 +97,7 @@ class DocCLI(CLI):
elif plugin_type == 'vars': elif plugin_type == 'vars':
loader = vars_loader loader = vars_loader
elif plugin_type == 'inventory': elif plugin_type == 'inventory':
loader = PluginLoader('InventoryModule', 'ansible.plugins.inventory', C.DEFAULT_INVENTORY_PLUGIN_PATH, 'inventory_plugins') loader = inventory_loader
else: else:
loader = module_loader loader = module_loader

View file

@ -1239,7 +1239,7 @@ HOST_KEY_CHECKING:
type: boolean type: boolean
INVENTORY_ENABLED: INVENTORY_ENABLED:
name: Active Inventory plugins name: Active Inventory plugins
default: ['host_list', 'script', 'yaml', 'ini'] default: ['host_list', 'script', 'yaml', 'ini', 'auto']
description: List of enabled inventory plugins, it also determines the order in which they are used. description: List of enabled inventory plugins, it also determines the order in which they are used.
env: [{name: ANSIBLE_INVENTORY_ENABLED}] env: [{name: ANSIBLE_INVENTORY_ENABLED}]
ini: ini:

View file

@ -30,7 +30,7 @@ from ansible.inventory.data import InventoryData
from ansible.module_utils.six import string_types from ansible.module_utils.six import string_types
from ansible.module_utils._text import to_bytes, to_native, to_text from ansible.module_utils._text import to_bytes, to_native, to_text
from ansible.parsing.utils.addresses import parse_address from ansible.parsing.utils.addresses import parse_address
from ansible.plugins.loader import PluginLoader from ansible.plugins.loader import inventory_loader
from ansible.utils.path import unfrackpath from ansible.utils.path import unfrackpath
try: try:
@ -178,7 +178,6 @@ class InventoryManager(object):
def _setup_inventory_plugins(self): def _setup_inventory_plugins(self):
''' sets up loaded inventory plugins for usage ''' ''' sets up loaded inventory plugins for usage '''
inventory_loader = PluginLoader('InventoryModule', 'ansible.plugins.inventory', C.DEFAULT_INVENTORY_PLUGIN_PATH, 'inventory_plugins')
display.vvvv('setting up inventory plugins') display.vvvv('setting up inventory plugins')
for name in C.INVENTORY_ENABLED: for name in C.INVENTORY_ENABLED:

View file

@ -0,0 +1,56 @@
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = '''
name: auto
plugin_type: inventory
authors:
- Matt Davis <@nitzmahone>
short_description: Loads and executes an inventory plugin specified in a YAML config
description:
- By whitelisting C(auto) as the final inventory plugin, any YAML inventory config file with a
C(plugin) key at its root will automatically cause the named plugin to be loaded and executed with that
config. This effectively provides automatic whitelisting of all installed/accessible inventory plugins.
- To disable this behavior, remove C(auto) from the C(INVENTORY_ENABLED) config element.
options:
'''
EXAMPLES = '''
# This plugin is not intended for direct use; it is a fallback mechanism for automatic whitelisting of
# all installed inventory plugins.
'''
from ansible.errors import AnsibleParserError
from ansible.plugins.inventory import BaseInventoryPlugin
from ansible.plugins.loader import inventory_loader
class InventoryModule(BaseInventoryPlugin):
NAME = 'auto'
def verify_file(self, path):
if not path.endswith('.yml') and not path.endswith('.yaml'):
return False
return super(InventoryModule, self).verify_file(path)
def parse(self, inventory, loader, path, cache=True):
config_data = loader.load_from_file(path)
plugin_name = config_data.get('plugin')
if not plugin_name:
raise AnsibleParserError("no root 'plugin' key found, '{0}' is not a valid YAML inventory plugin config file".format(path))
plugin = inventory_loader.get(plugin_name)
if not plugin:
raise AnsibleParserError("inventory config '{0}' specifies unknown plugin '{1}'".format(path, plugin_name))
if not plugin.verify_file(path):
raise AnsibleParserError("inventory config '{0}' could not be verified by plugin '{1}'".format(path, plugin_name))
plugin.parse(inventory, loader, path, cache=cache)

View file

@ -582,3 +582,10 @@ netconf_loader = PluginLoader(
'netconf_plugins', 'netconf_plugins',
required_base_class='NetconfBase' required_base_class='NetconfBase'
) )
inventory_loader = PluginLoader(
'InventoryModule',
'ansible.plugins.inventory',
C.DEFAULT_INVENTORY_PLUGIN_PATH,
'inventory_plugins'
)