mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 11:50:44 +00:00
finish removal of exportoptions
This commit is contained in:
parent
82ebcd1719
commit
37cc89ed8d
@ -167,7 +167,7 @@ var nonRoundTrippableTypes = sets.NewString(
|
|||||||
"PatchOptions",
|
"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
|
// TestCommonKindsRegistered verifies that all group/versions registered with
|
||||||
// the legacyscheme package have the common kinds.
|
// the legacyscheme package have the common kinds.
|
||||||
|
@ -64,7 +64,6 @@ var typesAllowedTags = map[reflect.Type]bool{
|
|||||||
reflect.TypeOf(metav1.OwnerReference{}): true,
|
reflect.TypeOf(metav1.OwnerReference{}): true,
|
||||||
reflect.TypeOf(metav1.LabelSelector{}): true,
|
reflect.TypeOf(metav1.LabelSelector{}): true,
|
||||||
reflect.TypeOf(metav1.GetOptions{}): true,
|
reflect.TypeOf(metav1.GetOptions{}): true,
|
||||||
reflect.TypeOf(metav1.ExportOptions{}): true,
|
|
||||||
reflect.TypeOf(metav1.ListOptions{}): true,
|
reflect.TypeOf(metav1.ListOptions{}): true,
|
||||||
reflect.TypeOf(metav1.DeleteOptions{}): true,
|
reflect.TypeOf(metav1.DeleteOptions{}): true,
|
||||||
reflect.TypeOf(metav1.GroupVersionKind{}): true,
|
reflect.TypeOf(metav1.GroupVersionKind{}): true,
|
||||||
|
@ -160,18 +160,7 @@ func TestLegacyRestStorageStrategies(t *testing.T) {
|
|||||||
t.Errorf("failed to create legacy REST storage: %v", err)
|
t.Errorf("failed to create legacy REST storage: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any new stores with export logic will need to be added here:
|
strategyErrors := registrytest.ValidateStorageStrategies(apiGroupInfo.VersionedResourcesStorageMap["v1"])
|
||||||
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)
|
|
||||||
for _, err := range strategyErrors {
|
for _, err := range strategyErrors {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -187,14 +176,8 @@ func TestCertificatesRestStorageStrategies(t *testing.T) {
|
|||||||
t.Fatalf("unexpected error from REST storage: %v", err)
|
t.Fatalf("unexpected error from REST storage: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
exceptions := registrytest.StrategyExceptions{
|
|
||||||
HasExportStrategy: []string{
|
|
||||||
"certificatesigningrequests",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
strategyErrors := registrytest.ValidateStorageStrategies(
|
strategyErrors := registrytest.ValidateStorageStrategies(
|
||||||
apiGroupInfo.VersionedResourcesStorageMap[certificatesapiv1beta1.SchemeGroupVersion.Version], exceptions)
|
apiGroupInfo.VersionedResourcesStorageMap[certificatesapiv1beta1.SchemeGroupVersion.Version])
|
||||||
for _, err := range strategyErrors {
|
for _, err := range strategyErrors {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,6 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, *Approva
|
|||||||
CreateStrategy: csrregistry.Strategy,
|
CreateStrategy: csrregistry.Strategy,
|
||||||
UpdateStrategy: csrregistry.Strategy,
|
UpdateStrategy: csrregistry.Strategy,
|
||||||
DeleteStrategy: csrregistry.Strategy,
|
DeleteStrategy: csrregistry.Strategy,
|
||||||
ExportStrategy: csrregistry.Strategy,
|
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
|
@ -118,21 +118,6 @@ func (csrStrategy) AllowUnconditionalUpdate() bool {
|
|||||||
return true
|
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
|
// Storage strategy for the Status subresource
|
||||||
type csrStatusStrategy struct {
|
type csrStatusStrategy struct {
|
||||||
csrStrategy
|
csrStrategy
|
||||||
|
@ -40,7 +40,6 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, error) {
|
|||||||
CreateStrategy: limitrange.Strategy,
|
CreateStrategy: limitrange.Strategy,
|
||||||
UpdateStrategy: limitrange.Strategy,
|
UpdateStrategy: limitrange.Strategy,
|
||||||
DeleteStrategy: limitrange.Strategy,
|
DeleteStrategy: limitrange.Strategy,
|
||||||
ExportStrategy: limitrange.Strategy,
|
|
||||||
|
|
||||||
// TODO: define table converter that exposes more than name/creation timestamp
|
// TODO: define table converter that exposes more than name/creation timestamp
|
||||||
TableConvertor: rest.NewDefaultTableConvertor(api.Resource("limitranges")),
|
TableConvertor: rest.NewDefaultTableConvertor(api.Resource("limitranges")),
|
||||||
|
@ -72,10 +72,3 @@ func (limitrangeStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.O
|
|||||||
func (limitrangeStrategy) AllowUnconditionalUpdate() bool {
|
func (limitrangeStrategy) AllowUnconditionalUpdate() bool {
|
||||||
return true
|
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
|
|
||||||
}
|
|
||||||
|
@ -119,10 +119,6 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio
|
|||||||
return r.store.Watch(ctx, options)
|
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
|
// 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) {
|
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{})
|
nsObj, err := r.Get(ctx, name, &metav1.GetOptions{})
|
||||||
|
@ -88,7 +88,6 @@ func NewStorage(optsGetter generic.RESTOptionsGetter, kubeletClientConfig client
|
|||||||
CreateStrategy: node.Strategy,
|
CreateStrategy: node.Strategy,
|
||||||
UpdateStrategy: node.Strategy,
|
UpdateStrategy: node.Strategy,
|
||||||
DeleteStrategy: node.Strategy,
|
DeleteStrategy: node.Strategy,
|
||||||
ExportStrategy: node.Strategy,
|
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
|
@ -141,22 +141,6 @@ func (nodeStrategy) AllowUnconditionalUpdate() bool {
|
|||||||
return true
|
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 {
|
type nodeStatusStrategy struct {
|
||||||
nodeStrategy
|
nodeStrategy
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,6 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, error) {
|
|||||||
CreateStrategy: podtemplate.Strategy,
|
CreateStrategy: podtemplate.Strategy,
|
||||||
UpdateStrategy: podtemplate.Strategy,
|
UpdateStrategy: podtemplate.Strategy,
|
||||||
DeleteStrategy: podtemplate.Strategy,
|
DeleteStrategy: podtemplate.Strategy,
|
||||||
ExportStrategy: podtemplate.Strategy,
|
|
||||||
|
|
||||||
ReturnDeletedObject: true,
|
ReturnDeletedObject: true,
|
||||||
|
|
||||||
|
@ -87,8 +87,3 @@ func (podTemplateStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.
|
|||||||
func (podTemplateStrategy) AllowUnconditionalUpdate() bool {
|
func (podTemplateStrategy) AllowUnconditionalUpdate() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (podTemplateStrategy) Export(ctx context.Context, obj runtime.Object, exact bool) error {
|
|
||||||
// Do nothing
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -17,7 +17,6 @@ go_library(
|
|||||||
"//pkg/api/legacyscheme:go_default_library",
|
"//pkg/api/legacyscheme:go_default_library",
|
||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
"//pkg/apis/core/validation: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/fields:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime: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/api/testing:go_default_library",
|
||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
"//pkg/apis/core/install: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",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -44,7 +44,6 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, error) {
|
|||||||
CreateStrategy: secret.Strategy,
|
CreateStrategy: secret.Strategy,
|
||||||
UpdateStrategy: secret.Strategy,
|
UpdateStrategy: secret.Strategy,
|
||||||
DeleteStrategy: secret.Strategy,
|
DeleteStrategy: secret.Strategy,
|
||||||
ExportStrategy: secret.Strategy,
|
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
"k8s.io/apimachinery/pkg/fields"
|
"k8s.io/apimachinery/pkg/fields"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
@ -85,26 +84,6 @@ func (strategy) AllowUnconditionalUpdate() bool {
|
|||||||
return true
|
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.
|
// GetAttrs returns labels and fields of a given object for filtering purposes.
|
||||||
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
|
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
|
||||||
secret, ok := obj.(*api.Secret)
|
secret, ok := obj.(*api.Secret)
|
||||||
|
@ -17,12 +17,8 @@ limitations under the License.
|
|||||||
package secret
|
package secret
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
|
||||||
"testing"
|
"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"
|
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
|
|
||||||
@ -30,80 +26,6 @@ import (
|
|||||||
_ "k8s.io/kubernetes/pkg/apis/core/install"
|
_ "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) {
|
func TestSelectableFieldLabelConversions(t *testing.T) {
|
||||||
apitesting.TestSelectableFieldLabelConversionsOfKind(t,
|
apitesting.TestSelectableFieldLabelConversionsOfKind(t,
|
||||||
"v1",
|
"v1",
|
||||||
|
@ -79,7 +79,6 @@ type ServiceStorage interface {
|
|||||||
rest.CreaterUpdater
|
rest.CreaterUpdater
|
||||||
rest.GracefulDeleter
|
rest.GracefulDeleter
|
||||||
rest.Watcher
|
rest.Watcher
|
||||||
rest.Exporter
|
|
||||||
rest.StorageVersionProvider
|
rest.StorageVersionProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,10 +188,6 @@ func (rs *REST) Watch(ctx context.Context, options *metainternalversion.ListOpti
|
|||||||
return rs.services.Watch(ctx, options)
|
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) {
|
func (rs *REST) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
|
||||||
service := obj.(*api.Service)
|
service := obj.(*api.Service)
|
||||||
|
|
||||||
|
@ -163,10 +163,6 @@ func (s *serviceStorage) ConvertToTable(ctx context.Context, object runtime.Obje
|
|||||||
panic("not implemented")
|
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 {
|
func (s *serviceStorage) StorageVersion() runtime.GroupVersioner {
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,6 @@ func NewGenericREST(optsGetter generic.RESTOptionsGetter, serviceCIDR net.IPNet,
|
|||||||
CreateStrategy: strategy,
|
CreateStrategy: strategy,
|
||||||
UpdateStrategy: strategy,
|
UpdateStrategy: strategy,
|
||||||
DeleteStrategy: strategy,
|
DeleteStrategy: strategy,
|
||||||
ExportStrategy: strategy,
|
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
@ -37,7 +36,6 @@ import (
|
|||||||
|
|
||||||
type Strategy interface {
|
type Strategy interface {
|
||||||
rest.RESTCreateUpdateStrategy
|
rest.RESTCreateUpdateStrategy
|
||||||
rest.RESTExportStrategy
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// svcStrategy implements behavior for Services
|
// svcStrategy implements behavior for Services
|
||||||
@ -139,30 +137,6 @@ func (svcStrategy) AllowUnconditionalUpdate() bool {
|
|||||||
return true
|
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
|
// dropServiceDisabledFields drops fields that are not used if their associated feature gates
|
||||||
// are not enabled. The typical pattern is:
|
// are not enabled. The typical pattern is:
|
||||||
// if !utilfeature.DefaultFeatureGate.Enabled(features.MyFeature) && !myFeatureInUse(oldSvc) {
|
// if !utilfeature.DefaultFeatureGate.Enabled(features.MyFeature) && !myFeatureInUse(oldSvc) {
|
||||||
|
@ -47,115 +47,6 @@ func newStrategy(cidr string, hasSecondary bool) (testStrategy Strategy, testSta
|
|||||||
return
|
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) {
|
func TestCheckGeneratedNameError(t *testing.T) {
|
||||||
testStrategy, _ := newStrategy("10.0.0.0/16", false)
|
testStrategy, _ := newStrategy("10.0.0.0/16", false)
|
||||||
expect := errors.NewNotFound(api.Resource("foos"), "bar")
|
expect := errors.NewNotFound(api.Resource("foos"), "bar")
|
||||||
|
@ -21,7 +21,6 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
"//pkg/kubeapiserver: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/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/internalversion:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
@ -117,10 +117,3 @@ func (r *ServiceRegistry) WatchServices(ctx context.Context, options *metaintern
|
|||||||
|
|
||||||
return nil, r.Err
|
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
|
|
||||||
}
|
|
||||||
|
@ -21,17 +21,13 @@ import (
|
|||||||
|
|
||||||
"k8s.io/apiserver/pkg/registry/generic/registry"
|
"k8s.io/apiserver/pkg/registry/generic/registry"
|
||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"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
|
// ValidateStorageStrategies ensures any instances of the generic registry.Store in the given storage map
|
||||||
// have expected strategies defined.
|
// have expected strategies defined.
|
||||||
func ValidateStorageStrategies(storageMap map[string]rest.Storage, exceptions StrategyExceptions) []error {
|
func ValidateStorageStrategies(storageMap map[string]rest.Storage) []error {
|
||||||
errs := []error{}
|
errs := []error{}
|
||||||
|
|
||||||
// Used to ensure we saw all the expected exceptions:
|
|
||||||
hasExportExceptionsSeen := []string{}
|
|
||||||
|
|
||||||
for k, storage := range storageMap {
|
for k, storage := range storageMap {
|
||||||
switch t := storage.(type) {
|
switch t := storage.(type) {
|
||||||
case registry.GenericStore:
|
case registry.GenericStore:
|
||||||
@ -46,27 +42,6 @@ func ValidateStorageStrategies(storageMap map[string]rest.Storage, exceptions St
|
|||||||
if t.GetDeleteStrategy() == nil {
|
if t.GetDeleteStrategy() == nil {
|
||||||
errs = append(errs, fmt.Errorf("store for type [%v] does not have a DeleteStrategy", k))
|
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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,7 +388,7 @@ func (r *crdHandler) serveResource(w http.ResponseWriter, req *http.Request, req
|
|||||||
|
|
||||||
switch requestInfo.Verb {
|
switch requestInfo.Verb {
|
||||||
case "get":
|
case "get":
|
||||||
return handlers.GetResource(storage, storage, requestScope)
|
return handlers.GetResource(storage, requestScope)
|
||||||
case "list":
|
case "list":
|
||||||
forceWatch := false
|
forceWatch := false
|
||||||
return handlers.ListResource(storage, storage, requestScope, forceWatch, r.minRequestTimeout)
|
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 {
|
switch requestInfo.Verb {
|
||||||
case "get":
|
case "get":
|
||||||
return handlers.GetResource(storage, nil, requestScope)
|
return handlers.GetResource(storage, requestScope)
|
||||||
case "update":
|
case "update":
|
||||||
return handlers.UpdateResource(storage, requestScope, r.admission)
|
return handlers.UpdateResource(storage, requestScope, r.admission)
|
||||||
case "patch":
|
case "patch":
|
||||||
@ -448,7 +448,7 @@ func (r *crdHandler) serveScale(w http.ResponseWriter, req *http.Request, reques
|
|||||||
|
|
||||||
switch requestInfo.Verb {
|
switch requestInfo.Verb {
|
||||||
case "get":
|
case "get":
|
||||||
return handlers.GetResource(storage, nil, requestScope)
|
return handlers.GetResource(storage, requestScope)
|
||||||
case "update":
|
case "update":
|
||||||
return handlers.UpdateResource(storage, requestScope, r.admission)
|
return handlers.UpdateResource(storage, requestScope, r.admission)
|
||||||
case "patch":
|
case "patch":
|
||||||
@ -698,7 +698,6 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd
|
|||||||
parameterScheme := runtime.NewScheme()
|
parameterScheme := runtime.NewScheme()
|
||||||
parameterScheme.AddUnversionedTypes(schema.GroupVersion{Group: crd.Spec.Group, Version: v.Name},
|
parameterScheme.AddUnversionedTypes(schema.GroupVersion{Group: crd.Spec.Group, Version: v.Name},
|
||||||
&metav1.ListOptions{},
|
&metav1.ListOptions{},
|
||||||
&metav1.ExportOptions{},
|
|
||||||
&metav1.GetOptions{},
|
&metav1.GetOptions{},
|
||||||
&metav1.DeleteOptions{},
|
&metav1.DeleteOptions{},
|
||||||
)
|
)
|
||||||
|
@ -55,7 +55,6 @@ func newStorage(t *testing.T) (customresource.CustomResourceStorage, *etcd3testi
|
|||||||
parameterScheme := runtime.NewScheme()
|
parameterScheme := runtime.NewScheme()
|
||||||
parameterScheme.AddUnversionedTypes(schema.GroupVersion{Group: "mygroup.example.com", Version: "v1beta1"},
|
parameterScheme.AddUnversionedTypes(schema.GroupVersion{Group: "mygroup.example.com", Version: "v1beta1"},
|
||||||
&metav1.ListOptions{},
|
&metav1.ListOptions{},
|
||||||
&metav1.ExportOptions{},
|
|
||||||
&metav1.GetOptions{},
|
&metav1.GetOptions{},
|
||||||
&metav1.DeleteOptions{},
|
&metav1.DeleteOptions{},
|
||||||
)
|
)
|
||||||
|
@ -52,7 +52,6 @@ func addToGroupVersion(scheme *runtime.Scheme) error {
|
|||||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||||
&ListOptions{},
|
&ListOptions{},
|
||||||
&metav1.GetOptions{},
|
&metav1.GetOptions{},
|
||||||
&metav1.ExportOptions{},
|
|
||||||
&metav1.DeleteOptions{},
|
&metav1.DeleteOptions{},
|
||||||
&metav1.CreateOptions{},
|
&metav1.CreateOptions{},
|
||||||
&metav1.UpdateOptions{},
|
&metav1.UpdateOptions{},
|
||||||
|
@ -55,7 +55,6 @@ var ParameterCodec = runtime.NewParameterCodec(scheme)
|
|||||||
|
|
||||||
var optionsTypes = []runtime.Object{
|
var optionsTypes = []runtime.Object{
|
||||||
&ListOptions{},
|
&ListOptions{},
|
||||||
&ExportOptions{},
|
|
||||||
&GetOptions{},
|
&GetOptions{},
|
||||||
&DeleteOptions{},
|
&DeleteOptions{},
|
||||||
&CreateOptions{},
|
&CreateOptions{},
|
||||||
|
@ -142,10 +142,10 @@ func init() {
|
|||||||
|
|
||||||
func addGrouplessTypes() {
|
func addGrouplessTypes() {
|
||||||
scheme.AddKnownTypes(grouplessGroupVersion,
|
scheme.AddKnownTypes(grouplessGroupVersion,
|
||||||
&genericapitesting.Simple{}, &genericapitesting.SimpleList{}, &metav1.ListOptions{}, &metav1.ExportOptions{},
|
&genericapitesting.Simple{}, &genericapitesting.SimpleList{}, &metav1.ListOptions{},
|
||||||
&metav1.DeleteOptions{}, &genericapitesting.SimpleGetOptions{}, &genericapitesting.SimpleRoot{})
|
&metav1.DeleteOptions{}, &genericapitesting.SimpleGetOptions{}, &genericapitesting.SimpleRoot{})
|
||||||
scheme.AddKnownTypes(grouplessInternalGroupVersion,
|
scheme.AddKnownTypes(grouplessInternalGroupVersion,
|
||||||
&genericapitesting.Simple{}, &genericapitesting.SimpleList{}, &metav1.ExportOptions{},
|
&genericapitesting.Simple{}, &genericapitesting.SimpleList{},
|
||||||
&genericapitesting.SimpleGetOptions{}, &genericapitesting.SimpleRoot{})
|
&genericapitesting.SimpleGetOptions{}, &genericapitesting.SimpleRoot{})
|
||||||
|
|
||||||
utilruntime.Must(genericapitesting.RegisterConversions(scheme))
|
utilruntime.Must(genericapitesting.RegisterConversions(scheme))
|
||||||
@ -153,20 +153,20 @@ func addGrouplessTypes() {
|
|||||||
|
|
||||||
func addTestTypes() {
|
func addTestTypes() {
|
||||||
scheme.AddKnownTypes(testGroupVersion,
|
scheme.AddKnownTypes(testGroupVersion,
|
||||||
&genericapitesting.Simple{}, &genericapitesting.SimpleList{}, &metav1.ExportOptions{},
|
&genericapitesting.Simple{}, &genericapitesting.SimpleList{},
|
||||||
&metav1.DeleteOptions{}, &genericapitesting.SimpleGetOptions{}, &genericapitesting.SimpleRoot{},
|
&metav1.DeleteOptions{}, &genericapitesting.SimpleGetOptions{}, &genericapitesting.SimpleRoot{},
|
||||||
&genericapitesting.SimpleXGSubresource{})
|
&genericapitesting.SimpleXGSubresource{})
|
||||||
scheme.AddKnownTypes(testGroupVersion, &examplev1.Pod{})
|
scheme.AddKnownTypes(testGroupVersion, &examplev1.Pod{})
|
||||||
scheme.AddKnownTypes(testInternalGroupVersion,
|
scheme.AddKnownTypes(testInternalGroupVersion,
|
||||||
&genericapitesting.Simple{}, &genericapitesting.SimpleList{}, &metav1.ExportOptions{},
|
&genericapitesting.Simple{}, &genericapitesting.SimpleList{},
|
||||||
&genericapitesting.SimpleGetOptions{}, &genericapitesting.SimpleRoot{},
|
&genericapitesting.SimpleGetOptions{}, &genericapitesting.SimpleRoot{},
|
||||||
&genericapitesting.SimpleXGSubresource{})
|
&genericapitesting.SimpleXGSubresource{})
|
||||||
scheme.AddKnownTypes(testInternalGroupVersion, &example.Pod{})
|
scheme.AddKnownTypes(testInternalGroupVersion, &example.Pod{})
|
||||||
// Register SimpleXGSubresource in both testGroupVersion and testGroup2Version, and also their
|
// Register SimpleXGSubresource in both testGroupVersion and testGroup2Version, and also their
|
||||||
// their corresponding internal versions, to verify that the desired group version object is
|
// their corresponding internal versions, to verify that the desired group version object is
|
||||||
// served in the tests.
|
// served in the tests.
|
||||||
scheme.AddKnownTypes(testGroup2Version, &genericapitesting.SimpleXGSubresource{}, &metav1.ExportOptions{})
|
scheme.AddKnownTypes(testGroup2Version, &genericapitesting.SimpleXGSubresource{})
|
||||||
scheme.AddKnownTypes(testInternalGroup2Version, &genericapitesting.SimpleXGSubresource{}, &metav1.ExportOptions{})
|
scheme.AddKnownTypes(testInternalGroup2Version, &genericapitesting.SimpleXGSubresource{})
|
||||||
metav1.AddToGroupVersion(scheme, testGroupVersion)
|
metav1.AddToGroupVersion(scheme, testGroupVersion)
|
||||||
|
|
||||||
utilruntime.Must(genericapitesting.RegisterConversions(scheme))
|
utilruntime.Must(genericapitesting.RegisterConversions(scheme))
|
||||||
@ -174,7 +174,7 @@ func addTestTypes() {
|
|||||||
|
|
||||||
func addNewTestTypes() {
|
func addNewTestTypes() {
|
||||||
scheme.AddKnownTypes(newGroupVersion,
|
scheme.AddKnownTypes(newGroupVersion,
|
||||||
&genericapitesting.Simple{}, &genericapitesting.SimpleList{}, &metav1.ExportOptions{},
|
&genericapitesting.Simple{}, &genericapitesting.SimpleList{},
|
||||||
&metav1.DeleteOptions{}, &genericapitesting.SimpleGetOptions{}, &genericapitesting.SimpleRoot{},
|
&metav1.DeleteOptions{}, &genericapitesting.SimpleGetOptions{}, &genericapitesting.SimpleRoot{},
|
||||||
&examplev1.Pod{},
|
&examplev1.Pod{},
|
||||||
)
|
)
|
||||||
@ -368,21 +368,6 @@ func (storage *SimpleRESTStorage) NamespaceScoped() bool {
|
|||||||
return true
|
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) {
|
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)
|
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) {
|
func TestGet(t *testing.T) {
|
||||||
storage := map[string]rest.Storage{}
|
storage := map[string]rest.Storage{}
|
||||||
simpleStorage := SimpleRESTStorage{
|
simpleStorage := SimpleRESTStorage{
|
||||||
|
@ -19,14 +19,15 @@ package handlers
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
metainternalversionvalidation "k8s.io/apimachinery/pkg/apis/meta/internalversion/validation"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
metainternalversionvalidation "k8s.io/apimachinery/pkg/apis/meta/internalversion/validation"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"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.
|
// 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,
|
return getResourceHandler(scope,
|
||||||
func(ctx context.Context, name string, req *http.Request, trace *utiltrace.Trace) (runtime.Object, error) {
|
func(ctx context.Context, name string, req *http.Request, trace *utiltrace.Trace) (runtime.Object, error) {
|
||||||
// check for export
|
// check for export
|
||||||
options := metav1.GetOptions{}
|
options := metav1.GetOptions{}
|
||||||
if values := req.URL.Query(); len(values) > 0 {
|
if values := req.URL.Query(); len(values) > 0 {
|
||||||
exports := metav1.ExportOptions{}
|
if len(values["export"]) > 0 {
|
||||||
if err := metainternalversionscheme.ParameterCodec.DecodeParameters(values, scope.MetaGroupVersion, &exports); err != nil {
|
exportBool := true
|
||||||
err = errors.NewBadRequest(err.Error())
|
exportStrings := values["export"]
|
||||||
return nil, err
|
err := runtime.Convert_Slice_string_To_bool(&exportStrings, &exportBool, nil)
|
||||||
}
|
if err != nil {
|
||||||
if exports.Export {
|
return nil, errors.NewBadRequest(fmt.Sprintf("the export parameter cannot be parsed: %v", err))
|
||||||
if e == nil {
|
}
|
||||||
return nil, errors.NewBadRequest(fmt.Sprintf("export of %q is not supported", scope.Resource.Resource))
|
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 {
|
if err := metainternalversionscheme.ParameterCodec.DecodeParameters(values, scope.MetaGroupVersion, &options); err != nil {
|
||||||
err = errors.NewBadRequest(err.Error())
|
err = errors.NewBadRequest(err.Error())
|
||||||
|
@ -253,15 +253,6 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
if !isMetadata {
|
if !isMetadata {
|
||||||
storageMeta = defaultStorageMetadata{}
|
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 {
|
if isNamedCreater {
|
||||||
isCreater = true
|
isCreater = true
|
||||||
@ -684,7 +675,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
if isGetterWithOptions {
|
if isGetterWithOptions {
|
||||||
handler = restfulGetResourceWithOptions(getterWithOptions, reqScope, isSubresource)
|
handler = restfulGetResourceWithOptions(getterWithOptions, reqScope, isSubresource)
|
||||||
} else {
|
} else {
|
||||||
handler = restfulGetResource(getter, exporter, reqScope)
|
handler = restfulGetResource(getter, reqScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
if needOverride {
|
if needOverride {
|
||||||
@ -713,11 +704,6 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if isExporter {
|
|
||||||
if err := AddObjectParams(ws, route, versionedExportOptions); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addParams(route, action.Params)
|
addParams(route, action.Params)
|
||||||
routes = append(routes, route)
|
routes = append(routes, route)
|
||||||
case "LIST": // List all resources of a kind.
|
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) {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@ package registry
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -73,7 +72,6 @@ type GenericStore interface {
|
|||||||
GetCreateStrategy() rest.RESTCreateStrategy
|
GetCreateStrategy() rest.RESTCreateStrategy
|
||||||
GetUpdateStrategy() rest.RESTUpdateStrategy
|
GetUpdateStrategy() rest.RESTUpdateStrategy
|
||||||
GetDeleteStrategy() rest.RESTDeleteStrategy
|
GetDeleteStrategy() rest.RESTDeleteStrategy
|
||||||
GetExportStrategy() rest.RESTExportStrategy
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store implements k8s.io/apiserver/pkg/registry/rest.StandardStorage. It's
|
// Store implements k8s.io/apiserver/pkg/registry/rest.StandardStorage. It's
|
||||||
@ -199,10 +197,6 @@ type Store struct {
|
|||||||
// deletionTimestamp, and deletionGracePeriodSeconds checks.
|
// deletionTimestamp, and deletionGracePeriodSeconds checks.
|
||||||
ShouldDeleteDuringUpdate func(ctx context.Context, key string, obj, existing runtime.Object) bool
|
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
|
// TableConvertor is an optional interface for transforming items or lists
|
||||||
// of items into tabular output. If unset, the default will be used.
|
// of items into tabular output. If unset, the default will be used.
|
||||||
TableConvertor rest.TableConvertor
|
TableConvertor rest.TableConvertor
|
||||||
@ -223,7 +217,6 @@ type Store struct {
|
|||||||
|
|
||||||
// Note: the rest.StandardStorage interface aggregates the common REST verbs
|
// Note: the rest.StandardStorage interface aggregates the common REST verbs
|
||||||
var _ rest.StandardStorage = &Store{}
|
var _ rest.StandardStorage = &Store{}
|
||||||
var _ rest.Exporter = &Store{}
|
|
||||||
var _ rest.TableConvertor = &Store{}
|
var _ rest.TableConvertor = &Store{}
|
||||||
var _ GenericStore = &Store{}
|
var _ GenericStore = &Store{}
|
||||||
|
|
||||||
@ -312,11 +305,6 @@ func (e *Store) GetDeleteStrategy() rest.RESTDeleteStrategy {
|
|||||||
return e.DeleteStrategy
|
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
|
// List returns a list of items matching labels and field according to the
|
||||||
// store's PredicateFunc.
|
// store's PredicateFunc.
|
||||||
func (e *Store) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) {
|
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
|
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
|
// CompleteWithOptions updates the store with the provided options and
|
||||||
// defaults common fields.
|
// defaults common fields.
|
||||||
func (e *Store) CompleteWithOptions(options *generic.StoreOptions) error {
|
func (e *Store) CompleteWithOptions(options *generic.StoreOptions) error {
|
||||||
|
@ -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) {
|
func TestStoreGet(t *testing.T) {
|
||||||
podA := &example.Pod{
|
podA := &example.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo"},
|
ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo"},
|
||||||
|
@ -25,7 +25,6 @@ go_library(
|
|||||||
"create_update.go",
|
"create_update.go",
|
||||||
"delete.go",
|
"delete.go",
|
||||||
"doc.go",
|
"doc.go",
|
||||||
"export.go",
|
|
||||||
"meta.go",
|
"meta.go",
|
||||||
"rest.go",
|
"rest.go",
|
||||||
"table.go",
|
"table.go",
|
||||||
|
@ -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
|
|
||||||
}
|
|
@ -102,16 +102,6 @@ type Lister interface {
|
|||||||
TableConvertor
|
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.
|
// Getter is an object that can retrieve a named RESTful resource.
|
||||||
type Getter interface {
|
type Getter interface {
|
||||||
// Get finds a resource in the storage by name and returns it.
|
// Get finds a resource in the storage by name and returns it.
|
||||||
|
@ -10,6 +10,7 @@ go_test(
|
|||||||
size = "large",
|
size = "large",
|
||||||
srcs = [
|
srcs = [
|
||||||
"apiserver_test.go",
|
"apiserver_test.go",
|
||||||
|
"export_test.go",
|
||||||
"main_test.go",
|
"main_test.go",
|
||||||
"max_json_patch_operations_test.go",
|
"max_json_patch_operations_test.go",
|
||||||
"max_request_body_bytes_test.go",
|
"max_request_body_bytes_test.go",
|
||||||
|
57
test/integration/apiserver/export_test.go
Normal file
57
test/integration/apiserver/export_test.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user