From b403653bd2101f306434571c3a01b25cd9271347 Mon Sep 17 00:00:00 2001 From: Brian Coca <bcoca@users.noreply.github.com> Date: Wed, 14 Feb 2018 15:45:15 -0500 Subject: [PATCH] Inv export (#36188) * add export option * added 'export mode' to ansible-inventory this optimizes the output for exporting inventory vs representing the 'ansible view' fixes #30877 * added group priority when needed --- lib/ansible/cli/inventory.py | 89 +++++++++++++++++++++++++++++++++--- lib/ansible/config/base.yml | 8 ++++ 2 files changed, 91 insertions(+), 6 deletions(-) diff --git a/lib/ansible/cli/inventory.py b/lib/ansible/cli/inventory.py index d839567dd8c..cb0e8256d22 100644 --- a/lib/ansible/cli/inventory.py +++ b/lib/ansible/cli/inventory.py @@ -20,9 +20,13 @@ __metaclass__ = type import optparse from operator import attrgetter +from ansible import constants as C from ansible.cli import CLI -from ansible.errors import AnsibleOptionsError +from ansible.errors import AnsibleError, AnsibleOptionsError +from ansible.inventory.host import Host +from ansible.plugins.loader import vars_loader from ansible.parsing.dataloader import DataLoader +from ansible.utils.vars import combine_vars try: from __main__ import display @@ -83,11 +87,20 @@ class InventoryCLI(CLI): self.parser.add_option_group(action_group) # Options + + # graph self.parser.add_option("-y", "--yaml", action="store_true", default=False, dest='yaml', help='Use YAML format instead of default JSON, ignored for --graph') self.parser.add_option("--vars", action="store_true", default=False, dest='show_vars', help='Add vars to graph display, ignored unless used with --graph') + # list + self.parser.add_option("--export", action="store_true", default=C.INVENTORY_EXPORT, dest='export', + help="When doing an --list, represent in a way that is optimized for export," + "not as an accurate representation of how Ansible has processed it") + # self.parser.add_option("--ignore-vars-plugins", action="store_true", default=False, dest='ignore_vars_plugins', + # help="When doing an --list, skip vars data from vars plugins, by default, this would include group_vars/ and host_vars/") + super(InventoryCLI, self).parse() display.verbosity = self.options.verbosity @@ -183,11 +196,63 @@ class InventoryCLI(CLI): return results + # FIXME: refactor to use same for VM + def get_plugin_vars(self, path, entity): + + data = {} + + def _get_plugin_vars(plugin, path, entities): + data = {} + try: + data = plugin.get_vars(self.loader, path, entity) + except AttributeError: + try: + if isinstance(entity, Host): + data.update(plugin.get_host_vars(entity.name)) + else: + data.update(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 + + for plugin in vars_loader.all(): + data = combine_vars(data, _get_plugin_vars(plugin, path, entity)) + + return data + + def _get_group_variables(self, group): + + # get info from inventory source + res = group.get_vars() + + # FIXME: add switch to skip vars plugins + # add vars plugin info + for inventory_dir in self.inventory._sources: + res = combine_vars(res, self.get_plugin_vars(inventory_dir, group)) + + if group.priority != 1: + res['ansible_group_priority'] = group.priority + + return res + def _get_host_variables(self, host): - if self._new_api: - hostvars = self.vm.get_vars(host=host) + + if self.options.export: + hostvars = host.get_vars() + + # FIXME: add switch to skip vars plugins + # add vars plugin info + for inventory_dir in self.inventory._sources: + hostvars = combine_vars(hostvars, self.get_plugin_vars(inventory_dir, host)) else: - hostvars = self.vm.get_vars(self.loader, host=host) + if self._new_api: + hostvars = self.vm.get_vars(host=host, include_hostvars=False) + else: + hostvars = self.vm.get_vars(self.loader, host=host, include_hostvars=False) + return hostvars def _get_group(self, gname): @@ -257,8 +322,11 @@ class InventoryCLI(CLI): for subgroup in sorted(group.child_groups, key=attrgetter('name')): results[group.name]['children'].append(subgroup.name) results.update(format_group(subgroup)) + if self.options.export: + results[group.name]['vars'] = self._get_group_variables(group) self._remove_empty(results[group.name]) + return results results = format_group(top) @@ -267,8 +335,10 @@ class InventoryCLI(CLI): results['_meta'] = {'hostvars': {}} hosts = self.inventory.get_hosts() for host in hosts: - results['_meta']['hostvars'][host.name] = self._get_host_variables(host=host) - self._remove_internal(results['_meta']['hostvars'][host.name]) + hvars = self._get_host_variables(host) + if hvars: + self._remove_internal(hvars) + results['_meta']['hostvars'][host.name] = hvars return results @@ -299,7 +369,14 @@ class InventoryCLI(CLI): self._remove_internal(myvars) results[group.name]['hosts'][h.name] = myvars + if self.options.export: + + gvars = self._get_group_variables(group) + if gvars: + results[group.name]['vars'] = gvars + self._remove_empty(results[group.name]) + return results return format_group(top) diff --git a/lib/ansible/config/base.yml b/lib/ansible/config/base.yml index 8dfe354e929..b5fe5c2cd5c 100644 --- a/lib/ansible/config/base.yml +++ b/lib/ansible/config/base.yml @@ -1309,6 +1309,14 @@ INVENTORY_ENABLED: ini: - {key: enable_plugins, section: inventory} type: list +INVENTORY_EXPORT: + name: Set ansible-inventory into export mode + default: False + description: Controls if ansible-inventory will accurately reflect Ansible's view into inventory or its optimized for exporting. + env: [{name: ANSIBLE_INVENTORY_EXPORT}] + ini: + - {key: export, section: inventory} + type: bool INVENTORY_IGNORE_EXTS: name: Inventory ignore extensions default: "{{(BLACKLIST_EXTS + ( '~', '.orig', '.ini', '.cfg', '.retry'))}}"