From 99bb035bbae6c24e3656692ca62ab5e29904ad16 Mon Sep 17 00:00:00 2001 From: Austin Zhao Date: Tue, 26 Jul 2022 10:14:30 -0400 Subject: [PATCH] [TEP-0104] Populate Task-level Resource Requirements from Pipeline- Run to TaskRun Task-level resource requirements will be populated from PipelineRun to the created TaskRun and applied on the related Pod. --- .../pipeline/v1beta1/pipelinerun_types.go | 1 + pkg/reconciler/pipelinerun/pipelinerun.go | 1 + .../pipelinerun/pipelinerun_test.go | 152 ++++++++++++++++++ 3 files changed, 154 insertions(+) diff --git a/pkg/apis/pipeline/v1beta1/pipelinerun_types.go b/pkg/apis/pipeline/v1beta1/pipelinerun_types.go index 93500365c97..5024e54b5a3 100644 --- a/pkg/apis/pipeline/v1beta1/pipelinerun_types.go +++ b/pkg/apis/pipeline/v1beta1/pipelinerun_types.go @@ -542,6 +542,7 @@ func (pr *PipelineRun) GetTaskRunSpec(pipelineTaskName string) PipelineTaskRunSp s.StepOverrides = task.StepOverrides s.SidecarOverrides = task.SidecarOverrides s.Metadata = task.Metadata + s.ComputeResources = task.ComputeResources } } return s diff --git a/pkg/reconciler/pipelinerun/pipelinerun.go b/pkg/reconciler/pipelinerun/pipelinerun.go index 6ee83b10a20..fcbe245cb92 100644 --- a/pkg/reconciler/pipelinerun/pipelinerun.go +++ b/pkg/reconciler/pipelinerun/pipelinerun.go @@ -832,6 +832,7 @@ func (c *Reconciler) createTaskRun(ctx context.Context, taskRunName string, para PodTemplate: taskRunSpec.TaskPodTemplate, StepOverrides: taskRunSpec.StepOverrides, SidecarOverrides: taskRunSpec.SidecarOverrides, + ComputeResources: taskRunSpec.ComputeResources, }} if rpt.ResolvedTaskResources.TaskName != "" { diff --git a/pkg/reconciler/pipelinerun/pipelinerun_test.go b/pkg/reconciler/pipelinerun/pipelinerun_test.go index a43c7f3e4cc..5c39e0cb989 100644 --- a/pkg/reconciler/pipelinerun/pipelinerun_test.go +++ b/pkg/reconciler/pipelinerun/pipelinerun_test.go @@ -50,6 +50,7 @@ import ( "gomodules.xyz/jsonpatch/v2" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -9484,5 +9485,156 @@ spec: verifyTaskRunStatusesCount(t, embeddedStatus, reconciledRun.Status, 2) verifyTaskRunStatusesNames(t, embeddedStatus, reconciledRun.Status, tr1Name, tr2Name) +} + +func TestReconcile_CreateTaskRunWithComputeResources(t *testing.T) { + simplePipeline := parse.MustParsePipeline(t, ` +metadata: + name: foo-pipeline + namespace: default +spec: + tasks: + - name: 1st-task + taskSpec: + steps: + - name: 1st-step + image: foo-image + command: + - /foo-cmd + - name: 2nd-step + image: foo-image + command: + - /foo-cmd +`) + + testCases := []struct { + name string + pipeline *v1beta1.Pipeline + pipelineRun *v1beta1.PipelineRun + expectedComputeResources []corev1.ResourceRequirements + }{{ + name: "only with requests", + pipeline: simplePipeline, + pipelineRun: parse.MustParsePipelineRun(t, ` +metadata: + name: foo-pipeline-run + namespace: default +spec: + pipelineRef: + name: foo-pipeline + taskRunSpecs: + - pipelineTaskName: 1st-task + computeResources: + requests: + cpu: "500m" +`), + expectedComputeResources: []corev1.ResourceRequirements{{ + Requests: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("500m")}, + }}, + }, { + name: "only with limits", + pipeline: simplePipeline, + pipelineRun: parse.MustParsePipelineRun(t, ` +metadata: + name: foo-pipeline-run + namespace: default +spec: + pipelineRef: + name: foo-pipeline + taskRunSpecs: + - pipelineTaskName: 1st-task + computeResources: + limits: + cpu: "2" +`), + expectedComputeResources: []corev1.ResourceRequirements{{ + Limits: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("2")}, + }}, + }, { + name: "both with requests and limits", + pipeline: simplePipeline, + pipelineRun: parse.MustParsePipelineRun(t, ` +metadata: + name: foo-pipeline-run + namespace: default +spec: + pipelineRef: + name: foo-pipeline + taskRunSpecs: + - pipelineTaskName: 1st-task + computeResources: + requests: + cpu: "500m" + limits: + cpu: "2" +`), + expectedComputeResources: []corev1.ResourceRequirements{{ + Requests: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("500m")}, + Limits: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("2")}, + }}, + }, { + name: "both with cpu and memory", + pipeline: simplePipeline, + pipelineRun: parse.MustParsePipelineRun(t, ` +metadata: + name: foo-pipeline-run + namespace: default +spec: + pipelineRef: + name: foo-pipeline + taskRunSpecs: + - pipelineTaskName: 1st-task + computeResources: + requests: + cpu: "1" + memory: "1Gi" + limits: + cpu: "2" +`), + expectedComputeResources: []corev1.ResourceRequirements{{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("1"), + corev1.ResourceMemory: resource.MustParse("1Gi")}, + Limits: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("2")}, + }}, + }} + + // verifyTaskLevelComputeResources verifies that the created TaskRuns have the expected compute resources + verifyTaskLevelComputeResources := func(expectedComputeResources []corev1.ResourceRequirements, taskRuns []v1beta1.TaskRun) error { + if len(expectedComputeResources) != len(taskRuns) { + return fmt.Errorf("expected %d compute resource requirements, got %d", len(expectedComputeResources), len(taskRuns)) + } + for i, r := range expectedComputeResources { + if d := cmp.Diff(r, *taskRuns[i].Spec.ComputeResources); d != "" { + return fmt.Errorf("TaskRun #%d resource requirements don't match %s", i, diff.PrintWantGot(d)) + } + } + return nil + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + d := test.Data{ + PipelineRuns: []*v1beta1.PipelineRun{tc.pipelineRun}, + Pipelines: []*v1beta1.Pipeline{tc.pipeline}, + } + prt := newPipelineRunTest(d, t) + defer prt.Cancel() + + reconciledRun, clients := prt.reconcileRun("default", tc.pipelineRun.Name, []string{}, false) + + if reconciledRun.Status.CompletionTime != nil { + t.Errorf("Expected a CompletionTime on valid PipelineRun, but got nil") + } + + TaskRunList, err := clients.Pipeline.TektonV1beta1().TaskRuns("default").List(prt.TestAssets.Ctx, metav1.ListOptions{}) + if err != nil { + t.Fatalf("Failure to list TaskRun's %s", err) + } + + if err := verifyTaskLevelComputeResources(tc.expectedComputeResources, TaskRunList.Items); err != nil { + t.Errorf("TaskRun \"%s\" failed to verify task-level compute resource requirements, because: %v", tc.name, err) + } + }) + } }