Allow the group_vars and host_vars directories to be stored alongside the playbook as well as inventory.

This commit is contained in:
Michael DeHaan 2013-06-01 10:38:16 -04:00
parent 9736ec03a9
commit 6cd3ba5b06
3 changed files with 86 additions and 22 deletions

View file

@ -113,6 +113,9 @@ def main(args):
# run all playbooks specified on the command line
for playbook in args:
# let inventory know which playbooks are using so it can know the basedirs
inventory.set_playbook_basedir(os.path.dirname(playbook))
stats = callbacks.AggregateStats()
playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)
if options.step:

View file

@ -38,7 +38,7 @@ class Inventory(object):
__slots__ = [ 'host_list', 'groups', '_restriction', '_also_restriction', '_subset',
'parser', '_vars_per_host', '_vars_per_group', '_hosts_cache', '_groups_list',
'_vars_plugins']
'_vars_plugins', '_playbook_basedir']
def __init__(self, host_list=C.DEFAULT_HOST_LIST):
@ -54,6 +54,9 @@ class Inventory(object):
self._hosts_cache = {}
self._groups_list = {}
# to be set by calling set_playbook_basedir by ansible-playbook
self._playbook_basedir = None
# the inventory object holds a list of groups
self.groups = []
@ -372,3 +375,16 @@ class Inventory(object):
if not self.is_file():
return None
return os.path.dirname(self.host_list)
def playbook_basedir(self):
""" returns the directory of the current playbook """
return self._playbook_basedir
def set_playbook_basedir(self, dir):
"""
sets the base directory of the playbook so inventory plugins can use it to find
variable files and other things.
"""
self._playbook_basedir = dir

View file

@ -1,4 +1,4 @@
# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
# (c) 2012-2013, Michael DeHaan <michael.dehaan@gmail.com>
#
# This file is part of Ansible
#
@ -23,45 +23,90 @@ import ansible.constants as C
class VarsModule(object):
"""
Loads variables from group_vars/<groupname> and host_vars/<hostname> in directories parallel
to the inventory base directory or in the same directory as the playbook. Variables in the playbook
dir will win over the inventory dir if files are in both.
"""
def __init__(self, inventory):
""" constructor """
self.inventory = inventory
def run(self, host):
# return the inventory variables for the host
""" main body of the plugin, does actual loading """
inventory = self.inventory
#hostrec = inventory.get_host(host)
self.pb_basedir = inventory.playbook_basedir()
# sort groups by depth so deepest groups can override the less deep ones
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
inventory_basedir = inventory.basedir()
results = {}
scan_pass = 0
# load vars in inventory_dir/group_vars/name_of_group
# look in both the inventory base directory and the playbook base directory
for basedir in [ inventory_basedir, self.pb_basedir ]:
# this can happen from particular API usages, particularly if not run
# from /usr/bin/ansible-playbook
if basedir is None:
continue
scan_pass = scan_pass + 1
# it's not an eror if the directory does not exist, keep moving
if not os.path.exists(basedir):
continue
# save work of second scan if the directories are the same
if inventory_basedir == self.pb_basedir and scan_pass != 1:
continue
# load vars in dir/group_vars/name_of_group
for x in groups:
p = os.path.join(basedir, "group_vars/%s" % x)
# the file can be <groupname> or end in .yml or .yaml
# currently ALL will be loaded, even if more than one
paths = [p, '.'.join([p, 'yml']), '.'.join([p, 'yaml'])]
for path in paths:
if os.path.exists(path) and not os.path.isdir(path):
data = utils.parse_yaml_from_file(path)
if type(data) != dict:
raise errors.AnsibleError("%s must be stored as a dictionary/hash" % path)
# combine vars overrides by default but can be configured to do a hash
# merge in settings
results = utils.combine_vars(results, data)
# group vars have been loaded
# load vars in inventory_dir/hosts_vars/name_of_host
# these have greater precedence than group variables
p = os.path.join(basedir, "host_vars/%s" % host.name)
# again allow the file to be named filename or end in .yml or .yaml
paths = [p, '.'.join([p, 'yml']), '.'.join([p, 'yaml'])]
for path in paths:
if os.path.exists(path) and not os.path.isdir(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 = utils.combine_vars(results, data)
# all done, results is a dictionary of variables for this particular host.
return results