From d9c6b60b243c1ce101a2dc65c38f335967b36753 Mon Sep 17 00:00:00 2001 From: Daniel Hokka Zakrisson Date: Wed, 27 Feb 2013 21:24:45 +0100 Subject: [PATCH] Allow inventory to be a directory containing other inventories --- CHANGELOG.md | 1 + lib/ansible/inventory/__init__.py | 6 ++- lib/ansible/inventory/dir.py | 73 +++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 lib/ansible/inventory/dir.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bede1e637f..3ab6e21f76c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Core Features * a new chroot connection type * module common code now has basic type checking (and casting) capability * module common now supports a 'no_log' attribute to mark a field as not to be syslogged +* inventory can now point to a directory containing multiple scripts/hosts files Modules Added: diff --git a/lib/ansible/inventory/__init__.py b/lib/ansible/inventory/__init__.py index 0d5dc853ccf..422134a7c5b 100644 --- a/lib/ansible/inventory/__init__.py +++ b/lib/ansible/inventory/__init__.py @@ -25,6 +25,7 @@ import subprocess import ansible.constants as C from ansible.inventory.ini import InventoryParser from ansible.inventory.script import InventoryScript +from ansible.inventory.dir import InventoryDirectory from ansible.inventory.group import Group from ansible.inventory.host import Host from ansible import errors @@ -78,7 +79,10 @@ class Inventory(object): else: all.add_host(Host(x)) elif os.path.exists(host_list): - if utils.is_executable(host_list): + if os.path.isdir(host_list): + self.parser = InventoryDirectory(filename=host_list) + self.groups = self.parser.groups.values() + elif utils.is_executable(host_list): self.parser = InventoryScript(filename=host_list) self.groups = self.parser.groups.values() else: diff --git a/lib/ansible/inventory/dir.py b/lib/ansible/inventory/dir.py new file mode 100644 index 00000000000..389fd418051 --- /dev/null +++ b/lib/ansible/inventory/dir.py @@ -0,0 +1,73 @@ +# (c) 2013, Daniel Hokka Zakrisson +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +############################################# + +import os +import ansible.constants as C +from ansible.inventory.host import Host +from ansible.inventory.group import Group +from ansible.inventory.ini import InventoryParser +from ansible.inventory.script import InventoryScript +from ansible import utils +from ansible import errors + +class InventoryDirectory(object): + ''' Host inventory parser for ansible using a directory of inventories. ''' + + def __init__(self, filename=C.DEFAULT_HOST_LIST): + self.names = os.listdir(filename) + self.names.sort() + self.directory = filename + self.parsers = [] + self.hosts = {} + self.groups = {} + for i in self.names: + if i.endswith("~") or i.endswith(".orig") or i.endswith(".bak"): + continue + fullpath = os.path.join(self.directory, i) + if os.path.isdir(fullpath): + parser = InventoryDirectory(filename=fullpath) + elif utils.is_executable(fullpath): + parser = InventoryScript(filename=fullpath) + else: + parser = InventoryParser(filename=fullpath) + self.parsers.append(parser) + # This takes a lot of code because we can't directly use any of the objects, as they have to blend + for name, group in parser.groups.iteritems(): + if name not in self.groups: + self.groups[name] = Group(name) + for k, v in group.get_variables().iteritems(): + self.groups[name].set_variable(k, v) + for host in group.get_hosts(): + if host.name not in self.hosts: + self.hosts[host.name] = Host(host.name) + for k, v in host.get_variables().iteritems(): + self.hosts[host.name].set_variable(k, v) + self.groups[name].add_host(self.hosts[host.name]) + # This needs to be a second loop to ensure all the parent groups exist + for name, group in parser.groups.iteritems(): + for ancestor in group.get_ancestors(): + self.groups[ancestor.name].add_child_group(self.groups[name]) + + def get_host_variables(self, host): + """ Gets additional host variables from all inventories """ + vars = {} + for i in self.parsers: + vars.update(i.get_host_variables(host)) + return vars +