Merge pull request #42225 from nikhiljindal/DisableAlphaAPIs

Automatic merge from submit-queue (batch tested with PRs 44019, 42225)

federation: Fixing runtime-config support for federation-apiserver

Fixes https://github.com/kubernetes/kubernetes/issues/42587
Ref https://github.com/kubernetes/kubernetes/issues/38593

Fixing the broken `--runtime-config` flag support in federation-apiserver. Fixing the bugs and using it to disable batch and autoscaling groups. Users can enable them by passing `--runtime-config=apis/all=true` to federation-apiserver.
~This also includes a bug fix to kube-apiserver registry that allows users to disable api/v1 resources~

cc @kubernetes/sig-federation-pr-reviews
pull/6/head
Kubernetes Submit Queue 2017-04-10 00:49:15 -07:00 committed by GitHub
commit e18843d353
10 changed files with 305 additions and 91 deletions

View File

@ -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",

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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
}

View File

@ -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{

View File

@ -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")

View File

@ -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)