Skip to content
This repository has been archived by the owner on Feb 29, 2024. It is now read-only.

Commit

Permalink
Add per host groups to dynamic inventory
Browse files Browse the repository at this point in the history
Currently you can only run ad-hoc commands against roles, e.g
groups of nodes (unless, perhaps you have all the nodes in dns
or the undercloud hosts file).

We can add groups for each node, such that the nodes are accessible
via both the node name (as displayed e.g via nova list) and the IP,
e.g

ansible -i /usr/bin/tripleo-ansible-inventory  overcloud-controller-0 -m shell -a 'uname -a'

This may also be useful for performing rolling updates via ansible
in future.

Depends-On: I61efac5634e9b6fbb820e693c71a0adae5fa8b6a
Change-Id: I40192f009812ae9fa2bdc44d59d8b4e241318f39
  • Loading branch information
Steven Hardy committed May 23, 2017
1 parent 37d25a0 commit 60f9257
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 27 deletions.
18 changes: 12 additions & 6 deletions tripleo_validations/inventory.py
Expand Up @@ -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
Expand Down
117 changes: 96 additions & 21 deletions tripleo_validations/tests/test_inventory.py
Expand Up @@ -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(
Expand All @@ -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])

0 comments on commit 60f9257

Please sign in to comment.