diff --git a/pkg/api/testing/serialization_test.go b/pkg/api/testing/serialization_test.go index 6c95e78708e..77a50c7d052 100644 --- a/pkg/api/testing/serialization_test.go +++ b/pkg/api/testing/serialization_test.go @@ -167,7 +167,7 @@ var nonRoundTrippableTypes = sets.NewString( "PatchOptions", ) -var commonKinds = []string{"Status", "ListOptions", "DeleteOptions", "ExportOptions", "GetOptions", "CreateOptions", "UpdateOptions", "PatchOptions"} +var commonKinds = []string{"Status", "ListOptions", "DeleteOptions", "GetOptions", "CreateOptions", "UpdateOptions", "PatchOptions"} // TestCommonKindsRegistered verifies that all group/versions registered with // the legacyscheme package have the common kinds. diff --git a/pkg/controlplane/import_known_versions_test.go b/pkg/controlplane/import_known_versions_test.go index 64a373d0b8b..3bb74e49940 100644 --- a/pkg/controlplane/import_known_versions_test.go +++ b/pkg/controlplane/import_known_versions_test.go @@ -64,7 +64,6 @@ var typesAllowedTags = map[reflect.Type]bool{ reflect.TypeOf(metav1.OwnerReference{}): true, reflect.TypeOf(metav1.LabelSelector{}): true, reflect.TypeOf(metav1.GetOptions{}): true, - reflect.TypeOf(metav1.ExportOptions{}): true, reflect.TypeOf(metav1.ListOptions{}): true, reflect.TypeOf(metav1.DeleteOptions{}): true, reflect.TypeOf(metav1.GroupVersionKind{}): true, diff --git a/pkg/controlplane/instance_test.go b/pkg/controlplane/instance_test.go index 80789ac34f5..f1839edd889 100644 --- a/pkg/controlplane/instance_test.go +++ b/pkg/controlplane/instance_test.go @@ -160,18 +160,7 @@ func TestLegacyRestStorageStrategies(t *testing.T) { t.Errorf("failed to create legacy REST storage: %v", err) } - // Any new stores with export logic will need to be added here: - exceptions := registrytest.StrategyExceptions{ - // Only these stores should have an export strategy defined: - HasExportStrategy: []string{ - "secrets", - "limitRanges", - "nodes", - "podTemplates", - }, - } - - strategyErrors := registrytest.ValidateStorageStrategies(apiGroupInfo.VersionedResourcesStorageMap["v1"], exceptions) + strategyErrors := registrytest.ValidateStorageStrategies(apiGroupInfo.VersionedResourcesStorageMap["v1"]) for _, err := range strategyErrors { t.Error(err) } @@ -187,14 +176,8 @@ func TestCertificatesRestStorageStrategies(t *testing.T) { t.Fatalf("unexpected error from REST storage: %v", err) } - exceptions := registrytest.StrategyExceptions{ - HasExportStrategy: []string{ - "certificatesigningrequests", - }, - } - strategyErrors := registrytest.ValidateStorageStrategies( - apiGroupInfo.VersionedResourcesStorageMap[certificatesapiv1beta1.SchemeGroupVersion.Version], exceptions) + apiGroupInfo.VersionedResourcesStorageMap[certificatesapiv1beta1.SchemeGroupVersion.Version]) for _, err := range strategyErrors { t.Error(err) } diff --git a/pkg/registry/certificates/certificates/storage/storage.go b/pkg/registry/certificates/certificates/storage/storage.go index 8de9d57a58e..6e24dfd02fc 100644 --- a/pkg/registry/certificates/certificates/storage/storage.go +++ b/pkg/registry/certificates/certificates/storage/storage.go @@ -46,7 +46,6 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, *Approva CreateStrategy: csrregistry.Strategy, UpdateStrategy: csrregistry.Strategy, DeleteStrategy: csrregistry.Strategy, - ExportStrategy: csrregistry.Strategy, TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)}, } diff --git a/pkg/registry/certificates/certificates/strategy.go b/pkg/registry/certificates/certificates/strategy.go index 13d61c10d95..67bd853ceae 100644 --- a/pkg/registry/certificates/certificates/strategy.go +++ b/pkg/registry/certificates/certificates/strategy.go @@ -118,21 +118,6 @@ func (csrStrategy) AllowUnconditionalUpdate() bool { return true } -func (s csrStrategy) Export(ctx context.Context, obj runtime.Object, exact bool) error { - csr, ok := obj.(*certificates.CertificateSigningRequest) - if !ok { - // unexpected programmer error - return fmt.Errorf("unexpected object: %v", obj) - } - s.PrepareForCreate(ctx, obj) - if exact { - return nil - } - // CSRs allow direct subresource edits, we clear them without exact so the CSR value can be reused. - csr.Status = certificates.CertificateSigningRequestStatus{} - return nil -} - // Storage strategy for the Status subresource type csrStatusStrategy struct { csrStrategy diff --git a/pkg/registry/core/limitrange/storage/storage.go b/pkg/registry/core/limitrange/storage/storage.go index 95af1d4fd1d..b3fd401f701 100644 --- a/pkg/registry/core/limitrange/storage/storage.go +++ b/pkg/registry/core/limitrange/storage/storage.go @@ -40,7 +40,6 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, error) { CreateStrategy: limitrange.Strategy, UpdateStrategy: limitrange.Strategy, DeleteStrategy: limitrange.Strategy, - ExportStrategy: limitrange.Strategy, // TODO: define table converter that exposes more than name/creation timestamp TableConvertor: rest.NewDefaultTableConvertor(api.Resource("limitranges")), diff --git a/pkg/registry/core/limitrange/strategy.go b/pkg/registry/core/limitrange/strategy.go index 17e506e46d3..d9af7051a37 100644 --- a/pkg/registry/core/limitrange/strategy.go +++ b/pkg/registry/core/limitrange/strategy.go @@ -72,10 +72,3 @@ func (limitrangeStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.O func (limitrangeStrategy) AllowUnconditionalUpdate() bool { return true } - -func (limitrangeStrategy) Export(context.Context, runtime.Object, bool) error { - // Copied from OpenShift exporter - // TODO: this needs to be fixed - // limitrange.Strategy.PrepareForCreate(ctx, obj) - return nil -} diff --git a/pkg/registry/core/namespace/storage/storage.go b/pkg/registry/core/namespace/storage/storage.go index 91c923533a3..1d66a23203e 100644 --- a/pkg/registry/core/namespace/storage/storage.go +++ b/pkg/registry/core/namespace/storage/storage.go @@ -119,10 +119,6 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio return r.store.Watch(ctx, options) } -func (r *REST) Export(ctx context.Context, name string, opts metav1.ExportOptions) (runtime.Object, error) { - return r.store.Export(ctx, name, opts) -} - // Delete enforces life-cycle rules for namespace termination func (r *REST) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { nsObj, err := r.Get(ctx, name, &metav1.GetOptions{}) diff --git a/pkg/registry/core/node/storage/storage.go b/pkg/registry/core/node/storage/storage.go index 2716190f2b0..8357a450ba4 100644 --- a/pkg/registry/core/node/storage/storage.go +++ b/pkg/registry/core/node/storage/storage.go @@ -88,7 +88,6 @@ func NewStorage(optsGetter generic.RESTOptionsGetter, kubeletClientConfig client CreateStrategy: node.Strategy, UpdateStrategy: node.Strategy, DeleteStrategy: node.Strategy, - ExportStrategy: node.Strategy, TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)}, } diff --git a/pkg/registry/core/node/strategy.go b/pkg/registry/core/node/strategy.go index aaddb69e72a..e415b176bf5 100644 --- a/pkg/registry/core/node/strategy.go +++ b/pkg/registry/core/node/strategy.go @@ -141,22 +141,6 @@ func (nodeStrategy) AllowUnconditionalUpdate() bool { return true } -func (ns nodeStrategy) Export(ctx context.Context, obj runtime.Object, exact bool) error { - n, ok := obj.(*api.Node) - if !ok { - // unexpected programmer error - return fmt.Errorf("unexpected object: %v", obj) - } - ns.PrepareForCreate(ctx, obj) - if exact { - return nil - } - // Nodes are the only resources that allow direct status edits, therefore - // we clear that without exact so that the node value can be reused. - n.Status = api.NodeStatus{} - return nil -} - type nodeStatusStrategy struct { nodeStrategy } diff --git a/pkg/registry/core/podtemplate/storage/storage.go b/pkg/registry/core/podtemplate/storage/storage.go index 624290c067b..d7dca23868a 100644 --- a/pkg/registry/core/podtemplate/storage/storage.go +++ b/pkg/registry/core/podtemplate/storage/storage.go @@ -42,7 +42,6 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, error) { CreateStrategy: podtemplate.Strategy, UpdateStrategy: podtemplate.Strategy, DeleteStrategy: podtemplate.Strategy, - ExportStrategy: podtemplate.Strategy, ReturnDeletedObject: true, diff --git a/pkg/registry/core/podtemplate/strategy.go b/pkg/registry/core/podtemplate/strategy.go index 65055785a06..1b26dfab351 100644 --- a/pkg/registry/core/podtemplate/strategy.go +++ b/pkg/registry/core/podtemplate/strategy.go @@ -87,8 +87,3 @@ func (podTemplateStrategy) ValidateUpdate(ctx context.Context, obj, old runtime. func (podTemplateStrategy) AllowUnconditionalUpdate() bool { return true } - -func (podTemplateStrategy) Export(ctx context.Context, obj runtime.Object, exact bool) error { - // Do nothing - return nil -} diff --git a/pkg/registry/core/secret/BUILD b/pkg/registry/core/secret/BUILD index 4c88ba54abd..61412731397 100644 --- a/pkg/registry/core/secret/BUILD +++ b/pkg/registry/core/secret/BUILD @@ -17,7 +17,6 @@ go_library( "//pkg/api/legacyscheme:go_default_library", "//pkg/apis/core:go_default_library", "//pkg/apis/core/validation:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", @@ -37,9 +36,6 @@ go_test( "//pkg/api/testing:go_default_library", "//pkg/apis/core:go_default_library", "//pkg/apis/core/install:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library", ], ) diff --git a/pkg/registry/core/secret/storage/storage.go b/pkg/registry/core/secret/storage/storage.go index 8faf5f9a3b5..81e2892df57 100644 --- a/pkg/registry/core/secret/storage/storage.go +++ b/pkg/registry/core/secret/storage/storage.go @@ -44,7 +44,6 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, error) { CreateStrategy: secret.Strategy, UpdateStrategy: secret.Strategy, DeleteStrategy: secret.Strategy, - ExportStrategy: secret.Strategy, TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)}, } diff --git a/pkg/registry/core/secret/strategy.go b/pkg/registry/core/secret/strategy.go index ce2ea2b4d77..9d86faf1282 100644 --- a/pkg/registry/core/secret/strategy.go +++ b/pkg/registry/core/secret/strategy.go @@ -20,7 +20,6 @@ import ( "context" "fmt" - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" @@ -85,26 +84,6 @@ func (strategy) AllowUnconditionalUpdate() bool { return true } -func (s strategy) Export(ctx context.Context, obj runtime.Object, exact bool) error { - t, ok := obj.(*api.Secret) - if !ok { - // unexpected programmer error - return fmt.Errorf("unexpected object: %v", obj) - } - s.PrepareForCreate(ctx, obj) - if exact { - return nil - } - // secrets that are tied to the UID of a service account cannot be exported anyway - if t.Type == api.SecretTypeServiceAccountToken || len(t.Annotations[api.ServiceAccountUIDKey]) > 0 { - errs := []*field.Error{ - field.Invalid(field.NewPath("type"), t, "can not export service account secrets"), - } - return errors.NewInvalid(api.Kind("Secret"), t.Name, errs) - } - return nil -} - // GetAttrs returns labels and fields of a given object for filtering purposes. func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) { secret, ok := obj.(*api.Secret) diff --git a/pkg/registry/core/secret/strategy_test.go b/pkg/registry/core/secret/strategy_test.go index d942e26f130..252f3ad8a4a 100644 --- a/pkg/registry/core/secret/strategy_test.go +++ b/pkg/registry/core/secret/strategy_test.go @@ -17,12 +17,8 @@ limitations under the License. package secret import ( - "reflect" "testing" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - genericapirequest "k8s.io/apiserver/pkg/endpoints/request" apitesting "k8s.io/kubernetes/pkg/api/testing" api "k8s.io/kubernetes/pkg/apis/core" @@ -30,80 +26,6 @@ import ( _ "k8s.io/kubernetes/pkg/apis/core/install" ) -func TestExportSecret(t *testing.T) { - tests := []struct { - objIn runtime.Object - objOut runtime.Object - exact bool - expectErr bool - }{ - { - objIn: &api.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "bar", - }, - Data: map[string][]byte{ - "foo": []byte("bar"), - }, - }, - objOut: &api.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "bar", - }, - Data: map[string][]byte{ - "foo": []byte("bar"), - }, - }, - exact: true, - }, - { - objIn: &api.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "bar", - }, - Type: api.SecretTypeServiceAccountToken, - }, - expectErr: true, - }, - { - objIn: &api.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "bar", - Annotations: map[string]string{ - api.ServiceAccountUIDKey: "true", - }, - }, - }, - expectErr: true, - }, - { - objIn: &api.Pod{}, - expectErr: true, - }, - } - - for _, test := range tests { - err := Strategy.Export(genericapirequest.NewContext(), test.objIn, test.exact) - if err != nil { - if !test.expectErr { - t.Errorf("unexpected error: %v", err) - } - continue - } - if test.expectErr { - t.Error("unexpected non-error") - continue - } - if !reflect.DeepEqual(test.objIn, test.objOut) { - t.Errorf("expected:\n%v\nsaw:\n%v\n", test.objOut, test.objIn) - } - } -} - func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, "v1", diff --git a/pkg/registry/core/service/storage/rest.go b/pkg/registry/core/service/storage/rest.go index 694120a2302..06663d947ff 100644 --- a/pkg/registry/core/service/storage/rest.go +++ b/pkg/registry/core/service/storage/rest.go @@ -79,7 +79,6 @@ type ServiceStorage interface { rest.CreaterUpdater rest.GracefulDeleter rest.Watcher - rest.Exporter rest.StorageVersionProvider } @@ -189,10 +188,6 @@ func (rs *REST) Watch(ctx context.Context, options *metainternalversion.ListOpti return rs.services.Watch(ctx, options) } -func (rs *REST) Export(ctx context.Context, name string, opts metav1.ExportOptions) (runtime.Object, error) { - return rs.services.Export(ctx, name, opts) -} - func (rs *REST) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) { service := obj.(*api.Service) diff --git a/pkg/registry/core/service/storage/rest_test.go b/pkg/registry/core/service/storage/rest_test.go index c54b4efa777..4721988b9b7 100644 --- a/pkg/registry/core/service/storage/rest_test.go +++ b/pkg/registry/core/service/storage/rest_test.go @@ -163,10 +163,6 @@ func (s *serviceStorage) ConvertToTable(ctx context.Context, object runtime.Obje panic("not implemented") } -func (s *serviceStorage) Export(ctx context.Context, name string, opts metav1.ExportOptions) (runtime.Object, error) { - panic("not implemented") -} - func (s *serviceStorage) StorageVersion() runtime.GroupVersioner { panic("not implemented") } diff --git a/pkg/registry/core/service/storage/storage.go b/pkg/registry/core/service/storage/storage.go index 6aabaec0f2b..a704239fe23 100644 --- a/pkg/registry/core/service/storage/storage.go +++ b/pkg/registry/core/service/storage/storage.go @@ -57,7 +57,6 @@ func NewGenericREST(optsGetter generic.RESTOptionsGetter, serviceCIDR net.IPNet, CreateStrategy: strategy, UpdateStrategy: strategy, DeleteStrategy: strategy, - ExportStrategy: strategy, TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)}, } diff --git a/pkg/registry/core/service/strategy.go b/pkg/registry/core/service/strategy.go index 79c8b7c7d8b..bf6882e75d5 100644 --- a/pkg/registry/core/service/strategy.go +++ b/pkg/registry/core/service/strategy.go @@ -18,7 +18,6 @@ package service import ( "context" - "fmt" "net" "reflect" @@ -37,7 +36,6 @@ import ( type Strategy interface { rest.RESTCreateUpdateStrategy - rest.RESTExportStrategy } // svcStrategy implements behavior for Services @@ -139,30 +137,6 @@ func (svcStrategy) AllowUnconditionalUpdate() bool { return true } -func (svcStrategy) Export(ctx context.Context, obj runtime.Object, exact bool) error { - t, ok := obj.(*api.Service) - if !ok { - // unexpected programmer error - return fmt.Errorf("unexpected object: %v", obj) - } - // TODO: service does not yet have a prepare create strategy (see above) - t.Status = api.ServiceStatus{} - if exact { - return nil - } - //set ClusterIPs as nil - if ClusterIPs[0] != None - if len(t.Spec.ClusterIPs) > 0 && t.Spec.ClusterIPs[0] != api.ClusterIPNone { - t.Spec.ClusterIP = "" - t.Spec.ClusterIPs = nil - } - if t.Spec.Type == api.ServiceTypeNodePort { - for i := range t.Spec.Ports { - t.Spec.Ports[i].NodePort = 0 - } - } - return nil -} - // dropServiceDisabledFields drops fields that are not used if their associated feature gates // are not enabled. The typical pattern is: // if !utilfeature.DefaultFeatureGate.Enabled(features.MyFeature) && !myFeatureInUse(oldSvc) { diff --git a/pkg/registry/core/service/strategy_test.go b/pkg/registry/core/service/strategy_test.go index 5f130afdd82..7ee2cbabbc7 100644 --- a/pkg/registry/core/service/strategy_test.go +++ b/pkg/registry/core/service/strategy_test.go @@ -47,115 +47,6 @@ func newStrategy(cidr string, hasSecondary bool) (testStrategy Strategy, testSta return } -func TestExportService(t *testing.T) { - testStrategy, _ := newStrategy("10.0.0.0/16", false) - tests := []struct { - objIn runtime.Object - objOut runtime.Object - exact bool - expectErr bool - }{ - { - objIn: &api.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "bar", - }, - Status: api.ServiceStatus{ - LoadBalancer: api.LoadBalancerStatus{ - Ingress: []api.LoadBalancerIngress{ - {IP: "1.2.3.4"}, - }, - }, - }, - }, - objOut: &api.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "bar", - }, - }, - exact: true, - }, - { - objIn: &api.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "bar", - }, - Spec: api.ServiceSpec{ - ClusterIPs: []string{"10.0.0.1"}, - }, - Status: api.ServiceStatus{ - LoadBalancer: api.LoadBalancerStatus{ - Ingress: []api.LoadBalancerIngress{ - {IP: "1.2.3.4"}, - }, - }, - }, - }, - objOut: &api.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "bar", - }, - Spec: api.ServiceSpec{ - ClusterIPs: nil, - }, - }, - }, - { - objIn: &api.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "bar", - }, - Spec: api.ServiceSpec{ - ClusterIPs: []string{"10.0.0.1", "2001::1"}, - }, - Status: api.ServiceStatus{ - LoadBalancer: api.LoadBalancerStatus{ - Ingress: []api.LoadBalancerIngress{ - {IP: "1.2.3.4"}, - }, - }, - }, - }, - objOut: &api.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "bar", - }, - Spec: api.ServiceSpec{ - ClusterIPs: nil, - }, - }, - }, - - { - objIn: &api.Pod{}, - expectErr: true, - }, - } - - for _, test := range tests { - err := testStrategy.Export(genericapirequest.NewContext(), test.objIn, test.exact) - if err != nil { - if !test.expectErr { - t.Errorf("unexpected error: %v", err) - } - continue - } - if test.expectErr { - t.Error("unexpected non-error") - continue - } - if !reflect.DeepEqual(test.objIn, test.objOut) { - t.Errorf("expected:\n%v\nsaw:\n%v\n", test.objOut, test.objIn) - } - } -} - func TestCheckGeneratedNameError(t *testing.T) { testStrategy, _ := newStrategy("10.0.0.0/16", false) expect := errors.NewNotFound(api.Resource("foos"), "bar") diff --git a/pkg/registry/registrytest/BUILD b/pkg/registry/registrytest/BUILD index 2c2e1a75073..d5031ec3694 100644 --- a/pkg/registry/registrytest/BUILD +++ b/pkg/registry/registrytest/BUILD @@ -21,7 +21,6 @@ go_library( deps = [ "//pkg/apis/core:go_default_library", "//pkg/kubeapiserver:go_default_library", - "//pkg/util/slice:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/internalversion:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/registry/registrytest/service.go b/pkg/registry/registrytest/service.go index 490bc0e37e5..72a4a1fde6f 100644 --- a/pkg/registry/registrytest/service.go +++ b/pkg/registry/registrytest/service.go @@ -117,10 +117,3 @@ func (r *ServiceRegistry) WatchServices(ctx context.Context, options *metaintern return nil, r.Err } - -func (r *ServiceRegistry) ExportService(ctx context.Context, name string, options metav1.ExportOptions) (*api.Service, error) { - r.mu.Lock() - defer r.mu.Unlock() - - return r.Service, r.Err -} diff --git a/pkg/registry/registrytest/validate.go b/pkg/registry/registrytest/validate.go index 9016d57e5a1..63612d0c546 100644 --- a/pkg/registry/registrytest/validate.go +++ b/pkg/registry/registrytest/validate.go @@ -21,17 +21,13 @@ import ( "k8s.io/apiserver/pkg/registry/generic/registry" "k8s.io/apiserver/pkg/registry/rest" - "k8s.io/kubernetes/pkg/util/slice" ) // ValidateStorageStrategies ensures any instances of the generic registry.Store in the given storage map // have expected strategies defined. -func ValidateStorageStrategies(storageMap map[string]rest.Storage, exceptions StrategyExceptions) []error { +func ValidateStorageStrategies(storageMap map[string]rest.Storage) []error { errs := []error{} - // Used to ensure we saw all the expected exceptions: - hasExportExceptionsSeen := []string{} - for k, storage := range storageMap { switch t := storage.(type) { case registry.GenericStore: @@ -46,27 +42,6 @@ func ValidateStorageStrategies(storageMap map[string]rest.Storage, exceptions St if t.GetDeleteStrategy() == nil { errs = append(errs, fmt.Errorf("store for type [%v] does not have a DeleteStrategy", k)) } - - // Check that ExportStrategy is set if applicable: - if slice.ContainsString(exceptions.HasExportStrategy, k, nil) { - hasExportExceptionsSeen = append(hasExportExceptionsSeen, k) - if t.GetExportStrategy() == nil { - errs = append(errs, fmt.Errorf("store for type [%v] does not have an ExportStrategy", k)) - } - } else { - // By default we expect Stores to not have additional export logic: - if t.GetExportStrategy() != nil { - errs = append(errs, fmt.Errorf("store for type [%v] has an unexpected ExportStrategy", k)) - } - } - - } - } - - // Ensure that we saw all our expected exceptions: - for _, expKey := range exceptions.HasExportStrategy { - if !slice.ContainsString(hasExportExceptionsSeen, expKey, nil) { - errs = append(errs, fmt.Errorf("no generic store seen for expected ExportStrategy: %v", expKey)) } } diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go index 99a9481cad7..b317e30ebd2 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go @@ -388,7 +388,7 @@ func (r *crdHandler) serveResource(w http.ResponseWriter, req *http.Request, req switch requestInfo.Verb { case "get": - return handlers.GetResource(storage, storage, requestScope) + return handlers.GetResource(storage, requestScope) case "list": forceWatch := false return handlers.ListResource(storage, storage, requestScope, forceWatch, r.minRequestTimeout) @@ -428,7 +428,7 @@ func (r *crdHandler) serveStatus(w http.ResponseWriter, req *http.Request, reque switch requestInfo.Verb { case "get": - return handlers.GetResource(storage, nil, requestScope) + return handlers.GetResource(storage, requestScope) case "update": return handlers.UpdateResource(storage, requestScope, r.admission) case "patch": @@ -448,7 +448,7 @@ func (r *crdHandler) serveScale(w http.ResponseWriter, req *http.Request, reques switch requestInfo.Verb { case "get": - return handlers.GetResource(storage, nil, requestScope) + return handlers.GetResource(storage, requestScope) case "update": return handlers.UpdateResource(storage, requestScope, r.admission) case "patch": @@ -698,7 +698,6 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd parameterScheme := runtime.NewScheme() parameterScheme.AddUnversionedTypes(schema.GroupVersion{Group: crd.Spec.Group, Version: v.Name}, &metav1.ListOptions{}, - &metav1.ExportOptions{}, &metav1.GetOptions{}, &metav1.DeleteOptions{}, ) diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/etcd_test.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/etcd_test.go index 1bd740d7fff..8612eeeb31f 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/etcd_test.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/etcd_test.go @@ -55,7 +55,6 @@ func newStorage(t *testing.T) (customresource.CustomResourceStorage, *etcd3testi parameterScheme := runtime.NewScheme() parameterScheme.AddUnversionedTypes(schema.GroupVersion{Group: "mygroup.example.com", Version: "v1beta1"}, &metav1.ListOptions{}, - &metav1.ExportOptions{}, &metav1.GetOptions{}, &metav1.DeleteOptions{}, ) diff --git a/staging/src/k8s.io/apimachinery/pkg/apis/meta/internalversion/register.go b/staging/src/k8s.io/apimachinery/pkg/apis/meta/internalversion/register.go index ae39b74eb24..a59ac71268b 100644 --- a/staging/src/k8s.io/apimachinery/pkg/apis/meta/internalversion/register.go +++ b/staging/src/k8s.io/apimachinery/pkg/apis/meta/internalversion/register.go @@ -52,7 +52,6 @@ func addToGroupVersion(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &ListOptions{}, &metav1.GetOptions{}, - &metav1.ExportOptions{}, &metav1.DeleteOptions{}, &metav1.CreateOptions{}, &metav1.UpdateOptions{}, diff --git a/staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/register.go b/staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/register.go index c1a077178bf..1abdd626de0 100644 --- a/staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/register.go +++ b/staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/register.go @@ -55,7 +55,6 @@ var ParameterCodec = runtime.NewParameterCodec(scheme) var optionsTypes = []runtime.Object{ &ListOptions{}, - &ExportOptions{}, &GetOptions{}, &DeleteOptions{}, &CreateOptions{}, diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/apiserver_test.go b/staging/src/k8s.io/apiserver/pkg/endpoints/apiserver_test.go index f0da9ede17c..a7b977ee43d 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/apiserver_test.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/apiserver_test.go @@ -142,10 +142,10 @@ func init() { func addGrouplessTypes() { scheme.AddKnownTypes(grouplessGroupVersion, - &genericapitesting.Simple{}, &genericapitesting.SimpleList{}, &metav1.ListOptions{}, &metav1.ExportOptions{}, + &genericapitesting.Simple{}, &genericapitesting.SimpleList{}, &metav1.ListOptions{}, &metav1.DeleteOptions{}, &genericapitesting.SimpleGetOptions{}, &genericapitesting.SimpleRoot{}) scheme.AddKnownTypes(grouplessInternalGroupVersion, - &genericapitesting.Simple{}, &genericapitesting.SimpleList{}, &metav1.ExportOptions{}, + &genericapitesting.Simple{}, &genericapitesting.SimpleList{}, &genericapitesting.SimpleGetOptions{}, &genericapitesting.SimpleRoot{}) utilruntime.Must(genericapitesting.RegisterConversions(scheme)) @@ -153,20 +153,20 @@ func addGrouplessTypes() { func addTestTypes() { scheme.AddKnownTypes(testGroupVersion, - &genericapitesting.Simple{}, &genericapitesting.SimpleList{}, &metav1.ExportOptions{}, + &genericapitesting.Simple{}, &genericapitesting.SimpleList{}, &metav1.DeleteOptions{}, &genericapitesting.SimpleGetOptions{}, &genericapitesting.SimpleRoot{}, &genericapitesting.SimpleXGSubresource{}) scheme.AddKnownTypes(testGroupVersion, &examplev1.Pod{}) scheme.AddKnownTypes(testInternalGroupVersion, - &genericapitesting.Simple{}, &genericapitesting.SimpleList{}, &metav1.ExportOptions{}, + &genericapitesting.Simple{}, &genericapitesting.SimpleList{}, &genericapitesting.SimpleGetOptions{}, &genericapitesting.SimpleRoot{}, &genericapitesting.SimpleXGSubresource{}) scheme.AddKnownTypes(testInternalGroupVersion, &example.Pod{}) // Register SimpleXGSubresource in both testGroupVersion and testGroup2Version, and also their // their corresponding internal versions, to verify that the desired group version object is // served in the tests. - scheme.AddKnownTypes(testGroup2Version, &genericapitesting.SimpleXGSubresource{}, &metav1.ExportOptions{}) - scheme.AddKnownTypes(testInternalGroup2Version, &genericapitesting.SimpleXGSubresource{}, &metav1.ExportOptions{}) + scheme.AddKnownTypes(testGroup2Version, &genericapitesting.SimpleXGSubresource{}) + scheme.AddKnownTypes(testInternalGroup2Version, &genericapitesting.SimpleXGSubresource{}) metav1.AddToGroupVersion(scheme, testGroupVersion) utilruntime.Must(genericapitesting.RegisterConversions(scheme)) @@ -174,7 +174,7 @@ func addTestTypes() { func addNewTestTypes() { scheme.AddKnownTypes(newGroupVersion, - &genericapitesting.Simple{}, &genericapitesting.SimpleList{}, &metav1.ExportOptions{}, + &genericapitesting.Simple{}, &genericapitesting.SimpleList{}, &metav1.DeleteOptions{}, &genericapitesting.SimpleGetOptions{}, &genericapitesting.SimpleRoot{}, &examplev1.Pod{}, ) @@ -368,21 +368,6 @@ func (storage *SimpleRESTStorage) NamespaceScoped() bool { return true } -func (storage *SimpleRESTStorage) Export(ctx context.Context, name string, opts metav1.ExportOptions) (runtime.Object, error) { - obj, err := storage.Get(ctx, name, &metav1.GetOptions{}) - if err != nil { - return nil, err - } - s, ok := obj.(*genericapitesting.Simple) - if !ok { - return nil, fmt.Errorf("unexpected object") - } - - // Set a marker to verify the method was called - s.Other = "exported" - return obj, storage.errors["export"] -} - func (storage *SimpleRESTStorage) ConvertToTable(ctx context.Context, obj runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { return rest.NewDefaultTableConvertor(schema.GroupResource{Resource: "simple"}).ConvertToTable(ctx, obj, tableOptions) } @@ -1556,55 +1541,6 @@ func TestMetadata(t *testing.T) { } } -func TestExport(t *testing.T) { - storage := map[string]rest.Storage{} - simpleStorage := SimpleRESTStorage{ - item: genericapitesting.Simple{ - ObjectMeta: metav1.ObjectMeta{ - ResourceVersion: "1234", - CreationTimestamp: metav1.NewTime(time.Unix(10, 10)), - }, - Other: "foo", - }, - } - selfLinker := &setTestSelfLinker{ - t: t, - expectedSet: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/id", - name: "id", - namespace: "default", - } - storage["simple"] = &simpleStorage - handler := handleLinker(storage, selfLinker) - server := httptest.NewServer(handler) - defer server.Close() - - resp, err := http.Get(server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/id?export=true") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if resp.StatusCode != http.StatusOK { - data, _ := ioutil.ReadAll(resp.Body) - resp.Body.Close() - t.Fatalf("unexpected response: %#v\n%s\n", resp, string(data)) - } - var itemOut genericapitesting.Simple - body, err := extractBody(resp, &itemOut) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - if itemOut.Name != simpleStorage.item.Name { - t.Errorf("Unexpected data: %#v, expected %#v (%s)", itemOut, simpleStorage.item, string(body)) - } - if itemOut.Other != "exported" { - t.Errorf("Expected: exported, saw: %s", itemOut.Other) - } - - if utilfeature.DefaultFeatureGate.Enabled(features.RemoveSelfLink) == selfLinker.called { - t.Errorf("unexpected selfLinker.called: %v", selfLinker.called) - } -} - func TestGet(t *testing.T) { storage := map[string]rest.Storage{} simpleStorage := SimpleRESTStorage{ diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/get.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/get.go index da227e7aeda..6c09b496535 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/get.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/get.go @@ -19,14 +19,15 @@ package handlers import ( "context" "fmt" - metainternalversionvalidation "k8s.io/apimachinery/pkg/apis/meta/internalversion/validation" - "k8s.io/apimachinery/pkg/runtime/schema" "math/rand" "net/http" "net/url" "strings" "time" + metainternalversionvalidation "k8s.io/apimachinery/pkg/apis/meta/internalversion/validation" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/klog/v2" "k8s.io/apimachinery/pkg/api/errors" @@ -81,22 +82,22 @@ func getResourceHandler(scope *RequestScope, getter getterFunc) http.HandlerFunc } // GetResource returns a function that handles retrieving a single resource from a rest.Storage object. -func GetResource(r rest.Getter, e rest.Exporter, scope *RequestScope) http.HandlerFunc { +func GetResource(r rest.Getter, scope *RequestScope) http.HandlerFunc { return getResourceHandler(scope, func(ctx context.Context, name string, req *http.Request, trace *utiltrace.Trace) (runtime.Object, error) { // check for export options := metav1.GetOptions{} if values := req.URL.Query(); len(values) > 0 { - exports := metav1.ExportOptions{} - if err := metainternalversionscheme.ParameterCodec.DecodeParameters(values, scope.MetaGroupVersion, &exports); err != nil { - err = errors.NewBadRequest(err.Error()) - return nil, err - } - if exports.Export { - if e == nil { - return nil, errors.NewBadRequest(fmt.Sprintf("export of %q is not supported", scope.Resource.Resource)) + if len(values["export"]) > 0 { + exportBool := true + exportStrings := values["export"] + err := runtime.Convert_Slice_string_To_bool(&exportStrings, &exportBool, nil) + if err != nil { + return nil, errors.NewBadRequest(fmt.Sprintf("the export parameter cannot be parsed: %v", err)) + } + if exportBool { + return nil, errors.NewBadRequest("the export parameter, deprecated since v1.14, is no longer supported") } - return e.Export(ctx, name, exports) } if err := metainternalversionscheme.ParameterCodec.DecodeParameters(values, scope.MetaGroupVersion, &options); err != nil { err = errors.NewBadRequest(err.Error()) diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go b/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go index 6549771ced8..ec09454ed8d 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go @@ -253,15 +253,6 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag if !isMetadata { storageMeta = defaultStorageMetadata{} } - exporter, isExporter := storage.(rest.Exporter) - if !isExporter { - exporter = nil - } - - versionedExportOptions, err := a.group.Creater.New(optionsExternalVersion.WithKind("ExportOptions")) - if err != nil { - return nil, nil, err - } if isNamedCreater { isCreater = true @@ -684,7 +675,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag if isGetterWithOptions { handler = restfulGetResourceWithOptions(getterWithOptions, reqScope, isSubresource) } else { - handler = restfulGetResource(getter, exporter, reqScope) + handler = restfulGetResource(getter, reqScope) } if needOverride { @@ -713,11 +704,6 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag return nil, nil, err } } - if isExporter { - if err := AddObjectParams(ws, route, versionedExportOptions); err != nil { - return nil, nil, err - } - } addParams(route, action.Params) routes = append(routes, route) case "LIST": // List all resources of a kind. @@ -1227,9 +1213,9 @@ func restfulPatchResource(r rest.Patcher, scope handlers.RequestScope, admit adm } } -func restfulGetResource(r rest.Getter, e rest.Exporter, scope handlers.RequestScope) restful.RouteFunction { +func restfulGetResource(r rest.Getter, scope handlers.RequestScope) restful.RouteFunction { return func(req *restful.Request, res *restful.Response) { - handlers.GetResource(r, e, &scope)(res.ResponseWriter, req.Request) + handlers.GetResource(r, &scope)(res.ResponseWriter, req.Request) } } diff --git a/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go b/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go index 4a80a43948d..b5a3377493d 100644 --- a/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go +++ b/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go @@ -19,7 +19,6 @@ package registry import ( "context" "fmt" - "reflect" "strings" "sync" "time" @@ -73,7 +72,6 @@ type GenericStore interface { GetCreateStrategy() rest.RESTCreateStrategy GetUpdateStrategy() rest.RESTUpdateStrategy GetDeleteStrategy() rest.RESTDeleteStrategy - GetExportStrategy() rest.RESTExportStrategy } // Store implements k8s.io/apiserver/pkg/registry/rest.StandardStorage. It's @@ -199,10 +197,6 @@ type Store struct { // deletionTimestamp, and deletionGracePeriodSeconds checks. ShouldDeleteDuringUpdate func(ctx context.Context, key string, obj, existing runtime.Object) bool - // ExportStrategy implements resource-specific behavior during export, - // optional. Exported objects are not decorated. - ExportStrategy rest.RESTExportStrategy - // TableConvertor is an optional interface for transforming items or lists // of items into tabular output. If unset, the default will be used. TableConvertor rest.TableConvertor @@ -223,7 +217,6 @@ type Store struct { // Note: the rest.StandardStorage interface aggregates the common REST verbs var _ rest.StandardStorage = &Store{} -var _ rest.Exporter = &Store{} var _ rest.TableConvertor = &Store{} var _ GenericStore = &Store{} @@ -312,11 +305,6 @@ func (e *Store) GetDeleteStrategy() rest.RESTDeleteStrategy { return e.DeleteStrategy } -// GetExportStrategy implements GenericStore. -func (e *Store) GetExportStrategy() rest.RESTExportStrategy { - return e.ExportStrategy -} - // List returns a list of items matching labels and field according to the // store's PredicateFunc. func (e *Store) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) { @@ -1267,44 +1255,6 @@ func (e *Store) calculateTTL(obj runtime.Object, defaultTTL int64, update bool) return ttl, err } -// exportObjectMeta unsets the fields on the given object that should not be -// present when the object is exported. -func exportObjectMeta(accessor metav1.Object, exact bool) { - accessor.SetUID("") - if !exact { - accessor.SetNamespace("") - } - accessor.SetCreationTimestamp(metav1.Time{}) - accessor.SetDeletionTimestamp(nil) - accessor.SetResourceVersion("") - accessor.SetSelfLink("") - if len(accessor.GetGenerateName()) > 0 && !exact { - accessor.SetName("") - } -} - -// Export implements the rest.Exporter interface -func (e *Store) Export(ctx context.Context, name string, opts metav1.ExportOptions) (runtime.Object, error) { - obj, err := e.Get(ctx, name, &metav1.GetOptions{}) - if err != nil { - return nil, err - } - if accessor, err := meta.Accessor(obj); err == nil { - exportObjectMeta(accessor, opts.Exact) - } else { - klog.V(4).Infof("Object of type %v does not have ObjectMeta: %v", reflect.TypeOf(obj), err) - } - - if e.ExportStrategy != nil { - if err = e.ExportStrategy.Export(ctx, obj, opts.Exact); err != nil { - return nil, err - } - } else { - e.CreateStrategy.PrepareForCreate(ctx, obj) - } - return obj, nil -} - // CompleteWithOptions updates the store with the provided options and // defaults common fields. func (e *Store) CompleteWithOptions(options *generic.StoreOptions) error { diff --git a/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store_test.go b/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store_test.go index 3f89a3fac82..cd8556f7743 100644 --- a/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store_test.go +++ b/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store_test.go @@ -1162,104 +1162,6 @@ func TestStoreUpdateHooksInnerRetry(t *testing.T) { } } -// TODO: Add a test to check no-op update if we have object with ResourceVersion -// already stored in etcd. Currently there is no easy way to store object with -// ResourceVersion in etcd. - -type testPodExport struct{} - -func (t testPodExport) Export(ctx context.Context, obj runtime.Object, exact bool) error { - pod := obj.(*example.Pod) - if pod.Labels == nil { - pod.Labels = map[string]string{} - } - pod.Labels["exported"] = "true" - pod.Labels["exact"] = strconv.FormatBool(exact) - - return nil -} - -func TestStoreCustomExport(t *testing.T) { - podA := example.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "foo", - Labels: map[string]string{}, - }, - Spec: example.PodSpec{NodeName: "machine"}, - } - - destroyFunc, registry := NewTestGenericStoreRegistry(t) - defer destroyFunc() - - registry.ExportStrategy = testPodExport{} - - testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test") - registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = true - if !updateAndVerify(t, testContext, registry, &podA) { - t.Errorf("Unexpected error updating podA") - } - - obj, err := registry.Export(testContext, podA.Name, metav1.ExportOptions{}) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - exportedPod := obj.(*example.Pod) - if exportedPod.Labels["exported"] != "true" { - t.Errorf("expected: exported->true, found: %s", exportedPod.Labels["exported"]) - } - if exportedPod.Labels["exact"] != "false" { - t.Errorf("expected: exact->false, found: %s", exportedPod.Labels["exact"]) - } - if exportedPod.Labels["prepare_create"] != "true" { - t.Errorf("expected: prepare_create->true, found: %s", exportedPod.Labels["prepare_create"]) - } - delete(exportedPod.Labels, "exported") - delete(exportedPod.Labels, "exact") - delete(exportedPod.Labels, "prepare_create") - exportObjectMeta(&podA.ObjectMeta, false) - podA.Spec = exportedPod.Spec - if !reflect.DeepEqual(&podA, exportedPod) { - t.Errorf("expected:\n%v\nsaw:\n%v\n", &podA, exportedPod) - } -} - -func TestStoreBasicExport(t *testing.T) { - podA := example.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "foo", - Labels: map[string]string{}, - }, - Spec: example.PodSpec{NodeName: "machine"}, - Status: example.PodStatus{HostIP: "1.2.3.4"}, - } - - destroyFunc, registry := NewTestGenericStoreRegistry(t) - defer destroyFunc() - - testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test") - registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = true - if !updateAndVerify(t, testContext, registry, &podA) { - t.Errorf("Unexpected error updating podA") - } - - obj, err := registry.Export(testContext, podA.Name, metav1.ExportOptions{}) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - exportedPod := obj.(*example.Pod) - if exportedPod.Labels["prepare_create"] != "true" { - t.Errorf("expected: prepare_create->true, found: %s", exportedPod.Labels["prepare_create"]) - } - delete(exportedPod.Labels, "prepare_create") - exportObjectMeta(&podA.ObjectMeta, false) - podA.Spec = exportedPod.Spec - if !reflect.DeepEqual(&podA, exportedPod) { - t.Errorf("expected:\n%v\nsaw:\n%v\n", &podA, exportedPod) - } -} - func TestStoreGet(t *testing.T) { podA := &example.Pod{ ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo"}, diff --git a/staging/src/k8s.io/apiserver/pkg/registry/rest/BUILD b/staging/src/k8s.io/apiserver/pkg/registry/rest/BUILD index 1c04312bcd8..e8f3230acf6 100644 --- a/staging/src/k8s.io/apiserver/pkg/registry/rest/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/registry/rest/BUILD @@ -25,7 +25,6 @@ go_library( "create_update.go", "delete.go", "doc.go", - "export.go", "meta.go", "rest.go", "table.go", diff --git a/staging/src/k8s.io/apiserver/pkg/registry/rest/export.go b/staging/src/k8s.io/apiserver/pkg/registry/rest/export.go deleted file mode 100644 index b3fd8af3001..00000000000 --- a/staging/src/k8s.io/apiserver/pkg/registry/rest/export.go +++ /dev/null @@ -1,34 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package rest - -import ( - "context" - - "k8s.io/apimachinery/pkg/runtime" -) - -// RESTExportStrategy is the interface that defines how to export a Kubernetes -// object. An exported object is stripped of non-user-settable fields and -// optionally, the identifying information related to the object's identity in -// the cluster so that it can be loaded into a different namespace or entirely -// different cluster without conflict. -type RESTExportStrategy interface { - // Export strips fields that can not be set by the user. If 'exact' is false - // fields specific to the cluster are also stripped - Export(ctx context.Context, obj runtime.Object, exact bool) error -} diff --git a/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go b/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go index aca8da8b4a0..66e7844a277 100644 --- a/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go +++ b/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go @@ -102,16 +102,6 @@ type Lister interface { TableConvertor } -// Exporter is an object that knows how to strip a RESTful resource for export. A store should implement this interface -// if export is generally supported for that type. Errors can still be returned during the actual Export when certain -// instances of the type are not exportable. -type Exporter interface { - // Export an object. Fields that are not user specified (e.g. Status, ObjectMeta.ResourceVersion) are stripped out - // Returns the stripped object. If 'exact' is true, fields that are specific to the cluster (e.g. namespace) are - // retained, otherwise they are stripped also. - Export(ctx context.Context, name string, opts metav1.ExportOptions) (runtime.Object, error) -} - // Getter is an object that can retrieve a named RESTful resource. type Getter interface { // Get finds a resource in the storage by name and returns it. diff --git a/test/integration/apiserver/BUILD b/test/integration/apiserver/BUILD index 413adb999ca..57e1500efde 100644 --- a/test/integration/apiserver/BUILD +++ b/test/integration/apiserver/BUILD @@ -10,6 +10,7 @@ go_test( size = "large", srcs = [ "apiserver_test.go", + "export_test.go", "main_test.go", "max_json_patch_operations_test.go", "max_request_body_bytes_test.go", diff --git a/test/integration/apiserver/export_test.go b/test/integration/apiserver/export_test.go new file mode 100644 index 00000000000..5c03355c840 --- /dev/null +++ b/test/integration/apiserver/export_test.go @@ -0,0 +1,57 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apiserver + +import ( + "context" + "net/http" + "testing" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Tests that the apiserver rejects the export param +func TestExportRejection(t *testing.T) { + _, clientSet, closeFn := setup(t) + defer closeFn() + + _, err := clientSet.CoreV1().Namespaces().Create(context.Background(), &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: "export-fail"}, + }, metav1.CreateOptions{}) + if err != nil { + t.Fatal(err) + } + defer func() { + clientSet.CoreV1().Namespaces().Delete(context.Background(), "export-fail", metav1.DeleteOptions{}) + }() + + result := clientSet.Discovery().RESTClient().Get().AbsPath("/api/v1/namespaces/export-fail").Param("export", "true").Do(context.Background()) + statusCode := 0 + result.StatusCode(&statusCode) + if statusCode != http.StatusBadRequest { + t.Errorf("expected %v, got %v", http.StatusBadRequest, statusCode) + } + + result = clientSet.Discovery().RESTClient().Get().AbsPath("/api/v1/namespaces/export-fail").Param("export", "false").Do(context.Background()) + statusCode = 0 + result.StatusCode(&statusCode) + if statusCode != http.StatusOK { + t.Errorf("expected %v, got %v", http.StatusOK, statusCode) + } + +}