diff --git a/tripleo_validations/inventory.py b/tripleo_validations/inventory.py index 2a829220..af54e9c5 100644 --- a/tripleo_validations/inventory.py +++ b/tripleo_validations/inventory.py @@ -116,22 +116,28 @@ def list(self): horizon_endpoint role_net_ip_map = self.stack_outputs.get('RoleNetIpMap', {}) + role_net_hostname_map = self.stack_outputs.get( + 'RoleNetHostnameMap', {}) children = [] - - # Collect host ips for each role - for role, ips in role_net_ip_map.items(): - if ips and ips.get(HOST_NETWORK): + for role, hostnames in role_net_hostname_map.items(): + if hostnames: + names = hostnames.get(HOST_NETWORK) or [] + shortnames = [n.split(".%s." % HOST_NETWORK)[0] for n in names] children.append(role.lower()) ret[role.lower()] = { - 'hosts': ips.get(HOST_NETWORK), + 'children': sorted(shortnames), 'vars': { 'ansible_ssh_user': 'heat-admin', } } + # Create a group per hostname to map hostname to IP + ips = role_net_ip_map[role][HOST_NETWORK] + for idx, name in enumerate(shortnames): + ret[name] = {'hosts': [ips[idx]]} if children: ret['overcloud'] = { - 'children': children + 'children': sorted(children) } # Associate services with roles diff --git a/tripleo_validations/tests/test_inventory.py b/tripleo_validations/tests/test_inventory.py index a103b1f3..8763eb78 100644 --- a/tripleo_validations/tests/test_inventory.py +++ b/tripleo_validations/tests/test_inventory.py @@ -48,6 +48,61 @@ class TestInventory(base.TestCase): + def setUp(self): + super(TestInventory, self).setUp() + self.outputs_data = {'outputs': [ + {'output_key': 'EnabledServices', + 'output_value': { + 'Controller': ['a', 'b', 'c'], + 'Compute': ['d', 'e', 'f'], + 'CustomRole': ['g', 'h', 'i']}}, + {'output_key': 'KeystoneURL', + 'output_value': 'xyz://keystone'}, + {'output_key': 'RoleNetHostnameMap', + 'output_value': { + 'Controller': { + 'ctlplane': ['c-0.ctlplane.localdomain', + 'c-1.ctlplane.localdomain', + 'c-2.ctlplane.localdomain']}, + 'Compute': { + 'ctlplane': ['cp-0.ctlplane.localdomain']}, + 'CustomRole': { + 'ctlplane': ['cs-0.ctlplane.localdomain']}}}, + {'output_key': 'RoleNetIpMap', + 'output_value': { + 'Controller': { + 'ctlplane': ['x.x.x.1', + 'x.x.x.2', + 'x.x.x.3']}, + 'Compute': { + 'ctlplane': ['y.y.y.1']}, + 'CustomRole': { + 'ctlplane': ['z.z.z.1']}}}]} + self.plan_name = 'overcloud' + + def _mock_out_show(plan_name, key): + self.assertEqual(self.plan_name, plan_name) + out_data = [o for o in self.outputs_data['outputs'] + if o['output_key'] == key][0] + return {'output': out_data} + + self.hclient = MagicMock() + self.hclient.stacks.output_list.return_value = self.outputs_data + self.hclient.stacks.output_show.side_effect = _mock_out_show + self.hclient.stacks.environment.return_value = { + 'parameter_defaults': {'AdminPassword': 'theadminpw'}} + + self.configs = MagicMock() + self.configs.plan = self.plan_name + + self.session = MagicMock() + self.session.get_token.return_value = 'atoken' + self.session.get_endpoint.return_value = 'anendpoint' + + self.outputs = StackOutputs('overcloud', self.hclient) + self.inventory = TripleoInventory( + self.configs, self.session, self.hclient) + self.inventory.stack_outputs = self.outputs def test_get_roles_by_service(self): services = TripleoInventory.get_roles_by_service( @@ -64,34 +119,54 @@ def test_get_roles_by_service(self): } self.assertDictEqual(services, expected) - -class TestStackOutputs(base.TestCase): - - def setUp(self): - super(TestStackOutputs, self).setUp() - self.hclient = MagicMock() - self.hclient.stacks.output_list.return_value = dict( - outputs=[{'output_key': 'EnabledServices'}, - {'output_key': 'KeystoneURL'}]) - self.outputs = StackOutputs('overcloud', self.hclient) - - def test_valid_key_calls_api(self): - expected = 'http://localhost:5000/v3' + def test_outputs_valid_key_calls_api(self): + expected = 'xyz://keystone' self.hclient.stacks.output_show.return_value = dict(output=dict( output_value=expected)) - self.assertEqual(self.outputs['KeystoneURL'], expected) + self.assertEqual(expected, self.outputs['KeystoneURL']) # This should also support the get method - self.assertEqual(self.outputs.get('KeystoneURL'), expected) + self.assertEqual(expected, self.outputs.get('KeystoneURL')) self.assertTrue(self.hclient.called_once_with('overcloud', 'KeystoneURL')) - def test_invalid_key_raises_keyerror(self): + def test_outputs_invalid_key_raises_keyerror(self): self.assertRaises(KeyError, lambda: self.outputs['Invalid']) - def test_get_method_returns_default(self): + def test_outputs_get_method_returns_default(self): default = 'default value' - self.assertEqual(self.outputs.get('Invalid', default), default) + self.assertEqual(default, self.outputs.get('Invalid', default)) + + def test_outputs_iterating_returns_list_of_output_keys(self): + self.assertEqual( + ['EnabledServices', 'KeystoneURL', + 'RoleNetHostnameMap', 'RoleNetIpMap'], + [o for o in self.outputs]) - def test_iterating_returns_list_of_output_keys(self): - self.assertEqual([o for o in self.outputs], - ['EnabledServices', 'KeystoneURL']) + def test_inventory_list(self): + expected = {'c-0': {'hosts': ['x.x.x.1']}, + 'c-1': {'hosts': ['x.x.x.2']}, + 'c-2': {'hosts': ['x.x.x.3']}, + 'compute': { + 'children': ['cp-0'], + 'vars': {'ansible_ssh_user': 'heat-admin'}}, + 'controller': { + 'children': ['c-0', 'c-1', 'c-2'], + 'vars': {'ansible_ssh_user': 'heat-admin'}}, + 'cp-0': {'hosts': ['y.y.y.1']}, + 'cs-0': {'hosts': ['z.z.z.1']}, + 'customrole': { + 'children': ['cs-0'], + 'vars': {'ansible_ssh_user': 'heat-admin'}}, + 'overcloud': { + 'children': ['compute', 'controller', 'customrole']}, + 'undercloud': { + 'hosts': ['localhost'], + 'vars': {'ansible_connection': 'local', + 'os_auth_token': 'atoken', + 'overcloud_keystone_url': 'xyz://keystone', + 'overcloud_admin_password': 'theadminpw', + 'plan': 'overcloud', + 'undercloud_swift_url': 'anendpoint'}}} + inv_list = self.inventory.list() + for k in expected: + self.assertEqual(expected[k], inv_list[k])