diff --git a/awx/main/models/workflow.py b/awx/main/models/workflow.py index 3326356f72..de2767e2d7 100644 --- a/awx/main/models/workflow.py +++ b/awx/main/models/workflow.py @@ -129,7 +129,7 @@ class WorkflowNodeBase(CreatedModifiedModel, LaunchTimeConfig): class WorkflowJobTemplateNode(WorkflowNodeBase): FIELDS_TO_PRESERVE_AT_COPY = [ 'unified_job_template', 'workflow_job_template', 'success_nodes', 'failure_nodes', - 'always_nodes', 'parent_nodes', 'credentials', 'inventory', 'extra_data', 'survey_passwords', + 'always_nodes', 'credentials', 'inventory', 'extra_data', 'survey_passwords', 'char_prompts' ] REENCRYPTION_BLACKLIST_AT_COPY = ['extra_data', 'survey_passwords'] @@ -208,6 +208,11 @@ class WorkflowJobNode(WorkflowNodeBase): "semantics will mark this True if the node is in a path that will " "decidedly not be ran. A value of False means the node may not run."), ) + all_parents_must_converge = models.BooleanField( + default=False, + help_text=_("If enabled then the node will only run if all of the parent nodes " + "have met the criteria to reach this node") + ) def get_absolute_url(self, request=None): return reverse('api:workflow_job_node_detail', kwargs={'pk': self.pk}, request=request) diff --git a/awx/main/scheduler/dag_simple.py b/awx/main/scheduler/dag_simple.py index b2741e3538..af6a819914 100644 --- a/awx/main/scheduler/dag_simple.py +++ b/awx/main/scheduler/dag_simple.py @@ -140,36 +140,36 @@ class SimpleDAG(object): def find_ord(self, obj): return self.node_obj_to_node_index.get(obj, None) - def _get_dependencies_by_label(self, node_index, label): + def _get_children_by_label(self, node_index, label): return [self.nodes[index] for index in self.node_from_edges_by_label.get(label, {}) .get(node_index, [])] - def get_dependencies(self, obj, label=None): + def get_children(self, obj, label=None): this_ord = self.find_ord(obj) nodes = [] if label: - return self._get_dependencies_by_label(this_ord, label) + return self._get_children_by_label(this_ord, label) else: nodes = [] for l in self.node_from_edges_by_label.keys(): - nodes.extend(self._get_dependencies_by_label(this_ord, l)) + nodes.extend(self._get_children_by_label(this_ord, l)) return nodes - def _get_dependents_by_label(self, node_index, label): + def _get_parents_by_label(self, node_index, label): return [self.nodes[index] for index in self.node_to_edges_by_label.get(label, {}) .get(node_index, [])] - def get_dependents(self, obj, label=None): + def get_parents(self, obj, label=None): this_ord = self.find_ord(obj) nodes = [] if label: - return self._get_dependents_by_label(this_ord, label) + return self._get_parents_by_label(this_ord, label) else: nodes = [] for l in self.node_to_edges_by_label.keys(): - nodes.extend(self._get_dependents_by_label(this_ord, l)) + nodes.extend(self._get_parents_by_label(this_ord, l)) return nodes def get_root_nodes(self): @@ -188,7 +188,7 @@ class SimpleDAG(object): while stack: node_obj = stack.pop() - children = [node['node_object'] for node in self.get_dependencies(node_obj)] + children = [node['node_object'] for node in self.get_children(node_obj)] children_to_add = list(filter(lambda node_obj: node_obj not in node_objs_visited, children)) if children_to_add: @@ -212,7 +212,7 @@ class SimpleDAG(object): if obj.id in obj_ids_processed: return - for child in self.get_dependencies(obj): + for child in self.get_children(obj): visit(child) obj_ids_processed.add(obj.id) nodes_sorted.appendleft(node) diff --git a/awxkit/awxkit/api/pages/workflow_job_template_nodes.py b/awxkit/awxkit/api/pages/workflow_job_template_nodes.py index f33987ca3a..4a36968f54 100644 --- a/awxkit/awxkit/api/pages/workflow_job_template_nodes.py +++ b/awxkit/awxkit/api/pages/workflow_job_template_nodes.py @@ -83,17 +83,11 @@ class WorkflowJobTemplateNode(HasCreate, base.Base): def add_always_node(self, unified_job_template): return self._add_node(self.related.always_nodes, unified_job_template) - def add_any_successes_node(self, unified_job_template): - return self._add_node(self.related.success_nodes, unified_job_template) - - def add_all_successes_node(self, unified_job_template): - return self._add_node(self.related.success_nodes, unified_job_template) - - def add_any_failure_node(self, unified_job_template): + def add_failure_node(self, unified_job_template): return self._add_node(self.related.failure_nodes, unified_job_template) - def add_all_failures_node(self, unified_job_template): - return self._add_node(self.related.failure_nodes, unified_job_template) + def add_success_node(self, unified_job_template): + return self._add_node(self.related.success_nodes, unified_job_template) def add_credential(self, credential): with suppress(exc.NoContent):