From 88c9dd75344a00caa287da4e5762bdb419bf9aab Mon Sep 17 00:00:00 2001 From: Ben Luddy Date: Tue, 5 Nov 2024 08:54:16 -0500 Subject: [PATCH] Update AllAlpha integration tests to recognize CBOR. Setting AllAlpha=true in integration tests changes the dynamic client request encoding and the custom resource storage encoding to CBOR. The etcd storage path is updated to accept either JSON or CBOR as storage encoding. The client feature gate controlling the dynamic client request encoding is temporarily disabled until the serving codecs for builtin APIs are wired to the CBOR apiserver feature gate. --- .../transformation/kms_transformation_test.go | 5 ++ .../etcd/etcd_storage_path_test.go | 57 ++++++++++++------- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/test/integration/controlplane/transformation/kms_transformation_test.go b/test/integration/controlplane/transformation/kms_transformation_test.go index 01858351ea3..3ecc322ab26 100644 --- a/test/integration/controlplane/transformation/kms_transformation_test.go +++ b/test/integration/controlplane/transformation/kms_transformation_test.go @@ -53,6 +53,8 @@ import ( mock "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testing/v1beta1" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/client-go/dynamic" + clientfeatures "k8s.io/client-go/features" + clientfeaturestesting "k8s.io/client-go/features/testing" "k8s.io/client-go/rest" featuregatetesting "k8s.io/component-base/featuregate/testing" kmsapi "k8s.io/kms/apis/v1beta1" @@ -629,6 +631,9 @@ resources: // Need to enable this explicitly as the feature is deprecated featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.KMSv1, true) + // TODO: Remove this override when the codecs used for serving all built-in APIs are wired to the apiserver feature gate. + clientfeaturestesting.SetFeatureDuringTest(t, clientfeatures.ClientsPreferCBOR, false) + test, err := newTransformTest(t, encryptionConfig, false, "", nil) if err != nil { t.Fatalf("failed to start KUBE API Server with encryptionConfig") diff --git a/test/integration/etcd/etcd_storage_path_test.go b/test/integration/etcd/etcd_storage_path_test.go index 903f39f0ae6..5d13544dd1b 100644 --- a/test/integration/etcd/etcd_storage_path_test.go +++ b/test/integration/etcd/etcd_storage_path_test.go @@ -18,7 +18,6 @@ package etcd import ( "context" - "encoding/json" "fmt" "path/filepath" "reflect" @@ -33,10 +32,17 @@ import ( "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer/cbor" + "k8s.io/apimachinery/pkg/runtime/serializer/json" + "k8s.io/apimachinery/pkg/runtime/serializer/recognizer" + utiljson "k8s.io/apimachinery/pkg/util/json" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/util/feature" "k8s.io/client-go/dynamic" + clientfeatures "k8s.io/client-go/features" + clientfeaturestesting "k8s.io/client-go/features/testing" featuregatetesting "k8s.io/component-base/featuregate/testing" ) @@ -77,6 +83,9 @@ func TestEtcdStoragePath(t *testing.T) { featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, "AllAlpha", true) featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, "AllBeta", true) + // TODO: Remove this override when the codecs used for serving all built-in APIs are wired to the apiserver feature gate. + clientfeaturestesting.SetFeatureDuringTest(t, clientfeatures.ClientsPreferCBOR, false) + apiServer := StartRealAPIServerOrDie(t) defer apiServer.Cleanup() defer dumpEtcdKVOnFailure(t, apiServer.KV) @@ -124,7 +133,8 @@ func TestEtcdStoragePath(t *testing.T) { err error ) if shouldCreate { - if input, err = jsonToMetaObject([]byte(testData.Stub)); err != nil || input.isEmpty() { + input = new(metaObject) + if err = utiljson.Unmarshal([]byte(testData.Stub), input); err != nil || input.isEmpty() { t.Fatalf("invalid test data for %s: %v", gvResource, err) } // unset type meta fields - we only set these in the CRD test data and it makes @@ -152,7 +162,20 @@ func TestEtcdStoragePath(t *testing.T) { } } - output, err := getFromEtcd(apiServer.KV, testData.ExpectedEtcdPath) + // Build a decoder that can decode JSON and CBOR from storage. + scheme := runtime.NewScheme() + if testData.ExpectedGVK != nil { + scheme.AddKnownTypeWithName(*testData.ExpectedGVK, &metaObject{}) + } else { + scheme.AddKnownTypeWithName(gvk, &metaObject{}) + + } + decoder := recognizer.NewDecoder( + cbor.NewSerializer(scheme, scheme), + json.NewSerializerWithOptions(json.DefaultMetaFactory, scheme, scheme, json.SerializerOptions{}), + ) + + output, err := getFromEtcd(decoder, apiServer.KV, testData.ExpectedEtcdPath) if err != nil { t.Fatalf("failed to get from etcd for %s: %#v", gvResource, err) } @@ -208,7 +231,7 @@ func TestEtcdStoragePath(t *testing.T) { ) } - actualGVK := output.getGVK() + actualGVK := output.GroupVersionKind() if actualGVK != expectedGVK { t.Errorf("GVK for %s does not match, expected %s got %s", kind, expectedGVK, actualGVK) } @@ -289,9 +312,7 @@ func getEtcdBucket(path string) string { // stable fields to compare as a sanity check type metaObject struct { - // all of type meta - Kind string `json:"kind,omitempty"` - APIVersion string `json:"apiVersion,omitempty"` + metav1.TypeMeta `json:",inline"` // parts of object meta Metadata struct { @@ -300,8 +321,10 @@ type metaObject struct { } `json:"metadata,omitempty"` } -func (obj *metaObject) getGVK() schema.GroupVersionKind { - return schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind) +var _ runtime.Object = &metaObject{} + +func (*metaObject) DeepCopyObject() runtime.Object { + panic("unimplemented") } func (obj *metaObject) isEmpty() bool { @@ -315,14 +338,6 @@ type cleanupData struct { resource schema.GroupVersionResource } -func jsonToMetaObject(stub []byte) (*metaObject, error) { - obj := &metaObject{} - if err := json.Unmarshal(stub, obj); err != nil { - return nil, err - } - return obj, nil -} - func keyStringer(i interface{}) string { base := "\n\t" switch key := i.(type) { @@ -386,7 +401,7 @@ func (c *allClient) createPrerequisites(mapper meta.RESTMapper, ns string, prere return nil } -func getFromEtcd(keys clientv3.KV, path string) (*metaObject, error) { +func getFromEtcd(decoder runtime.Decoder, keys clientv3.KV, path string) (*metaObject, error) { response, err := keys.Get(context.Background(), path) if err != nil { return nil, err @@ -394,7 +409,11 @@ func getFromEtcd(keys clientv3.KV, path string) (*metaObject, error) { if response.More || response.Count != 1 || len(response.Kvs) != 1 { return nil, fmt.Errorf("Invalid etcd response (not found == %v): %#v", response.Count == 0, response) } - return jsonToMetaObject(response.Kvs[0].Value) + var obj metaObject + if err := runtime.DecodeInto(decoder, response.Kvs[0].Value, &obj); err != nil { + return nil, err + } + return &obj, nil } func diffMaps(a, b interface{}) ([]string, []string) {