Allow mapping additional hostvars in write-inventory

In OpenDev, we use an inventory file with the public v4 and v6
addresses listed as hostvars.  We would like to use that feature in
testing as well.  In order to do that, we need to mutate the inventory
so that the public_ipv4 address supplied by nodepool is mapped to
the public_v4 address in the inventory.  This additional option allows
the user to configure such mappings.

Change-Id: I48f03cacdf4531c42d33f6e807845d5c2a1da1d5
This commit is contained in:
James E. Blair 2020-05-18 10:01:58 -07:00
parent 9643fb1ace
commit 41d4d6c41d
4 changed files with 70 additions and 7 deletions

View File

@ -24,3 +24,18 @@ with the inventory for the job.
A list of facts about the host to exclude. By default, all A list of facts about the host to exclude. By default, all
variables about a host will be included. To exclude certain variables about a host will be included. To exclude certain
variables, list them here. variables, list them here.
.. zuul:rolevar:: write_inventory_additional_hostvars
:type: dict
Additional hostvars to include. This can be used to map
information from nodepool into the inventory if used as follows:
.. code-block:: yaml
write_inventory_additional_hostvars:
public_v4: nodepool.public_ipv4
public_v6: nodepool.public_ipv6
This will map hostvars[hostname]['nodepool']['public_ipv4'] to
hostvars[hostname]['public_v4'].

View File

@ -37,7 +37,6 @@ bionic:
private_ipv4: 10.210.196.115 private_ipv4: 10.210.196.115
provider: rax-ord provider: rax-ord
public_ipv4: 104.130.217.77 public_ipv4: 104.130.217.77
public_ipv6: 2001:4801:7828:101:be76:4eff:fe10:14eb
region: ORD region: ORD
xenial: xenial:
ansible_connection: ssh ansible_connection: ssh
@ -51,7 +50,6 @@ xenial:
label: ubuntu-xenial label: ubuntu-xenial
private_ipv4: 149.202.170.85 private_ipv4: 149.202.170.85
provider: ovh-gra1 provider: ovh-gra1
public_ipv4: 149.202.170.85
public_ipv6: 2001:41d0:302:1000::17:a32b public_ipv6: 2001:41d0:302:1000::17:a32b
region: GRA1 region: GRA1
""") """)
@ -75,7 +73,7 @@ class TestWriteInventory(testtools.TestCase):
'''Test passing all variables''' '''Test passing all variables'''
dest = self.useFixture(fixtures.TempDir()).path dest = self.useFixture(fixtures.TempDir()).path
dest = os.path.join(dest, 'out.yaml') dest = os.path.join(dest, 'out.yaml')
run(dest, INPUT, GROUPS_INPUT, None, None) run(dest, INPUT, GROUPS_INPUT, None, None, None)
self.assertOutput(dest, { self.assertOutput(dest, {
'all': { 'all': {
@ -108,7 +106,7 @@ class TestWriteInventory(testtools.TestCase):
'''Test incuding vars''' '''Test incuding vars'''
dest = self.useFixture(fixtures.TempDir()).path dest = self.useFixture(fixtures.TempDir()).path
dest = os.path.join(dest, 'out.yaml') dest = os.path.join(dest, 'out.yaml')
run(dest, INPUT, GROUPS_INPUT, ['ansible_host'], None) run(dest, INPUT, GROUPS_INPUT, ['ansible_host'], None, None)
self.assertOutput(dest, { self.assertOutput(dest, {
'all': { 'all': {
@ -135,7 +133,7 @@ class TestWriteInventory(testtools.TestCase):
'''Test passing all variables''' '''Test passing all variables'''
dest = self.useFixture(fixtures.TempDir()).path dest = self.useFixture(fixtures.TempDir()).path
dest = os.path.join(dest, 'out.yaml') dest = os.path.join(dest, 'out.yaml')
run(dest, INPUT, GROUPS_INPUT, None, ['ansible_user']) run(dest, INPUT, GROUPS_INPUT, None, ['ansible_user'], None)
self.assertOutput(dest, { self.assertOutput(dest, {
'all': { 'all': {
@ -161,3 +159,41 @@ class TestWriteInventory(testtools.TestCase):
} }
} }
}) })
def test_additional(self):
'''Test passing additional variables'''
dest = self.useFixture(fixtures.TempDir()).path
dest = os.path.join(dest, 'out.yaml')
run(dest, INPUT, GROUPS_INPUT, None, None,
{'public_v4': 'nodepool.public_ipv4',
'public_v6': 'nodepool.public_ipv6',
})
self.assertOutput(dest, {
'all': {
'children': {
'puppet': {
'hosts': {
'bionic': None,
'xenial': None,
},
},
},
'hosts': {
'bionic': {
"ansible_connection": "ssh",
"ansible_user": "zuul",
"ansible_host": "104.130.217.77",
"ansible_port": 22,
"public_v4": "104.130.217.77",
},
'xenial': {
"ansible_connection": "ssh",
"ansible_user": "zuul",
"ansible_host": "149.202.170.85",
"ansible_port": 22,
"public_v6": "2001:41d0:302:1000::17:a32b",
}
}
}
})

View File

@ -28,7 +28,7 @@ VARS = [
] ]
def run(dest, hostvars, groups, include, exclude): def run(dest, hostvars, groups, include, exclude, additional):
children = {} children = {}
for group, hostnames in groups.items(): for group, hostnames in groups.items():
if group == 'all' or group == 'ungrouped': if group == 'all' or group == 'ungrouped':
@ -58,6 +58,15 @@ def run(dest, hostvars, groups, include, exclude):
continue continue
d[v] = hvars[v] d[v] = hvars[v]
out_all[host] = d out_all[host] = d
if additional:
for new_var_name, old_var_name in additional.items():
old_var = hvars
for part in old_var_name.split('.'):
old_var = old_var.get(part)
if old_var is None:
break
else:
d[new_var_name] = old_var
with open(dest, 'w') as f: with open(dest, 'w') as f:
f.write(json.dumps(out)) f.write(json.dumps(out))
@ -71,6 +80,7 @@ def ansible_main():
groups=dict(required=True, type='raw'), groups=dict(required=True, type='raw'),
include_hostvars=dict(type='list'), include_hostvars=dict(type='list'),
exclude_hostvars=dict(type='list'), exclude_hostvars=dict(type='list'),
additional_hostvars=dict(type='raw'),
) )
) )
@ -81,8 +91,9 @@ def ansible_main():
groups = p.get('groups') groups = p.get('groups')
include = p.get('include_hostvars') include = p.get('include_hostvars')
exclude = p.get('exclude_hostvars') exclude = p.get('exclude_hostvars')
additional = p.get('additional_hostvars', {})
run(dest, hostvars, groups, include, exclude) run(dest, hostvars, groups, include, exclude, additional)
module.exit_json(changed=True) module.exit_json(changed=True)

View File

@ -5,3 +5,4 @@
groups: "{{ groups }}" groups: "{{ groups }}"
include_hostvars: "{{ write_inventory_include_hostvars | default(omit) }}" include_hostvars: "{{ write_inventory_include_hostvars | default(omit) }}"
exclude_hostvars: "{{ write_inventory_exclude_hostvars | default(omit) }}" exclude_hostvars: "{{ write_inventory_exclude_hostvars | default(omit) }}"
additional_hostvars: "{{ write_inventory_additional_hostvars | default(omit) }}"