diff --git a/docs/pipeline-api.md b/docs/pipeline-api.md index 5a07522b52b..3ae4c3e31ee 100644 --- a/docs/pipeline-api.md +++ b/docs/pipeline-api.md @@ -1454,6 +1454,17 @@ string

WhenExpressions is the list of checks guarding the execution of the PipelineTask

+ + +uid
+ +k8s.io/apimachinery/pkg/types.UID + + + +

UID is the TaskRun or Run’s UID

+ +

Combination @@ -2266,6 +2277,17 @@ CustomRunStatus

WhenExpressions is the list of checks guarding the execution of the PipelineTask

+ + +uid
+ +k8s.io/apimachinery/pkg/types.UID + + + +

UID is the Run’s UID

+ +

PipelineRunSpec @@ -2648,6 +2670,17 @@ TaskRunStatus

WhenExpressions is the list of checks guarding the execution of the PipelineTask

+ + +uid
+ +k8s.io/apimachinery/pkg/types.UID + + + +

UID is the TaskRun’s UID

+ +

PipelineSpec @@ -9782,6 +9815,17 @@ string

WhenExpressions is the list of checks guarding the execution of the PipelineTask

+ + +uid
+ +k8s.io/apimachinery/pkg/types.UID + + + +

UID is the TaskRun or Run’s UID

+ +

CloudEventCondition @@ -11073,6 +11117,17 @@ CustomRunStatus

WhenExpressions is the list of checks guarding the execution of the PipelineTask

+ + +uid
+ +k8s.io/apimachinery/pkg/types.UID + + + +

UID is the Run’s UID

+ +

PipelineRunSpec @@ -11535,6 +11590,17 @@ TaskRunStatus

WhenExpressions is the list of checks guarding the execution of the PipelineTask

+ + +uid
+ +k8s.io/apimachinery/pkg/types.UID + + + +

UID is the TaskRun’s UID

+ +

