diff --git a/go.mod b/go.mod index f1a8a6a04..60fda774e 100644 --- a/go.mod +++ b/go.mod @@ -50,17 +50,17 @@ require ( gopkg.in/evanphx/json-patch.v4 v4.12.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/square/go-jose.v2 v2.6.0 - k8s.io/api v0.0.0-20241030034125-271c79cac830 - k8s.io/apimachinery v0.0.0-20241030224344-a25029a669a1 - k8s.io/client-go v0.0.0-20241030185032-6ba2fc71bc40 - k8s.io/component-base v0.0.0-20241031225408-ecd78b707a2d + k8s.io/api v0.0.0-20241101030658-23d2de5610f2 + k8s.io/apimachinery v0.0.0-20241101025844-cbe039cffd7e + k8s.io/client-go v0.0.0-20241101031653-c5d71b267c2a + k8s.io/component-base v0.0.0-20241101033950-7aab75e7eb7d k8s.io/klog/v2 v2.130.1 k8s.io/kms v0.0.0-20241018044332-f1456fc96237 k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 + sigs.k8s.io/structured-merge-diff/v4 v4.4.2 sigs.k8s.io/yaml v1.4.0 ) diff --git a/go.sum b/go.sum index d5a02b62b..94284001f 100644 --- a/go.sum +++ b/go.sum @@ -360,7 +360,6 @@ gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -368,14 +367,14 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.0.0-20241030034125-271c79cac830 h1:zu5fMzQV/xp3VSln7QIaHNb2ghUQ3YJngYo1y52wpsc= -k8s.io/api v0.0.0-20241030034125-271c79cac830/go.mod h1:aywKYMtpaiAtWkkKBmWO/iXvZmEmVXmBwQwOuQqkP0c= -k8s.io/apimachinery v0.0.0-20241030224344-a25029a669a1 h1:g9b84AV41Gw+L6Hh2Fwuqqn91NerIp9s7xQWnql6CWs= -k8s.io/apimachinery v0.0.0-20241030224344-a25029a669a1/go.mod h1:y/FzDt/GaPgPceo5rJcCtD4qW5l8SwtbzESSMGEY6P8= -k8s.io/client-go v0.0.0-20241030185032-6ba2fc71bc40 h1:eHBHdbsmesREwHCcf4WC6W3n33Gx33qd6Ui8SKKEy8I= -k8s.io/client-go v0.0.0-20241030185032-6ba2fc71bc40/go.mod h1:2yz8Bjwdfx1R8vPByI1NQckShJfDEPVnOT+6mumccr0= -k8s.io/component-base v0.0.0-20241031225408-ecd78b707a2d h1:48kCV8dYKjJiHOeF746BfL1ONS2cO3dzugJEa8TGW9g= -k8s.io/component-base v0.0.0-20241031225408-ecd78b707a2d/go.mod h1:rvwTzqjhUKsK+pr8yaEMHAj4tbcNRArH52wT2hefL/I= +k8s.io/api v0.0.0-20241101030658-23d2de5610f2 h1:iDi7dxAgLLw/rV2rxmZcI1xDjHPkNa6Xxiq5mUHU134= +k8s.io/api v0.0.0-20241101030658-23d2de5610f2/go.mod h1:TzFPxppSfonJM6VXn8BGw8k8IZyCvAIg+m3gce9fWcQ= +k8s.io/apimachinery v0.0.0-20241101025844-cbe039cffd7e h1:1I6mSLPZ8scSOna5iDpwfhNIoNv2Bl95vX25jPJ3DvU= +k8s.io/apimachinery v0.0.0-20241101025844-cbe039cffd7e/go.mod h1:JL4jbXpZvznF/cgaQmTb/duvBfZSMcFnoepN5YwqKrs= +k8s.io/client-go v0.0.0-20241101031653-c5d71b267c2a h1:6W5u98jUFbcCTRiPpe26S2UK+d6ngNR3RGtrX2bpxWM= +k8s.io/client-go v0.0.0-20241101031653-c5d71b267c2a/go.mod h1:Opld/qO4skIrfCzuRJ91JQrDzxs77fKkJGHKWG2zkwI= +k8s.io/component-base v0.0.0-20241101033950-7aab75e7eb7d h1:4bOLZvCyv965JICf1KaYAfqEoW4CLUYMHizkSOlTc+w= +k8s.io/component-base v0.0.0-20241101033950-7aab75e7eb7d/go.mod h1:IQWp+SjVEEQXXqTPGSHtmqt/Q+NTtLSO/m9JdgzwArc= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kms v0.0.0-20241018044332-f1456fc96237 h1:wB+v0IxpfNqEJhSrVLag6Z25llgoPgKq1dLkJvJvxbI= @@ -388,7 +387,7 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 h1:CPT0ExVicCzcp sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/pkg/endpoints/installer.go b/pkg/endpoints/installer.go index 707eb4a50..6a1826b4e 100644 --- a/pkg/endpoints/installer.go +++ b/pkg/endpoints/installer.go @@ -685,9 +685,27 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag reqScope.MetaGroupVersion = *a.group.MetaGroupVersion } - var resetFields map[fieldpath.APIVersion]*fieldpath.Set - if resetFieldsStrategy, isResetFieldsStrategy := storage.(rest.ResetFieldsStrategy); isResetFieldsStrategy { - resetFields = resetFieldsStrategy.GetResetFields() + // Strategies may ignore changes to some fields by resetting the field values. + // + // For instance, spec resource strategies should reset the status, and status subresource + // strategies should reset the spec. + // + // Strategies that reset fields must report to the field manager which fields are + // reset by implementing either the ResetFieldsStrategy or the ResetFieldsFilterStrategy + // interface. + // + // For subresources that provide write access to only specific nested fields + // fieldpath.NewPatternFilter can help create a filter to reset all other fields. + var resetFieldsFilter map[fieldpath.APIVersion]fieldpath.Filter + resetFieldsStrategy, isResetFieldsStrategy := storage.(rest.ResetFieldsStrategy) + if isResetFieldsStrategy { + resetFieldsFilter = fieldpath.NewExcludeFilterSetMap(resetFieldsStrategy.GetResetFields()) + } + if resetFieldsStrategy, isResetFieldsFilterStrategy := storage.(rest.ResetFieldsFilterStrategy); isResetFieldsFilterStrategy { + if isResetFieldsStrategy { + return nil, nil, fmt.Errorf("may not implement both ResetFieldsStrategy and ResetFieldsFilterStrategy") + } + resetFieldsFilter = resetFieldsStrategy.GetResetFieldsFilter() } reqScope.FieldManager, err = managedfields.NewDefaultFieldManager( @@ -698,7 +716,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag fqKindToRegister, reqScope.HubGroupVersion, subresource, - resetFields, + resetFieldsFilter, ) if err != nil { return nil, nil, fmt.Errorf("failed to create field manager: %v", err) diff --git a/pkg/registry/rest/rest.go b/pkg/registry/rest/rest.go index 03cea7bb7..fa0239170 100644 --- a/pkg/registry/rest/rest.go +++ b/pkg/registry/rest/rest.go @@ -22,12 +22,13 @@ import ( "net/http" "net/url" + "sigs.k8s.io/structured-merge-diff/v4/fieldpath" + metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/watch" - "sigs.k8s.io/structured-merge-diff/v4/fieldpath" ) //TODO: @@ -387,6 +388,12 @@ type ResetFieldsStrategy interface { GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set } +// ResetFieldsFilterStrategy is an optional interface that a storage object can +// implement if it wishes to provide a fields filter reset by its strategies. +type ResetFieldsFilterStrategy interface { + GetResetFieldsFilter() map[fieldpath.APIVersion]fieldpath.Filter +} + // CreateUpdateResetFieldsStrategy is a union of RESTCreateUpdateStrategy // and ResetFieldsStrategy. type CreateUpdateResetFieldsStrategy interface {