Support import of playbooks in other directories

Previously, importing a playbook in a different directory didn't
work because all of the relative paths were resolved relative to
the top-level playbook.

This patch resolves relative paths on a per-play level instead of
relative to the directory of the top-level playbook.

Also removes the dirname argument from the Play._get_vars method
since this argument wasn't used in the metho dbody.
pull/1030/head
Lorin Hochstein 12 years ago
parent 565f336182
commit b9e100a506

@ -112,7 +112,7 @@ class PlayBook(object):
self.global_vars.update(self.inventory.get_group_variables('all')) self.global_vars.update(self.inventory.get_group_variables('all'))
self.basedir = os.path.dirname(playbook) self.basedir = os.path.dirname(playbook)
self.playbook = self._load_playbook_from_file(playbook) (self.playbook, self.play_basedirs) = self._load_playbook_from_file(playbook)
self.module_path = self.module_path + os.pathsep + os.path.join(self.basedir, "library") self.module_path = self.module_path + os.pathsep + os.path.join(self.basedir, "library")
# ***************************************************** # *****************************************************
@ -124,6 +124,7 @@ class PlayBook(object):
playbook_data = utils.parse_yaml_from_file(path) playbook_data = utils.parse_yaml_from_file(path)
accumulated_plays = [] accumulated_plays = []
play_basedirs = []
if type(playbook_data) != list: if type(playbook_data) != list:
raise errors.AnsibleError("parse error: playbooks must be formatted as a YAML list") raise errors.AnsibleError("parse error: playbooks must be formatted as a YAML list")
@ -134,13 +135,17 @@ class PlayBook(object):
if 'include' in play: if 'include' in play:
if len(play.keys()) == 1: if len(play.keys()) == 1:
included_path = utils.path_dwim(self.basedir, play['include']) included_path = utils.path_dwim(self.basedir, play['include'])
accumulated_plays.extend(self._load_playbook_from_file(included_path)) (plays, basedirs) = self._load_playbook_from_file(included_path)
accumulated_plays.extend(plays)
play_basedirs.extend(basedirs)
else: else:
raise errors.AnsibleError("parse error: top level includes cannot be used with other directives: %s" % play) raise errors.AnsibleError("parse error: top level includes cannot be used with other directives: %s" % play)
else: else:
accumulated_plays.append(play) accumulated_plays.append(play)
play_basedirs.append(os.path.dirname(path))
return accumulated_plays return (accumulated_plays, play_basedirs)
# ***************************************************** # *****************************************************
@ -152,8 +157,8 @@ class PlayBook(object):
# loop through all patterns and run them # loop through all patterns and run them
self.callbacks.on_start() self.callbacks.on_start()
for play_ds in self.playbook: for (play_ds, play_basedir) in zip(self.playbook, self.play_basedirs):
play = Play(self,play_ds) play = Play(self, play_ds, play_basedir)
matched_tags, unmatched_tags = play.compare_tags(self.only_tags) matched_tags, unmatched_tags = play.compare_tags(self.only_tags)
matched_tags_all = matched_tags_all | matched_tags matched_tags_all = matched_tags_all | matched_tags
unmatched_tags_all = unmatched_tags_all | unmatched_tags unmatched_tags_all = unmatched_tags_all | unmatched_tags
@ -166,8 +171,8 @@ class PlayBook(object):
# if the playbook is invoked with --tags that don't exist at all in the playbooks # if the playbook is invoked with --tags that don't exist at all in the playbooks
# then we need to raise an error so that the user can correct the arguments. # then we need to raise an error so that the user can correct the arguments.
unknown_tags = set(self.only_tags) - (matched_tags_all | unmatched_tags_all) unknown_tags = set(self.only_tags) - (matched_tags_all | unmatched_tags_all)
unknown_tags.discard('all') unknown_tags.discard('all')
if len(unknown_tags) > 0: if len(unknown_tags) > 0:
unmatched_tags_all.discard('all') unmatched_tags_all.discard('all')
msg = 'tag(s) not found in playbook: %s. possible values: %s' msg = 'tag(s) not found in playbook: %s. possible values: %s'
@ -215,7 +220,7 @@ class PlayBook(object):
timeout=self.timeout, remote_user=task.play.remote_user, timeout=self.timeout, remote_user=task.play.remote_user,
remote_port=task.play.remote_port, module_vars=task.module_vars, remote_port=task.play.remote_port, module_vars=task.module_vars,
private_key_file=self.private_key_file, private_key_file=self.private_key_file,
setup_cache=self.SETUP_CACHE, basedir=self.basedir, setup_cache=self.SETUP_CACHE, basedir=task.play.basedir,
conditional=task.only_if, callbacks=self.runner_callbacks, conditional=task.only_if, callbacks=self.runner_callbacks,
sudo=task.play.sudo, sudo_user=task.play.sudo_user, sudo=task.play.sudo, sudo_user=task.play.sudo_user,
transport=task.play.transport, sudo_pass=self.sudo_pass, is_playbook=True transport=task.play.transport, sudo_pass=self.sudo_pass, is_playbook=True

