diff --git a/client/client.go b/client/client.go index e5a88f47a..66b0b0d16 100644 --- a/client/client.go +++ b/client/client.go @@ -111,9 +111,6 @@ func CreateOrPatch(ctx context.Context, c client.Client, obj client.Object, tran patch = client.MergeFrom(cur) } mod := transform(cur.DeepCopyObject().(client.Object), false) - if p, err := patch.Data(mod); err != nil || string(p) == "{}" { - return kutil.VerbUnchanged, err - } err = c.Patch(ctx, mod, patch, opts...) if err != nil { return kutil.VerbUnchanged, err @@ -149,9 +146,6 @@ func PatchStatus(ctx context.Context, c client.Client, obj client.Object, transf // - application/apply-patch+yaml patch := client.MergeFrom(cur) mod := transform(cur.DeepCopyObject().(client.Object)) - if p, err := patch.Data(mod); err != nil || string(p) == "{}" { - return kutil.VerbUnchanged, err - } err = c.Status().Patch(ctx, mod, patch, opts...) if err != nil { return kutil.VerbUnchanged, err diff --git a/go.mod b/go.mod index 33d80c752..ab08fa640 100644 --- a/go.mod +++ b/go.mod @@ -140,3 +140,5 @@ require ( sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect ) + +replace sigs.k8s.io/controller-runtime => github.com/kmodules/controller-runtime v0.13.1-0.20230725210630-f8273f9c4412 diff --git a/go.sum b/go.sum index ced0c2fc5..0d34a2a04 100644 --- a/go.sum +++ b/go.sum @@ -296,6 +296,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kmodules/controller-runtime v0.13.1-0.20230725210630-f8273f9c4412 h1:sy5gE/M+SfQdIK9wh1VIT0RhXxiVlPRQxpGy2TVvnzE= +github.com/kmodules/controller-runtime v0.13.1-0.20230725210630-f8273f9c4412/go.mod h1:Zbz+el8Yg31jubvAEyglRZGdLAjplZl+PgtYNI6WNTI= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -945,8 +947,6 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.32 h1:2WjukG7txtEsbXsSKWtTibCdsyYAhcu6KFnttyDdZOQ= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.32/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw= -sigs.k8s.io/controller-runtime v0.13.1 h1:tUsRCSJVM1QQOOeViGeX3GMT3dQF1eePPw6sEE3xSlg= -sigs.k8s.io/controller-runtime v0.13.1/go.mod h1:Zbz+el8Yg31jubvAEyglRZGdLAjplZl+PgtYNI6WNTI= sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM= diff --git a/vendor/modules.txt b/vendor/modules.txt index e3d6e681c..75d341784 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1220,7 +1220,7 @@ kmodules.xyz/apiversion ## explicit; go 1.17 sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client -# sigs.k8s.io/controller-runtime v0.13.1 +# sigs.k8s.io/controller-runtime v0.13.1 => github.com/kmodules/controller-runtime v0.13.1-0.20230725210630-f8273f9c4412 ## explicit; go 1.17 sigs.k8s.io/controller-runtime sigs.k8s.io/controller-runtime/pkg/builder @@ -1360,3 +1360,4 @@ sigs.k8s.io/structured-merge-diff/v4/value # sigs.k8s.io/yaml v1.3.0 ## explicit; go 1.12 sigs.k8s.io/yaml +# sigs.k8s.io/controller-runtime => github.com/kmodules/controller-runtime v0.13.1-0.20230725210630-f8273f9c4412 diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go index 9c2255123..852d0d73a 100644 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go @@ -113,17 +113,60 @@ func (c *CacheReader) List(_ context.Context, out client.ObjectList, opts ...cli listOpts.ApplyOptions(opts) switch { - case listOpts.FieldSelector != nil: + // listOpts.FieldSelector.Empty() == true means select all + case listOpts.FieldSelector != nil && !listOpts.FieldSelector.Empty(): // TODO(directxman12): support more complicated field selectors by // combining multiple indices, GetIndexers, etc - field, val, requiresExact := requiresExactMatch(listOpts.FieldSelector) + requiresExact := requiresExactMatch(listOpts.FieldSelector) if !requiresExact { return fmt.Errorf("non-exact field matches are not supported by the cache") } - // list all objects by the field selector. If this is namespaced and we have one, ask for the - // namespaced index key. Otherwise, ask for the non-namespaced variant by using the fake "all namespaces" - // namespace. - objs, err = c.indexer.ByIndex(FieldIndexName(field), KeyToNamespacedKey(listOpts.Namespace, val)) + + reqs := listOpts.FieldSelector.Requirements() + // len(reqs) == 0 means, select nothing + if len(reqs) > 0 { + req := reqs[0] + // list all objects by the field selector. If this is namespaced and we have one, ask for the + // namespaced index key. Otherwise, ask for the non-namespaced variant by using the fake "all namespaces" + // namespace. + list, err := c.indexer.ByIndex(FieldIndexName(req.Field), KeyToNamespacedKey(listOpts.Namespace, req.Value)) + if err != nil { + return err + } + if len(reqs) > 1 { + objmap := make(map[client.ObjectKey]interface{}, len(list)) + for i := range list { + obj := list[i].(client.Object) + objmap[client.ObjectKey{Namespace: obj.GetNamespace(), Name: obj.GetName()}] = obj + } + for _, req := range reqs[1:] { + list, err := c.indexer.ByIndex(FieldIndexName(req.Field), KeyToNamespacedKey(listOpts.Namespace, req.Value)) + if err != nil { + return err + } + + numap := make(map[client.ObjectKey]interface{}, len(list)) + for i := range list { + obj := list[i].(client.Object) + key := client.ObjectKey{Namespace: obj.GetNamespace(), Name: obj.GetName()} + if o, exists := objmap[key]; exists { + if o.(client.Object).GetGeneration() == obj.GetGeneration() { + numap[key] = obj + } else { + return fmt.Errorf("multiple generation found in indices for %+v %s/%s", obj.GetObjectKind().GroupVersionKind(), obj.GetNamespace(), obj.GetName()) + } + } + } + objmap = numap + } + objs = make([]interface{}, 0, len(objmap)) + for _, obj := range objmap { + objs = append(objs, obj) + } + } else { + objs = list + } + } case listOpts.Namespace != "": objs, err = c.indexer.ByIndex(cache.NamespaceIndex, listOpts.Namespace) default: @@ -187,16 +230,14 @@ func objectKeyToStoreKey(k client.ObjectKey) string { } // requiresExactMatch checks if the given field selector is of the form `k=v` or `k==v`. -func requiresExactMatch(sel fields.Selector) (field, val string, required bool) { +func requiresExactMatch(sel fields.Selector) (required bool) { reqs := sel.Requirements() - if len(reqs) != 1 { - return "", "", false - } - req := reqs[0] - if req.Operator != selection.Equals && req.Operator != selection.DoubleEquals { - return "", "", false + for _, req := range reqs { + if req.Operator != selection.Equals && req.Operator != selection.DoubleEquals { + return false + } } - return req.Field, req.Value, true + return true } // FieldIndexName constructs the name of the index over the given field, diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go index 2854556f3..1e1b0cb43 100644 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go @@ -98,14 +98,14 @@ func (mc *metadataClient) Patch(ctx context.Context, obj Object, patch Patch, op return err } + patchOpts := &PatchOptions{} + patchOpts.ApplyOptions(opts) + data, err := patch.Data(obj) - if err != nil { + if err != nil || (!patchOpts.SendEmptyPatch && string(data) == "{}") { return err } - patchOpts := &PatchOptions{} - patchOpts.ApplyOptions(opts) - res, err := resInt.Patch(ctx, metadata.Name, patch.Type(), data, *patchOpts.AsPatchOptions()) if err != nil { return err @@ -180,12 +180,14 @@ func (mc *metadataClient) PatchStatus(ctx context.Context, obj Object, patch Pat return err } + patchOpts := &PatchOptions{} + patchOpts.ApplyOptions(opts) + data, err := patch.Data(obj) - if err != nil { + if err != nil || (!patchOpts.SendEmptyPatch && string(data) == "{}") { return err } - patchOpts := &PatchOptions{} res, err := resInt.Patch(ctx, metadata.Name, patch.Type(), data, *patchOpts.AsPatchOptions(), "status") if err != nil { return err diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go index 495b86944..0edf4f04d 100644 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go @@ -368,7 +368,7 @@ type ListOptions struct { LabelSelector labels.Selector // FieldSelector filters results by a particular field. In order // to use this with cache-based implementations, restrict usage to - // a single field-value pair that's been added to the indexers. + // field-value pair exact matches that's been added to the indexers. FieldSelector fields.Selector // Namespace represents the namespace to list for, or empty for @@ -652,6 +652,9 @@ type PatchOptions struct { // Raw represents raw PatchOptions, as passed to the API server. Raw *metav1.PatchOptions + + // SendEmptyPatch is going to send empty patch calls to the API server. + SendEmptyPatch bool } // ApplyOptions applies the given patch options on these options, @@ -709,6 +712,16 @@ func (forceOwnership) ApplyToPatch(opts *PatchOptions) { opts.Force = &definitelyTrue } +// SendEmptyPatch sets the "sendEmptyPatch" option to true. +var SendEmptyPatch = sendEmptyPatch{} + +type sendEmptyPatch struct{} + +// ApplyToPatch applies this configuration to the given patch options. +func (sendEmptyPatch) ApplyToPatch(opts *PatchOptions) { + opts.SendEmptyPatch = true +} + // }}} // {{{ DeleteAllOf Options diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go index c4e56d9be..a7fbc1ffd 100644 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go @@ -115,17 +115,19 @@ func (c *typedClient) Patch(ctx context.Context, obj Object, patch Patch, opts . return err } + patchOpts := &PatchOptions{} + patchOpts.ApplyOptions(opts) + data, err := patch.Data(obj) - if err != nil { + if err != nil || (!patchOpts.SendEmptyPatch && string(data) == "{}") { return err } - patchOpts := &PatchOptions{} return o.Patch(patch.Type()). NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). Resource(o.resource()). Name(o.GetName()). - VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), c.paramCodec). + VersionedParams(patchOpts.AsPatchOptions(), c.paramCodec). Body(data). Do(ctx). Into(obj) @@ -190,19 +192,21 @@ func (c *typedClient) PatchStatus(ctx context.Context, obj Object, patch Patch, return err } + patchOpts := &PatchOptions{} + patchOpts.ApplyOptions(opts) + data, err := patch.Data(obj) - if err != nil { + if err != nil || (!patchOpts.SendEmptyPatch && string(data) == "{}") { return err } - patchOpts := &PatchOptions{} return o.Patch(patch.Type()). NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). Resource(o.resource()). Name(o.GetName()). SubResource("status"). Body(data). - VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), c.paramCodec). + VersionedParams(patchOpts.AsPatchOptions(), c.paramCodec). Do(ctx). Into(obj) } diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go index 3d3dbe7b2..1c00661d1 100644 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go @@ -148,17 +148,19 @@ func (uc *unstructuredClient) Patch(ctx context.Context, obj Object, patch Patch return err } + patchOpts := &PatchOptions{} + patchOpts.ApplyOptions(opts) + data, err := patch.Data(obj) - if err != nil { + if err != nil || (!patchOpts.SendEmptyPatch && string(data) == "{}") { return err } - patchOpts := &PatchOptions{} return o.Patch(patch.Type()). NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). Resource(o.resource()). Name(o.GetName()). - VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), uc.paramCodec). + VersionedParams(patchOpts.AsPatchOptions(), uc.paramCodec). Body(data). Do(ctx). Into(obj) @@ -254,19 +256,21 @@ func (uc *unstructuredClient) PatchStatus(ctx context.Context, obj Object, patch return err } + patchOpts := &PatchOptions{} + patchOpts.ApplyOptions(opts) + data, err := patch.Data(obj) - if err != nil { + if err != nil || (!patchOpts.SendEmptyPatch && string(data) == "{}") { return err } - patchOpts := &PatchOptions{} result := o.Patch(patch.Type()). NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). Resource(o.resource()). Name(o.GetName()). SubResource("status"). Body(data). - VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), uc.paramCodec). + VersionedParams(patchOpts.AsPatchOptions(), uc.paramCodec). Do(ctx). Into(u) diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/internal.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/internal.go index fb79c5544..5b22c628f 100644 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/internal.go +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/internal.go @@ -18,7 +18,6 @@ package manager import ( "context" - "crypto/tls" "errors" "fmt" "net" @@ -136,8 +135,6 @@ type controllerManager struct { // if not set, webhook server would look up the server key and certificate in // {TempDir}/k8s-webhook-server/serving-certs certDir string - // tlsOpts is used to allow configuring the TLS config used for the webhook server. - tlsOpts []func(*tls.Config) webhookServer *webhook.Server // webhookServerOnce will be called in GetWebhookServer() to optionally initialize @@ -308,7 +305,6 @@ func (cm *controllerManager) GetWebhookServer() *webhook.Server { Port: cm.port, Host: cm.host, CertDir: cm.certDir, - TLSOpts: cm.tlsOpts, } } if err := cm.Add(cm.webhookServer); err != nil { diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go index 2b28fa4b5..53716aa9f 100644 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go @@ -18,7 +18,6 @@ package manager import ( "context" - "crypto/tls" "fmt" "net" "net/http" @@ -242,9 +241,6 @@ type Options struct { // It is used to set webhook.Server.CertDir if WebhookServer is not set. CertDir string - // TLSOpts is used to allow configuring the TLS config used for the webhook server. - TLSOpts []func(*tls.Config) - // WebhookServer is an externally configured webhook.Server. By default, // a Manager will create a default server using Port, Host, and CertDir; // if this is set, the Manager will use this server instead. @@ -425,7 +421,6 @@ func New(config *rest.Config, options Options) (Manager, error) { port: options.Port, host: options.Host, certDir: options.CertDir, - tlsOpts: options.TLSOpts, webhookServer: options.WebhookServer, leaseDuration: *options.LeaseDuration, renewDeadline: *options.RenewDeadline,