From b9e100a5062d5899dbcfc87713aca9f54107dbe3 Mon Sep 17 00:00:00 2001 From: Lorin Hochstein Date: Sun, 9 Sep 2012 22:43:27 -0400 Subject: [PATCH] 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. --- lib/ansible/playbook/__init__.py | 21 +++++++++++++-------- lib/ansible/playbook/play.py | 17 +++++++++-------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/lib/ansible/playbook/__init__.py b/lib/ansible/playbook/__init__.py index 6838c01a602..d461c35ab50 100644 --- a/lib/ansible/playbook/__init__.py +++ b/lib/ansible/playbook/__init__.py @@ -112,7 +112,7 @@ class PlayBook(object): self.global_vars.update(self.inventory.get_group_variables('all')) 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") # ***************************************************** @@ -124,6 +124,7 @@ class PlayBook(object): playbook_data = utils.parse_yaml_from_file(path) accumulated_plays = [] + play_basedirs = [] if type(playbook_data) != 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 len(play.keys()) == 1: 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: raise errors.AnsibleError("parse error: top level includes cannot be used with other directives: %s" % play) else: 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 self.callbacks.on_start() - for play_ds in self.playbook: - play = Play(self,play_ds) + for (play_ds, play_basedir) in zip(self.playbook, self.play_basedirs): + play = Play(self, play_ds, play_basedir) matched_tags, unmatched_tags = play.compare_tags(self.only_tags) matched_tags_all = matched_tags_all | matched_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 # 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.discard('all') - + unknown_tags.discard('all') + if len(unknown_tags) > 0: unmatched_tags_all.discard('all') 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, remote_port=task.play.remote_port, module_vars=task.module_vars, 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, sudo=task.play.sudo, sudo_user=task.play.sudo_user, transport=task.play.transport, sudo_pass=self.sudo_pass, is_playbook=True diff --git a/lib/ansible/playbook/play.py b/lib/ansible/playbook/play.py index cd927cf5595..1b507df0ecf 100644 --- a/lib/ansible/playbook/play.py +++ b/lib/ansible/playbook/play.py @@ -29,7 +29,8 @@ class Play(object): 'hosts', 'name', 'vars', 'vars_prompt', 'vars_files', 'handlers', 'remote_user', 'remote_port', '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 @@ -42,7 +43,7 @@ class Play(object): # ************************************************* - def __init__(self, playbook, ds): + def __init__(self, playbook, ds, basedir): ''' constructor loads from a play datastructure ''' for x in ds.keys(): @@ -57,15 +58,15 @@ class Play(object): elif isinstance(hosts, list): hosts = ';'.join(hosts) hosts = utils.template(hosts, playbook.extra_vars) - self._ds = ds self.playbook = playbook + self.basedir = basedir self.hosts = hosts self.name = ds.get('name', self.hosts) self.vars = ds.get('vars', {}) self.vars_files = ds.get('vars_files', []) 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._handlers = ds.get('handlers', []) 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) task_vars[k] = utils.template(v, 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: data = [x] 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 including loading from yaml files, prompting, and conditional includes of the first file found in a list. ''' @@ -264,7 +265,7 @@ class Play(object): filename3 = filename2 if host is not None: 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) if os.path.exists(filename4): found = True @@ -297,7 +298,7 @@ class Play(object): filename3 = filename2 if host is not None: 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): return new_vars = utils.parse_yaml_from_file(filename4)