@ -29,7 +29,8 @@ class Play(object):
'hosts', 'name', 'vars', 'vars_prompt', 'vars_files', 'hosts', 'name', 'vars', 'vars_prompt', 'vars_files',
'handlers', 'remote_user', 'remote_port', 'handlers', 'remote_user', 'remote_port',
'sudo', 'sudo_user', 'transport', 'playbook', 'sudo', 'sudo_user', 'transport', 'playbook',
'tags', 'gather_facts', 'serial', '_ds', '_handlers', '_tasks' 'tags', 'gather_facts', 'serial', '_ds', '_handlers', '_tasks',
'basedir'
] ]
# to catch typos and so forth -- these are userland names # to catch typos and so forth -- these are userland names
@ -42,7 +43,7 @@ class Play(object):
# ************************************************* # *************************************************
def __init__(self, playbook, ds): def __init__(self, playbook, ds, basedir):
''' constructor loads from a play datastructure ''' ''' constructor loads from a play datastructure '''
for x in ds.keys(): for x in ds.keys():
@ -57,15 +58,15 @@ class Play(object):
elif isinstance(hosts, list): elif isinstance(hosts, list):
hosts = ';'.join(hosts) hosts = ';'.join(hosts)
hosts = utils.template(hosts, playbook.extra_vars) hosts = utils.template(hosts, playbook.extra_vars)
self._ds = ds self._ds = ds
self.playbook = playbook self.playbook = playbook
self.basedir = basedir
self.hosts = hosts self.hosts = hosts
self.name = ds.get('name', self.hosts) self.name = ds.get('name', self.hosts)
self.vars = ds.get('vars', {}) self.vars = ds.get('vars', {})
self.vars_files = ds.get('vars_files', []) self.vars_files = ds.get('vars_files', [])
self.vars_prompt = ds.get('vars_prompt', {}) self.vars_prompt = ds.get('vars_prompt', {})
self.vars = self._get_vars(self.playbook.basedir) self.vars = self._get_vars()
self._tasks = ds.get('tasks', []) self._tasks = ds.get('tasks', [])
self._handlers = ds.get('handlers', []) self._handlers = ds.get('handlers', [])
self.remote_user = utils.template(ds.get('user', self.playbook.remote_user), playbook.extra_vars) self.remote_user = utils.template(ds.get('user', self.playbook.remote_user), playbook.extra_vars)
@ -107,7 +108,7 @@ class Play(object):
(k,v) = t.split("=", 1) (k,v) = t.split("=", 1)
task_vars[k] = utils.template(v, task_vars) task_vars[k] = utils.template(v, task_vars)
include_file = utils.template(tokens[0], task_vars) include_file = utils.template(tokens[0], task_vars)
data = utils.parse_yaml_from_file(utils.path_dwim(self.playbook.basedir, include_file)) data = utils.parse_yaml_from_file(utils.path_dwim(self.basedir, include_file))
elif type(x) == dict: elif type(x) == dict:
data = [x] data = [x]
else: else:
@ -135,7 +136,7 @@ class Play(object):
# ************************************************* # *************************************************
def _get_vars(self, dirname): def _get_vars(self):
''' load the vars section from a play, accounting for all sorts of variable features ''' load the vars section from a play, accounting for all sorts of variable features
including loading from yaml files, prompting, and conditional includes of the first including loading from yaml files, prompting, and conditional includes of the first
file found in a list. ''' file found in a list. '''
@ -264,7 +265,7 @@ class Play(object):
filename3 = filename2 filename3 = filename2
if host is not None: if host is not None:
filename3 = utils.template(filename2, self.playbook.SETUP_CACHE[host]) filename3 = utils.template(filename2, self.playbook.SETUP_CACHE[host])
filename4 = utils.path_dwim(self.playbook.basedir, filename3) filename4 = utils.path_dwim(self.basedir, filename3)
sequence.append(filename4) sequence.append(filename4)
if os.path.exists(filename4): if os.path.exists(filename4):
found = True found = True
@ -297,7 +298,7 @@ class Play(object):
filename3 = filename2 filename3 = filename2
if host is not None: if host is not None:
filename3 = utils.template(filename2, self.playbook.SETUP_CACHE[host]) filename3 = utils.template(filename2, self.playbook.SETUP_CACHE[host])
filename4 = utils.path_dwim(self.playbook.basedir, filename3) filename4 = utils.path_dwim(self.basedir, filename3)
if self._has_vars_in(filename4): if self._has_vars_in(filename4):
return return
new_vars = utils.parse_yaml_from_file(filename4) new_vars = utils.parse_yaml_from_file(filename4)

Loading…
Cancel
Save