diff --git a/doc/source/developer-docs/inventory.rst b/doc/source/developer-docs/inventory.rst index 0256507191..e1ed871b11 100644 --- a/doc/source/developer-docs/inventory.rst +++ b/doc/source/developer-docs/inventory.rst @@ -142,6 +142,19 @@ Use the host's name as an argument. .. _`dynamic inventory functionality`: http://docs.ansible.com/ansible/intro_dynamic_inventory.html +Exporting Host Information +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Information on a per-host basis can be obtained with the ``--export/-e`` +parameter. + +This JSON output has two top-level keys: ``hosts`` and ``all``. + +``hosts`` contains a map of a host's name to its variable and group data. + +``all`` contains global network information such as the load balancer IPs and +provider network metadata. + The lxc_hosts Group ------------------- diff --git a/releasenotes/notes/export-hosts-flag-9c9f170eb89798ea.yaml b/releasenotes/notes/export-hosts-flag-9c9f170eb89798ea.yaml new file mode 100644 index 0000000000..2b17951230 --- /dev/null +++ b/releasenotes/notes/export-hosts-flag-9c9f170eb89798ea.yaml @@ -0,0 +1,6 @@ +--- +features: + - An export flag has been added to the ``inventory-manage.py`` script. This + flag allows exporting of host and network information from an + OpenStack-Ansible inventory for import into another system, or an + alternate view of the existing data. See the developer docs for more details. diff --git a/scripts/manage_inventory.py b/scripts/manage_inventory.py index 139fce129b..f46535a30a 100644 --- a/scripts/manage_inventory.py +++ b/scripts/manage_inventory.py @@ -143,6 +143,14 @@ def args(): default=False ) + exclusive_action.add_argument( + '-e', + '--export', + help='Export group and variable information per host in JSON.', + action='store_true', + default=False + ) + return vars(parser.parse_args()) @@ -296,6 +304,38 @@ def print_inventory(inventory, sort_key): return table +def export_host_info(inventory): + """Pivot variable information to be a per-host dict + + This command is meant for exporting an existing inventory's information. + The exported data re-arranges variable data so that the keys are the host, + and the values are hostvars and groups. + + Two top level keys are present: 'hosts' and 'all'. 'hosts' is a dictonary + of the host information. 'all' represents global data, mostly the load + balancer and provider network values. It is taken from + inventory['all']['vars']. + """ + export_info = {'hosts': {}} + host_info = export_info['hosts'] + + export_info['all'] = inventory['all']['vars'] + + for host, hostvars in inventory['_meta']['hostvars'].items(): + host_info[host] = {} + host_info[host]['hostvars'] = hostvars + + for group_name, group_info in inventory.items(): + if group_name in ('_meta', 'all'): + continue + for host in group_info['hosts']: + if 'groups' not in host_info[host]: + host_info[host]['groups'] = [] + host_info[host]['groups'].append(group_name) + + return export_info + + def main(): """Run the main application.""" # Parse user args @@ -318,6 +358,8 @@ def main(): # Containers in the first column, groups for each container on the right elif user_args['list_containers'] is True: print(print_containers_per_group(inventory)) + elif user_args['export'] is True: + print(json.dumps(export_host_info(inventory), indent=2)) else: recursive_dict_removal(inventory, user_args['remove_item']) with open(environment_file, 'wb') as f_handle: diff --git a/tests/test_manage.py b/tests/test_manage.py new file mode 100644 index 0000000000..9e23e22b62 --- /dev/null +++ b/tests/test_manage.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +import os +from os import path +import sys +import test_inventory +import unittest + +MANAGE_DIR = path.join(os.getcwd(), 'scripts') + +sys.path.append(MANAGE_DIR) + +import manage_inventory as mi + + +class TestExportFunction(unittest.TestCase): + def setUp(self): + self.inv = test_inventory.get_inventory() + + def tearDown(self): + test_inventory.cleanup() + + def test_host_is_present(self): + host_inv = mi.export_host_info(self.inv)['hosts'] + self.assertIn('aio1', host_inv.keys()) + + def test_groups_added(self): + host_inv = mi.export_host_info(self.inv)['hosts'] + self.assertIn('groups', host_inv['aio1'].keys()) + + def test_variables_added(self): + host_inv = mi.export_host_info(self.inv)['hosts'] + self.assertIn('hostvars', host_inv['aio1'].keys()) + + def test_number_of_hosts(self): + host_inv = mi.export_host_info(self.inv)['hosts'] + + self.assertEqual(len(self.inv['_meta']['hostvars']), + len(host_inv)) + + def test_all_information_added(self): + all_info = mi.export_host_info(self.inv)['all'] + self.assertIn('provider_networks', all_info) + + def test_all_lb_information(self): + all_info = mi.export_host_info(self.inv)['all'] + inv_all = self.inv['all']['vars'] + self.assertEqual(inv_all['internal_lb_vip_address'], + all_info['internal_lb_vip_address']) + + +if __name__ == '__main__': + unittest.main() diff --git a/tox.ini b/tox.ini index 882acabd43..0aa390f1e8 100644 --- a/tox.ini +++ b/tox.ini @@ -140,7 +140,6 @@ commands = -e 'force_containers_destroy=yes' \ {toxinidir}/playbooks/setup-everything.yml - [testenv:inventory] # Use a fixed seed since some inventory tests rely on specific ordering setenv = @@ -150,6 +149,9 @@ commands = coverage erase coverage run {toxinidir}/tests/test_inventory.py coverage report --show-missing --include={toxinidir}/playbooks/inventory/* + coverage erase + coverage run {toxinidir}/tests/test_manage.py + coverage report --show-missing --include={toxinidir}/scripts/* [testenv:linters]