From 472c5847940202cbd68717c3136193fd315bcdf0 Mon Sep 17 00:00:00 2001 From: "dom.bozzuto" Date: Wed, 27 Mar 2024 15:52:00 -0400 Subject: [PATCH] Use IETF-6901 encoding for resource patches Extended resources must be qualified by domain (e.g. example.com/dongle). The special '/' must be properly escaped the patch to be properly applied. --- .../resource/pod/patch/resource_updates.go | 6 +++- .../pod/patch/resource_updates_test.go | 28 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/vertical-pod-autoscaler/pkg/admission-controller/resource/pod/patch/resource_updates.go b/vertical-pod-autoscaler/pkg/admission-controller/resource/pod/patch/resource_updates.go index bed6119900ba..9e9769f6214f 100644 --- a/vertical-pod-autoscaler/pkg/admission-controller/resource/pod/patch/resource_updates.go +++ b/vertical-pod-autoscaler/pkg/admission-controller/resource/pod/patch/resource_updates.go @@ -26,6 +26,8 @@ import ( "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/admission-controller/resource/pod/recommendation" vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1" vpa_api_util "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/vpa" + + "github.com/go-openapi/jsonpointer" ) const ( @@ -105,9 +107,11 @@ func appendPatchesAndAnnotations(patches []resource_admission.PatchRecord, annot } func getAddResourceRequirementValuePatch(i int, kind string, resource core.ResourceName, quantity resource.Quantity) resource_admission.PatchRecord { + // Patch fields which can contain '/' characters (e.g. domain-qualified extended resources) must conform + // to IETF-6901 and escape those characters return resource_admission.PatchRecord{ Op: "add", - Path: fmt.Sprintf("/spec/containers/%d/resources/%s/%s", i, kind, resource), + Path: fmt.Sprintf("/spec/containers/%d/resources/%s/%s", i, kind, jsonpointer.Escape(resource.String())), Value: quantity.String()} } diff --git a/vertical-pod-autoscaler/pkg/admission-controller/resource/pod/patch/resource_updates_test.go b/vertical-pod-autoscaler/pkg/admission-controller/resource/pod/patch/resource_updates_test.go index 88f87636f5b3..68bf60d9c665 100644 --- a/vertical-pod-autoscaler/pkg/admission-controller/resource/pod/patch/resource_updates_test.go +++ b/vertical-pod-autoscaler/pkg/admission-controller/resource/pod/patch/resource_updates_test.go @@ -28,6 +28,7 @@ import ( "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/test" vpa_api_util "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/vpa" + "github.com/go-openapi/jsonpointer" "github.com/stretchr/testify/assert" ) @@ -248,6 +249,33 @@ func TestClalculatePatches_ResourceUpdates(t *testing.T) { addAnnotationRequest([][]string{{cpu}}, limit), }, }, + { + name: "patch for extended resource properly escaped", + pod: &core.Pod{ + Spec: core.PodSpec{ + Containers: []core.Container{{ + Resources: core.ResourceRequirements{ + Requests: core.ResourceList{ + "example.com/dongle": resource.MustParse("0"), + }, + }, + }}, + }, + }, + namespace: "default", + recommendResources: []vpa_api_util.ContainerResources{ + { + Requests: core.ResourceList{ + "example.com/dongle": resource.MustParse("1"), + }, + }, + }, + recommendAnnotations: vpa_api_util.ContainerToAnnotationsMap{}, + expectPatches: []resource_admission.PatchRecord{ + addResourceRequestPatch(0, jsonpointer.Escape("example.com/dongle"), "1"), + addAnnotationRequest([][]string{{"example.com/dongle"}}, request), + }, + }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) {