diff --git a/pkg/manager/impl/execution_manager.go b/pkg/manager/impl/execution_manager.go index bd57d4fb1..af8ff8d29 100644 --- a/pkg/manager/impl/execution_manager.go +++ b/pkg/manager/impl/execution_manager.go @@ -553,6 +553,7 @@ func (m *ExecutionManager) launchSingleTaskExecution( if err != nil { return nil, nil, err } + labels = m.addBaseExecutionLabel(ctx, workflowExecutionID.Name, labels) var annotations map[string]string if executionConfig.Annotations != nil { @@ -810,6 +811,8 @@ func (m *ExecutionManager) launchExecutionAndPrepareModel( if err != nil { return nil, nil, err } + labels = m.addBaseExecutionLabel(ctx, workflowExecutionID.Name, labels) + annotations, err := resolveStringMap(executionConfig.GetAnnotations(), launchPlan.Spec.Annotations, "annotations", m.config.RegistrationValidationConfiguration().GetMaxAnnotationEntries()) if err != nil { return nil, nil, err @@ -1687,6 +1690,19 @@ func (m *ExecutionManager) addProjectLabels(ctx context.Context, projectName str return initialLabels, nil } +// Adds base execution label to execution labels. Base execution label is ignored if a corresponding label is set on the execution already. +// An execution label will exist if Flytepropeller launches a child workflow execution, as it will copy the parent execution's labels. +// This label can later be used to retrieve all executions that were launched from a given execution, no matter how deep in the recursion tree. +func (m *ExecutionManager) addBaseExecutionLabel(_ context.Context, execID string, initialLabels map[string]string) map[string]string { + if initialLabels == nil { + initialLabels = make(map[string]string) + } + if _, ok := initialLabels[shared.BaseExecutionIDLabelKey]; !ok { + initialLabels[shared.BaseExecutionIDLabelKey] = execID + } + return initialLabels +} + func addStateFilter(filters []common.InlineFilter) ([]common.InlineFilter, error) { var stateFilterExists bool for _, inlineFilter := range filters { diff --git a/pkg/manager/impl/execution_manager_test.go b/pkg/manager/impl/execution_manager_test.go index 38bac0df1..1a9d5b18e 100644 --- a/pkg/manager/impl/execution_manager_test.go +++ b/pkg/manager/impl/execution_manager_test.go @@ -886,8 +886,9 @@ func TestCreateExecutionDynamicLabelsAndAnnotations(t *testing.T) { mockExecutor := workflowengineMocks.WorkflowExecutor{} mockExecutor.OnExecuteMatch(mock.Anything, mock.MatchedBy(func(executionData workflowengineInterfaces.ExecutionData) bool { assert.EqualValues(t, map[string]string{ - "dynamiclabel1": "dynamic1", - "dynamiclabel2": "dynamic2", + "dynamiclabel1": "dynamic1", + "dynamiclabel2": "dynamic2", + shared.BaseExecutionIDLabelKey: "name", }, executionData.ExecutionParameters.Labels) assert.EqualValues(t, map[string]string{ "dynamicannotation3": "dynamic3", @@ -3834,8 +3835,9 @@ func TestCreateExecution_LegacyClient(t *testing.T) { mockExecutor := workflowengineMocks.WorkflowExecutor{} mockExecutor.OnExecuteMatch(mock.Anything, mock.MatchedBy(func(execData workflowengineInterfaces.ExecutionData) bool { assert.EqualValues(t, map[string]string{ - "label1": "1", - "label2": "2", + "label1": "1", + "label2": "2", + shared.BaseExecutionIDLabelKey: "name", }, execData.ExecutionParameters.Labels) assert.EqualValues(t, map[string]string{ "annotation3": "3", diff --git a/pkg/manager/impl/shared/constants.go b/pkg/manager/impl/shared/constants.go index 469bd3e3b..e9bc1b79e 100644 --- a/pkg/manager/impl/shared/constants.go +++ b/pkg/manager/impl/shared/constants.go @@ -33,6 +33,9 @@ const ( Attributes = "attributes" MatchingAttributes = "matching_attributes" // Parent of a node execution in the node executions table - ParentID = "parent_id" - WorkflowClosure = "workflow_closure" + ParentID = "parent_id" + WorkflowClosure = "workflow_closure" + BaseExecutionIDLabelKey = "base_exec_id" + // BaseExecutionIDLabelKey is the label key for the base execution ID and is globally known. The UI, CLI and potentially + // other components use this label key to identify the base execution ID, so DO NOT CHANGE THIS VALUE. )