diff --git a/federation/cmd/federation-apiserver/app/BUILD b/federation/cmd/federation-apiserver/app/BUILD index b95951d13d3..b3200f956db 100644 --- a/federation/cmd/federation-apiserver/app/BUILD +++ b/federation/cmd/federation-apiserver/app/BUILD @@ -15,6 +15,7 @@ go_library( "core.go", "extensions.go", "federation.go", + "install.go", "plugins.go", "server.go", ], @@ -25,16 +26,21 @@ go_library( "//federation/apis/core/v1:go_default_library", "//federation/apis/federation:go_default_library", "//federation/apis/federation/install:go_default_library", + "//federation/apis/federation/v1beta1:go_default_library", "//federation/cmd/federation-apiserver/app/options:go_default_library", "//federation/registry/cluster/etcd:go_default_library", "//pkg/api:go_default_library", "//pkg/api/install:go_default_library", + "//pkg/api/v1:go_default_library", "//pkg/apis/autoscaling:go_default_library", "//pkg/apis/autoscaling/install:go_default_library", + "//pkg/apis/autoscaling/v1:go_default_library", "//pkg/apis/batch:go_default_library", "//pkg/apis/batch/install:go_default_library", + "//pkg/apis/batch/v1:go_default_library", "//pkg/apis/extensions:go_default_library", "//pkg/apis/extensions/install:go_default_library", + "//pkg/apis/extensions/v1beta1:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/informers/informers_generated/internalversion:go_default_library", "//pkg/cloudprovider/providers:go_default_library", diff --git a/federation/cmd/federation-apiserver/app/autoscaling.go b/federation/cmd/federation-apiserver/app/autoscaling.go index 6d91fd8ff50..ed147f830bb 100644 --- a/federation/cmd/federation-apiserver/app/autoscaling.go +++ b/federation/cmd/federation-apiserver/app/autoscaling.go @@ -21,24 +21,34 @@ import ( "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" genericapiserver "k8s.io/apiserver/pkg/server" + "k8s.io/apiserver/pkg/server/storage" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/apis/autoscaling" _ "k8s.io/kubernetes/pkg/apis/autoscaling/install" + autoscalingv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1" hpastorage "k8s.io/kubernetes/pkg/registry/autoscaling/horizontalpodautoscaler/storage" ) -func installAutoscalingAPIs(g *genericapiserver.GenericAPIServer, optsGetter generic.RESTOptionsGetter) { - hpaStorage, hpaStatusStorage := hpastorage.NewREST(optsGetter) - - autoscalingResources := map[string]rest.Storage{ - "horizontalpodautoscalers": hpaStorage, - "horizontalpodautoscalers/status": hpaStatusStorage, +func installAutoscalingAPIs(g *genericapiserver.GenericAPIServer, optsGetter generic.RESTOptionsGetter, apiResourceConfigSource storage.APIResourceConfigSource) { + hpaStorageFn := func() map[string]rest.Storage { + hpaStorage, hpaStatusStorage := hpastorage.NewREST(optsGetter) + return map[string]rest.Storage{ + "horizontalpodautoscalers": hpaStorage, + "horizontalpodautoscalers/status": hpaStatusStorage, + } + } + resourcesStorageMap := map[string]getResourcesStorageFunc{ + "horizontalpodautoscalers": hpaStorageFn, + } + shouldInstallGroup, resources := enabledResources(autoscalingv1.SchemeGroupVersion, resourcesStorageMap, apiResourceConfigSource) + if !shouldInstallGroup { + return } autoscalingGroupMeta := api.Registry.GroupOrDie(autoscaling.GroupName) apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *autoscalingGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ - "v1": autoscalingResources, + "v1": resources, }, OptionsExternalVersion: &api.Registry.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, diff --git a/federation/cmd/federation-apiserver/app/batch.go b/federation/cmd/federation-apiserver/app/batch.go index e9d1f6acc56..5076ca023df 100644 --- a/federation/cmd/federation-apiserver/app/batch.go +++ b/federation/cmd/federation-apiserver/app/batch.go @@ -21,24 +21,34 @@ import ( "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" genericapiserver "k8s.io/apiserver/pkg/server" + "k8s.io/apiserver/pkg/server/storage" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/apis/batch" _ "k8s.io/kubernetes/pkg/apis/batch/install" + batchv1 "k8s.io/kubernetes/pkg/apis/batch/v1" jobstorage "k8s.io/kubernetes/pkg/registry/batch/job/storage" ) -func installBatchAPIs(g *genericapiserver.GenericAPIServer, optsGetter generic.RESTOptionsGetter) { - jobStorage := jobstorage.NewStorage(optsGetter) - - batchResources := map[string]rest.Storage{ - "jobs": jobStorage.Job, - "jobs/status": jobStorage.Status, +func installBatchAPIs(g *genericapiserver.GenericAPIServer, optsGetter generic.RESTOptionsGetter, apiResourceConfigSource storage.APIResourceConfigSource) { + jobsStorageFn := func() map[string]rest.Storage { + jobStorage := jobstorage.NewStorage(optsGetter) + return map[string]rest.Storage{ + "jobs": jobStorage.Job, + "jobs/status": jobStorage.Status, + } + } + resourcesStorageMap := map[string]getResourcesStorageFunc{ + "jobs": jobsStorageFn, + } + shouldInstallGroup, resources := enabledResources(batchv1.SchemeGroupVersion, resourcesStorageMap, apiResourceConfigSource) + if !shouldInstallGroup { + return } batchGroupMeta := api.Registry.GroupOrDie(batch.GroupName) apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *batchGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ - "v1": batchResources, + "v1": resources, }, OptionsExternalVersion: &api.Registry.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, diff --git a/federation/cmd/federation-apiserver/app/core.go b/federation/cmd/federation-apiserver/app/core.go index 9fa60baf67f..6282530f8a6 100644 --- a/federation/cmd/federation-apiserver/app/core.go +++ b/federation/cmd/federation-apiserver/app/core.go @@ -29,9 +29,10 @@ import ( "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" genericapiserver "k8s.io/apiserver/pkg/server" + "k8s.io/apiserver/pkg/server/storage" "k8s.io/kubernetes/federation/apis/core" _ "k8s.io/kubernetes/federation/apis/core/install" - "k8s.io/kubernetes/federation/apis/core/v1" + corev1 "k8s.io/kubernetes/federation/apis/core/v1" "k8s.io/kubernetes/federation/cmd/federation-apiserver/app/options" "k8s.io/kubernetes/pkg/api" configmapstore "k8s.io/kubernetes/pkg/registry/core/configmap/storage" @@ -41,28 +42,56 @@ import ( servicestore "k8s.io/kubernetes/pkg/registry/core/service/storage" ) -func installCoreAPIs(s *options.ServerRunOptions, g *genericapiserver.GenericAPIServer, optsGetter generic.RESTOptionsGetter) { - serviceStore, serviceStatusStore := servicestore.NewREST(optsGetter) - namespaceStore, namespaceStatusStore, namespaceFinalizeStore := namespacestore.NewREST(optsGetter) - secretStore := secretstore.NewREST(optsGetter) - configMapStore := configmapstore.NewREST(optsGetter) - eventStore := eventstore.NewREST(optsGetter, uint64(s.EventTTL.Seconds())) - - coreResources := map[string]rest.Storage{ - "secrets": secretStore, - "services": serviceStore, - "services/status": serviceStatusStore, - "namespaces": namespaceStore, - "namespaces/status": namespaceStatusStore, - "namespaces/finalize": namespaceFinalizeStore, - "events": eventStore, - "configmaps": configMapStore, +func installCoreAPIs(s *options.ServerRunOptions, g *genericapiserver.GenericAPIServer, optsGetter generic.RESTOptionsGetter, apiResourceConfigSource storage.APIResourceConfigSource) { + servicesStorageFn := func() map[string]rest.Storage { + serviceStore, serviceStatusStore := servicestore.NewREST(optsGetter) + return map[string]rest.Storage{ + "services": serviceStore, + "services/status": serviceStatusStore, + } + } + namespacesStorageFn := func() map[string]rest.Storage { + namespaceStore, namespaceStatusStore, namespaceFinalizeStore := namespacestore.NewREST(optsGetter) + return map[string]rest.Storage{ + "namespaces": namespaceStore, + "namespaces/status": namespaceStatusStore, + "namespaces/finalize": namespaceFinalizeStore, + } + } + secretsStorageFn := func() map[string]rest.Storage { + secretStore := secretstore.NewREST(optsGetter) + return map[string]rest.Storage{ + "secrets": secretStore, + } + } + configmapsStorageFn := func() map[string]rest.Storage { + configMapStore := configmapstore.NewREST(optsGetter) + return map[string]rest.Storage{ + "configmaps": configMapStore, + } + } + eventsStorageFn := func() map[string]rest.Storage { + eventStore := eventstore.NewREST(optsGetter, uint64(s.EventTTL.Seconds())) + return map[string]rest.Storage{ + "events": eventStore, + } + } + resourcesStorageMap := map[string]getResourcesStorageFunc{ + "services": servicesStorageFn, + "namespaces": namespacesStorageFn, + "secrets": secretsStorageFn, + "configmaps": configmapsStorageFn, + "events": eventsStorageFn, + } + shouldInstallGroup, resources := enabledResources(corev1.SchemeGroupVersion, resourcesStorageMap, apiResourceConfigSource) + if !shouldInstallGroup { + return } coreGroupMeta := api.Registry.GroupOrDie(core.GroupName) apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *coreGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ - v1.SchemeGroupVersion.Version: coreResources, + corev1.SchemeGroupVersion.Version: resources, }, OptionsExternalVersion: &api.Registry.GroupOrDie(core.GroupName).GroupVersion, Scheme: core.Scheme, diff --git a/federation/cmd/federation-apiserver/app/extensions.go b/federation/cmd/federation-apiserver/app/extensions.go index 876c8f6b800..292979ae50b 100644 --- a/federation/cmd/federation-apiserver/app/extensions.go +++ b/federation/cmd/federation-apiserver/app/extensions.go @@ -21,39 +21,64 @@ import ( "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" genericapiserver "k8s.io/apiserver/pkg/server" + "k8s.io/apiserver/pkg/server/storage" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/apis/extensions" _ "k8s.io/kubernetes/pkg/apis/extensions/install" + extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" daemonsetstore "k8s.io/kubernetes/pkg/registry/extensions/daemonset/storage" deploymentstore "k8s.io/kubernetes/pkg/registry/extensions/deployment/storage" ingressstore "k8s.io/kubernetes/pkg/registry/extensions/ingress/storage" replicasetstore "k8s.io/kubernetes/pkg/registry/extensions/replicaset/storage" ) -func installExtensionsAPIs(g *genericapiserver.GenericAPIServer, optsGetter generic.RESTOptionsGetter) { - replicaSetStorage := replicasetstore.NewStorage(optsGetter) - deploymentStorage := deploymentstore.NewStorage(optsGetter) - ingressStorage, ingressStatusStorage := ingressstore.NewREST(optsGetter) - daemonSetStorage, daemonSetStatusStorage := daemonsetstore.NewREST(optsGetter) - - extensionsResources := map[string]rest.Storage{ - "replicasets": replicaSetStorage.ReplicaSet, - "replicasets/status": replicaSetStorage.Status, - "replicasets/scale": replicaSetStorage.Scale, - "ingresses": ingressStorage, - "ingresses/status": ingressStatusStorage, - "daemonsets": daemonSetStorage, - "daemonsets/status": daemonSetStatusStorage, - "deployments": deploymentStorage.Deployment, - "deployments/status": deploymentStorage.Status, - "deployments/scale": deploymentStorage.Scale, - "deployments/rollback": deploymentStorage.Rollback, +func installExtensionsAPIs(g *genericapiserver.GenericAPIServer, optsGetter generic.RESTOptionsGetter, apiResourceConfigSource storage.APIResourceConfigSource) { + replicasetsStorageFn := func() map[string]rest.Storage { + replicaSetStorage := replicasetstore.NewStorage(optsGetter) + return map[string]rest.Storage{ + "replicasets": replicaSetStorage.ReplicaSet, + "replicasets/status": replicaSetStorage.Status, + "replicasets/scale": replicaSetStorage.Scale, + } + } + deploymentsStorageFn := func() map[string]rest.Storage { + deploymentStorage := deploymentstore.NewStorage(optsGetter) + return map[string]rest.Storage{ + "deployments": deploymentStorage.Deployment, + "deployments/status": deploymentStorage.Status, + "deployments/scale": deploymentStorage.Scale, + "deployments/rollback": deploymentStorage.Rollback, + } + } + ingressesStorageFn := func() map[string]rest.Storage { + ingressStorage, ingressStatusStorage := ingressstore.NewREST(optsGetter) + return map[string]rest.Storage{ + "ingresses": ingressStorage, + "ingresses/status": ingressStatusStorage, + } + } + daemonsetsStorageFn := func() map[string]rest.Storage { + daemonSetStorage, daemonSetStatusStorage := daemonsetstore.NewREST(optsGetter) + return map[string]rest.Storage{ + "daemonsets": daemonSetStorage, + "daemonsets/status": daemonSetStatusStorage, + } + } + resourcesStorageMap := map[string]getResourcesStorageFunc{ + "replicasets": replicasetsStorageFn, + "deployments": deploymentsStorageFn, + "ingresses": ingressesStorageFn, + "daemonsets": daemonsetsStorageFn, + } + shouldInstallGroup, resources := enabledResources(extensionsv1beta1.SchemeGroupVersion, resourcesStorageMap, apiResourceConfigSource) + if !shouldInstallGroup { + return } extensionsGroupMeta := api.Registry.GroupOrDie(extensions.GroupName) apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *extensionsGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ - "v1beta1": extensionsResources, + "v1beta1": resources, }, OptionsExternalVersion: &api.Registry.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, diff --git a/federation/cmd/federation-apiserver/app/federation.go b/federation/cmd/federation-apiserver/app/federation.go index 38ed7ead593..4870ce5fe41 100644 --- a/federation/cmd/federation-apiserver/app/federation.go +++ b/federation/cmd/federation-apiserver/app/federation.go @@ -22,24 +22,35 @@ import ( "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" genericapiserver "k8s.io/apiserver/pkg/server" + "k8s.io/apiserver/pkg/server/storage" "k8s.io/kubernetes/federation/apis/federation" - "k8s.io/kubernetes/pkg/api" - _ "k8s.io/kubernetes/federation/apis/federation/install" + fedv1beta1 "k8s.io/kubernetes/federation/apis/federation/v1beta1" clusteretcd "k8s.io/kubernetes/federation/registry/cluster/etcd" + "k8s.io/kubernetes/pkg/api" ) -func installFederationAPIs(g *genericapiserver.GenericAPIServer, optsGetter generic.RESTOptionsGetter) { - clusterStorage, clusterStatusStorage := clusteretcd.NewREST(optsGetter) - federationResources := map[string]rest.Storage{ - "clusters": clusterStorage, - "clusters/status": clusterStatusStorage, +func installFederationAPIs(g *genericapiserver.GenericAPIServer, optsGetter generic.RESTOptionsGetter, apiResourceConfigSource storage.APIResourceConfigSource) { + groupName := federation.GroupName + clustersStorageFn := func() map[string]rest.Storage { + clusterStorage, clusterStatusStorage := clusteretcd.NewREST(optsGetter) + return map[string]rest.Storage{ + "clusters": clusterStorage, + "clusters/status": clusterStatusStorage, + } } - federationGroupMeta := api.Registry.GroupOrDie(federation.GroupName) + resourcesStorageMap := map[string]getResourcesStorageFunc{ + "clusters": clustersStorageFn, + } + shouldInstallGroup, resources := enabledResources(fedv1beta1.SchemeGroupVersion, resourcesStorageMap, apiResourceConfigSource) + if !shouldInstallGroup { + return + } + federationGroupMeta := api.Registry.GroupOrDie(groupName) apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *federationGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ - "v1beta1": federationResources, + "v1beta1": resources, }, OptionsExternalVersion: &api.Registry.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, diff --git a/federation/cmd/federation-apiserver/app/install.go b/federation/cmd/federation-apiserver/app/install.go new file mode 100644 index 00000000000..4e75a2df1a4 --- /dev/null +++ b/federation/cmd/federation-apiserver/app/install.go @@ -0,0 +1,55 @@ +/* +Copyright 2017 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 app + +import ( + "github.com/golang/glog" + + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/apiserver/pkg/server/storage" +) + +// Function to get a map of resources and the corresponding storages. +type getResourcesStorageFunc func() map[string]rest.Storage + +// Filters the resources from the given resources storage map to those that are enabled in the given apiResourceConfigSource. +// resourcesStorageMap is expected to contain all resources in a group version. +// Returns false if none of the resources are enabled and hence the whole group version should be disabled. +func enabledResources(groupVersion schema.GroupVersion, resourcesStorageMap map[string]getResourcesStorageFunc, apiResourceConfigSource storage.APIResourceConfigSource) (bool, map[string]rest.Storage) { + enabledResources := map[string]rest.Storage{} + groupName := groupVersion.Group + if !apiResourceConfigSource.AnyResourcesForGroupEnabled(groupName) { + glog.V(1).Infof("Skipping disabled API group %q", groupName) + return false, enabledResources + } + for resource, fn := range resourcesStorageMap { + if apiResourceConfigSource.ResourceEnabled(groupVersion.WithResource(resource)) { + resources := fn() + for k, v := range resources { + enabledResources[k] = v + } + } else { + glog.V(1).Infof("Skipping disabled resource %s in API group %q", resource, groupName) + } + } + if len(enabledResources) == 0 { + glog.V(1).Infof("Skipping API group %q since there is no enabled resource", groupName) + return false, enabledResources + } + return true, enabledResources +} diff --git a/federation/cmd/federation-apiserver/app/server.go b/federation/cmd/federation-apiserver/app/server.go index 0af1beff323..be6e37502c5 100644 --- a/federation/cmd/federation-apiserver/app/server.go +++ b/federation/cmd/federation-apiserver/app/server.go @@ -38,8 +38,11 @@ import ( genericapiserver "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server/filters" serverstorage "k8s.io/apiserver/pkg/server/storage" + federationv1beta1 "k8s.io/kubernetes/federation/apis/federation/v1beta1" "k8s.io/kubernetes/federation/cmd/federation-apiserver/app/options" "k8s.io/kubernetes/pkg/api" + apiv1 "k8s.io/kubernetes/pkg/api/v1" + extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion" "k8s.io/kubernetes/pkg/generated/openapi" @@ -124,8 +127,7 @@ func NonBlockingRun(s *options.ServerRunOptions, stopCh <-chan struct{}) error { return err } - // TODO: register cluster federation resources here. - resourceConfig := serverstorage.NewResourceConfig() + resourceConfig := defaultResourceConfig() if s.Etcd.StorageConfig.DeserializationCacheSize == 0 { // When size of cache is not explicitly set, set it to 50000 @@ -230,13 +232,12 @@ func NonBlockingRun(s *options.ServerRunOptions, stopCh <-chan struct{}) error { routes.UIRedirect{}.Install(m.FallThroughHandler) routes.Logs{}.Install(m.HandlerContainer) - installFederationAPIs(m, genericConfig.RESTOptionsGetter) - installCoreAPIs(s, m, genericConfig.RESTOptionsGetter) - installExtensionsAPIs(m, genericConfig.RESTOptionsGetter) - // Disable half-baked APIs for 1.6. - // TODO: Uncomment this once 1.6 is released. - // installBatchAPIs(m, genericConfig.RESTOptionsGetter) - // installAutoscalingAPIs(m, genericConfig.RESTOptionsGetter) + apiResourceConfigSource := storageFactory.APIResourceConfigSource + installFederationAPIs(m, genericConfig.RESTOptionsGetter, apiResourceConfigSource) + installCoreAPIs(s, m, genericConfig.RESTOptionsGetter, apiResourceConfigSource) + installExtensionsAPIs(m, genericConfig.RESTOptionsGetter, apiResourceConfigSource) + installBatchAPIs(m, genericConfig.RESTOptionsGetter, apiResourceConfigSource) + installAutoscalingAPIs(m, genericConfig.RESTOptionsGetter, apiResourceConfigSource) // run the insecure server now if insecureServingOptions != nil { @@ -253,6 +254,31 @@ func NonBlockingRun(s *options.ServerRunOptions, stopCh <-chan struct{}) error { return err } +func defaultResourceConfig() *serverstorage.ResourceConfig { + rc := serverstorage.NewResourceConfig() + + rc.EnableVersions( + federationv1beta1.SchemeGroupVersion, + ) + + // All core resources except these are disabled by default. + rc.EnableResources( + apiv1.SchemeGroupVersion.WithResource("secrets"), + apiv1.SchemeGroupVersion.WithResource("services"), + apiv1.SchemeGroupVersion.WithResource("namespaces"), + apiv1.SchemeGroupVersion.WithResource("events"), + apiv1.SchemeGroupVersion.WithResource("configmaps"), + ) + // All extension resources except these are disabled by default. + rc.EnableResources( + extensionsapiv1beta1.SchemeGroupVersion.WithResource("daemonsets"), + extensionsapiv1beta1.SchemeGroupVersion.WithResource("deployments"), + extensionsapiv1beta1.SchemeGroupVersion.WithResource("ingresses"), + extensionsapiv1beta1.SchemeGroupVersion.WithResource("replicasets"), + ) + return rc +} + // PostProcessSpec adds removed definitions for backward compatibility func postProcessOpenAPISpecForBackwardCompatibility(s *spec.Swagger) (*spec.Swagger, error) { compatibilityMap := map[string]string{ diff --git a/test/integration/federation/api_test.go b/test/integration/federation/api_test.go index 4db1871a911..5804aa9d2f6 100644 --- a/test/integration/federation/api_test.go +++ b/test/integration/federation/api_test.go @@ -35,18 +35,29 @@ import ( "k8s.io/kubernetes/test/integration/federation/framework" ) -var groupVersions = []schema.GroupVersion{ +// List of group versions that are enabled by default. +var enabledGroupVersions = []schema.GroupVersion{ fed_v1b1.SchemeGroupVersion, ext_v1b1.SchemeGroupVersion, - // batch_v1.SchemeGroupVersion, - // autoscaling_v1.SchemeGroupVersion, } -type apiTestFunc func(t *testing.T, host string) +// List of group versions that are disabled by default. +var disabledGroupVersions = []schema.GroupVersion{ + batch_v1.SchemeGroupVersion, + autoscaling_v1.SchemeGroupVersion, +} -func TestFederationAPI(t *testing.T) { +type apiTestFunc func(t *testing.T, host string, expectedGroupVersions []schema.GroupVersion) + +func testFederationAPI(t *testing.T, runtimeConfig string, expectedGroupVersions []schema.GroupVersion) { f := &framework.FederationAPIFixture{} - f.SetUp(t) + if runtimeConfig == "" { + f.SetUp(t) + } else { + runOptions := framework.GetRunOptions() + runOptions.APIEnablement.RuntimeConfig.Set(runtimeConfig) + f.SetUpWithRunOptions(t, runOptions) + } defer f.TearDown(t) testCases := map[string]apiTestFunc{ @@ -58,11 +69,23 @@ func TestFederationAPI(t *testing.T) { } for testName, testFunc := range testCases { t.Run(testName, func(t *testing.T) { - testFunc(t, f.Host) + testFunc(t, f.Host, expectedGroupVersions) }) } } +// Verifies that only default APIs are enabled when no runtime config is set. +func TestDefaultRun(t *testing.T) { + testFederationAPI(t, "", enabledGroupVersions) +} + +// Verifies that all APIs are enabled when runtime config is set to all. +func TestRunWithRuntimeConfigAll(t *testing.T) { + expectedGroupVersions := enabledGroupVersions + expectedGroupVersions = append(enabledGroupVersions, disabledGroupVersions...) + testFederationAPI(t, "api/all=true", expectedGroupVersions) +} + func readResponse(serverURL string) ([]byte, error) { response, err := http.Get(serverURL) if err != nil { @@ -79,7 +102,7 @@ func readResponse(serverURL string) ([]byte, error) { return contents, nil } -func testSwaggerSpec(t *testing.T, host string) { +func testSwaggerSpec(t *testing.T, host string, expectedGroupVersions []schema.GroupVersion) { serverURL := host + "/swaggerapi" _, err := readResponse(serverURL) if err != nil { @@ -87,7 +110,7 @@ func testSwaggerSpec(t *testing.T, host string) { } } -func testSupport(t *testing.T, host string) { +func testSupport(t *testing.T, host string, expectedGroupVersions []schema.GroupVersion) { serverURL := host + "/version" _, err := readResponse(serverURL) if err != nil { @@ -104,9 +127,9 @@ func findGroup(groups []metav1.APIGroup, groupName string) *metav1.APIGroup { return nil } -func testAPIGroupList(t *testing.T, host string) { +func testAPIGroupList(t *testing.T, host string, expectedGroupVersions []schema.GroupVersion) { groupVersionForDiscoveryMap := make(map[string]metav1.GroupVersionForDiscovery) - for _, groupVersion := range groupVersions { + for _, groupVersion := range expectedGroupVersions { groupVersionForDiscoveryMap[groupVersion.Group] = metav1.GroupVersionForDiscovery{ GroupVersion: groupVersion.String(), Version: groupVersion.Version, @@ -124,7 +147,8 @@ func testAPIGroupList(t *testing.T, host string) { t.Fatalf("Error in unmarshalling response from server %s: %v", serverURL, err) } - for _, groupVersion := range groupVersions { + assert.Equal(t, len(apiGroupList.Groups), len(expectedGroupVersions), "expected: %v, actual: %v", expectedGroupVersions, apiGroupList.Groups) + for _, groupVersion := range expectedGroupVersions { found := findGroup(apiGroupList.Groups, groupVersion.Group) assert.NotNil(t, found) assert.Equal(t, groupVersion.Group, found.Name) @@ -135,8 +159,8 @@ func testAPIGroupList(t *testing.T, host string) { } } -func testAPIGroup(t *testing.T, host string) { - for _, groupVersion := range groupVersions { +func testAPIGroup(t *testing.T, host string, expectedGroupVersions []schema.GroupVersion) { + for _, groupVersion := range expectedGroupVersions { serverURL := host + "/apis/" + groupVersion.Group contents, err := readResponse(serverURL) if err != nil { @@ -188,12 +212,25 @@ func findResource(resources []metav1.APIResource, resourceName string) *metav1.A return nil } -func testAPIResourceList(t *testing.T, host string) { +func testAPIResourceList(t *testing.T, host string, expectedGroupVersions []schema.GroupVersion) { testFederationResourceList(t, host) testCoreResourceList(t, host) testExtensionsResourceList(t, host) - // testBatchResourceList(t, host) - // testAutoscalingResourceList(t, host) + if contains(expectedGroupVersions, batch_v1.SchemeGroupVersion) { + testBatchResourceList(t, host) + } + if contains(expectedGroupVersions, autoscaling_v1.SchemeGroupVersion) { + testAutoscalingResourceList(t, host) + } +} + +func contains(gvs []schema.GroupVersion, requiredGV schema.GroupVersion) bool { + for _, gv := range gvs { + if gv.String() == requiredGV.String() { + return true + } + } + return false } func testFederationResourceList(t *testing.T, host string) { @@ -233,8 +270,7 @@ func testCoreResourceList(t *testing.T, host string) { } assert.Equal(t, "", apiResourceList.APIVersion) assert.Equal(t, v1.SchemeGroupVersion.String(), apiResourceList.GroupVersion) - // Assert that there are exactly 7 resources. - assert.Equal(t, 8, len(apiResourceList.APIResources)) + assert.Equal(t, 8, len(apiResourceList.APIResources), "ResourceList: %v", apiResourceList.APIResources) // Verify services. found := findResource(apiResourceList.APIResources, "services") diff --git a/test/integration/federation/framework/api.go b/test/integration/federation/framework/api.go index 3f1dc6c9684..f12f2d8f26d 100644 --- a/test/integration/federation/framework/api.go +++ b/test/integration/federation/framework/api.go @@ -33,7 +33,8 @@ import ( const apiNoun = "federation apiserver" -func getRunOptions() *options.ServerRunOptions { +// GetRunOptions returns the default run options that can be used to run a test federation apiserver. +func GetRunOptions() *options.ServerRunOptions { r := options.NewServerRunOptions() r.Etcd.StorageConfig.ServerList = []string{framework.GetEtcdURLFromEnv()} // Use a unique prefix to ensure isolation from other tests using the same etcd instance @@ -49,7 +50,14 @@ type FederationAPIFixture struct { stopChan chan struct{} } +// SetUp runs federation apiserver with default run options. func (f *FederationAPIFixture) SetUp(t *testing.T) { + f.SetUpWithRunOptions(t, GetRunOptions()) +} + +// SetUpWithRunOptions runs federation apiserver with the given run options. +// Uses default run options if runOptions is nil. +func (f *FederationAPIFixture) SetUpWithRunOptions(t *testing.T, runOptions *options.ServerRunOptions) { if f.stopChan != nil { t.Fatal("SetUp() already called") } @@ -57,8 +65,6 @@ func (f *FederationAPIFixture) SetUp(t *testing.T) { f.stopChan = make(chan struct{}) - runOptions := getRunOptions() - err := startServer(t, runOptions, f.stopChan) if err != nil { t.Fatal(err)