From 8d309e0fa305a1c35faa1f0feb173a61761157ee Mon Sep 17 00:00:00 2001 From: Daniel Hokka Zakrisson Date: Tue, 27 Nov 2012 00:13:56 +0100 Subject: [PATCH] Allow inventory scripts to define groups of groups and group vars --- docsite/rst/api.rst | 29 ++++++++++++++++++++++++----- lib/ansible/inventory/__init__.py | 8 +------- lib/ansible/inventory/script.py | 26 ++++++++++++++++++-------- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/docsite/rst/api.rst b/docsite/rst/api.rst index a901c86b72..e644986696 100644 --- a/docsite/rst/api.rst +++ b/docsite/rst/api.rst @@ -100,16 +100,35 @@ It's possible to write an external inventory script in any language. If you are Script Conventions `````````````````` -When the external node script is called with the single argument '--list', the script must return a JSON hash/dictionary of all the groups to be managed, with a list of each host/IP as the value for each hash/dictionary element, like so:: +When the external node script is called with the single argument '--list', the script must return a JSON hash/dictionary of all the groups to be managed. +Each group's value should be either a hash/dictionary containing a list of each host/IP, potential child groups, and potential group variables, or +simply a list of host/IP addresses, like so:: { - 'databases' : [ 'host1.example.com', 'host2.example.com' ], - 'webservers' : [ 'host2.example.com', 'host3.example.com' ], - 'atlanta' : [ 'host1.example.com', 'host4.example.com', 'host5.example.com' ] + 'databases' : { + 'hosts' : [ 'host1.example.com', 'host2.example.com' ], + 'vars' : { + 'a' : true + } + }, + 'webservers' : [ 'host2.example.com', 'host3.example.com' ], + 'atlanta' : { + 'hosts' : [ 'host1.example.com', 'host4.example.com', 'host5.example.com' ], + 'vars' : { + 'b' : false + }, + 'children': [ 'marietta', '5points' ], + }, + 'marietta' : [ 'host6.example.com' ], + '5points' : [ 'host7.example.com' ] } +.. versionadded: 1.0 + +Before version 1.0, each group could only have a list of hostnames/IP addresses, like the webservers, marietta, and 5points groups above. + When called with the arguments '--host ' (where is a host from above), the script must return either an empty JSON -hash/dictionary, or a list of key/value variables to make available to templates or playbooks. Returning variables is optional, +hash/dictionary, or a hash/dictionary of variables to make available to templates and playbooks. Returning variables is optional, if the script does not wish to do this, returning an empty hash/dictionary is the way to go:: { diff --git a/lib/ansible/inventory/__init__.py b/lib/ansible/inventory/__init__.py index 12bf0ffac3..6e1a356e9f 100644 --- a/lib/ansible/inventory/__init__.py +++ b/lib/ansible/inventory/__init__.py @@ -278,6 +278,7 @@ class Inventory(object): if updated is not None: vars.update(updated) + vars.update(host.get_variables()) if self._is_script: cmd = [self.host_list,"--host",hostname] try: @@ -287,14 +288,7 @@ class Inventory(object): (out, err) = sp.communicate() results = utils.parse_json(out) - # FIXME: this is a bit redundant with host.py and should share code - results['inventory_hostname'] = hostname - results['inventory_hostname_short'] = hostname.split('.')[0] - groups = [ g.name for g in host.get_groups() if g.name != 'all' ] - results['group_names'] = sorted(groups) vars.update(results) - else: - vars.update(host.get_variables()) return vars def add_group(self, group): diff --git a/lib/ansible/inventory/script.py b/lib/ansible/inventory/script.py index 77666580ce..b665d4322d 100644 --- a/lib/ansible/inventory/script.py +++ b/lib/ansible/inventory/script.py @@ -45,15 +45,25 @@ class InventoryScript(object): all=Group('all') groups = dict(all=all) group = None - for (group_name, hosts) in self.raw.items(): + for (group_name, data) in self.raw.items(): group = groups[group_name] = Group(group_name) host = None - for hostname in hosts: - if not hostname in all_hosts: - all_hosts[hostname] = Host(hostname) - host = all_hosts[hostname] - group.add_host(host) - # FIXME: hack shouldn't be needed - all.add_host(host) + if not isinstance(data, dict): + data = {'hosts': data} + if 'hosts' in data: + for hostname in data['hosts']: + if not hostname in all_hosts: + all_hosts[hostname] = Host(hostname) + host = all_hosts[hostname] + group.add_host(host) + if 'vars' in data: + for k, v in data['vars'].iteritems(): + group.set_variable(k, v) all.add_child_group(group) + # Separate loop to ensure all groups are defined + for (group_name, data) in self.raw.items(): + if isinstance(data, dict) and 'children' in data: + for child_name in data['children']: + if child_name in groups: + groups[group_name].add_child_group(groups[child_name]) return groups