diff --git a/hack/.linted_packages b/hack/.linted_packages index 1dc6c859993..289b3b2c76f 100644 --- a/hack/.linted_packages +++ b/hack/.linted_packages @@ -238,8 +238,6 @@ pkg/registry/core/service/ipallocator/controller pkg/registry/core/service/ipallocator/storage pkg/registry/core/serviceaccount pkg/registry/extensions/podsecuritypolicy/storage -pkg/registry/extensions/thirdpartyresource -pkg/registry/extensions/thirdpartyresource/storage pkg/registry/rbac/clusterrole/storage pkg/registry/rbac/clusterrolebinding/storage pkg/registry/rbac/role/storage diff --git a/pkg/master/BUILD b/pkg/master/BUILD index 77e7258ddfb..b532f76f0dc 100644 --- a/pkg/master/BUILD +++ b/pkg/master/BUILD @@ -43,7 +43,6 @@ go_library( "//pkg/client/clientset_generated/clientset/typed/core/v1:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library", "//pkg/kubelet/client:go_default_library", - "//pkg/master/thirdparty:go_default_library", "//pkg/master/tunneler:go_default_library", "//pkg/registry/admissionregistration/rest:go_default_library", "//pkg/registry/apps/rest:go_default_library", diff --git a/pkg/master/master.go b/pkg/master/master.go index d3fbd5cf9a5..20434f5ea2f 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -54,7 +54,6 @@ import ( corev1client "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/core/v1" coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" kubeletclient "k8s.io/kubernetes/pkg/kubelet/client" - "k8s.io/kubernetes/pkg/master/thirdparty" "k8s.io/kubernetes/pkg/master/tunneler" "k8s.io/kubernetes/pkg/routes" nodeutil "k8s.io/kubernetes/pkg/util/node" @@ -259,7 +258,7 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget, batchrest.RESTStorageProvider{}, certificatesrest.RESTStorageProvider{}, // TODO(enisoc): Remove crdRESTOptionsGetter input argument when TPR code is removed. - extensionsrest.RESTStorageProvider{ResourceInterface: thirdparty.NewThirdPartyResourceServer(s, s.DiscoveryGroupManager, c.StorageFactory, crdRESTOptionsGetter)}, + extensionsrest.RESTStorageProvider{}, networkingrest.RESTStorageProvider{}, policyrest.RESTStorageProvider{}, rbacrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorizer}, diff --git a/pkg/master/thirdparty/BUILD b/pkg/master/thirdparty/BUILD index 2ba97ed38a0..bbb0536fd4f 100644 --- a/pkg/master/thirdparty/BUILD +++ b/pkg/master/thirdparty/BUILD @@ -10,44 +10,19 @@ load( go_library( name = "go_default_library", - srcs = [ - "thirdparty.go", - "tprregistration_controller.go", - ], + srcs = ["tprregistration_controller.go"], tags = ["automanaged"], deps = [ - "//pkg/api:go_default_library", - "//pkg/apis/extensions:go_default_library", "//pkg/controller:go_default_library", - "//pkg/registry/extensions/rest:go_default_library", - "//pkg/registry/extensions/thirdpartyresourcedata:go_default_library", - "//pkg/registry/extensions/thirdpartyresourcedata/storage:go_default_library", "//vendor/github.com/golang/glog:go_default_library", "//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library", - "//vendor/k8s.io/apiextensions-apiserver/pkg/apiserver:go_default_library", - "//vendor/k8s.io/apiextensions-apiserver/pkg/client/clientset/internalclientset/typed/apiextensions/internalversion:go_default_library", "//vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/internalversion/apiextensions/internalversion:go_default_library", "//vendor/k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/internalversion:go_default_library", - "//vendor/k8s.io/apiextensions-apiserver/pkg/registry/customresource:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library", "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/json:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", - "//vendor/k8s.io/apiserver/pkg/endpoints:go_default_library", - "//vendor/k8s.io/apiserver/pkg/endpoints/discovery:go_default_library", - "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", - "//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library", - "//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library", - "//vendor/k8s.io/apiserver/pkg/server:go_default_library", - "//vendor/k8s.io/apiserver/pkg/server/storage:go_default_library", - "//vendor/k8s.io/apiserver/pkg/storage/storagebackend:go_default_library", - "//vendor/k8s.io/client-go/discovery:go_default_library", "//vendor/k8s.io/client-go/tools/cache:go_default_library", "//vendor/k8s.io/client-go/util/workqueue:go_default_library", "//vendor/k8s.io/kube-aggregator/pkg/apis/apiregistration:go_default_library", diff --git a/pkg/master/thirdparty/thirdparty.go b/pkg/master/thirdparty/thirdparty.go deleted file mode 100644 index 8e00569f996..00000000000 --- a/pkg/master/thirdparty/thirdparty.go +++ /dev/null @@ -1,462 +0,0 @@ -/* -Copyright 2016 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 thirdparty - -import ( - "fmt" - "strings" - "sync" - - "github.com/golang/glog" - - "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" - apiextensionsserver "k8s.io/apiextensions-apiserver/pkg/apiserver" - apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/internalclientset/typed/apiextensions/internalversion" - "k8s.io/apiextensions-apiserver/pkg/registry/customresource" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - utilerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/apimachinery/pkg/util/json" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - genericapi "k8s.io/apiserver/pkg/endpoints" - "k8s.io/apiserver/pkg/endpoints/discovery" - "k8s.io/apiserver/pkg/endpoints/request" - genericapirequest "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/apiserver/pkg/registry/generic" - "k8s.io/apiserver/pkg/registry/rest" - genericapiserver "k8s.io/apiserver/pkg/server" - serverstorgage "k8s.io/apiserver/pkg/server/storage" - "k8s.io/apiserver/pkg/storage/storagebackend" - discoveryclient "k8s.io/client-go/discovery" - "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/apis/extensions" - extensionsrest "k8s.io/kubernetes/pkg/registry/extensions/rest" - "k8s.io/kubernetes/pkg/registry/extensions/thirdpartyresourcedata" - thirdpartyresourcedatastore "k8s.io/kubernetes/pkg/registry/extensions/thirdpartyresourcedata/storage" -) - -// dynamicLister is used to list resources for dynamic third party -// apis. It implements the genericapihandlers.APIResourceLister interface -type dynamicLister struct { - m *ThirdPartyResourceServer - path string -} - -func (d dynamicLister) ListAPIResources() []metav1.APIResource { - return d.m.getExistingThirdPartyResources(d.path) -} - -var _ discovery.APIResourceLister = &dynamicLister{} - -type ThirdPartyResourceServer struct { - genericAPIServer *genericapiserver.GenericAPIServer - - availableGroupManager discovery.GroupManager - - deleteCollectionWorkers int - - // storage for third party objects - thirdPartyStorageConfig *storagebackend.Config - // map from api path to a tuple of (storage for the objects, APIGroup) - thirdPartyResources map[string]*thirdPartyEntry - // protects the map - thirdPartyResourcesLock sync.RWMutex - - // Useful for reliable testing. Shouldn't be used otherwise. - disableThirdPartyControllerForTesting bool - - crdRESTOptionsGetter generic.RESTOptionsGetter -} - -func NewThirdPartyResourceServer(genericAPIServer *genericapiserver.GenericAPIServer, availableGroupManager discovery.GroupManager, storageFactory serverstorgage.StorageFactory, crdRESTOptionsGetter generic.RESTOptionsGetter) *ThirdPartyResourceServer { - ret := &ThirdPartyResourceServer{ - genericAPIServer: genericAPIServer, - thirdPartyResources: map[string]*thirdPartyEntry{}, - availableGroupManager: availableGroupManager, - crdRESTOptionsGetter: crdRESTOptionsGetter, - } - - var err error - ret.thirdPartyStorageConfig, err = storageFactory.NewConfig(extensions.Resource("thirdpartyresources")) - if err != nil { - glog.Fatalf("Error building third party storage: %v", err) - } - - return ret -} - -// thirdPartyEntry combines objects storage and API group into one struct -// for easy lookup. -type thirdPartyEntry struct { - // Map from plural resource name to entry - storage map[string]*thirdpartyresourcedatastore.REST - group metav1.APIGroup -} - -// HasThirdPartyResource returns true if a particular third party resource currently installed. -func (m *ThirdPartyResourceServer) HasThirdPartyResource(rsrc *extensions.ThirdPartyResource) (bool, error) { - kind, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind(rsrc) - if err != nil { - return false, err - } - path := extensionsrest.MakeThirdPartyPath(group) - m.thirdPartyResourcesLock.Lock() - defer m.thirdPartyResourcesLock.Unlock() - entry := m.thirdPartyResources[path] - if entry == nil { - return false, nil - } - plural, _ := meta.UnsafeGuessKindToResource(schema.GroupVersionKind{ - Group: group, - Version: rsrc.Versions[0].Name, - Kind: kind, - }) - _, found := entry.storage[plural.Resource] - return found, nil -} - -func (m *ThirdPartyResourceServer) removeThirdPartyStorage(path, resource string) error { - m.thirdPartyResourcesLock.Lock() - defer m.thirdPartyResourcesLock.Unlock() - entry, found := m.thirdPartyResources[path] - if !found { - return nil - } - storage, found := entry.storage[resource] - if !found { - return nil - } - if err := m.removeThirdPartyResourceData(&entry.group, resource, storage); err != nil { - return err - } - delete(entry.storage, resource) - if len(entry.storage) == 0 { - delete(m.thirdPartyResources, path) - m.availableGroupManager.RemoveGroup(extensionsrest.GetThirdPartyGroupName(path)) - } else { - m.thirdPartyResources[path] = entry - } - return nil -} - -// RemoveThirdPartyResource removes all resources matching `path`. Also deletes any stored data -func (m *ThirdPartyResourceServer) RemoveThirdPartyResource(path string) error { - ix := strings.LastIndex(path, "/") - if ix == -1 { - return fmt.Errorf("expected /, saw: %s", path) - } - resource := path[ix+1:] - path = path[0:ix] - - if err := m.removeThirdPartyStorage(path, resource); err != nil { - return err - } - - services := m.genericAPIServer.Handler.GoRestfulContainer.RegisteredWebServices() - for ix := range services { - root := services[ix].RootPath() - if root == path || strings.HasPrefix(root, path+"/") { - m.genericAPIServer.Handler.GoRestfulContainer.Remove(services[ix]) - } - } - return nil -} - -func (m *ThirdPartyResourceServer) removeThirdPartyResourceData(group *metav1.APIGroup, resource string, registry *thirdpartyresourcedatastore.REST) error { - // Freeze TPR data to prevent new writes via this apiserver process. - // Other apiservers can still write. This is best-effort because there - // are worse problems with TPR data than the possibility of going back - // in time when migrating to CRD [citation needed]. - registry.Freeze() - - ctx := genericapirequest.NewContext() - existingData, err := registry.List(ctx, nil) - if err != nil { - return err - } - list, ok := existingData.(*extensions.ThirdPartyResourceDataList) - if !ok { - return fmt.Errorf("expected a *ThirdPartyResourceDataList, got %T", existingData) - } - - // Migrate TPR data to CRD if requested. - gvk := schema.GroupVersionKind{Group: group.Name, Version: group.PreferredVersion.Version, Kind: registry.Kind()} - migrationRequested, err := m.migrateThirdPartyResourceData(gvk, resource, list) - if err != nil { - // Migration is best-effort. Log and continue. - utilruntime.HandleError(fmt.Errorf("failed to migrate TPR data: %v", err)) - } - - // Skip deletion of TPR data if migration was requested (whether or not it succeeded). - // This leaves the etcd data around for rollback, and to avoid sending DELETE watch events. - if migrationRequested { - return nil - } - - for i := range list.Items { - item := &list.Items[i] - - // Use registry.Store.Delete() to bypass the frozen registry.Delete(). - if _, _, err := registry.Store.Delete(genericapirequest.WithNamespace(ctx, item.Namespace), item.Name, nil); err != nil { - return err - } - } - return nil -} - -func (m *ThirdPartyResourceServer) findMatchingCRD(gvk schema.GroupVersionKind, resource string) (*apiextensions.CustomResourceDefinition, error) { - // CustomResourceDefinitionList does not implement the protobuf marshalling interface. - config := *m.genericAPIServer.LoopbackClientConfig - config.ContentType = "application/json" - crdClient, err := apiextensionsclient.NewForConfig(&config) - if err != nil { - return nil, fmt.Errorf("can't create apiextensions client: %v", err) - } - crdList, err := crdClient.CustomResourceDefinitions().List(metav1.ListOptions{}) - if err != nil { - return nil, fmt.Errorf("can't list CustomResourceDefinitions: %v", err) - } - for i := range crdList.Items { - item := &crdList.Items[i] - if item.Spec.Scope == apiextensions.NamespaceScoped && - item.Spec.Group == gvk.Group && item.Spec.Version == gvk.Version && - item.Status.AcceptedNames.Kind == gvk.Kind && item.Status.AcceptedNames.Plural == resource { - return item, nil - } - } - return nil, nil -} - -func (m *ThirdPartyResourceServer) migrateThirdPartyResourceData(gvk schema.GroupVersionKind, resource string, dataList *extensions.ThirdPartyResourceDataList) (bool, error) { - // A matching CustomResourceDefinition implies migration is requested. - crd, err := m.findMatchingCRD(gvk, resource) - if err != nil { - return false, fmt.Errorf("can't determine if TPR should migrate: %v", err) - } - if crd == nil { - // No migration requested. - return false, nil - } - - // Talk directly to CustomResource storage. - // We have to bypass the API server because TPR is shadowing CRD at this point. - storage := customresource.NewREST( - schema.GroupResource{Group: crd.Spec.Group, Resource: crd.Spec.Names.Plural}, - schema.GroupVersionKind{Group: crd.Spec.Group, Version: crd.Spec.Version, Kind: crd.Spec.Names.ListKind}, - apiextensionsserver.UnstructuredCopier{}, - customresource.NewStrategy(discoveryclient.NewUnstructuredObjectTyper(nil), true, gvk), - m.crdRESTOptionsGetter, - ) - - // Copy TPR data to CustomResource. - var errs []error - ctx := request.NewContext() - for i := range dataList.Items { - item := &dataList.Items[i] - - // Convert TPR data to Unstructured. - objMap := make(map[string]interface{}) - if err := json.Unmarshal(item.Data, &objMap); err != nil { - errs = append(errs, fmt.Errorf("can't unmarshal TPR data %q: %v", item.Name, err)) - continue - } - - // Convert metadata to Unstructured and merge with data. - // cf. thirdpartyresourcedata.encodeToJSON() - metaMap := make(map[string]interface{}) - buf, err := json.Marshal(&item.ObjectMeta) - if err != nil { - errs = append(errs, fmt.Errorf("can't marshal metadata for TPR data %q: %v", item.Name, err)) - continue - } - if err := json.Unmarshal(buf, &metaMap); err != nil { - errs = append(errs, fmt.Errorf("can't unmarshal TPR data %q: %v", item.Name, err)) - continue - } - // resourceVersion cannot be set when creating objects. - delete(metaMap, "resourceVersion") - objMap["metadata"] = metaMap - - // Store CustomResource. - obj := &unstructured.Unstructured{Object: objMap} - createCtx := request.WithNamespace(ctx, obj.GetNamespace()) - if _, err := storage.Create(createCtx, obj, false); err != nil { - errs = append(errs, fmt.Errorf("can't create CustomResource for TPR data %q: %v", item.Name, err)) - continue - } - } - return true, utilerrors.NewAggregate(errs) -} - -// ListThirdPartyResources lists all currently installed third party resources -// The format is / -func (m *ThirdPartyResourceServer) ListThirdPartyResources() []string { - m.thirdPartyResourcesLock.RLock() - defer m.thirdPartyResourcesLock.RUnlock() - result := []string{} - for key := range m.thirdPartyResources { - for rsrc := range m.thirdPartyResources[key].storage { - result = append(result, key+"/"+rsrc) - } - } - return result -} - -func (m *ThirdPartyResourceServer) getExistingThirdPartyResources(path string) []metav1.APIResource { - result := []metav1.APIResource{} - m.thirdPartyResourcesLock.Lock() - defer m.thirdPartyResourcesLock.Unlock() - entry := m.thirdPartyResources[path] - if entry != nil { - for key, obj := range entry.storage { - result = append(result, metav1.APIResource{ - Name: key, - Namespaced: true, - Kind: obj.Kind(), - Verbs: metav1.Verbs([]string{ - "delete", "deletecollection", "get", "list", "patch", "create", "update", "watch", - }), - }) - } - } - return result -} - -func (m *ThirdPartyResourceServer) hasThirdPartyGroupStorage(path string) bool { - m.thirdPartyResourcesLock.Lock() - defer m.thirdPartyResourcesLock.Unlock() - _, found := m.thirdPartyResources[path] - return found -} - -func (m *ThirdPartyResourceServer) addThirdPartyResourceStorage(path, resource string, storage *thirdpartyresourcedatastore.REST, apiGroup metav1.APIGroup) { - m.thirdPartyResourcesLock.Lock() - defer m.thirdPartyResourcesLock.Unlock() - entry, found := m.thirdPartyResources[path] - if entry == nil { - entry = &thirdPartyEntry{ - group: apiGroup, - storage: map[string]*thirdpartyresourcedatastore.REST{}, - } - m.thirdPartyResources[path] = entry - } - entry.storage[resource] = storage - if !found { - m.availableGroupManager.AddGroup(apiGroup) - } -} - -// InstallThirdPartyResource installs a third party resource specified by 'rsrc'. When a resource is -// installed a corresponding RESTful resource is added as a valid path in the web service provided by -// the master. -// -// For example, if you install a resource ThirdPartyResource{ Name: "foo.company.com", Versions: {"v1"} } -// then the following RESTful resource is created on the server: -// http:///apis/company.com/v1/foos/... -func (m *ThirdPartyResourceServer) InstallThirdPartyResource(rsrc *extensions.ThirdPartyResource) error { - kind, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind(rsrc) - if err != nil { - return err - } - if len(rsrc.Versions) == 0 { - return fmt.Errorf("ThirdPartyResource %s has no defined versions", rsrc.Name) - } - plural, _ := meta.UnsafeGuessKindToResource(schema.GroupVersionKind{ - Group: group, - Version: rsrc.Versions[0].Name, - Kind: kind, - }) - path := extensionsrest.MakeThirdPartyPath(group) - - groupVersion := metav1.GroupVersionForDiscovery{ - GroupVersion: group + "/" + rsrc.Versions[0].Name, - Version: rsrc.Versions[0].Name, - } - apiGroup := metav1.APIGroup{ - Name: group, - Versions: []metav1.GroupVersionForDiscovery{groupVersion}, - PreferredVersion: groupVersion, - } - - thirdparty := m.thirdpartyapi(group, kind, rsrc.Versions[0].Name, plural.Resource) - - // If storage exists, this group has already been added, just update - // the group with the new API - if m.hasThirdPartyGroupStorage(path) { - m.addThirdPartyResourceStorage(path, plural.Resource, thirdparty.Storage[plural.Resource].(*thirdpartyresourcedatastore.REST), apiGroup) - return thirdparty.UpdateREST(m.genericAPIServer.Handler.GoRestfulContainer) - } - - if err := thirdparty.InstallREST(m.genericAPIServer.Handler.GoRestfulContainer); err != nil { - glog.Errorf("Unable to setup thirdparty api: %v", err) - } - m.genericAPIServer.Handler.GoRestfulContainer.Add(discovery.NewAPIGroupHandler(api.Codecs, apiGroup, m.genericAPIServer.RequestContextMapper()).WebService()) - - m.addThirdPartyResourceStorage(path, plural.Resource, thirdparty.Storage[plural.Resource].(*thirdpartyresourcedatastore.REST), apiGroup) - api.Registry.AddThirdPartyAPIGroupVersions(schema.GroupVersion{Group: group, Version: rsrc.Versions[0].Name}) - return nil -} - -func (m *ThirdPartyResourceServer) thirdpartyapi(group, kind, version, pluralResource string) *genericapi.APIGroupVersion { - resourceStorage := thirdpartyresourcedatastore.NewREST( - generic.RESTOptions{ - StorageConfig: m.thirdPartyStorageConfig, - Decorator: generic.UndecoratedStorage, - DeleteCollectionWorkers: m.deleteCollectionWorkers, - }, - group, - kind, - ) - - storage := map[string]rest.Storage{ - pluralResource: resourceStorage, - } - - optionsExternalVersion := api.Registry.GroupOrDie(api.GroupName).GroupVersion - internalVersion := schema.GroupVersion{Group: group, Version: runtime.APIVersionInternal} - externalVersion := schema.GroupVersion{Group: group, Version: version} - - apiRoot := extensionsrest.MakeThirdPartyPath("") - return &genericapi.APIGroupVersion{ - Root: apiRoot, - GroupVersion: externalVersion, - - Creater: thirdpartyresourcedata.NewObjectCreator(group, version, api.Scheme), - Convertor: api.Scheme, - Copier: api.Scheme, - Defaulter: api.Scheme, - Typer: api.Scheme, - UnsafeConvertor: api.Scheme, - - Mapper: thirdpartyresourcedata.NewMapper(api.Registry.GroupOrDie(extensions.GroupName).RESTMapper, kind, version, group), - Linker: api.Registry.GroupOrDie(extensions.GroupName).SelfLinker, - Storage: storage, - OptionsExternalVersion: &optionsExternalVersion, - - Serializer: thirdpartyresourcedata.NewNegotiatedSerializer(api.Codecs, kind, externalVersion, internalVersion), - ParameterCodec: thirdpartyresourcedata.NewThirdPartyParameterCodec(api.ParameterCodec), - - Context: m.genericAPIServer.RequestContextMapper(), - - MinRequestTimeout: m.genericAPIServer.MinRequestTimeout(), - - ResourceLister: dynamicLister{m, extensionsrest.MakeThirdPartyPath(group)}, - } -} diff --git a/pkg/registry/BUILD b/pkg/registry/BUILD index 77b76f2c059..e401174a2f3 100644 --- a/pkg/registry/BUILD +++ b/pkg/registry/BUILD @@ -71,8 +71,6 @@ filegroup( "//pkg/registry/extensions/podsecuritypolicy:all-srcs", "//pkg/registry/extensions/replicaset:all-srcs", "//pkg/registry/extensions/rest:all-srcs", - "//pkg/registry/extensions/thirdpartyresource:all-srcs", - "//pkg/registry/extensions/thirdpartyresourcedata:all-srcs", "//pkg/registry/networking/networkpolicy:all-srcs", "//pkg/registry/networking/rest:all-srcs", "//pkg/registry/policy/poddisruptionbudget:all-srcs", diff --git a/pkg/registry/extensions/rest/BUILD b/pkg/registry/extensions/rest/BUILD index 6904731a9b4..c88831d6bb5 100644 --- a/pkg/registry/extensions/rest/BUILD +++ b/pkg/registry/extensions/rest/BUILD @@ -5,33 +5,15 @@ licenses(["notice"]) load( "@io_bazel_rules_go//go:def.bzl", "go_library", - "go_test", -) - -go_test( - name = "go_default_test", - srcs = ["thirdparty_controller_test.go"], - library = ":go_default_library", - tags = ["automanaged"], - deps = [ - "//pkg/apis/extensions:go_default_library", - "//pkg/registry/extensions/thirdpartyresourcedata:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", - ], ) go_library( name = "go_default_library", - srcs = [ - "storage_extensions.go", - "thirdparty_controller.go", - ], + srcs = ["storage_extensions.go"], tags = ["automanaged"], deps = [ "//pkg/api:go_default_library", "//pkg/apis/extensions:go_default_library", - "//pkg/client/clientset_generated/internalclientset/typed/extensions/internalversion:go_default_library", "//pkg/registry/extensions/controller/storage:go_default_library", "//pkg/registry/extensions/daemonset/storage:go_default_library", "//pkg/registry/extensions/deployment/storage:go_default_library", @@ -39,11 +21,7 @@ go_library( "//pkg/registry/extensions/networkpolicy/storage:go_default_library", "//pkg/registry/extensions/podsecuritypolicy/storage:go_default_library", "//pkg/registry/extensions/replicaset/storage:go_default_library", - "//pkg/registry/extensions/thirdpartyresourcedata:go_default_library", "//vendor/k8s.io/api/extensions/v1beta1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library", "//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library", "//vendor/k8s.io/apiserver/pkg/server:go_default_library", diff --git a/pkg/registry/extensions/rest/storage_extensions.go b/pkg/registry/extensions/rest/storage_extensions.go index a593921b48a..674b2aab79e 100644 --- a/pkg/registry/extensions/rest/storage_extensions.go +++ b/pkg/registry/extensions/rest/storage_extensions.go @@ -34,7 +34,6 @@ import ( ) type RESTStorageProvider struct { - ResourceInterface ResourceInterface } func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (genericapiserver.APIGroupInfo, bool) { diff --git a/pkg/registry/extensions/rest/thirdparty_controller.go b/pkg/registry/extensions/rest/thirdparty_controller.go deleted file mode 100644 index 2db39b2376c..00000000000 --- a/pkg/registry/extensions/rest/thirdparty_controller.go +++ /dev/null @@ -1,131 +0,0 @@ -/* -Copyright 2016 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 ( - "fmt" - "strings" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/kubernetes/pkg/apis/extensions" - extensionsclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/extensions/internalversion" - "k8s.io/kubernetes/pkg/registry/extensions/thirdpartyresourcedata" -) - -// ResourceInterface is the interface for the parts of the master that know how to add/remove -// third party resources. Extracted into an interface for injection for testing. -type ResourceInterface interface { - // Remove a third party resource based on the RESTful path for that resource, the path is / - RemoveThirdPartyResource(path string) error - // Install a third party resource described by 'rsrc' - InstallThirdPartyResource(rsrc *extensions.ThirdPartyResource) error - // Is a particular third party resource currently installed? - HasThirdPartyResource(rsrc *extensions.ThirdPartyResource) (bool, error) - // List all currently installed third party resources, the returned - // names are of the form / - ListThirdPartyResources() []string -} - -const thirdpartyprefix = "/apis" - -// ThirdPartyController is a control loop that knows how to synchronize ThirdPartyResource objects with -// RESTful resources which are present in the API server. -type ThirdPartyController struct { - master ResourceInterface - client extensionsclient.ThirdPartyResourcesGetter -} - -// SyncOneResource synchronizes a single resource with RESTful resources on the master -func (t *ThirdPartyController) SyncOneResource(rsrc *extensions.ThirdPartyResource) error { - // TODO: we also need to test if the existing installed resource matches the resource we are sync-ing. - // Currently, if there is an older, incompatible resource installed, we won't remove it. We should detect - // older, incompatible resources and remove them before testing if the resource exists. - hasResource, err := t.master.HasThirdPartyResource(rsrc) - if err != nil { - return err - } - if !hasResource { - return t.master.InstallThirdPartyResource(rsrc) - } - return nil -} - -// Synchronize all resources with RESTful resources on the master -func (t *ThirdPartyController) SyncResources() error { - list, err := t.client.ThirdPartyResources().List(metav1.ListOptions{}) - if err != nil { - return err - } - return t.syncResourceList(list) -} - -func (t *ThirdPartyController) syncResourceList(list runtime.Object) error { - existing := sets.String{} - switch list := list.(type) { - case *extensions.ThirdPartyResourceList: - // Loop across all schema objects for third party resources - for ix := range list.Items { - item := &list.Items[ix] - // extract the api group and resource kind from the schema - _, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind(item) - if err != nil { - return err - } - // place it in the set of resources that we expect, so that we don't delete it in the delete pass - existing.Insert(MakeThirdPartyPath(group)) - // ensure a RESTful resource for this schema exists on the master - if err := t.SyncOneResource(item); err != nil { - return err - } - } - default: - return fmt.Errorf("expected a *ThirdPartyResourceList, got %#v", list) - } - // deletion phase, get all installed RESTful resources - installed := t.master.ListThirdPartyResources() - for _, installedAPI := range installed { - found := false - // search across the expected restful resources to see if this resource belongs to one of the expected ones - for _, apiPath := range existing.List() { - if installedAPI == apiPath || strings.HasPrefix(installedAPI, apiPath+"/") { - found = true - break - } - } - // not expected, delete the resource - if !found { - if err := t.master.RemoveThirdPartyResource(installedAPI); err != nil { - return err - } - } - } - - return nil -} - -func MakeThirdPartyPath(group string) string { - if len(group) == 0 { - return thirdpartyprefix - } - return thirdpartyprefix + "/" + group -} - -func GetThirdPartyGroupName(path string) string { - return strings.TrimPrefix(strings.TrimPrefix(path, thirdpartyprefix), "/") -} diff --git a/pkg/registry/extensions/rest/thirdparty_controller_test.go b/pkg/registry/extensions/rest/thirdparty_controller_test.go deleted file mode 100644 index 74c0781057d..00000000000 --- a/pkg/registry/extensions/rest/thirdparty_controller_test.go +++ /dev/null @@ -1,177 +0,0 @@ -/* -Copyright 2014 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 ( - "testing" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/sets" - expapi "k8s.io/kubernetes/pkg/apis/extensions" - "k8s.io/kubernetes/pkg/registry/extensions/thirdpartyresourcedata" -) - -type FakeAPIInterface struct { - removed []string - installed []*expapi.ThirdPartyResource - apis []string - t *testing.T -} - -func (f *FakeAPIInterface) RemoveThirdPartyResource(path string) error { - f.removed = append(f.removed, path) - return nil -} - -func (f *FakeAPIInterface) InstallThirdPartyResource(rsrc *expapi.ThirdPartyResource) error { - f.installed = append(f.installed, rsrc) - _, group, _ := thirdpartyresourcedata.ExtractApiGroupAndKind(rsrc) - f.apis = append(f.apis, MakeThirdPartyPath(group)) - return nil -} - -func (f *FakeAPIInterface) HasThirdPartyResource(rsrc *expapi.ThirdPartyResource) (bool, error) { - if f.apis == nil { - return false, nil - } - _, group, _ := thirdpartyresourcedata.ExtractApiGroupAndKind(rsrc) - path := MakeThirdPartyPath(group) - for _, api := range f.apis { - if api == path { - return true, nil - } - } - return false, nil -} - -func (f *FakeAPIInterface) ListThirdPartyResources() []string { - return f.apis -} - -func TestSyncAPIs(t *testing.T) { - resourcesNamed := func(names ...string) []expapi.ThirdPartyResource { - result := []expapi.ThirdPartyResource{} - for _, name := range names { - result = append(result, expapi.ThirdPartyResource{ObjectMeta: metav1.ObjectMeta{Name: name}}) - } - return result - } - - tests := []struct { - list *expapi.ThirdPartyResourceList - apis []string - expectedInstalled []string - expectedRemoved []string - name string - }{ - { - list: &expapi.ThirdPartyResourceList{ - Items: resourcesNamed("foo.example.com"), - }, - expectedInstalled: []string{"foo.example.com"}, - name: "simple add", - }, - { - list: &expapi.ThirdPartyResourceList{ - Items: resourcesNamed("foo.example.com"), - }, - apis: []string{ - "/apis/example.com", - "/apis/example.com/v1", - }, - name: "does nothing", - }, - { - list: &expapi.ThirdPartyResourceList{ - Items: resourcesNamed("foo.example.com"), - }, - apis: []string{ - "/apis/example.com", - "/apis/example.com/v1", - "/apis/example.co", - "/apis/example.co/v1", - }, - name: "deletes substring API", - expectedRemoved: []string{ - "/apis/example.co", - "/apis/example.co/v1", - }, - }, - { - list: &expapi.ThirdPartyResourceList{ - Items: resourcesNamed("foo.example.com", "foo.company.com"), - }, - apis: []string{ - "/apis/company.com", - "/apis/company.com/v1", - }, - expectedInstalled: []string{"foo.example.com"}, - name: "adds with existing", - }, - { - list: &expapi.ThirdPartyResourceList{ - Items: resourcesNamed("foo.example.com"), - }, - apis: []string{ - "/apis/company.com", - "/apis/company.com/v1", - }, - expectedInstalled: []string{"foo.example.com"}, - expectedRemoved: []string{"/apis/company.com", "/apis/company.com/v1"}, - name: "removes with existing", - }, - } - - for _, test := range tests { - fake := FakeAPIInterface{ - apis: test.apis, - t: t, - } - - cntrl := ThirdPartyController{master: &fake} - - if err := cntrl.syncResourceList(test.list); err != nil { - t.Errorf("[%s] unexpected error: %v", test.name, err) - } - if len(test.expectedInstalled) != len(fake.installed) { - t.Errorf("[%s] unexpected installed APIs: %d, expected %d (%#v)", test.name, len(fake.installed), len(test.expectedInstalled), fake.installed[0]) - continue - } else { - names := sets.String{} - for ix := range fake.installed { - names.Insert(fake.installed[ix].Name) - } - for _, name := range test.expectedInstalled { - if !names.Has(name) { - t.Errorf("[%s] missing installed API: %s", test.name, name) - } - } - } - if len(test.expectedRemoved) != len(fake.removed) { - t.Errorf("[%s] unexpected installed APIs: %d, expected %d", test.name, len(fake.removed), len(test.expectedRemoved)) - continue - } else { - names := sets.String{} - names.Insert(fake.removed...) - for _, name := range test.expectedRemoved { - if !names.Has(name) { - t.Errorf("[%s] missing removed API: %s (%s)", test.name, name, names) - } - } - } - } -} diff --git a/pkg/registry/extensions/thirdpartyresource/BUILD b/pkg/registry/extensions/thirdpartyresource/BUILD deleted file mode 100644 index 177124b8c44..00000000000 --- a/pkg/registry/extensions/thirdpartyresource/BUILD +++ /dev/null @@ -1,59 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -licenses(["notice"]) - -load( - "@io_bazel_rules_go//go:def.bzl", - "go_library", - "go_test", -) - -go_library( - name = "go_default_library", - srcs = [ - "doc.go", - "strategy.go", - ], - tags = ["automanaged"], - deps = [ - "//pkg/api:go_default_library", - "//pkg/apis/extensions:go_default_library", - "//pkg/apis/extensions/validation:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/fields:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", - "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", - "//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library", - "//vendor/k8s.io/apiserver/pkg/storage:go_default_library", - ], -) - -go_test( - name = "go_default_test", - srcs = ["strategy_test.go"], - library = ":go_default_library", - tags = ["automanaged"], - deps = [ - "//pkg/api:go_default_library", - "//pkg/api/testapi:go_default_library", - "//pkg/api/testing:go_default_library", - "//pkg/apis/extensions:go_default_library", - ], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [ - ":package-srcs", - "//pkg/registry/extensions/thirdpartyresource/storage:all-srcs", - ], - tags = ["automanaged"], -) diff --git a/pkg/registry/extensions/thirdpartyresource/doc.go b/pkg/registry/extensions/thirdpartyresource/doc.go deleted file mode 100644 index 5cfaf25637b..00000000000 --- a/pkg/registry/extensions/thirdpartyresource/doc.go +++ /dev/null @@ -1,19 +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 thirdpartyresource provides Registry interface and its REST -// implementation for storing ThirdPartyResource api objects. -package thirdpartyresource // import "k8s.io/kubernetes/pkg/registry/extensions/thirdpartyresource" diff --git a/pkg/registry/extensions/thirdpartyresource/storage/BUILD b/pkg/registry/extensions/thirdpartyresource/storage/BUILD deleted file mode 100644 index 070d0db0706..00000000000 --- a/pkg/registry/extensions/thirdpartyresource/storage/BUILD +++ /dev/null @@ -1,55 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -licenses(["notice"]) - -load( - "@io_bazel_rules_go//go:def.bzl", - "go_library", - "go_test", -) - -go_test( - name = "go_default_test", - srcs = ["storage_test.go"], - library = ":go_default_library", - tags = ["automanaged"], - deps = [ - "//pkg/apis/extensions:go_default_library", - "//pkg/registry/registrytest:go_default_library", - "//vendor/k8s.io/api/extensions/v1beta1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/fields:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", - "//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library", - "//vendor/k8s.io/apiserver/pkg/storage/etcd/testing:go_default_library", - ], -) - -go_library( - name = "go_default_library", - srcs = ["storage.go"], - tags = ["automanaged"], - deps = [ - "//pkg/api:go_default_library", - "//pkg/apis/extensions:go_default_library", - "//pkg/registry/cachesize:go_default_library", - "//pkg/registry/extensions/thirdpartyresource:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", - "//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library", - "//vendor/k8s.io/apiserver/pkg/registry/generic/registry:go_default_library", - ], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [":package-srcs"], - tags = ["automanaged"], -) diff --git a/pkg/registry/extensions/thirdpartyresource/storage/storage.go b/pkg/registry/extensions/thirdpartyresource/storage/storage.go deleted file mode 100644 index 01c98ff6ffe..00000000000 --- a/pkg/registry/extensions/thirdpartyresource/storage/storage.go +++ /dev/null @@ -1,62 +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 storage - -import ( - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apiserver/pkg/registry/generic" - genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" - "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/apis/extensions" - "k8s.io/kubernetes/pkg/registry/cachesize" - "k8s.io/kubernetes/pkg/registry/extensions/thirdpartyresource" -) - -// REST implements a RESTStorage for ThirdPartyResources -type REST struct { - *genericregistry.Store -} - -// NewREST returns a registry which will store ThirdPartyResource in the given helper -func NewREST(optsGetter generic.RESTOptionsGetter) *REST { - resource := extensions.Resource("thirdpartyresources") - opts, err := optsGetter.GetRESTOptions(resource) - if err != nil { - panic(err) // TODO: Propagate error up - } - - // We explicitly do NOT do any decoration here yet. // TODO determine why we do not want to cache here - opts.Decorator = generic.UndecoratedStorage - - store := &genericregistry.Store{ - Copier: api.Scheme, - NewFunc: func() runtime.Object { return &extensions.ThirdPartyResource{} }, - NewListFunc: func() runtime.Object { return &extensions.ThirdPartyResourceList{} }, - PredicateFunc: thirdpartyresource.Matcher, - QualifiedResource: resource, - WatchCacheSize: cachesize.GetWatchCacheSizeByResource(resource.Resource), - - CreateStrategy: thirdpartyresource.Strategy, - UpdateStrategy: thirdpartyresource.Strategy, - DeleteStrategy: thirdpartyresource.Strategy, - } - options := &generic.StoreOptions{RESTOptions: opts, AttrFunc: thirdpartyresource.GetAttrs} // Pass in opts to use UndecoratedStorage - if err := store.CompleteWithOptions(options); err != nil { - panic(err) // TODO: Propagate error up - } - return &REST{store} -} diff --git a/pkg/registry/extensions/thirdpartyresource/storage/storage_test.go b/pkg/registry/extensions/thirdpartyresource/storage/storage_test.go deleted file mode 100644 index cbcf60a4d5e..00000000000 --- a/pkg/registry/extensions/thirdpartyresource/storage/storage_test.go +++ /dev/null @@ -1,143 +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 storage - -import ( - "fmt" - "testing" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/kubernetes/pkg/apis/extensions" - // Ensure that extensions/v1beta1 package is initialized. - _ "k8s.io/api/extensions/v1beta1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apiserver/pkg/registry/generic" - etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing" - "k8s.io/kubernetes/pkg/registry/registrytest" -) - -func newStorage(t *testing.T) (*REST, *etcdtesting.EtcdTestServer) { - etcdStorage, server := registrytest.NewEtcdStorage(t, extensions.GroupName) - restOptions := generic.RESTOptions{ - StorageConfig: etcdStorage, - Decorator: generic.UndecoratedStorage, - DeleteCollectionWorkers: 1, - ResourcePrefix: "thirdpartyresources", - } - return NewREST(restOptions), server -} - -func validNewThirdPartyResource(name string) *extensions.ThirdPartyResource { - return &extensions.ThirdPartyResource{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - }, - Versions: []extensions.APIVersion{ - { - Name: "v1", - }, - }, - } -} - -func namer(i int) string { - return fmt.Sprintf("kind%d.example.com", i) -} - -func TestCreate(t *testing.T) { - storage, server := newStorage(t) - defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store).ClusterScope().Namer(namer).GeneratesName() - rsrc := validNewThirdPartyResource("kind.domain.tld") - test.TestCreate( - // valid - rsrc, - // invalid - &extensions.ThirdPartyResource{}, - &extensions.ThirdPartyResource{ObjectMeta: metav1.ObjectMeta{Name: "kind"}, Versions: []extensions.APIVersion{{Name: "v1"}}}, - &extensions.ThirdPartyResource{ObjectMeta: metav1.ObjectMeta{Name: "kind.tld"}, Versions: []extensions.APIVersion{{Name: "v1"}}}, - &extensions.ThirdPartyResource{ObjectMeta: metav1.ObjectMeta{Name: "kind.domain.tld"}, Versions: []extensions.APIVersion{{Name: "v.1"}}}, - &extensions.ThirdPartyResource{ObjectMeta: metav1.ObjectMeta{Name: "kind.domain.tld"}, Versions: []extensions.APIVersion{{Name: "stable/v1"}}}, - ) -} - -func TestUpdate(t *testing.T) { - storage, server := newStorage(t) - defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store).ClusterScope().Namer(namer) - test.TestUpdate( - // valid - validNewThirdPartyResource("kind.domain.tld"), - // updateFunc - func(obj runtime.Object) runtime.Object { - object := obj.(*extensions.ThirdPartyResource) - object.Description = "new description" - return object - }, - ) -} - -func TestDelete(t *testing.T) { - storage, server := newStorage(t) - defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store).ClusterScope().Namer(namer) - test.TestDelete(validNewThirdPartyResource("kind.domain.tld")) -} - -func TestGet(t *testing.T) { - storage, server := newStorage(t) - defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store).ClusterScope().Namer(namer) - test.TestGet(validNewThirdPartyResource("kind.domain.tld")) -} - -func TestList(t *testing.T) { - storage, server := newStorage(t) - defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store).ClusterScope().Namer(namer) - test.TestList(validNewThirdPartyResource("kind.domain.tld")) -} - -func TestWatch(t *testing.T) { - storage, server := newStorage(t) - defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store).ClusterScope().Namer(namer) - test.TestWatch( - validNewThirdPartyResource("kind.domain.tld"), - // matching labels - []labels.Set{}, - // not matching labels - []labels.Set{ - {"foo": "bar"}, - }, - // matching fields - []fields.Set{}, - // not matching fields - []fields.Set{ - {"metadata.name": "bar"}, - {"name": "foo"}, - }, - ) -} diff --git a/pkg/registry/extensions/thirdpartyresource/strategy.go b/pkg/registry/extensions/thirdpartyresource/strategy.go deleted file mode 100644 index baf13844c87..00000000000 --- a/pkg/registry/extensions/thirdpartyresource/strategy.go +++ /dev/null @@ -1,102 +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 thirdpartyresource - -import ( - "fmt" - - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/validation/field" - genericapirequest "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/apiserver/pkg/registry/rest" - "k8s.io/apiserver/pkg/storage" - "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/apis/extensions" - "k8s.io/kubernetes/pkg/apis/extensions/validation" -) - -// strategy implements behavior for ThirdPartyResource objects -type strategy struct { - runtime.ObjectTyper -} - -// Strategy is the default logic that applies when creating and updating ThirdPartyResource -// objects via the REST API. -var Strategy = strategy{api.Scheme} - -var _ = rest.RESTCreateStrategy(Strategy) - -var _ = rest.RESTUpdateStrategy(Strategy) - -func (strategy) NamespaceScoped() bool { - return false -} - -func (strategy) GenerateName(base string) string { - return "" -} - -func (strategy) PrepareForCreate(ctx genericapirequest.Context, obj runtime.Object) { -} - -func (strategy) Validate(ctx genericapirequest.Context, obj runtime.Object) field.ErrorList { - return validation.ValidateThirdPartyResource(obj.(*extensions.ThirdPartyResource)) -} - -// Canonicalize normalizes the object after validation. -func (strategy) Canonicalize(obj runtime.Object) { -} - -func (strategy) AllowCreateOnUpdate() bool { - return false -} - -func (strategy) PrepareForUpdate(ctx genericapirequest.Context, obj, old runtime.Object) { -} - -func (strategy) ValidateUpdate(ctx genericapirequest.Context, obj, old runtime.Object) field.ErrorList { - return validation.ValidateThirdPartyResourceUpdate(obj.(*extensions.ThirdPartyResource), old.(*extensions.ThirdPartyResource)) -} - -func (strategy) AllowUnconditionalUpdate() bool { - return true -} - -// GetAttrs returns labels and fields of a given object for filtering purposes. -func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, bool, error) { - tpr, ok := obj.(*extensions.ThirdPartyResource) - if !ok { - return nil, nil, false, fmt.Errorf("not a ThirdPartyResource") - } - return labels.Set(tpr.Labels), SelectableFields(tpr), tpr.Initializers != nil, nil -} - -// Matcher returns a generic matcher for a given label and field selector. -func Matcher(label labels.Selector, field fields.Selector) storage.SelectionPredicate { - return storage.SelectionPredicate{ - Label: label, - Field: field, - GetAttrs: GetAttrs, - } -} - -// SelectableFields returns a field set that can be used for filter selection -func SelectableFields(obj *extensions.ThirdPartyResource) fields.Set { - return nil -} diff --git a/pkg/registry/extensions/thirdpartyresource/strategy_test.go b/pkg/registry/extensions/thirdpartyresource/strategy_test.go deleted file mode 100644 index 927d2713b5f..00000000000 --- a/pkg/registry/extensions/thirdpartyresource/strategy_test.go +++ /dev/null @@ -1,35 +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 thirdpartyresource - -import ( - "testing" - - _ "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/testapi" - apitesting "k8s.io/kubernetes/pkg/api/testing" - "k8s.io/kubernetes/pkg/apis/extensions" -) - -func TestSelectableFieldLabelConversions(t *testing.T) { - apitesting.TestSelectableFieldLabelConversionsOfKind(t, - testapi.Extensions.GroupVersion().String(), - "ThirdPartyResource", - SelectableFields(&extensions.ThirdPartyResource{}), - nil, - ) -} diff --git a/pkg/registry/extensions/thirdpartyresourcedata/BUILD b/pkg/registry/extensions/thirdpartyresourcedata/BUILD deleted file mode 100644 index 6e5ad937bc0..00000000000 --- a/pkg/registry/extensions/thirdpartyresourcedata/BUILD +++ /dev/null @@ -1,80 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -licenses(["notice"]) - -load( - "@io_bazel_rules_go//go:def.bzl", - "go_library", - "go_test", -) - -go_library( - name = "go_default_library", - srcs = [ - "codec.go", - "doc.go", - "registry.go", - "strategy.go", - "util.go", - ], - tags = ["automanaged"], - deps = [ - "//pkg/api:go_default_library", - "//pkg/api/util:go_default_library", - "//pkg/apis/extensions:go_default_library", - "//pkg/apis/extensions/validation:go_default_library", - "//vendor/k8s.io/api/core/v1:go_default_library", - "//vendor/k8s.io/api/extensions/v1beta1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/fields:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/json:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/yaml:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library", - "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", - "//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library", - "//vendor/k8s.io/apiserver/pkg/storage:go_default_library", - "//vendor/k8s.io/apiserver/pkg/storage/names:go_default_library", - ], -) - -go_test( - name = "go_default_test", - srcs = [ - "codec_test.go", - "strategy_test.go", - "util_test.go", - ], - library = ":go_default_library", - tags = ["automanaged"], - deps = [ - "//pkg/api:go_default_library", - "//pkg/api/testapi:go_default_library", - "//pkg/api/testing:go_default_library", - "//pkg/apis/extensions:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", - ], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [ - ":package-srcs", - "//pkg/registry/extensions/thirdpartyresourcedata/storage:all-srcs", - ], - tags = ["automanaged"], -) diff --git a/pkg/registry/extensions/thirdpartyresourcedata/codec.go b/pkg/registry/extensions/thirdpartyresourcedata/codec.go deleted file mode 100644 index 573d7b5bf87..00000000000 --- a/pkg/registry/extensions/thirdpartyresourcedata/codec.go +++ /dev/null @@ -1,593 +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 thirdpartyresourcedata - -import ( - "bytes" - gojson "encoding/json" - "fmt" - "io" - "net/url" - "strings" - - "k8s.io/api/core/v1" - "k8s.io/api/extensions/v1beta1" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/util/json" - "k8s.io/apimachinery/pkg/util/yaml" - "k8s.io/kubernetes/pkg/api" - apiutil "k8s.io/kubernetes/pkg/api/util" - "k8s.io/kubernetes/pkg/apis/extensions" -) - -type thirdPartyObjectConverter struct { - converter runtime.ObjectConvertor -} - -func (t *thirdPartyObjectConverter) ConvertToVersion(in runtime.Object, outVersion runtime.GroupVersioner) (out runtime.Object, err error) { - switch in.(type) { - // This seems weird, but in this case the ThirdPartyResourceData is really just a wrapper on the raw 3rd party data. - // The actual thing printed/sent to server is the actual raw third party resource data, which only has one version. - case *extensions.ThirdPartyResourceData: - return in, nil - default: - return t.converter.ConvertToVersion(in, outVersion) - } -} - -func (t *thirdPartyObjectConverter) Convert(in, out, context interface{}) error { - return t.converter.Convert(in, out, context) -} - -func (t *thirdPartyObjectConverter) ConvertFieldLabel(version, kind, label, value string) (string, string, error) { - return t.converter.ConvertFieldLabel(version, kind, label, value) -} - -func NewThirdPartyObjectConverter(converter runtime.ObjectConvertor) runtime.ObjectConvertor { - return &thirdPartyObjectConverter{converter} -} - -type thirdPartyResourceDataMapper struct { - mapper meta.RESTMapper - kind string - version string - group string -} - -var _ meta.RESTMapper = &thirdPartyResourceDataMapper{} - -func (t *thirdPartyResourceDataMapper) getResource() schema.GroupVersionResource { - plural, _ := meta.UnsafeGuessKindToResource(t.getKind()) - - return plural -} - -func (t *thirdPartyResourceDataMapper) getKind() schema.GroupVersionKind { - return schema.GroupVersionKind{Group: t.group, Version: t.version, Kind: t.kind} -} - -func (t *thirdPartyResourceDataMapper) isThirdPartyResource(partialResource schema.GroupVersionResource) bool { - actualResource := t.getResource() - if strings.ToLower(partialResource.Resource) != strings.ToLower(actualResource.Resource) { - return false - } - if len(partialResource.Group) != 0 && partialResource.Group != actualResource.Group { - return false - } - if len(partialResource.Version) != 0 && partialResource.Version != actualResource.Version { - return false - } - - return true -} - -func (t *thirdPartyResourceDataMapper) ResourcesFor(resource schema.GroupVersionResource) ([]schema.GroupVersionResource, error) { - if t.isThirdPartyResource(resource) { - return []schema.GroupVersionResource{t.getResource()}, nil - } - return t.mapper.ResourcesFor(resource) -} - -func (t *thirdPartyResourceDataMapper) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) { - if t.isThirdPartyResource(resource) { - return []schema.GroupVersionKind{t.getKind()}, nil - } - return t.mapper.KindsFor(resource) -} - -func (t *thirdPartyResourceDataMapper) ResourceFor(resource schema.GroupVersionResource) (schema.GroupVersionResource, error) { - if t.isThirdPartyResource(resource) { - return t.getResource(), nil - } - return t.mapper.ResourceFor(resource) -} - -func (t *thirdPartyResourceDataMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) { - if t.isThirdPartyResource(resource) { - return t.getKind(), nil - } - return t.mapper.KindFor(resource) -} - -func (t *thirdPartyResourceDataMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) { - if len(versions) != 1 { - return nil, fmt.Errorf("unexpected set of versions: %v", versions) - } - if gk.Group != t.group { - return nil, fmt.Errorf("unknown group %q expected %s", gk.Group, t.group) - } - if gk.Kind != "ThirdPartyResourceData" { - return nil, fmt.Errorf("unknown kind %s expected %s", gk.Kind, t.kind) - } - if versions[0] != t.version { - return nil, fmt.Errorf("unknown version %q expected %q", versions[0], t.version) - } - - // TODO figure out why we're doing this rewriting - extensionGK := schema.GroupKind{Group: extensions.GroupName, Kind: "ThirdPartyResourceData"} - - mapping, err := t.mapper.RESTMapping(extensionGK, api.Registry.GroupOrDie(extensions.GroupName).GroupVersion.Version) - if err != nil { - return nil, err - } - mapping.ObjectConvertor = &thirdPartyObjectConverter{mapping.ObjectConvertor} - return mapping, nil -} - -func (t *thirdPartyResourceDataMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) { - if gk.Group != t.group { - return nil, fmt.Errorf("unknown group %q expected %s", gk.Group, t.group) - } - if gk.Kind != "ThirdPartyResourceData" { - return nil, fmt.Errorf("unknown kind %s expected %s", gk.Kind, t.kind) - } - - // TODO figure out why we're doing this rewriting - extensionGK := schema.GroupKind{Group: extensions.GroupName, Kind: "ThirdPartyResourceData"} - - mappings, err := t.mapper.RESTMappings(extensionGK, versions...) - if err != nil { - return nil, err - } - for _, m := range mappings { - m.ObjectConvertor = &thirdPartyObjectConverter{m.ObjectConvertor} - } - return mappings, nil -} - -func (t *thirdPartyResourceDataMapper) ResourceSingularizer(resource string) (singular string, err error) { - return t.mapper.ResourceSingularizer(resource) -} - -func NewMapper(mapper meta.RESTMapper, kind, version, group string) meta.RESTMapper { - return &thirdPartyResourceDataMapper{ - mapper: mapper, - kind: kind, - version: version, - group: group, - } -} - -type thirdPartyResourceDataCodecFactory struct { - delegate runtime.NegotiatedSerializer - kind string - encodeGV schema.GroupVersion - decodeGV schema.GroupVersion -} - -func NewNegotiatedSerializer(s runtime.NegotiatedSerializer, kind string, encodeGV, decodeGV schema.GroupVersion) runtime.NegotiatedSerializer { - return &thirdPartyResourceDataCodecFactory{ - delegate: s, - kind: kind, - encodeGV: encodeGV, - decodeGV: decodeGV, - } -} - -func (t *thirdPartyResourceDataCodecFactory) SupportedMediaTypes() []runtime.SerializerInfo { - for _, info := range t.delegate.SupportedMediaTypes() { - if info.MediaType == runtime.ContentTypeJSON { - return []runtime.SerializerInfo{info} - } - } - return nil -} - -func (t *thirdPartyResourceDataCodecFactory) EncoderForVersion(s runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder { - return &thirdPartyResourceDataEncoder{delegate: t.delegate.EncoderForVersion(s, gv), gvk: t.encodeGV.WithKind(t.kind)} -} - -func (t *thirdPartyResourceDataCodecFactory) DecoderToVersion(s runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder { - return NewDecoder(t.delegate.DecoderToVersion(s, gv), t.kind) -} - -func NewCodec(delegate runtime.Codec, gvk schema.GroupVersionKind) runtime.Codec { - return runtime.NewCodec(NewEncoder(delegate, gvk), NewDecoder(delegate, gvk.Kind)) -} - -type thirdPartyResourceDataDecoder struct { - delegate runtime.Decoder - kind string -} - -func NewDecoder(delegate runtime.Decoder, kind string) runtime.Decoder { - return &thirdPartyResourceDataDecoder{delegate: delegate, kind: kind} -} - -var _ runtime.Decoder = &thirdPartyResourceDataDecoder{} - -func parseObject(data []byte) (map[string]interface{}, error) { - var mapObj map[string]interface{} - if err := json.Unmarshal(data, &mapObj); err != nil { - return nil, err - } - - return mapObj, nil -} - -func (t *thirdPartyResourceDataDecoder) populate(data []byte) (runtime.Object, *schema.GroupVersionKind, error) { - mapObj, err := parseObject(data) - if err != nil { - return nil, nil, err - } - return t.populateFromObject(mapObj, data) -} - -func (t *thirdPartyResourceDataDecoder) populateFromObject(mapObj map[string]interface{}, data []byte) (runtime.Object, *schema.GroupVersionKind, error) { - typeMeta := metav1.TypeMeta{} - if err := json.Unmarshal(data, &typeMeta); err != nil { - return nil, nil, err - } - - gv, err := schema.ParseGroupVersion(typeMeta.APIVersion) - if err != nil { - return nil, nil, err - } - gvk := gv.WithKind(typeMeta.Kind) - - isList := strings.HasSuffix(typeMeta.Kind, "List") - switch { - case !isList && (len(t.kind) == 0 || typeMeta.Kind == t.kind): - result := &extensions.ThirdPartyResourceData{} - if err := t.populateResource(result, mapObj, data); err != nil { - return nil, nil, err - } - return result, &gvk, nil - case isList && (len(t.kind) == 0 || typeMeta.Kind == t.kind+"List"): - list := &extensions.ThirdPartyResourceDataList{} - if err := t.populateListResource(list, mapObj); err != nil { - return nil, nil, err - } - return list, &gvk, nil - default: - return nil, nil, fmt.Errorf("unexpected kind: %s, expected %s", typeMeta.Kind, t.kind) - } -} - -func (t *thirdPartyResourceDataDecoder) populateResource(objIn *extensions.ThirdPartyResourceData, mapObj map[string]interface{}, data []byte) error { - metadata, ok := mapObj["metadata"].(map[string]interface{}) - if !ok { - return fmt.Errorf("unexpected object for metadata: %#v", mapObj["metadata"]) - } - - metadataData, err := json.Marshal(metadata) - if err != nil { - return err - } - - if err := json.Unmarshal(metadataData, &objIn.ObjectMeta); err != nil { - return err - } - - // Override API Version with the ThirdPartyResourceData value - // TODO: fix this hard code - objIn.APIVersion = v1beta1.SchemeGroupVersion.String() - - objIn.Data = data - return nil -} - -func IsThirdPartyObject(rawData []byte, gvk *schema.GroupVersionKind) (isThirdParty bool, gvkOut *schema.GroupVersionKind, err error) { - var gv schema.GroupVersion - if gvk == nil { - data, err := yaml.ToJSON(rawData) - if err != nil { - return false, nil, err - } - metadata := metav1.TypeMeta{} - if err = json.Unmarshal(data, &metadata); err != nil { - return false, nil, err - } - gv, err = schema.ParseGroupVersion(metadata.APIVersion) - if err != nil { - return false, nil, err - } - gvkOut = &schema.GroupVersionKind{ - Group: gv.Group, - Version: gv.Version, - Kind: metadata.Kind, - } - } else { - gv = gvk.GroupVersion() - gvkOut = gvk - } - return api.Registry.IsThirdPartyAPIGroupVersion(gv), gvkOut, nil -} - -func (t *thirdPartyResourceDataDecoder) Decode(data []byte, gvk *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) { - if into == nil { - if gvk == nil || gvk.Kind != t.kind { - if isThirdParty, _, err := IsThirdPartyObject(data, gvk); err != nil { - return nil, nil, err - } else if !isThirdParty { - return t.delegate.Decode(data, gvk, into) - } - } - return t.populate(data) - } - switch o := into.(type) { - case *extensions.ThirdPartyResourceData: - break - case *runtime.VersionedObjects: - // We're not sure that it's third party, we need to test - if gvk == nil || gvk.Kind != t.kind { - if isThirdParty, _, err := IsThirdPartyObject(data, gvk); err != nil { - return nil, nil, err - } else if !isThirdParty { - return t.delegate.Decode(data, gvk, into) - } - } - obj, outGVK, err := t.populate(data) - if err != nil { - return nil, nil, err - } - o.Objects = []runtime.Object{ - obj, - } - return o, outGVK, nil - default: - if gvk != nil && api.Registry.IsThirdPartyAPIGroupVersion(gvk.GroupVersion()) { - // delegate won't recognize a thirdparty group version - gvk = nil - } - return t.delegate.Decode(data, gvk, into) - } - - thirdParty := into.(*extensions.ThirdPartyResourceData) - var mapObj map[string]interface{} - if err := json.Unmarshal(data, &mapObj); err != nil { - return nil, nil, err - } - - /*if gvk.Kind != "ThirdPartyResourceData" { - return nil, nil, fmt.Errorf("unexpected kind: %s", gvk.Kind) - }*/ - actual := &schema.GroupVersionKind{} - if kindObj, found := mapObj["kind"]; !found { - if gvk == nil { - return nil, nil, runtime.NewMissingKindErr(string(data)) - } - mapObj["kind"] = gvk.Kind - actual.Kind = gvk.Kind - } else { - kindStr, ok := kindObj.(string) - if !ok { - return nil, nil, fmt.Errorf("unexpected object for 'kind': %v", kindObj) - } - if len(t.kind) > 0 && kindStr != t.kind { - return nil, nil, fmt.Errorf("kind doesn't match, expecting: %s, got %s", t.kind, kindStr) - } - actual.Kind = kindStr - } - if versionObj, found := mapObj["apiVersion"]; !found { - if gvk == nil { - return nil, nil, runtime.NewMissingVersionErr(string(data)) - } - mapObj["apiVersion"] = gvk.GroupVersion().String() - actual.Group, actual.Version = gvk.Group, gvk.Version - } else { - versionStr, ok := versionObj.(string) - if !ok { - return nil, nil, fmt.Errorf("unexpected object for 'apiVersion': %v", versionObj) - } - if gvk != nil && versionStr != gvk.GroupVersion().String() { - return nil, nil, fmt.Errorf("version doesn't match, expecting: %v, got %s", gvk.GroupVersion(), versionStr) - } - gv, err := schema.ParseGroupVersion(versionStr) - if err != nil { - return nil, nil, err - } - actual.Group, actual.Version = gv.Group, gv.Version - } - - mapObj, err := parseObject(data) - if err != nil { - return nil, actual, err - } - if err := t.populateResource(thirdParty, mapObj, data); err != nil { - return nil, actual, err - } - return thirdParty, actual, nil -} - -func (t *thirdPartyResourceDataDecoder) populateListResource(objIn *extensions.ThirdPartyResourceDataList, mapObj map[string]interface{}) error { - items, ok := mapObj["items"].([]interface{}) - if !ok { - return fmt.Errorf("unexpected object for items: %#v", mapObj["items"]) - } - objIn.Items = make([]extensions.ThirdPartyResourceData, len(items)) - for ix := range items { - objData, err := json.Marshal(items[ix]) - if err != nil { - return err - } - objMap, err := parseObject(objData) - if err != nil { - return err - } - if err := t.populateResource(&objIn.Items[ix], objMap, objData); err != nil { - return err - } - } - return nil -} - -type thirdPartyResourceDataEncoder struct { - delegate runtime.Encoder - gvk schema.GroupVersionKind -} - -func NewEncoder(delegate runtime.Encoder, gvk schema.GroupVersionKind) runtime.Encoder { - return &thirdPartyResourceDataEncoder{delegate: delegate, gvk: gvk} -} - -var _ runtime.Encoder = &thirdPartyResourceDataEncoder{} - -func encodeToJSON(obj *extensions.ThirdPartyResourceData, stream io.Writer) error { - var objMap map[string]interface{} - if err := json.Unmarshal(obj.Data, &objMap); err != nil { - return err - } - - objMap["metadata"] = &obj.ObjectMeta - encoder := json.NewEncoder(stream) - return encoder.Encode(objMap) -} - -func (t *thirdPartyResourceDataEncoder) Encode(obj runtime.Object, stream io.Writer) (err error) { - switch obj := obj.(type) { - case *extensions.ThirdPartyResourceData: - return encodeToJSON(obj, stream) - case *extensions.ThirdPartyResourceDataList: - // TODO: There are likely still better ways to do this... - listItems := make([]gojson.RawMessage, len(obj.Items)) - - for ix := range obj.Items { - buff := &bytes.Buffer{} - err := encodeToJSON(&obj.Items[ix], buff) - if err != nil { - return err - } - listItems[ix] = gojson.RawMessage(buff.Bytes()) - } - - if t.gvk.Empty() { - return fmt.Errorf("thirdPartyResourceDataEncoder was not given a target version") - } - - encMap := struct { - // +optional - Kind string `json:"kind,omitempty"` - Items []gojson.RawMessage `json:"items"` - // +optional - Metadata metav1.ListMeta `json:"metadata,omitempty"` - // +optional - APIVersion string `json:"apiVersion,omitempty"` - }{ - Kind: t.gvk.Kind + "List", - Items: listItems, - Metadata: obj.ListMeta, - APIVersion: t.gvk.GroupVersion().String(), - } - - encBytes, err := json.Marshal(encMap) - if err != nil { - return err - } - - _, err = stream.Write(encBytes) - return err - case *metav1.InternalEvent: - event := &metav1.WatchEvent{} - err := metav1.Convert_versioned_InternalEvent_to_versioned_Event(obj, event, nil) - if err != nil { - return err - } - - enc := json.NewEncoder(stream) - err = enc.Encode(event) - if err != nil { - return err - } - - return nil - case *metav1.WatchEvent: - // This is the same as the InternalEvent case above, except the caller - // already did the conversion for us (see #44350). - // In theory, we probably don't need the InternalEvent case anymore, - // but the test coverage for TPR is too low to risk removing it. - return json.NewEncoder(stream).Encode(obj) - case *metav1.Status, *metav1.APIResourceList: - return t.delegate.Encode(obj, stream) - default: - return fmt.Errorf("unexpected object to encode: %#v", obj) - } -} - -func NewObjectCreator(group, version string, delegate runtime.ObjectCreater) runtime.ObjectCreater { - return &thirdPartyResourceDataCreator{group, version, delegate} -} - -type thirdPartyResourceDataCreator struct { - group string - version string - delegate runtime.ObjectCreater -} - -func (t *thirdPartyResourceDataCreator) New(kind schema.GroupVersionKind) (out runtime.Object, err error) { - switch kind.Kind { - case "ThirdPartyResourceData": - if apiutil.GetGroupVersion(t.group, t.version) != kind.GroupVersion().String() { - return nil, fmt.Errorf("unknown kind %v", kind) - } - return &extensions.ThirdPartyResourceData{}, nil - case "ThirdPartyResourceDataList": - if apiutil.GetGroupVersion(t.group, t.version) != kind.GroupVersion().String() { - return nil, fmt.Errorf("unknown kind %v", kind) - } - return &extensions.ThirdPartyResourceDataList{}, nil - // TODO: this list needs to be formalized higher in the chain - case "ListOptions", "WatchEvent": - if apiutil.GetGroupVersion(t.group, t.version) == kind.GroupVersion().String() { - // Translate third party group to external group. - gvk := api.Registry.EnabledVersionsForGroup(api.GroupName)[0].WithKind(kind.Kind) - return t.delegate.New(gvk) - } - return t.delegate.New(kind) - default: - return t.delegate.New(kind) - } -} - -func NewThirdPartyParameterCodec(p runtime.ParameterCodec) runtime.ParameterCodec { - return &thirdPartyParameterCodec{p} -} - -type thirdPartyParameterCodec struct { - delegate runtime.ParameterCodec -} - -func (t *thirdPartyParameterCodec) DecodeParameters(parameters url.Values, from schema.GroupVersion, into runtime.Object) error { - return t.delegate.DecodeParameters(parameters, v1.SchemeGroupVersion, into) -} - -func (t *thirdPartyParameterCodec) EncodeParameters(obj runtime.Object, to schema.GroupVersion) (url.Values, error) { - return t.delegate.EncodeParameters(obj, v1.SchemeGroupVersion) -} diff --git a/pkg/registry/extensions/thirdpartyresourcedata/codec_test.go b/pkg/registry/extensions/thirdpartyresourcedata/codec_test.go deleted file mode 100644 index 685a5e06920..00000000000 --- a/pkg/registry/extensions/thirdpartyresourcedata/codec_test.go +++ /dev/null @@ -1,329 +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 thirdpartyresourcedata - -import ( - "bytes" - "encoding/json" - "reflect" - "strings" - "testing" - "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/testapi" - "k8s.io/kubernetes/pkg/apis/extensions" -) - -type Foo struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty" description:"standard object metadata"` - - SomeField string `json:"someField"` - OtherField int `json:"otherField"` -} - -func (*Foo) GetObjectKind() schema.ObjectKind { - return schema.EmptyObjectKind -} - -type FooList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty" description:"standard list metadata; see https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"` - - Items []Foo `json:"items"` -} - -func TestCodec(t *testing.T) { - tests := []struct { - into runtime.Object - obj *Foo - expectErr bool - name string - }{ - { - into: &runtime.VersionedObjects{}, - obj: &Foo{ - ObjectMeta: metav1.ObjectMeta{Name: "bar"}, - TypeMeta: metav1.TypeMeta{APIVersion: "company.com/v1", Kind: "Foo"}, - }, - expectErr: false, - name: "versioned objects list", - }, - { - obj: &Foo{ObjectMeta: metav1.ObjectMeta{Name: "bar"}}, - expectErr: true, - name: "missing kind", - }, - { - obj: &Foo{ - ObjectMeta: metav1.ObjectMeta{Name: "bar"}, - TypeMeta: metav1.TypeMeta{APIVersion: "company.com/v1", Kind: "Foo"}, - }, - name: "basic", - }, - { - into: &extensions.ThirdPartyResourceData{}, - obj: &Foo{ - ObjectMeta: metav1.ObjectMeta{Name: "bar"}, - TypeMeta: metav1.TypeMeta{Kind: "ThirdPartyResourceData"}, - }, - expectErr: true, - name: "broken kind", - }, - { - obj: &Foo{ - ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "baz"}, - TypeMeta: metav1.TypeMeta{APIVersion: "company.com/v1", Kind: "Foo"}, - }, - name: "resource version", - }, - { - obj: &Foo{ - ObjectMeta: metav1.ObjectMeta{ - Name: "bar", - CreationTimestamp: metav1.Time{Time: time.Unix(100, 0)}, - }, - TypeMeta: metav1.TypeMeta{ - APIVersion: "company.com/v1", - Kind: "Foo", - }, - }, - name: "creation time", - }, - { - obj: &Foo{ - ObjectMeta: metav1.ObjectMeta{ - Name: "bar", - ResourceVersion: "baz", - Labels: map[string]string{"foo": "bar", "baz": "blah"}, - }, - TypeMeta: metav1.TypeMeta{APIVersion: "company.com/v1", Kind: "Foo"}, - }, - name: "labels", - }, - } - api.Registry.AddThirdPartyAPIGroupVersions(schema.GroupVersion{Group: "company.com", Version: "v1"}) - for _, test := range tests { - d := &thirdPartyResourceDataDecoder{kind: "Foo", delegate: testapi.Extensions.Codec()} - e := &thirdPartyResourceDataEncoder{gvk: schema.GroupVersionKind{ - Group: "company.com", - Version: "v1", - Kind: "Foo", - }, delegate: testapi.Extensions.Codec()} - data, err := json.Marshal(test.obj) - if err != nil { - t.Errorf("[%s] unexpected error: %v", test.name, err) - continue - } - var obj runtime.Object - if test.into != nil { - err = runtime.DecodeInto(d, data, test.into) - obj = test.into - } else { - obj, err = runtime.Decode(d, data) - } - if err != nil && !test.expectErr { - t.Errorf("[%s] unexpected error: %v", test.name, err) - continue - } - if test.expectErr { - if err == nil { - t.Errorf("[%s] unexpected non-error", test.name) - } - continue - } - var rsrcObj *extensions.ThirdPartyResourceData - switch o := obj.(type) { - case *extensions.ThirdPartyResourceData: - rsrcObj = o - case *runtime.VersionedObjects: - rsrcObj = o.First().(*extensions.ThirdPartyResourceData) - default: - t.Errorf("[%s] unexpected object: %v", test.name, obj) - continue - } - if !reflect.DeepEqual(rsrcObj.ObjectMeta, test.obj.ObjectMeta) { - t.Errorf("[%s]\nexpected\n%v\nsaw\n%v\n", test.name, rsrcObj.ObjectMeta, test.obj.ObjectMeta) - } - var output Foo - if err := json.Unmarshal(rsrcObj.Data, &output); err != nil { - t.Errorf("[%s] unexpected error: %v", test.name, err) - continue - } - if !reflect.DeepEqual(&output, test.obj) { - t.Errorf("[%s]\nexpected\n%v\nsaw\n%v\n", test.name, test.obj, &output) - } - - data, err = runtime.Encode(e, rsrcObj) - if err != nil { - t.Errorf("[%s] unexpected error: %v", test.name, err) - } - - var output2 Foo - if err := json.Unmarshal(data, &output2); err != nil { - t.Errorf("[%s] unexpected error: %v", test.name, err) - continue - } - if !reflect.DeepEqual(&output2, test.obj) { - t.Errorf("[%s]\nexpected\n%v\nsaw\n%v\n", test.name, test.obj, &output2) - } - } -} - -func TestCreater(t *testing.T) { - creater := NewObjectCreator("creater group", "creater version", api.Scheme) - tests := []struct { - name string - kind schema.GroupVersionKind - expectedObj runtime.Object - expectErr bool - }{ - { - name: "valid ThirdPartyResourceData creation", - kind: schema.GroupVersionKind{Group: "creater group", Version: "creater version", Kind: "ThirdPartyResourceData"}, - expectedObj: &extensions.ThirdPartyResourceData{}, - expectErr: false, - }, - { - name: "invalid ThirdPartyResourceData creation", - kind: schema.GroupVersionKind{Version: "invalid version", Kind: "ThirdPartyResourceData"}, - expectedObj: nil, - expectErr: true, - }, - { - name: "valid ListOptions creation", - kind: schema.GroupVersionKind{Version: "v1", Kind: "ListOptions"}, - expectedObj: &metav1.ListOptions{}, - expectErr: false, - }, - } - for _, test := range tests { - out, err := creater.New(test.kind) - if err != nil && !test.expectErr { - t.Errorf("[%s] unexpected error: %v", test.name, err) - } - if err == nil && test.expectErr { - t.Errorf("[%s] unexpected non-error", test.name) - } - if !reflect.DeepEqual(test.expectedObj, out) { - t.Errorf("[%s] unexpected error: expect: %v, got: %v", test.name, test.expectedObj, out) - } - - } -} - -func TestEncodeToStreamForInternalEvent(t *testing.T) { - e := &thirdPartyResourceDataEncoder{gvk: schema.GroupVersionKind{ - Group: "company.com", - Version: "v1", - Kind: "Foo", - }, delegate: testapi.Extensions.Codec()} - buf := bytes.NewBuffer([]byte{}) - expected := &metav1.WatchEvent{ - Type: "Added", - } - err := e.Encode(&metav1.InternalEvent{ - Type: "Added", - }, buf) - - jBytes, _ := json.Marshal(expected) - - if string(jBytes) == buf.String() { - t.Errorf("unexpected encoding expected %s got %s", string(jBytes), buf.String()) - } - - if err != nil { - t.Errorf("unexpected error encoding: %v", err) - } -} - -func TestThirdPartyResourceDataListEncoding(t *testing.T) { - gv := schema.GroupVersion{Group: "stable.foo.faz", Version: "v1"} - gvk := gv.WithKind("Bar") - e := &thirdPartyResourceDataEncoder{delegate: testapi.Extensions.Codec(), gvk: gvk} - subject := &extensions.ThirdPartyResourceDataList{} - - buf := bytes.NewBuffer([]byte{}) - err := e.Encode(subject, buf) - if err != nil { - t.Errorf("encoding unexpected error: %v", err) - } - - targetOutput := struct { - Kind string `json:"kind,omitempty"` - Items []json.RawMessage `json:"items"` - Metadata metav1.ListMeta `json:"metadata,omitempty"` - APIVersion string `json:"apiVersion,omitempty"` - }{} - err = json.Unmarshal(buf.Bytes(), &targetOutput) - - if err != nil { - t.Errorf("unmarshal unexpected error: %v", err) - } - - if expectedKind := gvk.Kind + "List"; expectedKind != targetOutput.Kind { - t.Errorf("unexpected kind on list got %s expected %s", targetOutput.Kind, expectedKind) - } - - if targetOutput.Metadata != subject.ListMeta { - t.Errorf("metadata mismatch %v != %v", targetOutput.Metadata, subject.ListMeta) - } - - if targetOutput.APIVersion != gv.String() { - t.Errorf("apiversion mismatch %v != %v", targetOutput.APIVersion, gv.String()) - } -} - -func TestDecodeNumbers(t *testing.T) { - gv := schema.GroupVersion{Group: "stable.foo.faz", Version: "v1"} - gvk := gv.WithKind("Foo") - e := &thirdPartyResourceDataEncoder{delegate: testapi.Extensions.Codec(), gvk: gvk} - d := &thirdPartyResourceDataDecoder{kind: "Foo", delegate: testapi.Extensions.Codec()} - - // Use highest int64 number and 1000000. - subject := &extensions.ThirdPartyResourceDataList{ - Items: []extensions.ThirdPartyResourceData{ - { - Data: []byte(`{"num1": 9223372036854775807, "num2": 1000000}`), - }, - }, - } - - // Encode to get original JSON. - originalJSON := bytes.NewBuffer([]byte{}) - err := e.Encode(subject, originalJSON) - if err != nil { - t.Errorf("encoding unexpected error: %v", err) - } - - // Decode original JSON. - var into runtime.Object - into, _, err = d.Decode(originalJSON.Bytes(), &gvk, into) - if err != nil { - t.Errorf("decoding unexpected error: %v", err) - } - - // Check if int is preserved. - decodedJSON := into.(*extensions.ThirdPartyResourceDataList).Items[0].Data - if !strings.Contains(string(decodedJSON), `"num1":9223372036854775807,"num2":1000000`) { - t.Errorf("Expected %s, got %s", `"num1":9223372036854775807,"num2":1000000`, string(decodedJSON)) - } -} diff --git a/pkg/registry/extensions/thirdpartyresourcedata/doc.go b/pkg/registry/extensions/thirdpartyresourcedata/doc.go deleted file mode 100644 index c5555ce4fed..00000000000 --- a/pkg/registry/extensions/thirdpartyresourcedata/doc.go +++ /dev/null @@ -1,19 +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 thirdpartyresourcedata provides Registry interface and its REST -// implementation for storing ThirdPartyResourceData api objects. -package thirdpartyresourcedata // import "k8s.io/kubernetes/pkg/registry/extensions/thirdpartyresourcedata" diff --git a/pkg/registry/extensions/thirdpartyresourcedata/registry.go b/pkg/registry/extensions/thirdpartyresourcedata/registry.go deleted file mode 100644 index d8266046add..00000000000 --- a/pkg/registry/extensions/thirdpartyresourcedata/registry.go +++ /dev/null @@ -1,83 +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 thirdpartyresourcedata - -import ( - metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/watch" - genericapirequest "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/apiserver/pkg/registry/rest" - "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/apis/extensions" -) - -// Registry is an interface implemented by things that know how to store ThirdPartyResourceData objects. -type Registry interface { - ListThirdPartyResourceData(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*extensions.ThirdPartyResourceDataList, error) - WatchThirdPartyResourceData(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) - GetThirdPartyResourceData(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*extensions.ThirdPartyResourceData, error) - CreateThirdPartyResourceData(ctx genericapirequest.Context, resource *extensions.ThirdPartyResourceData) (*extensions.ThirdPartyResourceData, error) - UpdateThirdPartyResourceData(ctx genericapirequest.Context, resource *extensions.ThirdPartyResourceData) (*extensions.ThirdPartyResourceData, error) - DeleteThirdPartyResourceData(ctx genericapirequest.Context, name string) error -} - -// storage puts strong typing around storage calls -type storage struct { - rest.StandardStorage -} - -// NewRegistry returns a new Registry interface for the given Storage. Any mismatched -// types will panic. -func NewRegistry(s rest.StandardStorage) Registry { - return &storage{s} -} - -func (s *storage) ListThirdPartyResourceData(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*extensions.ThirdPartyResourceDataList, error) { - obj, err := s.List(ctx, options) - if err != nil { - return nil, err - } - return obj.(*extensions.ThirdPartyResourceDataList), nil -} - -func (s *storage) WatchThirdPartyResourceData(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) { - return s.Watch(ctx, options) -} - -func (s *storage) GetThirdPartyResourceData(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*extensions.ThirdPartyResourceData, error) { - obj, err := s.Get(ctx, name, options) - if err != nil { - return nil, err - } - return obj.(*extensions.ThirdPartyResourceData), nil -} - -func (s *storage) CreateThirdPartyResourceData(ctx genericapirequest.Context, ThirdPartyResourceData *extensions.ThirdPartyResourceData) (*extensions.ThirdPartyResourceData, error) { - obj, err := s.Create(ctx, ThirdPartyResourceData, false) - return obj.(*extensions.ThirdPartyResourceData), err -} - -func (s *storage) UpdateThirdPartyResourceData(ctx genericapirequest.Context, ThirdPartyResourceData *extensions.ThirdPartyResourceData) (*extensions.ThirdPartyResourceData, error) { - obj, _, err := s.Update(ctx, ThirdPartyResourceData.Name, rest.DefaultUpdatedObjectInfo(ThirdPartyResourceData, api.Scheme)) - return obj.(*extensions.ThirdPartyResourceData), err -} - -func (s *storage) DeleteThirdPartyResourceData(ctx genericapirequest.Context, name string) error { - _, _, err := s.Delete(ctx, name, nil) - return err -} diff --git a/pkg/registry/extensions/thirdpartyresourcedata/storage/BUILD b/pkg/registry/extensions/thirdpartyresourcedata/storage/BUILD deleted file mode 100644 index c8a16f61dd7..00000000000 --- a/pkg/registry/extensions/thirdpartyresourcedata/storage/BUILD +++ /dev/null @@ -1,60 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -licenses(["notice"]) - -load( - "@io_bazel_rules_go//go:def.bzl", - "go_library", - "go_test", -) - -go_test( - name = "go_default_test", - srcs = ["storage_test.go"], - library = ":go_default_library", - tags = ["automanaged"], - deps = [ - "//pkg/apis/extensions:go_default_library", - "//pkg/registry/registrytest:go_default_library", - "//vendor/k8s.io/api/extensions/v1beta1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/fields:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", - "//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library", - "//vendor/k8s.io/apiserver/pkg/storage/etcd/testing:go_default_library", - ], -) - -go_library( - name = "go_default_library", - srcs = ["storage.go"], - tags = ["automanaged"], - deps = [ - "//pkg/api:go_default_library", - "//pkg/apis/extensions:go_default_library", - "//pkg/registry/cachesize:go_default_library", - "//pkg/registry/extensions/thirdpartyresourcedata:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", - "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", - "//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library", - "//vendor/k8s.io/apiserver/pkg/registry/generic/registry:go_default_library", - "//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library", - ], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [":package-srcs"], - tags = ["automanaged"], -) diff --git a/pkg/registry/extensions/thirdpartyresourcedata/storage/storage.go b/pkg/registry/extensions/thirdpartyresourcedata/storage/storage.go deleted file mode 100644 index 3693dff82b8..00000000000 --- a/pkg/registry/extensions/thirdpartyresourcedata/storage/storage.go +++ /dev/null @@ -1,127 +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 storage - -import ( - "strings" - "sync/atomic" - - "k8s.io/apimachinery/pkg/api/errors" - metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - genericapirequest "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/apiserver/pkg/registry/generic" - genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" - "k8s.io/apiserver/pkg/registry/rest" - "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/apis/extensions" - "k8s.io/kubernetes/pkg/registry/cachesize" - "k8s.io/kubernetes/pkg/registry/extensions/thirdpartyresourcedata" -) - -// errFrozen is a transient error to indicate that clients should retry with backoff. -var errFrozen = errors.NewServiceUnavailable("TPR data is temporarily frozen") - -// REST implements a RESTStorage for ThirdPartyResourceData. -type REST struct { - *genericregistry.Store - kind string - frozen atomic.Value -} - -// Freeze causes all future calls to Create/Update/Delete/DeleteCollection to return a transient error. -// This is irreversible and meant for use when the TPR data is being deleted or migrated/abandoned. -func (r *REST) Freeze() { - r.frozen.Store(true) -} - -func (r *REST) isFrozen() bool { - return r.frozen.Load() != nil -} - -// Create is a wrapper to support Freeze. -func (r *REST) Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { - if r.isFrozen() { - return nil, errFrozen - } - return r.Store.Create(ctx, obj, includeUninitialized) -} - -// Update is a wrapper to support Freeze. -func (r *REST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { - if r.isFrozen() { - return nil, false, errFrozen - } - return r.Store.Update(ctx, name, objInfo) -} - -// Delete is a wrapper to support Freeze. -func (r *REST) Delete(ctx genericapirequest.Context, name string, options *metav1.DeleteOptions) (runtime.Object, bool, error) { - if r.isFrozen() { - return nil, false, errFrozen - } - return r.Store.Delete(ctx, name, options) -} - -// DeleteCollection is a wrapper to support Freeze. -func (r *REST) DeleteCollection(ctx genericapirequest.Context, options *metav1.DeleteOptions, listOptions *metainternalversion.ListOptions) (runtime.Object, error) { - if r.isFrozen() { - return nil, errFrozen - } - return r.Store.DeleteCollection(ctx, options, listOptions) -} - -// NewREST returns a registry which will store ThirdPartyResourceData in the given helper -func NewREST(optsGetter generic.RESTOptionsGetter, group, kind string) *REST { - resource := extensions.Resource("thirdpartyresourcedatas") - opts, err := optsGetter.GetRESTOptions(resource) - if err != nil { - panic(err) // TODO: Propagate error up - } - - // We explicitly do NOT do any decoration here yet. - opts.Decorator = generic.UndecoratedStorage // TODO use watchCacheSize=-1 to signal UndecoratedStorage - opts.ResourcePrefix = "/ThirdPartyResourceData/" + group + "/" + strings.ToLower(kind) + "s" - - store := &genericregistry.Store{ - Copier: api.Scheme, - NewFunc: func() runtime.Object { return &extensions.ThirdPartyResourceData{} }, - NewListFunc: func() runtime.Object { return &extensions.ThirdPartyResourceDataList{} }, - PredicateFunc: thirdpartyresourcedata.Matcher, - QualifiedResource: resource, - WatchCacheSize: cachesize.GetWatchCacheSizeByResource(resource.Resource), - - CreateStrategy: thirdpartyresourcedata.Strategy, - UpdateStrategy: thirdpartyresourcedata.Strategy, - DeleteStrategy: thirdpartyresourcedata.Strategy, - } - options := &generic.StoreOptions{RESTOptions: opts, AttrFunc: thirdpartyresourcedata.GetAttrs} // Pass in opts to use UndecoratedStorage and custom ResourcePrefix - if err := store.CompleteWithOptions(options); err != nil { - panic(err) // TODO: Propagate error up - } - - return &REST{ - Store: store, - kind: kind, - } -} - -// Implements the rest.KindProvider interface -func (r *REST) Kind() string { - return r.kind -} diff --git a/pkg/registry/extensions/thirdpartyresourcedata/storage/storage_test.go b/pkg/registry/extensions/thirdpartyresourcedata/storage/storage_test.go deleted file mode 100644 index 6b0b3405e6d..00000000000 --- a/pkg/registry/extensions/thirdpartyresourcedata/storage/storage_test.go +++ /dev/null @@ -1,127 +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 storage - -import ( - "testing" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/kubernetes/pkg/apis/extensions" - // Ensure that extensions/v1beta1 package is initialized. - _ "k8s.io/api/extensions/v1beta1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apiserver/pkg/registry/generic" - etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing" - "k8s.io/kubernetes/pkg/registry/registrytest" -) - -func newStorage(t *testing.T) (*REST, *etcdtesting.EtcdTestServer) { - etcdStorage, server := registrytest.NewEtcdStorage(t, extensions.GroupName) - restOptions := generic.RESTOptions{StorageConfig: etcdStorage, Decorator: generic.UndecoratedStorage, DeleteCollectionWorkers: 1} - return NewREST(restOptions, "foo", "bar"), server -} - -func validNewThirdPartyResourceData(name string) *extensions.ThirdPartyResourceData { - return &extensions.ThirdPartyResourceData{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: metav1.NamespaceDefault, - }, - Data: []byte("foobarbaz"), - } -} - -func TestCreate(t *testing.T) { - storage, server := newStorage(t) - defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store) - rsrc := validNewThirdPartyResourceData("foo") - rsrc.ObjectMeta = metav1.ObjectMeta{} - test.TestCreate( - // valid - rsrc, - // invalid - &extensions.ThirdPartyResourceData{}, - ) -} - -func TestUpdate(t *testing.T) { - storage, server := newStorage(t) - defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store) - test.TestUpdate( - // valid - validNewThirdPartyResourceData("foo"), - // updateFunc - func(obj runtime.Object) runtime.Object { - object := obj.(*extensions.ThirdPartyResourceData) - object.Data = []byte("new description") - return object - }, - ) -} - -func TestDelete(t *testing.T) { - storage, server := newStorage(t) - defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store) - test.TestDelete(validNewThirdPartyResourceData("foo")) -} - -func TestGet(t *testing.T) { - storage, server := newStorage(t) - defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store) - test.TestGet(validNewThirdPartyResourceData("foo")) -} - -func TestList(t *testing.T) { - storage, server := newStorage(t) - defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store) - test.TestList(validNewThirdPartyResourceData("foo")) -} - -func TestWatch(t *testing.T) { - storage, server := newStorage(t) - defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store) - test.TestWatch( - validNewThirdPartyResourceData("foo"), - // matching labels - []labels.Set{}, - // not matching labels - []labels.Set{ - {"foo": "bar"}, - }, - // matching fields - []fields.Set{}, - // not matching fields - []fields.Set{ - {"metadata.name": "bar"}, - {"name": "foo"}, - }, - ) -} diff --git a/pkg/registry/extensions/thirdpartyresourcedata/strategy.go b/pkg/registry/extensions/thirdpartyresourcedata/strategy.go deleted file mode 100644 index ba3746d45c7..00000000000 --- a/pkg/registry/extensions/thirdpartyresourcedata/strategy.go +++ /dev/null @@ -1,100 +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 thirdpartyresourcedata - -import ( - "fmt" - - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/validation/field" - genericapirequest "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/apiserver/pkg/registry/rest" - apistorage "k8s.io/apiserver/pkg/storage" - "k8s.io/apiserver/pkg/storage/names" - "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/apis/extensions" - "k8s.io/kubernetes/pkg/apis/extensions/validation" -) - -// strategy implements behavior for ThirdPartyResource objects -type strategy struct { - runtime.ObjectTyper - names.NameGenerator -} - -// Strategy is the default logic that applies when creating and updating ThirdPartyResource -// objects via the REST API. -var Strategy = strategy{api.Scheme, names.SimpleNameGenerator} - -var _ = rest.RESTCreateStrategy(Strategy) - -var _ = rest.RESTUpdateStrategy(Strategy) - -func (strategy) NamespaceScoped() bool { - return true -} - -func (strategy) PrepareForCreate(ctx genericapirequest.Context, obj runtime.Object) { -} - -func (strategy) Validate(ctx genericapirequest.Context, obj runtime.Object) field.ErrorList { - return validation.ValidateThirdPartyResourceData(obj.(*extensions.ThirdPartyResourceData)) -} - -// Canonicalize normalizes the object after validation. -func (strategy) Canonicalize(obj runtime.Object) { -} - -func (strategy) AllowCreateOnUpdate() bool { - return false -} - -func (strategy) PrepareForUpdate(ctx genericapirequest.Context, obj, old runtime.Object) { -} - -func (strategy) ValidateUpdate(ctx genericapirequest.Context, obj, old runtime.Object) field.ErrorList { - return validation.ValidateThirdPartyResourceDataUpdate(obj.(*extensions.ThirdPartyResourceData), old.(*extensions.ThirdPartyResourceData)) -} - -func (strategy) AllowUnconditionalUpdate() bool { - return true -} - -// GetAttrs returns labels and fields of a given object for filtering purposes. -func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, bool, error) { - tprd, ok := obj.(*extensions.ThirdPartyResourceData) - if !ok { - return nil, nil, false, fmt.Errorf("not a ThirdPartyResourceData") - } - return labels.Set(tprd.Labels), SelectableFields(tprd), tprd.Initializers != nil, nil -} - -// Matcher returns a generic matcher for a given label and field selector. -func Matcher(label labels.Selector, field fields.Selector) apistorage.SelectionPredicate { - return apistorage.SelectionPredicate{ - Label: label, - Field: field, - GetAttrs: GetAttrs, - } -} - -// SelectableFields returns a field set that can be used for filter selection -func SelectableFields(obj *extensions.ThirdPartyResourceData) fields.Set { - return nil -} diff --git a/pkg/registry/extensions/thirdpartyresourcedata/strategy_test.go b/pkg/registry/extensions/thirdpartyresourcedata/strategy_test.go deleted file mode 100644 index 52079c0bb0e..00000000000 --- a/pkg/registry/extensions/thirdpartyresourcedata/strategy_test.go +++ /dev/null @@ -1,35 +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 thirdpartyresourcedata - -import ( - "testing" - - _ "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/testapi" - apitesting "k8s.io/kubernetes/pkg/api/testing" - "k8s.io/kubernetes/pkg/apis/extensions" -) - -func TestSelectableFieldLabelConversions(t *testing.T) { - apitesting.TestSelectableFieldLabelConversionsOfKind(t, - testapi.Extensions.GroupVersion().String(), - "ThirdPartyResourceData", - SelectableFields(&extensions.ThirdPartyResourceData{}), - nil, - ) -} diff --git a/pkg/registry/extensions/thirdpartyresourcedata/util.go b/pkg/registry/extensions/thirdpartyresourcedata/util.go deleted file mode 100644 index 294760e5bf5..00000000000 --- a/pkg/registry/extensions/thirdpartyresourcedata/util.go +++ /dev/null @@ -1,68 +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 thirdpartyresourcedata - -import ( - "fmt" - "strings" - - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/kubernetes/pkg/apis/extensions" -) - -func ExtractGroupVersionKind(list *extensions.ThirdPartyResourceList) ([]schema.GroupVersion, []schema.GroupVersionKind, error) { - gvs := []schema.GroupVersion{} - gvks := []schema.GroupVersionKind{} - for ix := range list.Items { - rsrc := &list.Items[ix] - kind, group, err := ExtractApiGroupAndKind(rsrc) - if err != nil { - return nil, nil, err - } - for _, version := range rsrc.Versions { - gv := schema.GroupVersion{Group: group, Version: version.Name} - gvs = append(gvs, gv) - gvks = append(gvks, schema.GroupVersionKind{Group: group, Version: version.Name, Kind: kind}) - } - } - return gvs, gvks, nil -} - -func convertToCamelCase(input string) string { - result := "" - toUpper := true - for ix := range input { - char := input[ix] - if toUpper { - result = result + string([]byte{(char - 32)}) - toUpper = false - } else if char == '-' { - toUpper = true - } else { - result = result + string([]byte{char}) - } - } - return result -} - -func ExtractApiGroupAndKind(rsrc *extensions.ThirdPartyResource) (kind string, group string, err error) { - parts := strings.Split(rsrc.Name, ".") - if len(parts) < 3 { - return "", "", fmt.Errorf("unexpectedly short resource name: %s, expected at least ..", rsrc.Name) - } - return convertToCamelCase(parts[0]), strings.Join(parts[1:], "."), nil -} diff --git a/pkg/registry/extensions/thirdpartyresourcedata/util_test.go b/pkg/registry/extensions/thirdpartyresourcedata/util_test.go deleted file mode 100644 index 025cb55f80c..00000000000 --- a/pkg/registry/extensions/thirdpartyresourcedata/util_test.go +++ /dev/null @@ -1,66 +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 thirdpartyresourcedata - -import ( - "testing" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/kubernetes/pkg/apis/extensions" -) - -func TestExtractAPIGroupAndKind(t *testing.T) { - tests := []struct { - input string - expectedKind string - expectedGroup string - expectErr bool - }{ - { - input: "foo.company.com", - expectedKind: "Foo", - expectedGroup: "company.com", - }, - { - input: "cron-tab.company.com", - expectedKind: "CronTab", - expectedGroup: "company.com", - }, - { - input: "foo", - expectErr: true, - }, - } - - for _, test := range tests { - kind, group, err := ExtractApiGroupAndKind(&extensions.ThirdPartyResource{ObjectMeta: metav1.ObjectMeta{Name: test.input}}) - if err != nil && !test.expectErr { - t.Errorf("unexpected error: %v", err) - continue - } - if err == nil && test.expectErr { - t.Errorf("unexpected non-error") - continue - } - if kind != test.expectedKind { - t.Errorf("expected: %s, saw: %s", test.expectedKind, kind) - } - if group != test.expectedGroup { - t.Errorf("expected: %s, saw: %s", test.expectedGroup, group) - } - } -}