diff --git a/pkg/internal/defaultresourcerequirements/transformer.go b/pkg/internal/defaultresourcerequirements/transformer.go new file mode 100644 index 00000000000..69af7f842d1 --- /dev/null +++ b/pkg/internal/defaultresourcerequirements/transformer.go @@ -0,0 +1,130 @@ +/* +Copyright 2024 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package defaultresourcerequirements + +import ( + "context" + "strings" + + "github.com/tektoncd/pipeline/pkg/apis/config" + "github.com/tektoncd/pipeline/pkg/pod" + corev1 "k8s.io/api/core/v1" +) + +// NewTransformer returns a pod.Transformer that will modify container resources if needed +func NewTransformer(ctx context.Context) pod.Transformer { + // update init container and containers resource requirements + // resource limits and requests values are taken from a config map + configDefaults := config.FromContextOrDefaults(ctx).Defaults + return func(pod *corev1.Pod) (*corev1.Pod, error) { + return updateResourceRequirements(configDefaults.DefaultContainerResourceRequirements, pod), nil + } +} + +// updates init containers and containers resource requirements of a pod base of config_defaults configmap. +func updateResourceRequirements(resourceRequirementsMap map[string]corev1.ResourceRequirements, pod *corev1.Pod) *corev1.Pod { + if len(resourceRequirementsMap) == 0 { + return pod + } + + // collect all the available container names from the resource requirement map + // some of the container names: place-scripts, prepare, working-dir-initializer + // some of the container names with prefix: prefix-scripts, prefix-sidecar-scripts + containerNames := []string{} + containerNamesWithPrefix := []string{} + for containerName := range resourceRequirementsMap { + // skip the default key + if containerName == config.ResourceRequirementDefaultContainerKey { + continue + } + + if strings.HasPrefix(containerName, "prefix-") { + containerNamesWithPrefix = append(containerNamesWithPrefix, containerName) + } else { + containerNames = append(containerNames, containerName) + } + } + + // update the containers resource requirements which does not have resource requirements + for _, containerName := range containerNames { + resourceRequirements := resourceRequirementsMap[containerName] + if resourceRequirements.Size() == 0 { + continue + } + + // update init containers + for index := range pod.Spec.InitContainers { + targetContainer := pod.Spec.InitContainers[index] + if containerName == targetContainer.Name && targetContainer.Resources.Size() == 0 { + pod.Spec.InitContainers[index].Resources = resourceRequirements + } + } + // update containers + for index := range pod.Spec.Containers { + targetContainer := pod.Spec.Containers[index] + if containerName == targetContainer.Name && targetContainer.Resources.Size() == 0 { + pod.Spec.Containers[index].Resources = resourceRequirements + } + } + } + + // update the containers resource requirements which does not have resource requirements with the mentioned prefix + for _, containerPrefix := range containerNamesWithPrefix { + resourceRequirements := resourceRequirementsMap[containerPrefix] + if resourceRequirements.Size() == 0 { + continue + } + + // get actual container name, remove "prefix-" string and append "-" at the end + // append '-' in the container prefix + containerPrefix = strings.Replace(containerPrefix, "prefix-", "", 1) + containerPrefix += "-" + + // update init containers + for index := range pod.Spec.InitContainers { + targetContainer := pod.Spec.InitContainers[index] + if strings.HasPrefix(targetContainer.Name, containerPrefix) && targetContainer.Resources.Size() == 0 { + pod.Spec.InitContainers[index].Resources = resourceRequirements + } + } + // update containers + for index := range pod.Spec.Containers { + targetContainer := pod.Spec.Containers[index] + if strings.HasPrefix(targetContainer.Name, containerPrefix) && targetContainer.Resources.Size() == 0 { + pod.Spec.Containers[index].Resources = resourceRequirements + } + } + } + + // reset of the containers resource requirements which has empty resource requirements + if resourceRequirements, found := resourceRequirementsMap[config.ResourceRequirementDefaultContainerKey]; found && resourceRequirements.Size() != 0 { + // update init containers + for index := range pod.Spec.InitContainers { + if pod.Spec.InitContainers[index].Resources.Size() == 0 { + pod.Spec.InitContainers[index].Resources = resourceRequirements + } + } + // update containers + for index := range pod.Spec.Containers { + if pod.Spec.Containers[index].Resources.Size() == 0 { + pod.Spec.Containers[index].Resources = resourceRequirements + } + } + } + + return pod +} diff --git a/pkg/internal/defaultresourcerequirements/transformer_test.go b/pkg/internal/defaultresourcerequirements/transformer_test.go new file mode 100644 index 00000000000..6febc92e63c --- /dev/null +++ b/pkg/internal/defaultresourcerequirements/transformer_test.go @@ -0,0 +1,416 @@ +/* +Copyright 2024 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package defaultresourcerequirements + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/tektoncd/pipeline/pkg/apis/config" + "github.com/tektoncd/pipeline/test/diff" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestNewTransformer(t *testing.T) { + testPod := &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{Name: "test-pod", Namespace: "custom-ns"}, + Spec: corev1.PodSpec{ + InitContainers: []corev1.Container{ + {Name: "place-scripts"}, + {Name: "prepare"}, + {Name: "working-dir-initializer"}, + {Name: "test-01"}, + {Name: "foo"}, + }, + Containers: []corev1.Container{ + {Name: "scripts-01"}, + {Name: "scripts-02"}, + {Name: "sidecar-scripts-01"}, + {Name: "sidecar-scripts-02"}, + {Name: "test-01"}, + {Name: "foo"}, + }, + }, + } + + tcs := []struct { + name string + targetPod *corev1.Pod + resourceRequirements map[string]corev1.ResourceRequirements + getExpectedPod func() *corev1.Pod + }{ + // verifies with no resource requirements data from a config map + { + name: "test-with-no-data", + targetPod: testPod.DeepCopy(), + resourceRequirements: map[string]corev1.ResourceRequirements{}, + getExpectedPod: func() *corev1.Pod { + return testPod.DeepCopy() + }, + }, + + // verifies with empty resource requirements data from a config map + { + name: "test-with-empty-resource-requirements", + targetPod: testPod.DeepCopy(), + resourceRequirements: map[string]corev1.ResourceRequirements{ + "default": {}, + "place-scripts": {}, + "prefix-scripts": {}, + }, + getExpectedPod: func() *corev1.Pod { + return testPod.DeepCopy() + }, + }, + + // verifies only with 'default' resource requirements data from a config map + { + name: "test-with-default-set", + targetPod: testPod.DeepCopy(), + resourceRequirements: map[string]corev1.ResourceRequirements{ + "default": { + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + }, + }, + getExpectedPod: func() *corev1.Pod { + expectedPod := testPod.DeepCopy() + defaultResource := corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + } + expectedPod.Spec = corev1.PodSpec{ + InitContainers: []corev1.Container{ + {Name: "place-scripts", Resources: defaultResource}, + {Name: "prepare", Resources: defaultResource}, + {Name: "working-dir-initializer", Resources: defaultResource}, + {Name: "test-01", Resources: defaultResource}, + {Name: "foo", Resources: defaultResource}, + }, + Containers: []corev1.Container{ + {Name: "scripts-01", Resources: defaultResource}, + {Name: "scripts-02", Resources: defaultResource}, + {Name: "sidecar-scripts-01", Resources: defaultResource}, + {Name: "sidecar-scripts-02", Resources: defaultResource}, + {Name: "test-01", Resources: defaultResource}, + {Name: "foo", Resources: defaultResource}, + }, + } + return expectedPod + }, + }, + + // verifies only with 'place-scripts' resource requirements data from a config map + { + name: "test-with-place-scripts-set", + targetPod: testPod.DeepCopy(), + resourceRequirements: map[string]corev1.ResourceRequirements{ + "place-scripts": { + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("128Mi"), + corev1.ResourceCPU: resource.MustParse("200m"), + }, + }, + }, + getExpectedPod: func() *corev1.Pod { + expectedPod := testPod.DeepCopy() + expectedPod.Spec.InitContainers = []corev1.Container{ + { + Name: "place-scripts", + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("128Mi"), + corev1.ResourceCPU: resource.MustParse("200m"), + }, + }, + }, + {Name: "prepare"}, + {Name: "working-dir-initializer"}, + {Name: "test-01"}, + {Name: "foo"}, + } + return expectedPod + }, + }, + + // verifies only with 'prefix-scripts' resource requirements data from a config map + { + name: "test-with-prefix-scripts-set", + targetPod: testPod.DeepCopy(), + resourceRequirements: map[string]corev1.ResourceRequirements{ + "prefix-scripts": { + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("128Mi"), + corev1.ResourceCPU: resource.MustParse("200m"), + }, + }, + }, + getExpectedPod: func() *corev1.Pod { + expectedPod := testPod.DeepCopy() + prefixScripts := corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("128Mi"), + corev1.ResourceCPU: resource.MustParse("200m"), + }, + } + expectedPod.Spec.Containers = []corev1.Container{ + {Name: "scripts-01", Resources: prefixScripts}, + {Name: "scripts-02", Resources: prefixScripts}, + {Name: "sidecar-scripts-01"}, + {Name: "sidecar-scripts-02"}, + {Name: "test-01"}, + {Name: "foo"}, + } + return expectedPod + }, + }, + + // verifies with 'working-dir-initializer', 'prefix-sidecar-scripts', and 'default' resource requirements data from a config map + { + name: "test-with_name_prefix_and_default-set", + targetPod: testPod.DeepCopy(), + resourceRequirements: map[string]corev1.ResourceRequirements{ + "working-dir-initializer": { + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("400m"), + corev1.ResourceMemory: resource.MustParse("512Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("256Mi"), + corev1.ResourceCPU: resource.MustParse("250m"), + }, + }, + "prefix-sidecar-scripts": { + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("1"), + corev1.ResourceMemory: resource.MustParse("1Gi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("512Mi"), + corev1.ResourceCPU: resource.MustParse("500m"), + }, + }, + "default": { + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + }, + "prefix-test": { + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("100m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + }, + "foo": { + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("200m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + }, + }, + getExpectedPod: func() *corev1.Pod { + expectedPod := testPod.DeepCopy() + workDirResourceReqs := corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("400m"), + corev1.ResourceMemory: resource.MustParse("512Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("256Mi"), + corev1.ResourceCPU: resource.MustParse("250m"), + }, + } + sideCarResourceReqs := corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("1"), + corev1.ResourceMemory: resource.MustParse("1Gi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("512Mi"), + corev1.ResourceCPU: resource.MustParse("500m"), + }, + } + defaultResourceReqs := corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + } + + testResourceReqs := corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("100m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + } + fooResourceReqs := corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("200m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + } + + expectedPod.Spec = corev1.PodSpec{ + InitContainers: []corev1.Container{ + {Name: "place-scripts", Resources: defaultResourceReqs}, + {Name: "prepare", Resources: defaultResourceReqs}, + {Name: "working-dir-initializer", Resources: workDirResourceReqs}, + {Name: "test-01", Resources: testResourceReqs}, + {Name: "foo", Resources: fooResourceReqs}, + }, + Containers: []corev1.Container{ + {Name: "scripts-01", Resources: defaultResourceReqs}, + {Name: "scripts-02", Resources: defaultResourceReqs}, + {Name: "sidecar-scripts-01", Resources: sideCarResourceReqs}, + {Name: "sidecar-scripts-02", Resources: sideCarResourceReqs}, + {Name: "test-01", Resources: testResourceReqs}, + {Name: "foo", Resources: fooResourceReqs}, + }, + } + return expectedPod + }, + }, + + // verifies with existing data + { + name: "test-with-existing-data", + targetPod: &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{Name: "test-pod", Namespace: "custom-ns"}, + Spec: corev1.PodSpec{ + InitContainers: []corev1.Container{ + {Name: "place-scripts"}, + {Name: "prepare", Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + }}, + {Name: "working-dir-initializer"}, + }, + Containers: []corev1.Container{ + {Name: "scripts-01"}, + {Name: "scripts-02"}, + {Name: "sidecar-scripts-01"}, + {Name: "sidecar-scripts-02"}, + }, + }, + }, + resourceRequirements: map[string]corev1.ResourceRequirements{ + "prepare": { + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("1"), + corev1.ResourceMemory: resource.MustParse("512Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + }, + }, + }, + getExpectedPod: func() *corev1.Pod { + expectedPod := &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{Name: "test-pod", Namespace: "custom-ns"}, + Spec: corev1.PodSpec{ + InitContainers: []corev1.Container{ + {Name: "place-scripts"}, + {Name: "prepare", Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + }}, + {Name: "working-dir-initializer"}, + }, + Containers: []corev1.Container{ + {Name: "scripts-01"}, + {Name: "scripts-02"}, + {Name: "sidecar-scripts-01"}, + {Name: "sidecar-scripts-02"}, + }, + }, + } + return expectedPod + }, + }, + } + + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + ctx := context.Background() + // add default container resource requirements on the context + ctx = config.ToContext(ctx, &config.Config{ + Defaults: &config.Defaults{ + DefaultContainerResourceRequirements: tc.resourceRequirements, + }, + }) + + // get the transformer and call the transformer + transformer := NewTransformer(ctx) + transformedPod, err := transformer(tc.targetPod) + if err != nil { + t.Errorf("unexpected error %s", err) + } + + expectedPod := tc.getExpectedPod() + if d := cmp.Diff(expectedPod, transformedPod); d != "" { + t.Errorf("Diff %s", diff.PrintWantGot(d)) + } + }) + } +} diff --git a/pkg/pod/pod.go b/pkg/pod/pod.go index fc0db922d8a..95161166728 100644 --- a/pkg/pod/pod.go +++ b/pkg/pod/pod.go @@ -544,106 +544,9 @@ func (b *Builder) Build(ctx context.Context, taskRun *v1.TaskRun, taskSpec v1.Ta } } - // update init container and containers resource requirements - // resource limits values are taken from a config map - configDefaults := config.FromContextOrDefaults(ctx).Defaults - updateResourceRequirements(configDefaults.DefaultContainerResourceRequirements, newPod) - return newPod, nil } -// updates init containers and containers resource requirements of a pod base of config_defaults configmap. -func updateResourceRequirements(resourceRequirementsMap map[string]corev1.ResourceRequirements, pod *corev1.Pod) { - if len(resourceRequirementsMap) == 0 { - return - } - - // collect all the available container names from the resource requirement map - // some of the container names: place-scripts, prepare, working-dir-initializer - // some of the container names with prefix: prefix-scripts, prefix-sidecar-scripts - containerNames := []string{} - containerNamesWithPrefix := []string{} - for containerName := range resourceRequirementsMap { - // skip the default key - if containerName == config.ResourceRequirementDefaultContainerKey { - continue - } - - if strings.HasPrefix(containerName, "prefix-") { - containerNamesWithPrefix = append(containerNamesWithPrefix, containerName) - } else { - containerNames = append(containerNames, containerName) - } - } - - // update the containers resource requirements which does not have resource requirements - for _, containerName := range containerNames { - resourceRequirements := resourceRequirementsMap[containerName] - if resourceRequirements.Size() == 0 { - continue - } - - // update init containers - for index := range pod.Spec.InitContainers { - targetContainer := pod.Spec.InitContainers[index] - if containerName == targetContainer.Name && targetContainer.Resources.Size() == 0 { - pod.Spec.InitContainers[index].Resources = resourceRequirements - } - } - // update containers - for index := range pod.Spec.Containers { - targetContainer := pod.Spec.Containers[index] - if containerName == targetContainer.Name && targetContainer.Resources.Size() == 0 { - pod.Spec.Containers[index].Resources = resourceRequirements - } - } - } - - // update the containers resource requirements which does not have resource requirements with the mentioned prefix - for _, containerPrefix := range containerNamesWithPrefix { - resourceRequirements := resourceRequirementsMap[containerPrefix] - if resourceRequirements.Size() == 0 { - continue - } - - // get actual container name, remove "prefix-" string and append "-" at the end - // append '-' in the container prefix - containerPrefix = strings.Replace(containerPrefix, "prefix-", "", 1) - containerPrefix += "-" - - // update init containers - for index := range pod.Spec.InitContainers { - targetContainer := pod.Spec.InitContainers[index] - if strings.HasPrefix(targetContainer.Name, containerPrefix) && targetContainer.Resources.Size() == 0 { - pod.Spec.InitContainers[index].Resources = resourceRequirements - } - } - // update containers - for index := range pod.Spec.Containers { - targetContainer := pod.Spec.Containers[index] - if strings.HasPrefix(targetContainer.Name, containerPrefix) && targetContainer.Resources.Size() == 0 { - pod.Spec.Containers[index].Resources = resourceRequirements - } - } - } - - // reset of the containers resource requirements which has empty resource requirements - if resourceRequirements, found := resourceRequirementsMap[config.ResourceRequirementDefaultContainerKey]; found && resourceRequirements.Size() != 0 { - // update init containers - for index := range pod.Spec.InitContainers { - if pod.Spec.InitContainers[index].Resources.Size() == 0 { - pod.Spec.InitContainers[index].Resources = resourceRequirements - } - } - // update containers - for index := range pod.Spec.Containers { - if pod.Spec.Containers[index].Resources.Size() == 0 { - pod.Spec.Containers[index].Resources = resourceRequirements - } - } - } -} - // makeLabels constructs the labels we will propagate from TaskRuns to Pods. func makeLabels(s *v1.TaskRun) map[string]string { labels := make(map[string]string, len(s.ObjectMeta.Labels)+1) diff --git a/pkg/pod/pod_test.go b/pkg/pod/pod_test.go index 8eb65ae5e60..be976634ac2 100644 --- a/pkg/pod/pod_test.go +++ b/pkg/pod/pod_test.go @@ -3501,381 +3501,6 @@ func TestUsesWindows(t *testing.T) { } } -func TestUpdateResourceRequirements(t *testing.T) { - testPod := &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "test-pod", Namespace: "custom-ns"}, - Spec: corev1.PodSpec{ - InitContainers: []corev1.Container{ - {Name: "place-scripts"}, - {Name: "prepare"}, - {Name: "working-dir-initializer"}, - {Name: "test-01"}, - {Name: "foo"}, - }, - Containers: []corev1.Container{ - {Name: "scripts-01"}, - {Name: "scripts-02"}, - {Name: "sidecar-scripts-01"}, - {Name: "sidecar-scripts-02"}, - {Name: "test-01"}, - {Name: "foo"}, - }, - }, - } - - tcs := []struct { - name string - targetPod *corev1.Pod - resourceRequirements map[string]corev1.ResourceRequirements - getExpectedPod func() *corev1.Pod - }{ - // verifies with no resource requirements data from a config map - { - name: "test-with-no-data", - targetPod: testPod.DeepCopy(), - resourceRequirements: map[string]corev1.ResourceRequirements{}, - getExpectedPod: func() *corev1.Pod { - return testPod.DeepCopy() - }, - }, - - // verifies with empty resource requirements data from a config map - { - name: "test-with-empty-resource-requirements", - targetPod: testPod.DeepCopy(), - resourceRequirements: map[string]corev1.ResourceRequirements{ - "default": {}, - "place-scripts": {}, - "prefix-scripts": {}, - }, - getExpectedPod: func() *corev1.Pod { - return testPod.DeepCopy() - }, - }, - - // verifies only with 'default' resource requirements data from a config map - { - name: "test-with-default-set", - targetPod: testPod.DeepCopy(), - resourceRequirements: map[string]corev1.ResourceRequirements{ - "default": { - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resource.MustParse("128Mi"), - }, - }, - }, - getExpectedPod: func() *corev1.Pod { - expectedPod := testPod.DeepCopy() - defaultResource := corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resource.MustParse("128Mi"), - }, - } - expectedPod.Spec = corev1.PodSpec{ - InitContainers: []corev1.Container{ - {Name: "place-scripts", Resources: defaultResource}, - {Name: "prepare", Resources: defaultResource}, - {Name: "working-dir-initializer", Resources: defaultResource}, - {Name: "test-01", Resources: defaultResource}, - {Name: "foo", Resources: defaultResource}, - }, - Containers: []corev1.Container{ - {Name: "scripts-01", Resources: defaultResource}, - {Name: "scripts-02", Resources: defaultResource}, - {Name: "sidecar-scripts-01", Resources: defaultResource}, - {Name: "sidecar-scripts-02", Resources: defaultResource}, - {Name: "test-01", Resources: defaultResource}, - {Name: "foo", Resources: defaultResource}, - }, - } - return expectedPod - }, - }, - - // verifies only with 'place-scripts' resource requirements data from a config map - { - name: "test-with-place-scripts-set", - targetPod: testPod.DeepCopy(), - resourceRequirements: map[string]corev1.ResourceRequirements{ - "place-scripts": { - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resource.MustParse("128Mi"), - corev1.ResourceCPU: resource.MustParse("200m"), - }, - }, - }, - getExpectedPod: func() *corev1.Pod { - expectedPod := testPod.DeepCopy() - expectedPod.Spec.InitContainers = []corev1.Container{ - { - Name: "place-scripts", - Resources: corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resource.MustParse("128Mi"), - corev1.ResourceCPU: resource.MustParse("200m"), - }, - }, - }, - {Name: "prepare"}, - {Name: "working-dir-initializer"}, - {Name: "test-01"}, - {Name: "foo"}, - } - return expectedPod - }, - }, - - // verifies only with 'prefix-scripts' resource requirements data from a config map - { - name: "test-with-prefix-scripts-set", - targetPod: testPod.DeepCopy(), - resourceRequirements: map[string]corev1.ResourceRequirements{ - "prefix-scripts": { - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resource.MustParse("128Mi"), - corev1.ResourceCPU: resource.MustParse("200m"), - }, - }, - }, - getExpectedPod: func() *corev1.Pod { - expectedPod := testPod.DeepCopy() - prefixScripts := corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resource.MustParse("128Mi"), - corev1.ResourceCPU: resource.MustParse("200m"), - }, - } - expectedPod.Spec.Containers = []corev1.Container{ - {Name: "scripts-01", Resources: prefixScripts}, - {Name: "scripts-02", Resources: prefixScripts}, - {Name: "sidecar-scripts-01"}, - {Name: "sidecar-scripts-02"}, - {Name: "test-01"}, - {Name: "foo"}, - } - return expectedPod - }, - }, - - // verifies with 'working-dir-initializer', 'prefix-sidecar-scripts', and 'default' resource requirements data from a config map - { - name: "test-with_name_prefix_and_default-set", - targetPod: testPod.DeepCopy(), - resourceRequirements: map[string]corev1.ResourceRequirements{ - "working-dir-initializer": { - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("400m"), - corev1.ResourceMemory: resource.MustParse("512Mi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resource.MustParse("256Mi"), - corev1.ResourceCPU: resource.MustParse("250m"), - }, - }, - "prefix-sidecar-scripts": { - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("1"), - corev1.ResourceMemory: resource.MustParse("1Gi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resource.MustParse("512Mi"), - corev1.ResourceCPU: resource.MustParse("500m"), - }, - }, - "default": { - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resource.MustParse("128Mi"), - }, - }, - "prefix-test": { - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("100m"), - corev1.ResourceMemory: resource.MustParse("32Mi"), - }, - }, - "foo": { - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("200m"), - corev1.ResourceMemory: resource.MustParse("64Mi"), - }, - }, - }, - getExpectedPod: func() *corev1.Pod { - expectedPod := testPod.DeepCopy() - workDirResourceReqs := corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("400m"), - corev1.ResourceMemory: resource.MustParse("512Mi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resource.MustParse("256Mi"), - corev1.ResourceCPU: resource.MustParse("250m"), - }, - } - sideCarResourceReqs := corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("1"), - corev1.ResourceMemory: resource.MustParse("1Gi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resource.MustParse("512Mi"), - corev1.ResourceCPU: resource.MustParse("500m"), - }, - } - defaultResourceReqs := corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resource.MustParse("128Mi"), - }, - } - - testResourceReqs := corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("100m"), - corev1.ResourceMemory: resource.MustParse("32Mi"), - }, - } - fooResourceReqs := corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("200m"), - corev1.ResourceMemory: resource.MustParse("64Mi"), - }, - } - - expectedPod.Spec = corev1.PodSpec{ - InitContainers: []corev1.Container{ - {Name: "place-scripts", Resources: defaultResourceReqs}, - {Name: "prepare", Resources: defaultResourceReqs}, - {Name: "working-dir-initializer", Resources: workDirResourceReqs}, - {Name: "test-01", Resources: testResourceReqs}, - {Name: "foo", Resources: fooResourceReqs}, - }, - Containers: []corev1.Container{ - {Name: "scripts-01", Resources: defaultResourceReqs}, - {Name: "scripts-02", Resources: defaultResourceReqs}, - {Name: "sidecar-scripts-01", Resources: sideCarResourceReqs}, - {Name: "sidecar-scripts-02", Resources: sideCarResourceReqs}, - {Name: "test-01", Resources: testResourceReqs}, - {Name: "foo", Resources: fooResourceReqs}, - }, - } - return expectedPod - }, - }, - - // verifies with existing data - { - name: "test-with-existing-data", - targetPod: &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "test-pod", Namespace: "custom-ns"}, - Spec: corev1.PodSpec{ - InitContainers: []corev1.Container{ - {Name: "place-scripts"}, - {Name: "prepare", Resources: corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resource.MustParse("128Mi"), - }, - }}, - {Name: "working-dir-initializer"}, - }, - Containers: []corev1.Container{ - {Name: "scripts-01"}, - {Name: "scripts-02"}, - {Name: "sidecar-scripts-01"}, - {Name: "sidecar-scripts-02"}, - }, - }, - }, - resourceRequirements: map[string]corev1.ResourceRequirements{ - "prepare": { - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("1"), - corev1.ResourceMemory: resource.MustParse("512Mi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), - }, - }, - }, - getExpectedPod: func() *corev1.Pod { - expectedPod := &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "test-pod", Namespace: "custom-ns"}, - Spec: corev1.PodSpec{ - InitContainers: []corev1.Container{ - {Name: "place-scripts"}, - {Name: "prepare", Resources: corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resource.MustParse("128Mi"), - }, - }}, - {Name: "working-dir-initializer"}, - }, - Containers: []corev1.Container{ - {Name: "scripts-01"}, - {Name: "scripts-02"}, - {Name: "sidecar-scripts-01"}, - {Name: "sidecar-scripts-02"}, - }, - }, - } - return expectedPod - }, - }, - } - - for _, tc := range tcs { - t.Run(tc.name, func(t *testing.T) { - targetPod := tc.targetPod - updateResourceRequirements(tc.resourceRequirements, targetPod) - - expectedPod := tc.getExpectedPod() - if d := cmp.Diff(expectedPod, targetPod); d != "" { - t.Errorf("Diff %s", diff.PrintWantGot(d)) - } - }) - } -} - func Test_artifactsPathReferenced(t *testing.T) { tests := []struct { name string diff --git a/pkg/reconciler/taskrun/taskrun.go b/pkg/reconciler/taskrun/taskrun.go index 4fef3109571..df19b6df51d 100644 --- a/pkg/reconciler/taskrun/taskrun.go +++ b/pkg/reconciler/taskrun/taskrun.go @@ -39,6 +39,7 @@ import ( alphalisters "github.com/tektoncd/pipeline/pkg/client/listers/pipeline/v1alpha1" "github.com/tektoncd/pipeline/pkg/internal/affinityassistant" "github.com/tektoncd/pipeline/pkg/internal/computeresources" + "github.com/tektoncd/pipeline/pkg/internal/defaultresourcerequirements" resolutionutil "github.com/tektoncd/pipeline/pkg/internal/resolution" podconvert "github.com/tektoncd/pipeline/pkg/pod" tknreconciler "github.com/tektoncd/pipeline/pkg/reconciler" @@ -896,6 +897,7 @@ func (c *Reconciler) createPod(ctx context.Context, ts *v1.TaskSpec, tr *v1.Task EntrypointCache: c.entrypointCache, } pod, err := podbuilder.Build(ctx, tr, *ts, + defaultresourcerequirements.NewTransformer(ctx), computeresources.NewTransformer(ctx, tr.Namespace, c.limitrangeLister), affinityassistant.NewTransformer(ctx, tr.Annotations), )