PipelineSpec diff --git a/pkg/apis/pipeline/v1/openapi_generated.go b/pkg/apis/pipeline/v1/openapi_generated.go index b5e5f19fa0a..4a8cf216536 100644 --- a/pkg/apis/pipeline/v1/openapi_generated.go +++ b/pkg/apis/pipeline/v1/openapi_generated.go @@ -514,6 +514,13 @@ func schema_pkg_apis_pipeline_v1_ChildStatusReference(ref common.ReferenceCallba }, }, }, + "uid": { + SchemaProps: spec.SchemaProps{ + Description: "UID is the TaskRun or Run's UID", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, @@ -1285,6 +1292,13 @@ func schema_pkg_apis_pipeline_v1_PipelineRunRunStatus(ref common.ReferenceCallba }, }, }, + "uid": { + SchemaProps: spec.SchemaProps{ + Description: "UID is the Run's UID", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, @@ -1713,6 +1727,13 @@ func schema_pkg_apis_pipeline_v1_PipelineRunTaskRunStatus(ref common.ReferenceCa }, }, }, + "uid": { + SchemaProps: spec.SchemaProps{ + Description: "UID is the TaskRun's UID", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, diff --git a/pkg/apis/pipeline/v1/pipelinerun_types.go b/pkg/apis/pipeline/v1/pipelinerun_types.go index 9c9bcd85566..b252161623a 100644 --- a/pkg/apis/pipeline/v1/pipelinerun_types.go +++ b/pkg/apis/pipeline/v1/pipelinerun_types.go @@ -494,6 +494,9 @@ type ChildStatusReference struct { // +optional // +listType=atomic WhenExpressions []WhenExpression `json:"whenExpressions,omitempty"` + + // UID is the TaskRun or Run's UID + UID types.UID `json:"uid,omitempty"` } // PipelineRunStatusFields holds the fields of PipelineRunStatus' status. @@ -598,6 +601,8 @@ type PipelineRunTaskRunStatus struct { // +optional // +listType=atomic WhenExpressions []WhenExpression `json:"whenExpressions,omitempty"` + // UID is the TaskRun's UID + UID types.UID `json:"uid,omitempty"` } // PipelineRunRunStatus contains the name of the PipelineTask for this Run and the Run's Status @@ -611,6 +616,8 @@ type PipelineRunRunStatus struct { // +optional // +listType=atomic WhenExpressions []WhenExpression `json:"whenExpressions,omitempty"` + // UID is the Run's UID + UID types.UID `json:"uid,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/pipeline/v1/swagger.json b/pkg/apis/pipeline/v1/swagger.json index 04538db544b..21a9517ac26 100644 --- a/pkg/apis/pipeline/v1/swagger.json +++ b/pkg/apis/pipeline/v1/swagger.json @@ -207,6 +207,10 @@ "description": "PipelineTaskName is the name of the PipelineTask this is referencing.", "type": "string" }, + "uid": { + "description": "UID is the TaskRun or Run's UID", + "type": "string" + }, "whenExpressions": { "description": "WhenExpressions is the list of checks guarding the execution of the PipelineTask", "type": "array", @@ -621,6 +625,10 @@ "description": "Status is the RunStatus for the corresponding Run", "$ref": "#/definitions/github.com.tektoncd.pipeline.pkg.apis.run.v1beta1.CustomRunStatus" }, + "uid": { + "description": "UID is the Run's UID", + "type": "string" + }, "whenExpressions": { "description": "WhenExpressions is the list of checks guarding the execution of the PipelineTask", "type": "array", @@ -841,6 +849,10 @@ "description": "Status is the TaskRunStatus for the corresponding TaskRun", "$ref": "#/definitions/v1.TaskRunStatus" }, + "uid": { + "description": "UID is the TaskRun's UID", + "type": "string" + }, "whenExpressions": { "description": "WhenExpressions is the list of checks guarding the execution of the PipelineTask", "type": "array", diff --git a/pkg/apis/pipeline/v1beta1/openapi_generated.go b/pkg/apis/pipeline/v1beta1/openapi_generated.go index 75817a84c3a..1a333240ab3 100644 --- a/pkg/apis/pipeline/v1beta1/openapi_generated.go +++ b/pkg/apis/pipeline/v1beta1/openapi_generated.go @@ -538,6 +538,13 @@ func schema_pkg_apis_pipeline_v1beta1_ChildStatusReference(ref common.ReferenceC }, }, }, + "uid": { + SchemaProps: spec.SchemaProps{ + Description: "UID is the TaskRun or Run's UID", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, @@ -1930,6 +1937,13 @@ func schema_pkg_apis_pipeline_v1beta1_PipelineRunRunStatus(ref common.ReferenceC }, }, }, + "uid": { + SchemaProps: spec.SchemaProps{ + Description: "UID is the Run's UID", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, @@ -2444,6 +2458,13 @@ func schema_pkg_apis_pipeline_v1beta1_PipelineRunTaskRunStatus(ref common.Refere }, }, }, + "uid": { + SchemaProps: spec.SchemaProps{ + Description: "UID is the TaskRun's UID", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, diff --git a/pkg/apis/pipeline/v1beta1/pipelinerun_conversion.go b/pkg/apis/pipeline/v1beta1/pipelinerun_conversion.go index 4e9ebf2ac90..3410226a506 100644 --- a/pkg/apis/pipeline/v1beta1/pipelinerun_conversion.go +++ b/pkg/apis/pipeline/v1beta1/pipelinerun_conversion.go @@ -332,6 +332,7 @@ func (st *SkippedTask) convertFrom(ctx context.Context, source v1.SkippedTask) { func (csr ChildStatusReference) convertTo(ctx context.Context, sink *v1.ChildStatusReference) { sink.TypeMeta = csr.TypeMeta sink.Name = csr.Name + sink.UID = csr.UID sink.DisplayName = csr.DisplayName sink.PipelineTaskName = csr.PipelineTaskName sink.WhenExpressions = nil @@ -345,6 +346,7 @@ func (csr ChildStatusReference) convertTo(ctx context.Context, sink *v1.ChildSta func (csr *ChildStatusReference) convertFrom(ctx context.Context, source v1.ChildStatusReference) { csr.TypeMeta = source.TypeMeta csr.Name = source.Name + csr.UID = source.UID csr.DisplayName = source.DisplayName csr.PipelineTaskName = source.PipelineTaskName csr.WhenExpressions = nil diff --git a/pkg/apis/pipeline/v1beta1/pipelinerun_conversion_test.go b/pkg/apis/pipeline/v1beta1/pipelinerun_conversion_test.go index 04397c0708b..a830025810f 100644 --- a/pkg/apis/pipeline/v1beta1/pipelinerun_conversion_test.go +++ b/pkg/apis/pipeline/v1beta1/pipelinerun_conversion_test.go @@ -35,6 +35,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/selection" + "k8s.io/apimachinery/pkg/types" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" ) @@ -43,6 +44,7 @@ var ( childRefTaskRuns = []v1beta1.ChildStatusReference{{ TypeMeta: runtime.TypeMeta{Kind: "TaskRun", APIVersion: "tekton.dev/v1beta1"}, Name: "tr-0", + UID: types.UID("22222222-2222-2222-2222-222222222222"), DisplayName: "TR 0", PipelineTaskName: "ptn", WhenExpressions: []v1beta1.WhenExpression{{Input: "default-value", Operator: "in", Values: []string{"val"}}}, @@ -50,12 +52,14 @@ var ( childRefRuns = []v1beta1.ChildStatusReference{{ TypeMeta: runtime.TypeMeta{Kind: "Run", APIVersion: "tekton.dev/v1alpha1"}, Name: "r-0", + UID: types.UID("22222222-2222-2222-2222-222222222222"), DisplayName: "R 0", PipelineTaskName: "ptn-0", WhenExpressions: []v1beta1.WhenExpression{{Input: "default-value-0", Operator: "in", Values: []string{"val-0", "val-1"}}}, }} trs = &v1beta1.PipelineRunTaskRunStatus{ PipelineTaskName: "ptn", + UID: types.UID("22222222-2222-2222-2222-222222222222"), Status: &v1beta1.TaskRunStatus{ TaskRunStatusFields: v1beta1.TaskRunStatusFields{ PodName: "pod-name", @@ -88,13 +92,14 @@ var ( }, }, }, - Sidecars: []v1beta1.SidecarState{{ContainerState: corev1.ContainerState{ - Terminated: &corev1.ContainerStateTerminated{ - ExitCode: 1, - Reason: "Error", - Message: "Error", + Sidecars: []v1beta1.SidecarState{{ + ContainerState: corev1.ContainerState{ + Terminated: &corev1.ContainerStateTerminated{ + ExitCode: 1, + Reason: "Error", + Message: "Error", + }, }, - }, Name: "error", ImageID: "image-id", ContainerName: "sidecar-error", @@ -109,6 +114,7 @@ var ( } rrs = &v1beta1.PipelineRunRunStatus{ PipelineTaskName: "ptn-0", + UID: types.UID("22222222-2222-2222-2222-222222222222"), Status: &runv1beta1.CustomRunStatus{ CustomRunStatusFields: runv1beta1.CustomRunStatusFields{ Results: []runv1beta1.CustomRunResult{{ @@ -268,17 +274,21 @@ func TestPipelineRunConversion(t *testing.T) { }, HostNetwork: false, }, - StepOverrides: []v1beta1.TaskRunStepOverride{{ - Name: "test-so", - Resources: corev1.ResourceRequirements{ - Requests: corev1.ResourceList{corev1.ResourceMemory: corev1resources.MustParse("1Gi")}, - }}, + StepOverrides: []v1beta1.TaskRunStepOverride{ + { + Name: "test-so", + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{corev1.ResourceMemory: corev1resources.MustParse("1Gi")}, + }, + }, }, - SidecarOverrides: []v1beta1.TaskRunSidecarOverride{{ - Name: "test-so", - Resources: corev1.ResourceRequirements{ - Requests: corev1.ResourceList{corev1.ResourceMemory: corev1resources.MustParse("1Gi")}, - }}, + SidecarOverrides: []v1beta1.TaskRunSidecarOverride{ + { + Name: "test-so", + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{corev1.ResourceMemory: corev1resources.MustParse("1Gi")}, + }, + }, }, Metadata: &v1beta1.PipelineTaskMetadata{ Labels: map[string]string{ @@ -315,7 +325,8 @@ func TestPipelineRunConversion(t *testing.T) { Value: *v1beta1.NewObject(map[string]string{ "pkey1": "val1", "pkey2": "rae", - })}, { + }), + }, { Name: "pipeline-result-2", Value: *v1beta1.NewObject(map[string]string{ "pkey1": "val2", @@ -349,6 +360,7 @@ func TestPipelineRunConversion(t *testing.T) { TypeMeta: runtime.TypeMeta{Kind: "TaskRun"}, Name: "t1", PipelineTaskName: "task-1", + UID: types.UID("22222222-2222-2222-2222-222222222222"), WhenExpressions: []v1beta1.WhenExpression{{ Input: "foo", Operator: "notin", @@ -358,6 +370,7 @@ func TestPipelineRunConversion(t *testing.T) { { TypeMeta: runtime.TypeMeta{Kind: "Run"}, Name: "t2", + UID: types.UID("22222222-2222-2222-2222-222222222222"), PipelineTaskName: "task-2", }, }, diff --git a/pkg/apis/pipeline/v1beta1/pipelinerun_types.go b/pkg/apis/pipeline/v1beta1/pipelinerun_types.go index c3a111a978b..82c33e61e1a 100644 --- a/pkg/apis/pipeline/v1beta1/pipelinerun_types.go +++ b/pkg/apis/pipeline/v1beta1/pipelinerun_types.go @@ -442,6 +442,9 @@ type ChildStatusReference struct { // +optional // +listType=atomic WhenExpressions []WhenExpression `json:"whenExpressions,omitempty"` + + // UID is the TaskRun or Run's UID + UID types.UID `json:"uid,omitempty"` } // PipelineRunStatusFields holds the fields of PipelineRunStatus' status. @@ -562,6 +565,8 @@ type PipelineRunTaskRunStatus struct { // +optional // +listType=atomic WhenExpressions []WhenExpression `json:"whenExpressions,omitempty"` + // UID is the TaskRun's UID + UID types.UID `json:"uid,omitempty"` } // PipelineRunRunStatus contains the name of the PipelineTask for this CustomRun or Run and the CustomRun or Run's Status @@ -575,6 +580,8 @@ type PipelineRunRunStatus struct { // +optional // +listType=atomic WhenExpressions []WhenExpression `json:"whenExpressions,omitempty"` + // UID is the Run's UID + UID types.UID `json:"uid,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/pipeline/v1beta1/swagger.json b/pkg/apis/pipeline/v1beta1/swagger.json index 00322afb0e1..ad1ab8d4fe2 100644 --- a/pkg/apis/pipeline/v1beta1/swagger.json +++ b/pkg/apis/pipeline/v1beta1/swagger.json @@ -207,6 +207,10 @@ "description": "PipelineTaskName is the name of the PipelineTask this is referencing.", "type": "string" }, + "uid": { + "description": "UID is the TaskRun or Run's UID", + "type": "string" + }, "whenExpressions": { "description": "WhenExpressions is the list of checks guarding the execution of the PipelineTask", "type": "array", @@ -962,6 +966,10 @@ "description": "Status is the CustomRunStatus for the corresponding CustomRun or Run", "$ref": "#/definitions/github.com.tektoncd.pipeline.pkg.apis.run.v1beta1.CustomRunStatus" }, + "uid": { + "description": "UID is the Run's UID", + "type": "string" + }, "whenExpressions": { "description": "WhenExpressions is the list of checks guarding the execution of the PipelineTask", "type": "array", @@ -1225,6 +1233,10 @@ "description": "Status is the TaskRunStatus for the corresponding TaskRun", "$ref": "#/definitions/v1beta1.TaskRunStatus" }, + "uid": { + "description": "UID is the TaskRun's UID", + "type": "string" + }, "whenExpressions": { "description": "WhenExpressions is the list of checks guarding the execution of the PipelineTask", "type": "array", diff --git a/pkg/reconciler/pipelinerun/pipelinerun.go b/pkg/reconciler/pipelinerun/pipelinerun.go index 8756c1282f4..c50f266c191 100644 --- a/pkg/reconciler/pipelinerun/pipelinerun.go +++ b/pkg/reconciler/pipelinerun/pipelinerun.go @@ -66,6 +66,7 @@ import ( k8slabels "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/kubernetes" "k8s.io/utils/clock" @@ -111,7 +112,7 @@ var ( ReasonFailedValidation = v1.PipelineRunReasonFailedValidation.String() // ReasonInvalidGraph indicates that the reason for the failure status is that the // associated Pipeline is an invalid graph (a.k.a wrong order, cycle, …) - ReasonInvalidGraph = v1.PipelineRunReasonInvalidGraph.String() + RewasonInvalidGraph = v1.PipelineRunReasonInvalidGraph.String() // ReasonCancelled indicates that a PipelineRun was cancelled. ReasonCancelled = v1.PipelineRunReasonCancelled.String() // ReasonPending indicates that a PipelineRun is pending. @@ -338,7 +339,8 @@ func (c *Reconciler) resolvePipelineState( tasks []v1.PipelineTask, pipelineMeta *metav1.ObjectMeta, pr *v1.PipelineRun, - pst resources.PipelineRunState) (resources.PipelineRunState, error) { + pst resources.PipelineRunState, +) (resources.PipelineRunState, error) { ctx, span := c.tracerProvider.Tracer(TracerName).Start(ctx, "resolvePipelineState") defer span.End() // Resolve each task individually because they each could have a different reference context (remote or local). @@ -385,9 +387,12 @@ func (c *Reconciler) resolvePipelineState( "Pipeline %s/%s can't be Run; it contains Tasks that don't exist: %s", pipelineMeta.Namespace, pipelineMeta.Name, nfErr) } else { + if !strings.Contains(err.Error(), "mismatched UID") { + err = pipelineErrors.WrapUserError(err) + } pr.Status.MarkFailed(v1.PipelineRunReasonFailedValidation.String(), "PipelineRun %s/%s can't be Run; couldn't resolve all references: %s", - pipelineMeta.Namespace, pr.Name, pipelineErrors.WrapUserError(err)) + pipelineMeta.Namespace, pr.Name, err) } return nil, controller.NewPermanentError(err) } @@ -1512,11 +1517,12 @@ func filterTaskRunsForPipelineRunStatus(logger *zap.SugaredLogger, pr *v1.Pipeli } // filterCustomRunsForPipelineRunStatus filters the given slice of customRuns, returning information only those owned by the given PipelineRun. -func filterCustomRunsForPipelineRunStatus(logger *zap.SugaredLogger, pr *v1.PipelineRun, customRuns []*v1beta1.CustomRun) ([]string, []string, []schema.GroupVersionKind, []*v1beta1.CustomRunStatus) { +func filterCustomRunsForPipelineRunStatus(logger *zap.SugaredLogger, pr *v1.PipelineRun, customRuns []*v1beta1.CustomRun) ([]string, []string, []schema.GroupVersionKind, []*v1beta1.CustomRunStatus, []types.UID) { var names []string var taskLabels []string var gvks []schema.GroupVersionKind var statuses []*v1beta1.CustomRunStatus + var uids []types.UID // Loop over all the customRuns associated to Tasks for _, cr := range customRuns { @@ -1529,13 +1535,14 @@ func filterCustomRunsForPipelineRunStatus(logger *zap.SugaredLogger, pr *v1.Pipe names = append(names, cr.GetObjectMeta().GetName()) taskLabels = append(taskLabels, cr.GetObjectMeta().GetLabels()[pipeline.PipelineTaskLabelKey]) + uids = append(uids, cr.GetObjectMeta().GetUID()) statuses = append(statuses, &cr.Status) // We can't just get the gvk from the customRun's TypeMeta because that isn't populated for resources created through the fake client. gvks = append(gvks, v1beta1.SchemeGroupVersion.WithKind(customRun)) } - return names, taskLabels, gvks, statuses + return names, taskLabels, gvks, statuses, uids } func updatePipelineRunStatusFromChildRefs(logger *zap.SugaredLogger, pr *v1.PipelineRun, trs []*v1.TaskRun, customRuns []*v1beta1.CustomRun) { @@ -1572,18 +1579,20 @@ func updatePipelineRunStatusFromChildRefs(logger *zap.SugaredLogger, pr *v1.Pipe }, Name: tr.Name, PipelineTaskName: pipelineTaskName, + UID: tr.UID, } } } // Get the names, their task label values, and their group/version/kind info for all CustomRuns or Runs associated with the PipelineRun - names, taskLabels, gvks, _ := filterCustomRunsForPipelineRunStatus(logger, pr, customRuns) + names, taskLabels, gvks, _, uids := filterCustomRunsForPipelineRunStatus(logger, pr, customRuns) // Loop over that data and populate the child references for idx := range names { name := names[idx] taskLabel := taskLabels[idx] gvk := gvks[idx] + uid := uids[idx] if _, ok := childRefByName[name]; !ok { // This run was missing from the status. @@ -1598,6 +1607,7 @@ func updatePipelineRunStatusFromChildRefs(logger *zap.SugaredLogger, pr *v1.Pipe }, Name: name, PipelineTaskName: taskLabel, + UID: uid, } } } diff --git a/pkg/reconciler/pipelinerun/pipelinerun_test.go b/pkg/reconciler/pipelinerun/pipelinerun_test.go index 71d1e776f1c..dc62daf9cb8 100644 --- a/pkg/reconciler/pipelinerun/pipelinerun_test.go +++ b/pkg/reconciler/pipelinerun/pipelinerun_test.go @@ -332,7 +332,8 @@ spec: type: string - name: contextRetriesParam type: string -`)} +`), + } clusterTasks := []*v1beta1.ClusterTask{ parse.MustParseClusterTask(t, ` metadata: @@ -347,7 +348,8 @@ spec: type: string - name: contextPipelineParam type: string -`)} +`), + } d := test.Data{ PipelineRuns: prs, @@ -713,7 +715,8 @@ spec: `, v1.ParamTypeObject)), } - ps := []*v1.Pipeline{parse.MustParseV1Pipeline(t, ` + ps := []*v1.Pipeline{ + parse.MustParseV1Pipeline(t, ` metadata: name: pipeline-missing-tasks namespace: foo @@ -793,6 +796,7 @@ spec: for _, tc := range []struct { name string pipelineRun *v1.PipelineRun + taskRuns []*v1.TaskRun reason string hasNoDefaultLabels bool permanentError bool @@ -1020,14 +1024,62 @@ spec: "Normal Started", "Warning Failed [User error] PipelineRun foo/pipeline-invalid-final-graph's Pipeline DAG is invalid for finally clause: task final-task-1 is already present in Graph, can't add it again: duplicate pipeline task", }, + }, { + name: "mismatched-taskrun-uid", + pipelineRun: parse.MustParseV1PipelineRun(t, ` +metadata: + name: pipeline-with-mismatched-taskrun-uid + namespace: foo +spec: + pipelineSpec: + tasks: + - name: hello-world-task-1 + taskSpec: + steps: + - image: myimage + name: mystep +status: + conditions: + - status: Unknown + type: Succeeded + startTime: "2021-12-31T23:58:59Z" + childReferences: + - apiVersion: tekton.dev/v1beta1 + kind: TaskRun + name: mismatched-taskrun-uid-task + pipelineTaskName: hello-world-task-1 + uid: 11111111-1111-1111-1111-111111111111 +`), + taskRuns: []*v1.TaskRun{mustParseTaskRunWithObjectMeta(t, + taskRunObjectMetaWithUID("mismatched-taskrun-uid-task", "foo", + "pipeline-with-mismatched-taskrun-uid", "", "hello-world-task-1", true, + "22222222-2222-2222-2222-222222222222"), + ` +spec: + taskSpec: + steps: + - image: otherImage + name: otherStep +status: + conditions: + - status: "Unknown" + type: Succeeded +`)}, + reason: ReasonFailedValidation, + permanentError: true, + wantEvents: []string{ + "Warning Failed PipelineRun foo/pipeline-with-mismatched-taskrun-uid can't be Run; couldn't resolve all references: mismatched UID for TaskRun mismatched-taskrun-uid-task; expected 11111111-1111-1111-1111-111111111111, found 22222222-2222-2222-2222-222222222222", + }, }} { t.Run(tc.name, func(t *testing.T) { + tc := tc cms := []*corev1.ConfigMap{withEnabledAlphaAPIFields(newFeatureFlagsConfigMap())} d := test.Data{ PipelineRuns: []*v1.PipelineRun{tc.pipelineRun}, Pipelines: ps, Tasks: ts, + TaskRuns: tc.taskRuns, ConfigMaps: cms, } prt := newPipelineRunTest(t, d) @@ -1192,8 +1244,7 @@ status: value: 123 `)} - expectedPipelineRun := - parse.MustParseV1PipelineRun(t, ` + expectedPipelineRun := parse.MustParseV1PipelineRun(t, ` metadata: name: test-pipeline-missing-results namespace: foo @@ -2199,14 +2250,15 @@ status: "hello-world", corev1.ConditionTrue, )}, - initialChildReferences: []v1.ChildStatusReference{{ - TypeMeta: runtime.TypeMeta{ - APIVersion: v1.SchemeGroupVersion.String(), - Kind: "TaskRun", + initialChildReferences: []v1.ChildStatusReference{ + { + TypeMeta: runtime.TypeMeta{ + APIVersion: v1.SchemeGroupVersion.String(), + Kind: "TaskRun", + }, + Name: "test-pipeline-run-stopped-run-finally-hello-world", + PipelineTaskName: "hello-world-1", }, - Name: "test-pipeline-run-stopped-run-finally-hello-world", - PipelineTaskName: "hello-world-1", - }, }, expectedEvents: []string{"Warning Failed PipelineRun \"test-pipeline-run-stopped-run-finally\" was cancelled"}, hasNilCompletionTime: false, @@ -2876,7 +2928,8 @@ spec: taskRef: name: hello-world kind: Task -`)} +`), + } oneStartedTRs := []*v1.TaskRun{ getTaskRun( t, @@ -3159,7 +3212,8 @@ spec: taskRef: name: hello-world kind: Task -`)}, +`), + }, ps: []*v1.Pipeline{pipelineFinalTask}, pr: parse.MustParseV1PipelineRun(t, fmt.Sprintf(` metadata: @@ -4102,7 +4156,6 @@ spec: LabelSelector: "tekton.dev/pipelineTask=b-task,tekton.dev/pipelineRun=test-pipeline-run-different-service-accs", Limit: 1, }) - if err != nil { t.Fatalf("Failure to list TaskRun's %s", err) } @@ -4293,7 +4346,6 @@ spec: LabelSelector: fmt.Sprintf("tekton.dev/pipelineTask=%s,tekton.dev/pipelineRun=test-pipeline-run-different-service-accs", taskName), Limit: 1, }) - if err != nil { t.Fatalf("Failure to list TaskRuns %s", err) } @@ -4451,7 +4503,6 @@ status: LabelSelector: "tekton.dev/pipelineTask=c-task,tekton.dev/pipelineRun=test-pipeline-run-different-service-accs", Limit: 1, }) - if err != nil { t.Fatalf("Failure to list TaskRuns %s", err) } @@ -4596,7 +4647,6 @@ spec: LabelSelector: "tekton.dev/pipelineTask=b-task,tekton.dev/pipelineRun=test-pipeline-run-different-service-accs", Limit: 1, }) - if err != nil { t.Fatalf("Failure to list TaskRun's %s", err) } @@ -4762,7 +4812,6 @@ spec: LabelSelector: "tekton.dev/pipelineTask=f-c-task,tekton.dev/pipelineRun=test-pipeline-run-different-final-task-when", Limit: 1, }) - if err != nil { t.Fatalf("Failure to list TaskRun's %s", err) } @@ -5820,7 +5869,6 @@ spec: LabelSelector: "tekton.dev/pipelineTask=b-task,tekton.dev/pipelineRun=test-pipeline-run-different-service-accs", Limit: 1, }) - if err != nil { t.Fatalf("Failure to list TaskRun's %s", err) } @@ -6178,7 +6226,6 @@ spec: LabelSelector: "tekton.dev/pipelineTask=b-task,tekton.dev/pipelineRun=test-pipeline-run-variable-substitution", Limit: 1, }) - if err != nil { t.Fatalf("Failure to list TaskRun's %s", err) } @@ -6777,7 +6824,7 @@ metadata: resolvedObjectMeta *resolutionutil.ResolvedObjectMeta } - var tests = []struct { + tests := []struct { name string reconcile1Args *args reconcile2Args *args @@ -7631,7 +7678,8 @@ func TestReconcilePipeline_FinalTasks(t *testing.T) { // checkTaskRunStatusFromChildRefs checks the status of taskruns from ChildReferences to be expected. func checkTaskRunStatusFromChildRefs(ctx context.Context, t *testing.T, namespace string, clients test.Clients, - childRefs []v1.ChildStatusReference, expectedTaskRuns map[string]*v1.PipelineRunTaskRunStatus) { + childRefs []v1.ChildStatusReference, expectedTaskRuns map[string]*v1.PipelineRunTaskRunStatus, +) { t.Helper() taskrunsToCheck := len(expectedTaskRuns) if taskrunsToCheck == 0 { @@ -7960,7 +8008,8 @@ spec: params: - name: pipelineRun-tasks-task1 type: string -`)} +`), + } trs := []*v1.TaskRun{mustParseTaskRunWithObjectMeta(t, taskRunObjectMeta(pipelineRunName+"-task1-xxyy", "foo", pipelineRunName, pipelineName, "task1", false), @@ -8006,7 +8055,6 @@ spec: LabelSelector: "tekton.dev/pipelineTask=finaltask,tekton.dev/pipelineRun=" + pipelineRunName, Limit: 1, }) - if err != nil { t.Fatalf("Failure to list TaskRun's %s", err) } @@ -8212,7 +8260,6 @@ spec: LabelSelector: "tekton.dev/pipelineTask=final-task-1,tekton.dev/pipelineRun=test-pipeline-run-final-task-results", Limit: 1, }) - if err != nil { t.Fatalf("Failure to list TaskRun's %s", err) } @@ -8781,7 +8828,7 @@ spec: } // Mock a successful resolution - var pipelineBytes = []byte(` + pipelineBytes := []byte(` kind: Pipeline apiVersion: tekton.dev/v1 metadata: @@ -9046,6 +9093,12 @@ func baseObjectMeta(name, ns string) metav1.ObjectMeta { } } +func taskRunObjectMetaWithUID(trName, ns, prName, pipelineName, pipelineTaskName string, skipMemberOfLabel bool, uid string) metav1.ObjectMeta { + om := taskRunObjectMeta(trName, ns, prName, pipelineName, pipelineTaskName, skipMemberOfLabel) + om.UID = types.UID(uid) + return om +} + func taskRunObjectMeta(trName, ns, prName, pipelineName, pipelineTaskName string, skipMemberOfLabel bool) metav1.ObjectMeta { om := metav1.ObjectMeta{ Name: trName, @@ -9138,6 +9191,7 @@ spec: status: startTime: %s`, prName, specStatus, now.Format(time.RFC3339))) } + func verifyTaskRunStatusesCount(t *testing.T, prStatus v1.PipelineRunStatus, taskCount int) { t.Helper() @@ -9145,6 +9199,7 @@ func verifyTaskRunStatusesCount(t *testing.T, prStatus v1.PipelineRunStatus, tas t.Errorf("Expected PipelineRun status ChildReferences to have %d tasks, but was %d", taskCount, len(filterChildRefsForKind(prStatus.ChildReferences, taskRun))) } } + func verifyTaskRunStatusesNames(t *testing.T, prStatus v1.PipelineRunStatus, taskNames ...string) { t.Helper() @@ -9258,9 +9313,10 @@ func TestGetTaskrunWorkspaces_Failure(t *testing.T) { name string pr *v1.PipelineRun expectedError string - }{{ - name: "failure declaring workspace with different name", - pr: parse.MustParseV1PipelineRun(t, ` + }{ + { + name: "failure declaring workspace with different name", + pr: parse.MustParseV1PipelineRun(t, ` metadata: name: pipeline spec: @@ -9274,8 +9330,8 @@ spec: workspaces: - name: not-source `), - expectedError: `expected workspace "not-source" to be provided by pipelinerun for pipeline task "resolved-pipelinetask"`, - }, + expectedError: `expected workspace "not-source" to be provided by pipelinerun for pipeline task "resolved-pipelinetask"`, + }, { name: "failure mapping workspace with different name", pr: parse.MustParseV1PipelineRun(t, ` @@ -9367,24 +9423,25 @@ func TestGetTaskrunWorkspaces_Success(t *testing.T) { name string pr *v1.PipelineRun rprt *resources.ResolvedPipelineTask - }{{ - name: "valid declaration of workspace names", - pr: parse.MustParseV1PipelineRun(t, ` + }{ + { + name: "valid declaration of workspace names", + pr: parse.MustParseV1PipelineRun(t, ` metadata: name: pipeline spec: workspaces: - name: source`), - rprt: &resources.ResolvedPipelineTask{ - PipelineTask: &v1.PipelineTask{ - Name: "resolved-pipelinetask", - Workspaces: []v1.WorkspacePipelineTaskBinding{{ - Name: "my-task-workspace", - Workspace: "source", - }}, + rprt: &resources.ResolvedPipelineTask{ + PipelineTask: &v1.PipelineTask{ + Name: "resolved-pipelinetask", + Workspaces: []v1.WorkspacePipelineTaskBinding{{ + Name: "my-task-workspace", + Workspace: "source", + }}, + }, }, }, - }, { name: "valid mapping with same workspace names", pr: parse.MustParseV1PipelineRun(t, ` @@ -9460,7 +9517,6 @@ spec: KubeClientSet: fakek8s.NewSimpleClientset(), } _, _, err := c.getTaskrunWorkspaces(context.Background(), tt.pr, tt.rprt) - if err != nil { t.Errorf("Pipeline.getTaskrunWorkspaces() returned error for valid pipeline: %v", err) } @@ -10470,6 +10526,7 @@ labels: }) } } + func TestReconciler_PipelineTaskIncludeParams(t *testing.T) { names.TestingSeed() @@ -11102,10 +11159,11 @@ spec: p *v1.Pipeline tr *v1.TaskRun expectedPipelineRun *v1.PipelineRun - }{{ - name: "p-dag", - memberOf: "tasks", - p: parse.MustParseV1Pipeline(t, fmt.Sprintf(` + }{ + { + name: "p-dag", + memberOf: "tasks", + p: parse.MustParseV1Pipeline(t, fmt.Sprintf(` metadata: name: %s namespace: foo @@ -11135,7 +11193,7 @@ spec: - name: DOCKERFILE value: path/to/Dockerfile3 `, "p-dag")), - expectedPipelineRun: parse.MustParseV1PipelineRun(t, ` + expectedPipelineRun: parse.MustParseV1PipelineRun(t, ` metadata: name: pr namespace: foo @@ -11196,7 +11254,7 @@ status: displayName: build-3 pipelineTaskName: matrix-include `), - }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -13666,12 +13724,11 @@ spec: if tt.tr != nil { d.TaskRuns = []*v1.TaskRun{tt.tr} } - wantEvents := - []string{ - "Normal Started", - "Warning Failed [User error] PipelineRun foo/pr can't be Run; couldn't resolve all references: array Result Index 3 for Task pt-with-result Result platforms is out of bound of size 3", - "Warning InternalError 1 error occurred:", - } + wantEvents := []string{ + "Normal Started", + "Warning Failed [User error] PipelineRun foo/pr can't be Run; couldn't resolve all references: array Result Index 3 for Task pt-with-result Result platforms is out of bound of size 3", + "Warning InternalError 1 error occurred:", + } prt := newPipelineRunTest(t, d) defer prt.Cancel() pipelineRun, clients := prt.reconcileRun(pr.Namespace, pr.Name, wantEvents /* wantEvents*/, true /* permanentError*/) @@ -15526,6 +15583,7 @@ spec: }) } } + func TestReconcile_SetDefaults(t *testing.T) { names.TestingSeed() @@ -15757,7 +15815,8 @@ spec: expectedComputeResources: []corev1.ResourceRequirements{{ Requests: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("1"), - corev1.ResourceMemory: resource.MustParse("1Gi")}, + corev1.ResourceMemory: resource.MustParse("1Gi"), + }, Limits: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("2")}, }}, }} @@ -15848,6 +15907,7 @@ spec: t.Fatalf("Should have filtered chains.tekton.dev/* and results.tekton.dev/* annotations and only have one annotations, got %v", tr.ObjectMeta.Annotations) } } + func TestReconcile_CancelUnscheduled(t *testing.T) { pipelineRunName := "cancel-test-run" prs := []*v1.PipelineRun{parse.MustParseV1PipelineRun(t, `metadata: @@ -15969,7 +16029,8 @@ spec: }, Spec: v1alpha1.VerificationPolicySpec{ Resources: []v1alpha1.ResourcePattern{{Pattern: "no-match"}}, - }}} + }, + }} // warnPolicy doesn't contain keys so it will fail verification but doesn't fail the run warnPolicy := []*v1alpha1.VerificationPolicy{{ ObjectMeta: metav1.ObjectMeta{ @@ -15979,7 +16040,8 @@ spec: Spec: v1alpha1.VerificationPolicySpec{ Resources: []v1alpha1.ResourcePattern{{Pattern: ".*"}}, Mode: v1alpha1.ModeWarn, - }}} + }, + }} prs := parse.MustParseV1PipelineRun(t, fmt.Sprintf(` metadata: @@ -16010,27 +16072,28 @@ spec: noMatchPolicy string verificationPolicies []*v1alpha1.VerificationPolicy wantTrustedResourcesCondition *apis.Condition - }{{ - name: "ignore no match policy", - noMatchPolicy: config.IgnoreNoMatchPolicy, - verificationPolicies: noMatchPolicy, - wantTrustedResourcesCondition: nil, - }, { - name: "warn no match policy", - noMatchPolicy: config.WarnNoMatchPolicy, - verificationPolicies: noMatchPolicy, - wantTrustedResourcesCondition: failNoMatchCondition, - }, { - name: "pass enforce policy", - noMatchPolicy: config.FailNoMatchPolicy, - verificationPolicies: vps, - wantTrustedResourcesCondition: passCondition, - }, { - name: "only fail warn policy", - noMatchPolicy: config.FailNoMatchPolicy, - verificationPolicies: warnPolicy, - wantTrustedResourcesCondition: failNoKeysCondition, - }, + }{ + { + name: "ignore no match policy", + noMatchPolicy: config.IgnoreNoMatchPolicy, + verificationPolicies: noMatchPolicy, + wantTrustedResourcesCondition: nil, + }, { + name: "warn no match policy", + noMatchPolicy: config.WarnNoMatchPolicy, + verificationPolicies: noMatchPolicy, + wantTrustedResourcesCondition: failNoMatchCondition, + }, { + name: "pass enforce policy", + noMatchPolicy: config.FailNoMatchPolicy, + verificationPolicies: vps, + wantTrustedResourcesCondition: passCondition, + }, { + name: "only fail warn policy", + noMatchPolicy: config.FailNoMatchPolicy, + verificationPolicies: warnPolicy, + wantTrustedResourcesCondition: failNoKeysCondition, + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { @@ -16303,7 +16366,8 @@ spec: }, Spec: v1alpha1.VerificationPolicySpec{ Resources: []v1alpha1.ResourcePattern{{Pattern: "no-match"}}, - }}} + }, + }} // warnPolicy doesn't contain keys so it will fail verification but doesn't fail the run warnPolicy := []*v1alpha1.VerificationPolicy{{ ObjectMeta: metav1.ObjectMeta{ @@ -16313,7 +16377,8 @@ spec: Spec: v1alpha1.VerificationPolicySpec{ Resources: []v1alpha1.ResourcePattern{{Pattern: ".*"}}, Mode: v1alpha1.ModeWarn, - }}} + }, + }} prs := parse.MustParseV1PipelineRun(t, fmt.Sprintf(` metadata: @@ -16344,27 +16409,28 @@ spec: noMatchPolicy string verificationPolicies []*v1alpha1.VerificationPolicy wantTrustedResourcesCondition *apis.Condition - }{{ - name: "ignore no match policy", - noMatchPolicy: config.IgnoreNoMatchPolicy, - verificationPolicies: noMatchPolicy, - wantTrustedResourcesCondition: nil, - }, { - name: "warn no match policy", - noMatchPolicy: config.WarnNoMatchPolicy, - verificationPolicies: noMatchPolicy, - wantTrustedResourcesCondition: failNoMatchCondition, - }, { - name: "pass enforce policy", - noMatchPolicy: config.FailNoMatchPolicy, - verificationPolicies: vps, - wantTrustedResourcesCondition: passCondition, - }, { - name: "only fail warn policy", - noMatchPolicy: config.FailNoMatchPolicy, - verificationPolicies: warnPolicy, - wantTrustedResourcesCondition: failNoKeysCondition, - }, + }{ + { + name: "ignore no match policy", + noMatchPolicy: config.IgnoreNoMatchPolicy, + verificationPolicies: noMatchPolicy, + wantTrustedResourcesCondition: nil, + }, { + name: "warn no match policy", + noMatchPolicy: config.WarnNoMatchPolicy, + verificationPolicies: noMatchPolicy, + wantTrustedResourcesCondition: failNoMatchCondition, + }, { + name: "pass enforce policy", + noMatchPolicy: config.FailNoMatchPolicy, + verificationPolicies: vps, + wantTrustedResourcesCondition: passCondition, + }, { + name: "only fail warn policy", + noMatchPolicy: config.FailNoMatchPolicy, + verificationPolicies: warnPolicy, + wantTrustedResourcesCondition: failNoKeysCondition, + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { @@ -16638,7 +16704,8 @@ spec: echo "hello world" workspaces: - name: source -`)} +`), + } trs := []*v1.TaskRun{} @@ -17075,7 +17142,8 @@ status: type: string value: bar-value startTime: "2023-10-03T10:55:12Z" -`)} +`), + } d := test.Data{ PipelineRuns: prs, diff --git a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go index 6f1cadc34af..440f72fc27b 100644 --- a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go +++ b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go @@ -33,6 +33,7 @@ import ( "github.com/tektoncd/pipeline/pkg/remote" "github.com/tektoncd/pipeline/pkg/substitution" kerrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" "knative.dev/pkg/apis" "knative.dev/pkg/kmeta" ) @@ -590,9 +591,42 @@ func ResolvePipelineTask( } } } + + existingPipelineTaskUIDs := getPipelineTaskUIDs(pipelineRun.Status) + + for _, run := range rpt.CustomRuns { + if run == nil { + continue + } + if existingUID, ok := existingPipelineTaskUIDs[run.GetObjectMeta().GetName()]; ok && existingUID != run.GetObjectMeta().GetUID() && existingUID != "" { + return nil, fmt.Errorf("mismatched UID for Run %s; expected %s, found %s", run.GetObjectMeta().GetName(), existingUID, run.GetObjectMeta().GetUID()) + } + } + + for _, tr := range rpt.TaskRuns { + if tr == nil { + continue + } + if existingUID, ok := existingPipelineTaskUIDs[tr.Name]; ok && existingUID != tr.UID && existingUID != "" { + return nil, fmt.Errorf("mismatched UID for TaskRun %s; expected %s, found %s", tr.Name, existingUID, tr.UID) + } + } + return &rpt, nil } +func getPipelineTaskUIDs(prs v1.PipelineRunStatus) map[string]types.UID { + m := make(map[string]types.UID) + + if len(prs.ChildReferences) > 0 { + for _, cr := range prs.ChildReferences { + m[cr.Name] = cr.UID + } + return m + } + return m +} + // setTaskRunsAndResolvedTask fetches the named TaskRun using the input function getTaskRun, // and the resolved Task spec of the Pipeline Task using the input function getTask. // It updates the ResolvedPipelineTask with the ResolvedTask and a pointer to the fetched TaskRun. diff --git a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go index a1633b68ea6..9f1fefc6ba4 100644 --- a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go +++ b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go @@ -35,6 +35,7 @@ import ( "github.com/tektoncd/pipeline/pkg/trustedresources" "github.com/tektoncd/pipeline/test/diff" "github.com/tektoncd/pipeline/test/names" + "github.com/tektoncd/pipeline/test/parse" corev1 "k8s.io/api/core/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -48,9 +49,11 @@ import ( func nopGetCustomRun(string) (*v1beta1.CustomRun, error) { return nil, errors.New("GetRun should not be called") } + func nopGetTask(context.Context, string) (*v1.Task, *v1.RefSource, *trustedresources.VerificationResult, error) { return nil, nil, nil, errors.New("GetTask should not be called") } + func nopGetTaskRun(string) (*v1.TaskRun, error) { return nil, errors.New("GetTaskRun should not be called") } @@ -128,14 +131,16 @@ var pts = []v1.PipelineTask{{ Params: v1.Params{{ Name: "browser", Value: v1.ParamValue{ArrayVal: []string{"safari", "chrome"}}, - }}}, + }}, + }, }, { Name: "mytask17", Matrix: &v1.Matrix{ Params: v1.Params{{ Name: "browser", Value: v1.ParamValue{ArrayVal: []string{"safari", "chrome"}}, - }}}, + }}, + }, }, { Name: "mytask18", TaskRef: &v1.TaskRef{Name: "task"}, @@ -144,7 +149,8 @@ var pts = []v1.PipelineTask{{ Params: v1.Params{{ Name: "browser", Value: v1.ParamValue{ArrayVal: []string{"safari", "chrome"}}, - }}}, + }}, + }, }, { Name: "mytask19", TaskRef: &v1.TaskRef{APIVersion: "example.dev/v0", Kind: "Example", Name: "customtask"}, @@ -152,7 +158,8 @@ var pts = []v1.PipelineTask{{ Params: v1.Params{{ Name: "browser", Value: v1.ParamValue{ArrayVal: []string{"safari", "chrome"}}, - }}}, + }}, + }, }, { Name: "mytask20", TaskRef: &v1.TaskRef{APIVersion: "example.dev/v0", Kind: "Example", Name: "customtask"}, @@ -160,7 +167,8 @@ var pts = []v1.PipelineTask{{ Params: v1.Params{{ Name: "browser", Value: v1.ParamValue{ArrayVal: []string{"safari", "chrome"}}, - }}}, + }}, + }, }, { Name: "mytask21", TaskRef: &v1.TaskRef{Name: "task"}, @@ -169,7 +177,8 @@ var pts = []v1.PipelineTask{{ Params: v1.Params{{ Name: "browser", Value: v1.ParamValue{ArrayVal: []string{"safari", "chrome"}}, - }}}, + }}, + }, }} var p = &v1.Pipeline{ @@ -243,12 +252,14 @@ var matrixedPipelineTask = &v1.PipelineTask{ Image: "bash:latest", Script: `#!/usr/bin/env bash\necho -n "$(params.browser)" | sha256sum | tee $(results.BROWSER.path)"`, }}, - }}, + }, + }, Matrix: &v1.Matrix{ Params: v1.Params{{ Name: "browser", Value: v1.ParamValue{ArrayVal: []string{"safari", "chrome"}}, - }}}, + }}, + }, } func makeScheduled(tr v1.TaskRun) *v1.TaskRun { @@ -1137,7 +1148,8 @@ func TestIsSkipped(t *testing.T) { Type: v1.ParamTypeArray, ArrayVal: []string{"foo", "bar"}, }, - }}}, + }}, + }, }, TaskRunNames: []string{"pipelinerun-matrix-empty-params"}, TaskRuns: nil, @@ -1156,7 +1168,8 @@ func TestIsSkipped(t *testing.T) { Type: v1.ParamTypeArray, ArrayVal: []string{}, }, - }}}, + }}, + }, }, TaskRunNames: []string{"pipelinerun-matrix-empty-params"}, TaskRuns: nil, @@ -1181,7 +1194,8 @@ func TestIsSkipped(t *testing.T) { Type: v1.ParamTypeArray, ArrayVal: []string{}, }, - }}}, + }}, + }, }, TaskRunNames: []string{"pipelinerun-matrix-empty-params"}, TaskRuns: nil, @@ -2317,7 +2331,8 @@ func TestSkipBecauseParentTaskWasSkipped(t *testing.T) { } func getExpectedMessage(runName string, specStatus v1.PipelineRunSpecStatus, status corev1.ConditionStatus, - successful, incomplete, skipped, failed, cancelled int) string { + successful, incomplete, skipped, failed, cancelled int, +) string { if status == corev1.ConditionFalse && (specStatus == v1.PipelineRunSpecStatusCancelledRunFinally || specStatus == v1.PipelineRunSpecStatusStoppedRunFinally) { @@ -2475,7 +2490,8 @@ func TestResolvePipelineRun_TaskDoesntExist(t *testing.T) { Name: "bar", Value: *v1.NewStructuredValues("b", "a", "r"), }}, - }}} + }, + }} // Return an error when the Task is retrieved, as if it didn't exist getTask := func(ctx context.Context, name string) (*v1.Task, *v1.RefSource, *trustedresources.VerificationResult, error) { @@ -2518,7 +2534,8 @@ func TestResolvePipelineRun_VerificationFailed(t *testing.T) { Name: "bar", Value: *v1.NewStructuredValues("b", "a", "r"), }}, - }}} + }, + }} verificationResult := &trustedresources.VerificationResult{VerificationResultType: trustedresources.VerificationError, Err: trustedresources.ErrResourceVerificationFailed} getTask := func(ctx context.Context, name string) (*v1.Task, *v1.RefSource, *trustedresources.VerificationResult, error) { return task, nil, verificationResult, nil @@ -2537,6 +2554,71 @@ func TestResolvePipelineRun_VerificationFailed(t *testing.T) { } } +func TestResolvePipelineRun_MismatchedTaskRunUID(t *testing.T) { + names.TestingSeed() + + p := &v1.Pipeline{ + ObjectMeta: metav1.ObjectMeta{Name: "pipelines"}, + Spec: v1.PipelineSpec{ + Tasks: []v1.PipelineTask{ + { + Name: "mytask1", + TaskSpec: &v1.EmbeddedTask{ + TaskSpec: v1.TaskSpec{ + Steps: []v1.Step{{Name: "step1"}}, + }, + }, + }, + }, + }, + } + + pr := v1.PipelineRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pipelinerun", + }, + Status: v1.PipelineRunStatus{ + PipelineRunStatusFields: v1.PipelineRunStatusFields{ + ChildReferences: []v1.ChildStatusReference{{ + TypeMeta: runtime.TypeMeta{ + APIVersion: v1.SchemeGroupVersion.Version, + Kind: "TaskRun", + }, + Name: "mytask1-1", + PipelineTaskName: "mytask1", + UID: "11111111-1111-1111-1111-111111111111", + }}, + }, + }, + } + // The Task "task" doesn't actually take any inputs or outputs, but validating + // that is not done as part of Run resolution + getTask := func(ctx context.Context, name string) (*v1.Task, *v1.RefSource, *trustedresources.VerificationResult, error) { + return nil, nil, nil, nil + } + getTaskRun := func(name string) (*v1.TaskRun, error) { + return parse.MustParseV1TaskRun(t, ` +metadata: + name: mytask1-1 + uid: 22222222-2222-2222-2222-222222222222 +spec: + steps: + - name: mystep + image: myimage +`), nil + } + + _, err := ResolvePipelineTask(context.Background(), pr, getTask, getTaskRun, nopGetCustomRun, p.Spec.Tasks[0], nil) + if err == nil { + t.Fatalf("Expected error getting tasks for fake pipeline %s, but did not get one", p.ObjectMeta.Name) + } + + expectedErrStr := "mismatched UID for TaskRun mytask1-1; expected 11111111-1111-1111-1111-111111111111, found 22222222-2222-2222-2222-222222222222" + if err.Error() != expectedErrStr { + t.Fatalf("Expected error %s, but got %s", expectedErrStr, err.Error()) + } +} + func TestValidateWorkspaceBindingsWithValidWorkspaces(t *testing.T) { for _, tc := range []struct { name string @@ -2984,7 +3066,8 @@ func TestResolvedPipelineRunTask_IsFinallySkipped(t *testing.T) { Params: v1.Params{{ Name: "platform", Value: v1.ParamValue{Type: v1.ParamTypeArray, ArrayVal: []string{}}, - }}}, + }}, + }, }, }} @@ -3206,7 +3289,8 @@ func TestResolvedPipelineRunTask_IsFinallySkippedByCondition(t *testing.T) { }, }, }, - }}, + }, + }, want: TaskSkipStatus{ IsSkipped: false, SkippingReason: v1.None, @@ -3271,23 +3355,24 @@ func TestResolvedPipelineRunTask_IsFinalTask(t *testing.T) { }, } - state := PipelineRunState{{ - TaskRunNames: []string{"dag-task"}, - TaskRuns: []*v1.TaskRun{tr}, - PipelineTask: &v1.PipelineTask{ - Name: "dag-task", - TaskRef: &v1.TaskRef{Name: "task"}, - }, - }, { - PipelineTask: &v1.PipelineTask{ - Name: "final-task", - TaskRef: &v1.TaskRef{Name: "task"}, - Params: v1.Params{{ - Name: "commit", - Value: *v1.NewStructuredValues("$(tasks.dag-task.results.commit)"), - }}, + state := PipelineRunState{ + { + TaskRunNames: []string{"dag-task"}, + TaskRuns: []*v1.TaskRun{tr}, + PipelineTask: &v1.PipelineTask{ + Name: "dag-task", + TaskRef: &v1.TaskRef{Name: "task"}, + }, + }, { + PipelineTask: &v1.PipelineTask{ + Name: "final-task", + TaskRef: &v1.TaskRef{Name: "task"}, + Params: v1.Params{{ + Name: "commit", + Value: *v1.NewStructuredValues("$(tasks.dag-task.results.commit)"), + }}, + }, }, - }, } tasks := v1.PipelineTaskList([]v1.PipelineTask{*state[0].PipelineTask}) @@ -3575,7 +3660,8 @@ func TestIsMatrixed(t *testing.T) { Params: v1.Params{{ Name: "platform", Value: v1.ParamValue{Type: v1.ParamTypeArray, ArrayVal: []string{"linux", "mac", "windows"}}, - }}}, + }}, + }, }, want: true, }, { @@ -3597,7 +3683,8 @@ func TestIsMatrixed(t *testing.T) { Params: v1.Params{{ Name: "platform", Value: v1.ParamValue{Type: v1.ParamTypeArray, ArrayVal: []string{"linux", "mac", "windows"}}, - }}}, + }}, + }, }, want: true, }, { @@ -3665,7 +3752,8 @@ func TestResolvePipelineRunTask_WithMatrix(t *testing.T) { Params: v1.Params{{ Name: "platform", Value: v1.ParamValue{Type: v1.ParamTypeArray, ArrayVal: []string{"linux", "mac", "windows"}}, - }}}, + }}, + }, }, { Name: "pipelinetask", TaskRef: &v1.TaskRef{ @@ -3699,7 +3787,7 @@ func TestResolvePipelineRunTask_WithMatrix(t *testing.T) { }}}, } - var pipelineRunState = PipelineRunState{{ + pipelineRunState := PipelineRunState{{ TaskRunNames: []string{"get-platforms"}, TaskRuns: []*v1.TaskRun{{ ObjectMeta: metav1.ObjectMeta{ @@ -3824,7 +3912,8 @@ func TestResolvePipelineRunTask_WithMatrixedCustomTask(t *testing.T) { Params: v1.Params{{ Name: "platform", Value: v1.ParamValue{Type: v1.ParamTypeArray, ArrayVal: []string{"linux", "mac", "windows"}}, - }}}, + }}, + }, }, { Name: "pipelinetask", TaskRef: &v1.TaskRef{ @@ -3839,7 +3928,8 @@ func TestResolvePipelineRunTask_WithMatrixedCustomTask(t *testing.T) { }, { Name: "browsers", Value: v1.ParamValue{Type: v1.ParamTypeArray, ArrayVal: []string{"chrome", "safari", "firefox"}}, - }}}, + }}, + }, }, { Name: "customTask-with-whole-array-results", TaskRef: &v1.TaskRef{APIVersion: "example.dev/v0", Kind: "Example", Name: "aTask"}, @@ -3849,7 +3939,7 @@ func TestResolvePipelineRunTask_WithMatrixedCustomTask(t *testing.T) { }}, }} - var pipelineRunState = PipelineRunState{{ + pipelineRunState := PipelineRunState{{ TaskRunNames: []string{"get-platforms"}, TaskRuns: []*v1.TaskRun{{ ObjectMeta: metav1.ObjectMeta{ @@ -4997,25 +5087,26 @@ func TestEvaluateCEL_invalid(t *testing.T) { for _, tc := range []struct { name string rpt *ResolvedPipelineTask - }{{ - name: "compile error - token unrecogniezd", - rpt: &ResolvedPipelineTask{ - PipelineTask: &v1.PipelineTask{ - When: v1.WhenExpressions{{ - CEL: "$(params.foo)=='foo'", - }}, + }{ + { + name: "compile error - token unrecogniezd", + rpt: &ResolvedPipelineTask{ + PipelineTask: &v1.PipelineTask{ + When: v1.WhenExpressions{{ + CEL: "$(params.foo)=='foo'", + }}, + }, }, - }, - }, { - name: "CEL result is not true or false", - rpt: &ResolvedPipelineTask{ - PipelineTask: &v1.PipelineTask{ - When: v1.WhenExpressions{{ - CEL: "{'blue': '0x000080', 'red': '0xFF0000'}['red']", - }}, + }, { + name: "CEL result is not true or false", + rpt: &ResolvedPipelineTask{ + PipelineTask: &v1.PipelineTask{ + When: v1.WhenExpressions{{ + CEL: "{'blue': '0x000080', 'red': '0xFF0000'}['red']", + }}, + }, }, }, - }, } { t.Run(tc.name, func(t *testing.T) { err := tc.rpt.EvaluateCEL()