From 184152f07e45e71648f61a78ec3bd82f75440d6d Mon Sep 17 00:00:00 2001 From: Ian Wienand Date: Wed, 8 Jul 2020 15:02:56 +1000 Subject: [PATCH] write-inventory: add per-host variables This allows us to write out host-specific variables into the inventory from external jobs. Change-Id: I0c3d08f6446174cb38d5eebaeae1db9dceb956b2 --- roles/write-inventory/README.rst | 18 ++++++ .../library/test_write_inventory.py | 62 +++++++++++++++++-- .../library/write_inventory.py | 9 ++- roles/write-inventory/tasks/main.yaml | 1 + 4 files changed, 84 insertions(+), 6 deletions(-) diff --git a/roles/write-inventory/README.rst b/roles/write-inventory/README.rst index 9e1ba37a9..8e4f5dadd 100644 --- a/roles/write-inventory/README.rst +++ b/roles/write-inventory/README.rst @@ -39,3 +39,21 @@ with the inventory for the job. This will map hostvars[hostname]['nodepool']['public_ipv4'] to hostvars[hostname]['public_v4']. + +.. zuul:rolevar:: write_inventory_per_host_hostvars + :type: dict + + An additional dictionary added on a per-host basis. The keys of + this dictionary should be hostnames, if the host name matches, the + value (also a dictionary) is merged into the hostvars for that + host. For example below, ``hosta.com`` will have ``foo`` with + value ``bar``, while ``hostb.com`` will have ``foo`` with value + ``baz``. + + .. code-block:: yaml + + write_inventory_per_host_hostvars: + hosta.com: + foo: bar + hostb.com: + foo: baz diff --git a/roles/write-inventory/library/test_write_inventory.py b/roles/write-inventory/library/test_write_inventory.py index aeeced997..89ca3ab55 100644 --- a/roles/write-inventory/library/test_write_inventory.py +++ b/roles/write-inventory/library/test_write_inventory.py @@ -73,7 +73,7 @@ class TestWriteInventory(testtools.TestCase): '''Test passing all variables''' dest = self.useFixture(fixtures.TempDir()).path dest = os.path.join(dest, 'out.yaml') - run(dest, INPUT, GROUPS_INPUT, None, None, None) + run(dest, INPUT, GROUPS_INPUT, None, None, None, None) self.assertOutput(dest, { 'all': { @@ -106,7 +106,7 @@ class TestWriteInventory(testtools.TestCase): '''Test incuding vars''' dest = self.useFixture(fixtures.TempDir()).path dest = os.path.join(dest, 'out.yaml') - run(dest, INPUT, GROUPS_INPUT, ['ansible_host'], None, None) + run(dest, INPUT, GROUPS_INPUT, ['ansible_host'], None, None, None) self.assertOutput(dest, { 'all': { @@ -133,7 +133,7 @@ class TestWriteInventory(testtools.TestCase): '''Test passing all variables''' dest = self.useFixture(fixtures.TempDir()).path dest = os.path.join(dest, 'out.yaml') - run(dest, INPUT, GROUPS_INPUT, None, ['ansible_user'], None) + run(dest, INPUT, GROUPS_INPUT, None, ['ansible_user'], None, None) self.assertOutput(dest, { 'all': { @@ -167,7 +167,8 @@ class TestWriteInventory(testtools.TestCase): run(dest, INPUT, GROUPS_INPUT, None, None, {'public_v4': 'nodepool.public_ipv4', 'public_v6': 'nodepool.public_ipv6', - }) + }, + None) self.assertOutput(dest, { 'all': { @@ -197,3 +198,56 @@ class TestWriteInventory(testtools.TestCase): } } }) + + def test_per_host(self): + '''Test passing additional variables per host''' + 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', + }, + { + 'bionic': { + 'a': 'extra', + 'b': 'variable', + }, + 'xenial': { + 'c': 'extra', + 'd': 'variable', + }, + }) + + 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", + "a": "extra", + "b": "variable" + }, + 'xenial': { + "ansible_connection": "ssh", + "ansible_user": "zuul", + "ansible_host": "149.202.170.85", + "ansible_port": 22, + "public_v6": "2001:41d0:302:1000::17:a32b", + "c": "extra", + "d": "variable" + } + } + } + }) diff --git a/roles/write-inventory/library/write_inventory.py b/roles/write-inventory/library/write_inventory.py index 697abf30f..abe707639 100755 --- a/roles/write-inventory/library/write_inventory.py +++ b/roles/write-inventory/library/write_inventory.py @@ -28,7 +28,7 @@ VARS = [ ] -def run(dest, hostvars, groups, include, exclude, additional): +def run(dest, hostvars, groups, include, exclude, additional, per_host): children = {} for group, hostnames in groups.items(): if group == 'all' or group == 'ungrouped': @@ -67,6 +67,9 @@ def run(dest, hostvars, groups, include, exclude, additional): break else: d[new_var_name] = old_var + if per_host: + if host in per_host: + d.update(per_host[host]) with open(dest, 'w') as f: f.write(json.dumps(out)) @@ -81,6 +84,7 @@ def ansible_main(): include_hostvars=dict(type='list'), exclude_hostvars=dict(type='list'), additional_hostvars=dict(type='raw'), + per_host_hostvars=dict(type='raw'), ) ) @@ -92,8 +96,9 @@ def ansible_main(): include = p.get('include_hostvars') exclude = p.get('exclude_hostvars') additional = p.get('additional_hostvars', {}) + per_host = p.get('per_host_hostvars', {}) - run(dest, hostvars, groups, include, exclude, additional) + run(dest, hostvars, groups, include, exclude, additional, per_host) module.exit_json(changed=True) diff --git a/roles/write-inventory/tasks/main.yaml b/roles/write-inventory/tasks/main.yaml index 26a82facb..3a105b329 100644 --- a/roles/write-inventory/tasks/main.yaml +++ b/roles/write-inventory/tasks/main.yaml @@ -6,3 +6,4 @@ include_hostvars: "{{ write_inventory_include_hostvars | default(omit) }}" exclude_hostvars: "{{ write_inventory_exclude_hostvars | default(omit) }}" additional_hostvars: "{{ write_inventory_additional_hostvars | default(omit) }}" + per_host_hostvars: "{{ write_inventory_per_host_hostvars | default(omit) }}"