diff --git a/v2/ansible/executor/play_iterator.py b/v2/ansible/executor/play_iterator.py index 4f3d0e23200..11dcc329fe1 100644 --- a/v2/ansible/executor/play_iterator.py +++ b/v2/ansible/executor/play_iterator.py @@ -168,10 +168,18 @@ class PlayState: return None if task._role: - if cur_role and task._role != cur_role: + # if we had a current role, mark that role as completed + if cur_role and task._role != cur_role and not peek: cur_role._completed = True + cur_role = task._role + # if the current role has not had its task run flag set, mark + # clear the completed flag so we can correctly determine if the + # role was run + if not cur_role._had_task_run and not peek: + cur_role._completed = False + # If we're not just peeking at the next task, save the internal state if not peek: self._run_state = run_state diff --git a/v2/ansible/playbook/block.py b/v2/ansible/playbook/block.py index 6e60a0b1116..9e1e6924e62 100644 --- a/v2/ansible/playbook/block.py +++ b/v2/ansible/playbook/block.py @@ -148,23 +148,17 @@ class Block(Base, Conditional, Taggable): if self._parent_block is not None: if not self._parent_block.evaluate_conditional(all_vars): return False - if self._role is not None: + elif self._role is not None: if not self._role.evaluate_conditional(all_vars): return False return super(Block, self).evaluate_conditional(all_vars) - def get_tags(self): - tags = set(self.tags[:]) - if self._parent_block: - tags.update(self._parent_block.get_tags()) - if self._role: - tags.update(self._role.get_tags()) - return tags + def evaluate_tags(self, only_tags, skip_tags): + if self._parent_block is not None: + if not self._parent_block.evaluate_tags(only_tags=only_tags, skip_tags=skip_tags): + return False + elif self._role is not None: + if not self._role.evaluate_tags(only_tags=only_tags, skip_tags=skip_tags): + return False + return super(Block, self).evaluate_tags(only_tags=only_tags, skip_tags=skip_tags) - #def get_conditionals(self): - # conditionals = set(self.when[:]) - # if self._parent_block: - # conditionals.update(self._parent_block.get_conditionals()) - # if self._role: - # conditionals.update(self._role.get_conditionals()) - # return conditionals diff --git a/v2/ansible/playbook/role/__init__.py b/v2/ansible/playbook/role/__init__.py index 4e8d52217dd..a175e91333e 100644 --- a/v2/ansible/playbook/role/__init__.py +++ b/v2/ansible/playbook/role/__init__.py @@ -235,18 +235,6 @@ class Role(Base, Conditional, Taggable): return all_vars - def get_tags(self): - tags = set(self.tags[:]) - for parent in self._parents: - tags.update(parent.get_tags()) - return tags - - #def get_conditionals(self): - # conditionals = set(self.when[:]) - # for parent in self._parents: - # conditionals.update(parent.get_conditionals()) - # return conditionals - def get_direct_dependencies(self): return self._dependencies[:] @@ -279,18 +267,32 @@ class Role(Base, Conditional, Taggable): return self._had_task_run and self._completed - def compile(self): + def compile(self, dep_chain=[]): ''' Returns the task list for this role, which is created by first recursively compiling the tasks for all direct dependencies, and then adding on the tasks for this role. + + The role compile() also remembers and saves the dependency chain + with each task, so tasks know by which route they were found, and + can correctly take their parent's tags/conditionals into account. ''' task_list = [] + # update the dependency chain here + new_dep_chain = dep_chain + [self] + deps = self.get_direct_dependencies() for dep in deps: - task_list.extend(dep.compile()) + dep_tasks = dep.compile(dep_chain=new_dep_chain) + for dep_task in dep_tasks: + # since we're modifying the task, and need it to be unique, + # we make a copy of it here and assign the dependency chain + # to the copy, then append the copy to the task list. + new_dep_task = dep_task.copy() + new_dep_task._dep_chain = new_dep_chain + task_list.append(new_dep_task) task_list.extend(compile_block_list(self._task_blocks)) @@ -356,15 +358,3 @@ class Role(Base, Conditional, Taggable): super(Role, self).deserialize(data) - def evaluate_conditional(self, all_vars): - parent_conditionals = True - if len(self._parents) > 0: - parent_conditionals = False - for parent in self._parents: - parent_conditionals |= parent.evaluate_conditional(all_vars) - - if not parent_conditionals: - return False - else: - return super(Role, self).evaluate_conditional(all_vars) - diff --git a/v2/ansible/playbook/taggable.py b/v2/ansible/playbook/taggable.py index 12261f3adc0..1b2e25e3143 100644 --- a/v2/ansible/playbook/taggable.py +++ b/v2/ansible/playbook/taggable.py @@ -31,13 +31,11 @@ class Taggable: return self._tags[:] def evaluate_tags(self, only_tags, skip_tags): - my_tags = self.get_tags() - + my_tags = set(self.tags) if skip_tags: skipped_tags = my_tags.intersection(skip_tags) if len(skipped_tags) > 0: return False - matched_tags = my_tags.intersection(only_tags) if len(matched_tags) > 0 or 'all' in only_tags: return True diff --git a/v2/ansible/playbook/task.py b/v2/ansible/playbook/task.py index 71b4ebc0ce2..fa9b8cb1fac 100644 --- a/v2/ansible/playbook/task.py +++ b/v2/ansible/playbook/task.py @@ -99,6 +99,7 @@ class Task(Base, Conditional, Taggable): self._block = block self._role = role self._task_include = task_include + self._dep_chain = [] super(Task, self).__init__() @@ -185,25 +186,22 @@ class Task(Base, Conditional, Taggable): return new_ds + def post_validate(self, all_vars=dict(), ignore_undefined=False): + ''' + Override of base class post_validate, to also do final validation on + the block to which this task belongs. + ''' + + if self._block: + self._block.post_validate(all_vars=all_vars, ignore_undefined=ignore_undefined) + #if self._role: + # self._role.post_validate(all_vars=all_vars, ignore_undefined=ignore_undefined) + + super(Task, self).post_validate(all_vars=all_vars, ignore_undefined=ignore_undefined) + def get_vars(self): return self.serialize() - def get_tags(self): - tags = set(self.tags[:]) - if self._block: - tags.update(self._block.get_tags()) - if self._role: - tags.update(self._role.get_tags()) - return tags - - #def get_conditionals(self): - # conditionals = set(self.when[:]) - # if self._block: - # conditionals.update(self._block.get_conditionals()) - # if self._role: - # conditionals.update(self._role.get_conditionals()) - # return conditionals - def compile(self): ''' For tasks, this is just a dummy method returning an array @@ -215,6 +213,7 @@ class Task(Base, Conditional, Taggable): def copy(self): new_me = super(Task, self).copy() + new_me._dep_chain = self._dep_chain[:] new_me._block = None if self._block: @@ -232,6 +231,7 @@ class Task(Base, Conditional, Taggable): def serialize(self): data = super(Task, self).serialize() + data['dep_chain'] = self._dep_chain if self._block: data['block'] = self._block.serialize() @@ -243,6 +243,8 @@ class Task(Base, Conditional, Taggable): def deserialize(self, data): block_data = data.get('block') + self._dep_chain = data.get('dep_chain', []) + if block_data: b = Block() b.deserialize(block_data) @@ -259,18 +261,22 @@ class Task(Base, Conditional, Taggable): super(Task, self).deserialize(data) def evaluate_conditional(self, all_vars): + if len(self._dep_chain): + for dep in self._dep_chain: + if not dep.evaluate_conditional(all_vars): + return False if self._block is not None: if not self._block.evaluate_conditional(all_vars): return False return super(Task, self).evaluate_conditional(all_vars) - def post_validate(self, all_vars=dict(), ignore_undefined=False): - ''' - ''' + def evaluate_tags(self, only_tags, skip_tags): + if len(self._dep_chain): + for dep in self._dep_chain: + if not dep.evaluate_tags(only_tags=only_tags, skip_tags=skip_tags): + return False + if self._block is not None: + if not self._block.evaluate_tags(only_tags=only_tags, skip_tags=skip_tags): + return False + return super(Task, self).evaluate_tags(only_tags=only_tags, skip_tags=skip_tags) - if self._block: - self._block.post_validate(all_vars=all_vars, ignore_undefined=ignore_undefined) - if self._role: - self._role.post_validate(all_vars=all_vars, ignore_undefined=ignore_undefined) - - super(Task, self).post_validate(all_vars=all_vars, ignore_undefined=ignore_undefined)