diff --git a/examples/ansible.cfg b/examples/ansible.cfg index d99ff81825..e1bb2b316f 100644 --- a/examples/ansible.cfg +++ b/examples/ansible.cfg @@ -74,6 +74,14 @@ remote_port=22 # Example: ansible_managed = DONT TOUCH {file}: call {uid} at {host} for changes ansible_managed = Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid} on {host} +# additional plugin paths for non-core plugins + +action_plugins = /usr/share/ansible_plugins/action_plugins +callback_plugins = /usr/share/ansible_plugins/callback_plugins +connection_plugins = /usr/share/ansible_plugins/connection_plugins +lookup_plugins = /usr/share/ansible_plugins/lookup_plugins +inventory_plugins = /usr/share/ansible_plugins/inventory_plugins + [paramiko_connection] # nothing to configure yet diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py index c9ccd12e9e..e9a2056b34 100644 --- a/lib/ansible/constants.py +++ b/lib/ansible/constants.py @@ -87,6 +87,7 @@ DEFAULT_ACTION_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'acti DEFAULT_CALLBACK_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'callback_plugins', None, '/usr/share/ansible_plugins/callback_plugins')) DEFAULT_CONNECTION_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'connection_plugins', None, '/usr/share/ansible_plugins/connection_plugins')) DEFAULT_LOOKUP_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'lookup_plugins', None, '/usr/share/ansible_plugins/lookup_plugins')) +DEFAULT_VARS_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'vars_plugins', None, '/usr/share/ansible_plugins/vars_plugins')) # non-configurable things DEFAULT_REMOTE_PASS = None diff --git a/lib/ansible/inventory/__init__.py b/lib/ansible/inventory/__init__.py index 46a0dd3562..aab74eb43b 100644 --- a/lib/ansible/inventory/__init__.py +++ b/lib/ansible/inventory/__init__.py @@ -29,13 +29,20 @@ from ansible.inventory.host import Host from ansible import errors from ansible import utils +# FIXME, adapt. +dirname = os.path.dirname(__file__) +vars_plugin_list = utils.import_plugins(os.path.join(dirname, 'vars_plugins')) +for i in reversed(C.DEFAULT_VARS_PLUGIN_PATH.split(os.pathsep)): + vars_plugin_list.update(utils.import_plugins(i)) + class Inventory(object): """ Host inventory for ansible. """ __slots__ = [ 'host_list', 'groups', '_restriction', '_also_restriction', '_subset', '_is_script', - 'parser', '_vars_per_host', '_vars_per_group', '_hosts_cache', '_groups_list' ] + 'parser', '_vars_per_host', '_vars_per_group', '_hosts_cache', '_groups_list', + '_vars_plugins' ] def __init__(self, host_list=C.DEFAULT_HOST_LIST): @@ -88,6 +95,8 @@ class Inventory(object): else: raise errors.AnsibleError("YAML inventory support is deprecated in 0.6 and removed in 0.7, see the migration script in examples/scripts in the git checkout") + self._vars_plugins = [ i.VarsModule(self) for i in vars_plugin_list.values() ] + def _match(self, str, pattern_str): return fnmatch.fnmatch(str, pattern_str) @@ -270,6 +279,11 @@ class Inventory(object): if host is None: raise errors.AnsibleError("host not found: %s" % hostname) + vars = {} + for ip in self._vars_plugins: + updated = ip.run(host) + vars.update(updated) + if self._is_script: cmd = subprocess.Popen( [self.host_list,"--host",hostname], @@ -284,10 +298,10 @@ class Inventory(object): 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) - - return results + vars.update(results) else: - return host.get_variables() + vars.update(host.get_variables()) + return vars def add_group(self, group): self.groups.append(group) diff --git a/lib/ansible/inventory/host.py b/lib/ansible/inventory/host.py index b73d1c6588..b731dfcd82 100644 --- a/lib/ansible/inventory/host.py +++ b/lib/ansible/inventory/host.py @@ -62,3 +62,5 @@ class Host(object): groups = self.get_groups() results['group_names'] = sorted([ g.name for g in groups if g.name != 'all']) return results + + diff --git a/lib/ansible/inventory/vars_plugins/__init__.py b/lib/ansible/inventory/vars_plugins/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/ansible/inventory/vars_plugins/group_vars.py b/lib/ansible/inventory/vars_plugins/group_vars.py new file mode 100644 index 0000000000..57e8d82fe0 --- /dev/null +++ b/lib/ansible/inventory/vars_plugins/group_vars.py @@ -0,0 +1,61 @@ +# (c) 2012, Michael DeHaan +# +# 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 glob +from ansible import utils + +class VarsModule(object): + + def __init__(self, inventory): + self.inventory = inventory + + def run(self, host): + # return the inventory variables for the host + + inventory = self.inventory + #hostrec = inventory.get_host(host) + + groupz = sorted(inventory.groups_for_host(host.name), key=lambda g: g.depth) + groups = [ g.name for g in groupz ] + basedir = inventory.basedir() + + if basedir is None: + # could happen when inventory is passed in via the API + return + + results = {} + + # load vars in playbook_dir/group_vars/name_of_group + for x in groups: + path = os.path.join(basedir, "group_vars/%s" % x) + if os.path.exists(path): + data = utils.parse_yaml_from_file(path) + if type(data) != dict: + raise errors.AnsibleError("%s must be stored as a dictionary/hash" % path) + results.update(data) + + # load vars in playbook_dir/group_vars/name_of_host + path = os.path.join(basedir, "host_vars/%s" % host.name) + if os.path.exists(path): + data = utils.parse_yaml_from_file(path) + if type(data) != dict: + raise errors.AnsibleError("%s must be stored as a dictionary/hash" % path) + results.update(data) + + return results + diff --git a/lib/ansible/playbook/play.py b/lib/ansible/playbook/play.py index 06a4a8ed30..1edb90f63c 100644 --- a/lib/ansible/playbook/play.py +++ b/lib/ansible/playbook/play.py @@ -242,29 +242,6 @@ class Play(object): if type(self.vars_files) != list: self.vars_files = [ self.vars_files ] - if (host is not None): - self.playbook.SETUP_CACHE[host].update(self.vars) - - inventory = self.playbook.inventory - hostrec = inventory.get_host(host) - groupz = sorted(inventory.groups_for_host(host), key=lambda g: g.depth) - groups = [ g.name for g in groupz ] - basedir = inventory.basedir() - if basedir is not None: - for x in groups: - path = os.path.join(basedir, "group_vars/%s" % x) - if os.path.exists(path): - data = utils.parse_yaml_from_file(path) - if type(data) != dict: - raise errors.AnsibleError("%s must be stored as a dictionary/hash" % path) - self.playbook.SETUP_CACHE[host].update(data) - path = os.path.join(basedir, "host_vars/%s" % hostrec.name) - if os.path.exists(path): - data = utils.parse_yaml_from_file(path) - if type(data) != dict: - raise errors.AnsibleError("%s must be stored as a dictionary/hash" % path) - self.playbook.SETUP_CACHE[host].update(data) - for filename in self.vars_files: if type(filename) == list: diff --git a/setup.py b/setup.py index 4f905e4973..6c18064f95 100644 --- a/setup.py +++ b/setup.py @@ -26,6 +26,7 @@ setup(name='ansible', packages=[ 'ansible', 'ansible.inventory', + 'ansible.inventory.var_plugins', 'ansible.playbook', 'ansible.runner', 'ansible.runner.action_plugins', diff --git a/test/TestPlayBook.py b/test/TestPlayBook.py index 55d552da95..efce43a983 100644 --- a/test/TestPlayBook.py +++ b/test/TestPlayBook.py @@ -180,8 +180,6 @@ class TestPlaybook(unittest.TestCase): runner_callbacks=test_callbacks ) playbook.run() - assert playbook.SETUP_CACHE['host1'] == {'attr2': 2, 'attr1': 1} - assert playbook.SETUP_CACHE['host2'] == {'attr2': 2} def test_yaml_hosts_list(self): # Make sure playbooks support hosts: [host1, host2]