From 8cfff55144b24f5e1d9abc2d115f6a94d9c72001 Mon Sep 17 00:00:00 2001 From: filipcirtog Date: Fri, 10 Oct 2025 13:07:55 +0200 Subject: [PATCH 1/3] fix: enable apply after normal create --- pkg/client/client_rest_resources.go | 2 +- pkg/client/client_test.go | 52 +++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/pkg/client/client_rest_resources.go b/pkg/client/client_rest_resources.go index acff7a46a4..57753197a5 100644 --- a/pkg/client/client_rest_resources.go +++ b/pkg/client/client_rest_resources.go @@ -124,7 +124,7 @@ func (c *clientRestResources) getResource(obj any) (*resourceMeta, error) { r, known := resourceByType[gvk] c.mu.RUnlock() - if known { + if known && !forceDisableProtoBuf { return r, nil } diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index c775f28718..f224bee6ba 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -951,6 +951,58 @@ U5wwSivyi7vmegHKmblOzNVKA5qPO8zWzqBC Expect(cm.Data).To(BeComparableTo(data)) Expect(cm.Data).To(BeComparableTo(obj.Data)) }) + + It("should create a secret without SSA and later create update a secret using SSA", func(ctx SpecContext) { + cl, err := client.New(cfg, client.Options{}) + Expect(err).NotTo(HaveOccurred()) + Expect(cl).NotTo(BeNil()) + data := map[string][]byte{ + "some-key": []byte("some-value"), + } + secretObject := &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + Kind: "Secret", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "secret-one", + Namespace: "default", + }, + Data: data, + } + + secretApplyConfiguration := corev1applyconfigurations. + Secret("secret-two", "default"). + WithAPIVersion("v1"). + WithKind("Secret"). + WithData(data) + + err = cl.Create(ctx, secretObject) + Expect(err).NotTo(HaveOccurred()) + + err = cl.Apply(ctx, secretApplyConfiguration, &client.ApplyOptions{FieldManager: "test-manager"}) + Expect(err).NotTo(HaveOccurred()) + + cm, err := clientset.CoreV1().Secrets(ptr.Deref(secretApplyConfiguration.GetNamespace(), "")).Get(ctx, ptr.Deref(secretApplyConfiguration.GetName(), ""), metav1.GetOptions{}) + Expect(err).NotTo(HaveOccurred()) + + Expect(cm.Data).To(BeComparableTo(data)) + Expect(cm.Data).To(BeComparableTo(secretApplyConfiguration.Data)) + + data = map[string][]byte{ + "some-key": []byte("some-new-value"), + } + secretApplyConfiguration.Data = data + + err = cl.Apply(ctx, secretApplyConfiguration, &client.ApplyOptions{FieldManager: "test-manager"}) + Expect(err).NotTo(HaveOccurred()) + + cm, err = clientset.CoreV1().Secrets(ptr.Deref(secretApplyConfiguration.GetNamespace(), "")).Get(ctx, ptr.Deref(secretApplyConfiguration.GetName(), ""), metav1.GetOptions{}) + Expect(err).NotTo(HaveOccurred()) + + Expect(cm.Data).To(BeComparableTo(data)) + Expect(cm.Data).To(BeComparableTo(secretApplyConfiguration.Data)) + }) }) }) From 9b1be0b3f21a77ead76b001ea0843440b2ae0b05 Mon Sep 17 00:00:00 2001 From: filipcirtog Date: Fri, 10 Oct 2025 20:59:26 +0200 Subject: [PATCH 2/3] improvements: cache now considers disable protobuf flag for lookup --- pkg/client/client.go | 4 ++-- pkg/client/client_rest_resources.go | 24 ++++++++++++++++++------ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/pkg/client/client.go b/pkg/client/client.go index 092deb43d4..779453adf7 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -151,8 +151,8 @@ func newClient(config *rest.Config, options Options) (*client, error) { mapper: options.Mapper, codecs: serializer.NewCodecFactory(options.Scheme), - structuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta), - unstructuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta), + structuredResourceByType: make(map[cacheKey]*resourceMeta), + unstructuredResourceByType: make(map[cacheKey]*resourceMeta), } rawMetaClient, err := metadata.NewForConfigAndClient(metadata.ConfigFor(config), options.HTTPClient) diff --git a/pkg/client/client_rest_resources.go b/pkg/client/client_rest_resources.go index 57753197a5..e72d32aace 100644 --- a/pkg/client/client_rest_resources.go +++ b/pkg/client/client_rest_resources.go @@ -49,10 +49,17 @@ type clientRestResources struct { codecs serializer.CodecFactory // structuredResourceByType stores structured type metadata - structuredResourceByType map[schema.GroupVersionKind]*resourceMeta + structuredResourceByType map[cacheKey]*resourceMeta + // unstructuredResourceByType stores unstructured type metadata - unstructuredResourceByType map[schema.GroupVersionKind]*resourceMeta - mu sync.RWMutex + unstructuredResourceByType map[cacheKey]*resourceMeta + + mu sync.RWMutex +} + +type cacheKey struct { + gvk schema.GroupVersionKind + forceDisableProtoBuf bool } // newResource maps obj to a Kubernetes Resource and constructs a client for that Resource. @@ -117,14 +124,19 @@ func (c *clientRestResources) getResource(obj any) (*resourceMeta, error) { // It's better to do creation work twice than to not let multiple // people make requests at once c.mu.RLock() + + cacheKey := cacheKey{gvk: gvk, forceDisableProtoBuf: forceDisableProtoBuf} + resourceByType := c.structuredResourceByType if isUnstructured { resourceByType = c.unstructuredResourceByType } - r, known := resourceByType[gvk] + + r, known := resourceByType[cacheKey] + c.mu.RUnlock() - if known && !forceDisableProtoBuf { + if known { return r, nil } @@ -140,7 +152,7 @@ func (c *clientRestResources) getResource(obj any) (*resourceMeta, error) { if err != nil { return nil, err } - resourceByType[gvk] = r + resourceByType[cacheKey] = r return r, err } From 9235a0945b0aabed1efc6f9dc33582c29b6b0c26 Mon Sep 17 00:00:00 2001 From: filipcirtog Date: Fri, 10 Oct 2025 22:16:06 +0200 Subject: [PATCH 3/3] feedback improvements --- pkg/client/client.go | 3 +-- pkg/client/client_rest_resources.go | 16 ++++------------ pkg/client/client_test.go | 18 ++++++------------ 3 files changed, 11 insertions(+), 26 deletions(-) diff --git a/pkg/client/client.go b/pkg/client/client.go index 779453adf7..e9f731453b 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -151,8 +151,7 @@ func newClient(config *rest.Config, options Options) (*client, error) { mapper: options.Mapper, codecs: serializer.NewCodecFactory(options.Scheme), - structuredResourceByType: make(map[cacheKey]*resourceMeta), - unstructuredResourceByType: make(map[cacheKey]*resourceMeta), + resourceByType: make(map[cacheKey]*resourceMeta), } rawMetaClient, err := metadata.NewForConfigAndClient(metadata.ConfigFor(config), options.HTTPClient) diff --git a/pkg/client/client_rest_resources.go b/pkg/client/client_rest_resources.go index e72d32aace..d75d685cbb 100644 --- a/pkg/client/client_rest_resources.go +++ b/pkg/client/client_rest_resources.go @@ -48,11 +48,8 @@ type clientRestResources struct { // codecs are used to create a REST client for a gvk codecs serializer.CodecFactory - // structuredResourceByType stores structured type metadata - structuredResourceByType map[cacheKey]*resourceMeta - - // unstructuredResourceByType stores unstructured type metadata - unstructuredResourceByType map[cacheKey]*resourceMeta + // resourceByType stores type metadata + resourceByType map[cacheKey]*resourceMeta mu sync.RWMutex } @@ -127,12 +124,7 @@ func (c *clientRestResources) getResource(obj any) (*resourceMeta, error) { cacheKey := cacheKey{gvk: gvk, forceDisableProtoBuf: forceDisableProtoBuf} - resourceByType := c.structuredResourceByType - if isUnstructured { - resourceByType = c.unstructuredResourceByType - } - - r, known := resourceByType[cacheKey] + r, known := c.resourceByType[cacheKey] c.mu.RUnlock() @@ -152,7 +144,7 @@ func (c *clientRestResources) getResource(obj any) (*resourceMeta, error) { if err != nil { return nil, err } - resourceByType[cacheKey] = r + c.resourceByType[cacheKey] = r return r, err } diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index f224bee6ba..63d64ce838 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -960,10 +960,6 @@ U5wwSivyi7vmegHKmblOzNVKA5qPO8zWzqBC "some-key": []byte("some-value"), } secretObject := &corev1.Secret{ - TypeMeta: metav1.TypeMeta{ - Kind: "Secret", - APIVersion: "v1", - }, ObjectMeta: metav1.ObjectMeta{ Name: "secret-one", Namespace: "default", @@ -973,8 +969,6 @@ U5wwSivyi7vmegHKmblOzNVKA5qPO8zWzqBC secretApplyConfiguration := corev1applyconfigurations. Secret("secret-two", "default"). - WithAPIVersion("v1"). - WithKind("Secret"). WithData(data) err = cl.Create(ctx, secretObject) @@ -983,11 +977,11 @@ U5wwSivyi7vmegHKmblOzNVKA5qPO8zWzqBC err = cl.Apply(ctx, secretApplyConfiguration, &client.ApplyOptions{FieldManager: "test-manager"}) Expect(err).NotTo(HaveOccurred()) - cm, err := clientset.CoreV1().Secrets(ptr.Deref(secretApplyConfiguration.GetNamespace(), "")).Get(ctx, ptr.Deref(secretApplyConfiguration.GetName(), ""), metav1.GetOptions{}) + secret, err := clientset.CoreV1().Secrets(ptr.Deref(secretApplyConfiguration.GetNamespace(), "")).Get(ctx, ptr.Deref(secretApplyConfiguration.GetName(), ""), metav1.GetOptions{}) Expect(err).NotTo(HaveOccurred()) - Expect(cm.Data).To(BeComparableTo(data)) - Expect(cm.Data).To(BeComparableTo(secretApplyConfiguration.Data)) + Expect(secret.Data).To(BeComparableTo(data)) + Expect(secret.Data).To(BeComparableTo(secretApplyConfiguration.Data)) data = map[string][]byte{ "some-key": []byte("some-new-value"), @@ -997,11 +991,11 @@ U5wwSivyi7vmegHKmblOzNVKA5qPO8zWzqBC err = cl.Apply(ctx, secretApplyConfiguration, &client.ApplyOptions{FieldManager: "test-manager"}) Expect(err).NotTo(HaveOccurred()) - cm, err = clientset.CoreV1().Secrets(ptr.Deref(secretApplyConfiguration.GetNamespace(), "")).Get(ctx, ptr.Deref(secretApplyConfiguration.GetName(), ""), metav1.GetOptions{}) + secret, err = clientset.CoreV1().Secrets(ptr.Deref(secretApplyConfiguration.GetNamespace(), "")).Get(ctx, ptr.Deref(secretApplyConfiguration.GetName(), ""), metav1.GetOptions{}) Expect(err).NotTo(HaveOccurred()) - Expect(cm.Data).To(BeComparableTo(data)) - Expect(cm.Data).To(BeComparableTo(secretApplyConfiguration.Data)) + Expect(secret.Data).To(BeComparableTo(data)) + Expect(secret.Data).To(BeComparableTo(secretApplyConfiguration.Data)) }) }) })