Allow enabling/disabling specific extensions/v1beta1 resources

pull/564/head
Jordan Liggitt 2018-12-20 13:08:14 -05:00
parent 68451f301b
commit e016e132f5
6 changed files with 258 additions and 27 deletions

View File

@ -474,8 +474,6 @@ func DefaultAPIResourceConfigSource() *serverstorage.ResourceConfig {
ret.EnableVersions(
admissionregistrationv1beta1.SchemeGroupVersion,
apiv1.SchemeGroupVersion,
appsv1beta1.SchemeGroupVersion,
appsv1beta2.SchemeGroupVersion,
appsv1.SchemeGroupVersion,
authenticationv1.SchemeGroupVersion,
authenticationv1beta1.SchemeGroupVersion,
@ -499,6 +497,24 @@ func DefaultAPIResourceConfigSource() *serverstorage.ResourceConfig {
storageapiv1beta1.SchemeGroupVersion,
schedulingapiv1beta1.SchemeGroupVersion,
)
// enable non-deprecated beta resources in extensions/v1beta1 explicitly so we have a full list of what's possible to serve
ret.EnableResources(
extensionsapiv1beta1.SchemeGroupVersion.WithResource("ingresses"),
)
// enable deprecated beta resources in extensions/v1beta1 explicitly so we have a full list of what's possible to serve
ret.EnableResources(
extensionsapiv1beta1.SchemeGroupVersion.WithResource("daemonsets"),
extensionsapiv1beta1.SchemeGroupVersion.WithResource("deployments"),
extensionsapiv1beta1.SchemeGroupVersion.WithResource("networkpolicies"),
extensionsapiv1beta1.SchemeGroupVersion.WithResource("podsecuritypolicies"),
extensionsapiv1beta1.SchemeGroupVersion.WithResource("replicasets"),
extensionsapiv1beta1.SchemeGroupVersion.WithResource("replicationcontrollers"),
)
// enable deprecated beta versions explicitly so we have a full list of what's possible to serve
ret.EnableVersions(
appsv1beta1.SchemeGroupVersion,
appsv1beta2.SchemeGroupVersion,
)
// disable alpha versions explicitly so we have a full list of what's possible to serve
ret.DisableVersions(
auditregistrationv1alpha1.SchemeGroupVersion,

View File

@ -52,39 +52,53 @@ func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource serverstorag
// This is a dummy replication controller for scale subresource purposes.
// TODO: figure out how to enable this only if needed as a part of scale subresource GA.
controllerStorage := expcontrollerstore.NewStorage(restOptionsGetter)
storage["replicationcontrollers"] = controllerStorage.ReplicationController
storage["replicationcontrollers/scale"] = controllerStorage.Scale
if apiResourceConfigSource.ResourceEnabled(extensionsapiv1beta1.SchemeGroupVersion.WithResource("replicationcontrollers")) {
controllerStorage := expcontrollerstore.NewStorage(restOptionsGetter)
storage["replicationcontrollers"] = controllerStorage.ReplicationController
storage["replicationcontrollers/scale"] = controllerStorage.Scale
}
// daemonsets
daemonSetStorage, daemonSetStatusStorage := daemonstore.NewREST(restOptionsGetter)
storage["daemonsets"] = daemonSetStorage.WithCategories(nil)
storage["daemonsets/status"] = daemonSetStatusStorage
if apiResourceConfigSource.ResourceEnabled(extensionsapiv1beta1.SchemeGroupVersion.WithResource("daemonsets")) {
daemonSetStorage, daemonSetStatusStorage := daemonstore.NewREST(restOptionsGetter)
storage["daemonsets"] = daemonSetStorage.WithCategories(nil)
storage["daemonsets/status"] = daemonSetStatusStorage
}
//deployments
deploymentStorage := deploymentstore.NewStorage(restOptionsGetter)
storage["deployments"] = deploymentStorage.Deployment.WithCategories(nil)
storage["deployments/status"] = deploymentStorage.Status
storage["deployments/rollback"] = deploymentStorage.Rollback
storage["deployments/scale"] = deploymentStorage.Scale
if apiResourceConfigSource.ResourceEnabled(extensionsapiv1beta1.SchemeGroupVersion.WithResource("deployments")) {
deploymentStorage := deploymentstore.NewStorage(restOptionsGetter)
storage["deployments"] = deploymentStorage.Deployment.WithCategories(nil)
storage["deployments/status"] = deploymentStorage.Status
storage["deployments/rollback"] = deploymentStorage.Rollback
storage["deployments/scale"] = deploymentStorage.Scale
}
// ingresses
ingressStorage, ingressStatusStorage := ingressstore.NewREST(restOptionsGetter)
storage["ingresses"] = ingressStorage
storage["ingresses/status"] = ingressStatusStorage
if apiResourceConfigSource.ResourceEnabled(extensionsapiv1beta1.SchemeGroupVersion.WithResource("ingresses")) {
ingressStorage, ingressStatusStorage := ingressstore.NewREST(restOptionsGetter)
storage["ingresses"] = ingressStorage
storage["ingresses/status"] = ingressStatusStorage
}
// podsecuritypolicy
podSecurityPolicyStorage := pspstore.NewREST(restOptionsGetter)
storage["podSecurityPolicies"] = podSecurityPolicyStorage
if apiResourceConfigSource.ResourceEnabled(extensionsapiv1beta1.SchemeGroupVersion.WithResource("podsecuritypolicies")) {
podSecurityPolicyStorage := pspstore.NewREST(restOptionsGetter)
storage["podSecurityPolicies"] = podSecurityPolicyStorage
}
// replicasets
replicaSetStorage := replicasetstore.NewStorage(restOptionsGetter)
storage["replicasets"] = replicaSetStorage.ReplicaSet.WithCategories(nil)
storage["replicasets/status"] = replicaSetStorage.Status
storage["replicasets/scale"] = replicaSetStorage.Scale
if apiResourceConfigSource.ResourceEnabled(extensionsapiv1beta1.SchemeGroupVersion.WithResource("replicasets")) {
replicaSetStorage := replicasetstore.NewStorage(restOptionsGetter)
storage["replicasets"] = replicaSetStorage.ReplicaSet.WithCategories(nil)
storage["replicasets/status"] = replicaSetStorage.Status
storage["replicasets/scale"] = replicaSetStorage.Scale
}
// networkpolicies
networkExtensionsStorage := networkpolicystore.NewREST(restOptionsGetter)
storage["networkpolicies"] = networkExtensionsStorage
if apiResourceConfigSource.ResourceEnabled(extensionsapiv1beta1.SchemeGroupVersion.WithResource("networkpolicies")) {
networkExtensionsStorage := networkpolicystore.NewREST(restOptionsGetter)
storage["networkpolicies"] = networkExtensionsStorage
}
return storage
}

View File

@ -94,7 +94,7 @@ func MergeAPIResourceConfigs(
}
tokens := strings.Split(key, "/")
if len(tokens) != 2 {
if len(tokens) < 2 {
continue
}
groupVersionString := tokens[0] + "/" + tokens[1]
@ -103,6 +103,12 @@ func MergeAPIResourceConfigs(
return nil, fmt.Errorf("invalid key %s", key)
}
// individual resource enablement/disablement is only supported in the extensions/v1beta1 API group for legacy reasons.
// all other API groups are expected to contain coherent sets of resources that are enabled/disabled together.
if len(tokens) > 2 && (groupVersion != schema.GroupVersion{Group: "extensions", Version: "v1beta1"}) {
return nil, fmt.Errorf("invalid key %s, individual resource enablement/disablement is not supported in %s", key, groupVersion.String())
}
// Exclude group not registered into the registry.
if !registry.IsGroupRegistered(groupVersion.Group) {
continue
@ -117,10 +123,22 @@ func MergeAPIResourceConfigs(
return nil, err
}
if enabled {
// enable the groupVersion for "group/version=true" and "group/version/resource=true"
resourceConfig.EnableVersions(groupVersion)
} else {
} else if len(tokens) == 2 {
// disable the groupVersion only for "group/version=false", not "group/version/resource=false"
resourceConfig.DisableVersions(groupVersion)
}
if len(tokens) < 3 {
continue
}
groupVersionResource := groupVersion.WithResource(tokens[2])
if enabled {
resourceConfig.EnableResources(groupVersionResource)
} else {
resourceConfig.DisableResources(groupVersionResource)
}
}
return resourceConfig, nil

View File

@ -117,6 +117,11 @@ func TestParseRuntimeConfig(t *testing.T) {
expectedAPIConfig: func() *serverstore.ResourceConfig {
config := newFakeAPIResourceConfigSource()
config.EnableVersions(scheme.PrioritizedVersionsAllGroups()...)
config.EnableResources(
extensionsapiv1beta1.SchemeGroupVersion.WithResource("deployments"),
extensionsapiv1beta1.SchemeGroupVersion.WithResource("replicasets"),
extensionsapiv1beta1.SchemeGroupVersion.WithResource("daemonsets"),
)
return config
},
err: false,
@ -133,10 +138,71 @@ func TestParseRuntimeConfig(t *testing.T) {
expectedAPIConfig: func() *serverstore.ResourceConfig {
config := newFakeAPIResourceConfigSource()
config.DisableVersions(extensionsapiv1beta1.SchemeGroupVersion)
config.DisableResources(extensionsapiv1beta1.SchemeGroupVersion.WithResource("ingresses"))
return config
},
err: false,
},
{
// enable specific extensions resources
runtimeConfig: map[string]string{
"extensions/v1beta1/deployments": "true",
},
defaultResourceConfig: func() *serverstore.ResourceConfig {
return newFakeAPIResourceConfigSource()
},
expectedAPIConfig: func() *serverstore.ResourceConfig {
config := newFakeAPIResourceConfigSource()
config.EnableResources(extensionsapiv1beta1.SchemeGroupVersion.WithResource("deployments"))
return config
},
err: false,
},
{
// disable specific extensions resources
runtimeConfig: map[string]string{
"extensions/v1beta1/ingresses": "false",
},
defaultResourceConfig: func() *serverstore.ResourceConfig {
return newFakeAPIResourceConfigSource()
},
expectedAPIConfig: func() *serverstore.ResourceConfig {
config := newFakeAPIResourceConfigSource()
config.DisableResources(extensionsapiv1beta1.SchemeGroupVersion.WithResource("ingresses"))
return config
},
err: false,
},
{
// disable all extensions resources
runtimeConfig: map[string]string{
"extensions/v1beta1": "false",
},
defaultResourceConfig: func() *serverstore.ResourceConfig {
return newFakeAPIResourceConfigSource()
},
expectedAPIConfig: func() *serverstore.ResourceConfig {
config := newFakeAPIResourceConfigSource()
config.DisableVersions(extensionsapiv1beta1.SchemeGroupVersion)
return config
},
err: false,
},
{
// disable a non-extensions resource
runtimeConfig: map[string]string{
"apps/v1/deployments": "false",
},
defaultResourceConfig: func() *serverstore.ResourceConfig {
return newFakeAPIResourceConfigSource()
},
expectedAPIConfig: func() *serverstore.ResourceConfig {
config := newFakeAPIResourceConfigSource()
config.DisableVersions(extensionsapiv1beta1.SchemeGroupVersion)
return config
},
err: true,
},
}
for index, test := range testCases {
t.Log(scheme.PrioritizedVersionsAllGroups())
@ -161,6 +227,14 @@ func newFakeAPIResourceConfigSource() *serverstore.ResourceConfig {
apiv1.SchemeGroupVersion,
extensionsapiv1beta1.SchemeGroupVersion,
)
ret.EnableResources(
extensionsapiv1beta1.SchemeGroupVersion.WithResource("ingresses"),
)
ret.DisableResources(
extensionsapiv1beta1.SchemeGroupVersion.WithResource("deployments"),
extensionsapiv1beta1.SchemeGroupVersion.WithResource("replicasets"),
extensionsapiv1beta1.SchemeGroupVersion.WithResource("daemonsets"),
)
return ret
}

View File

@ -23,6 +23,7 @@ import (
// APIResourceConfigSource is the interface to determine which groups and versions are enabled
type APIResourceConfigSource interface {
VersionEnabled(version schema.GroupVersion) bool
ResourceEnabled(resource schema.GroupVersionResource) bool
AnyVersionForGroupEnabled(group string) bool
}
@ -30,22 +31,29 @@ var _ APIResourceConfigSource = &ResourceConfig{}
type ResourceConfig struct {
GroupVersionConfigs map[schema.GroupVersion]bool
ResourceConfigs map[schema.GroupVersionResource]bool
}
func NewResourceConfig() *ResourceConfig {
return &ResourceConfig{GroupVersionConfigs: map[schema.GroupVersion]bool{}}
return &ResourceConfig{GroupVersionConfigs: map[schema.GroupVersion]bool{}, ResourceConfigs: map[schema.GroupVersionResource]bool{}}
}
func (o *ResourceConfig) DisableAll() {
for k := range o.GroupVersionConfigs {
o.GroupVersionConfigs[k] = false
}
for k := range o.ResourceConfigs {
o.ResourceConfigs[k] = false
}
}
func (o *ResourceConfig) EnableAll() {
for k := range o.GroupVersionConfigs {
o.GroupVersionConfigs[k] = true
}
for k := range o.ResourceConfigs {
o.ResourceConfigs[k] = true
}
}
// DisableVersions disables the versions entirely.
@ -70,6 +78,29 @@ func (o *ResourceConfig) VersionEnabled(version schema.GroupVersion) bool {
return false
}
func (o *ResourceConfig) DisableResources(resources ...schema.GroupVersionResource) {
for _, resource := range resources {
o.ResourceConfigs[resource] = false
}
}
func (o *ResourceConfig) EnableResources(resources ...schema.GroupVersionResource) {
for _, resource := range resources {
o.ResourceConfigs[resource] = true
}
}
func (o *ResourceConfig) ResourceEnabled(resource schema.GroupVersionResource) bool {
if !o.VersionEnabled(resource.GroupVersion()) {
return false
}
resourceEnabled, explicitlySet := o.ResourceConfigs[resource]
if !explicitlySet {
return true
}
return resourceEnabled
}
func (o *ResourceConfig) AnyVersionForGroupEnabled(group string) bool {
for version := range o.GroupVersionConfigs {
if version.Group == group {

View File

@ -43,6 +43,84 @@ func TestDisabledVersion(t *testing.T) {
}
}
func TestDisabledResource(t *testing.T) {
g1v1 := schema.GroupVersion{Group: "group1", Version: "version1"}
g1v1rUnspecified := g1v1.WithResource("unspecified")
g1v1rEnabled := g1v1.WithResource("enabled")
g1v1rDisabled := g1v1.WithResource("disabled")
g1v2 := schema.GroupVersion{Group: "group1", Version: "version2"}
g1v2rUnspecified := g1v2.WithResource("unspecified")
g1v2rEnabled := g1v2.WithResource("enabled")
g1v2rDisabled := g1v2.WithResource("disabled")
g2v1 := schema.GroupVersion{Group: "group2", Version: "version1"}
g2v1rUnspecified := g2v1.WithResource("unspecified")
g2v1rEnabled := g2v1.WithResource("enabled")
g2v1rDisabled := g2v1.WithResource("disabled")
config := NewResourceConfig()
config.DisableVersions(g1v1)
config.EnableVersions(g1v2, g2v1)
config.EnableResources(g1v1rEnabled, g1v2rEnabled, g2v1rEnabled)
config.DisableResources(g1v1rDisabled, g1v2rDisabled, g2v1rDisabled)
// all resources under g1v1 are disabled because the group-version is disabled
if config.ResourceEnabled(g1v1rUnspecified) {
t.Errorf("expected disabled for %v, from %v", g1v1rUnspecified, config)
}
if config.ResourceEnabled(g1v1rEnabled) {
t.Errorf("expected disabled for %v, from %v", g1v1rEnabled, config)
}
if config.ResourceEnabled(g1v1rDisabled) {
t.Errorf("expected disabled for %v, from %v", g1v1rDisabled, config)
}
// explicitly disabled resources in enabled group-versions are disabled
if config.ResourceEnabled(g1v2rDisabled) {
t.Errorf("expected disabled for %v, from %v", g1v2rDisabled, config)
}
if config.ResourceEnabled(g2v1rDisabled) {
t.Errorf("expected disabled for %v, from %v", g2v1rDisabled, config)
}
// unspecified and explicitly enabled resources in enabled group-versions are enabled
if !config.ResourceEnabled(g1v2rUnspecified) {
t.Errorf("expected enabled for %v, from %v", g1v2rUnspecified, config)
}
if !config.ResourceEnabled(g1v2rEnabled) {
t.Errorf("expected enabled for %v, from %v", g1v2rEnabled, config)
}
if !config.ResourceEnabled(g2v1rUnspecified) {
t.Errorf("expected enabled for %v, from %v", g2v1rUnspecified, config)
}
if !config.ResourceEnabled(g2v1rEnabled) {
t.Errorf("expected enabled for %v, from %v", g2v1rEnabled, config)
}
// Enable all enables specific resources
config.EnableAll()
// all resources under g1v1 are now enabled
if !config.ResourceEnabled(g1v1rUnspecified) {
t.Errorf("expected enabled for %v, from %v", g1v1rUnspecified, config)
}
if !config.ResourceEnabled(g1v1rEnabled) {
t.Errorf("expected enabled for %v, from %v", g1v1rEnabled, config)
}
if !config.ResourceEnabled(g1v1rDisabled) {
t.Errorf("expected enabled for %v, from %v", g1v1rDisabled, config)
}
// previously disabled resources are now enabled
if !config.ResourceEnabled(g1v2rDisabled) {
t.Errorf("expected enabled for %v, from %v", g1v2rDisabled, config)
}
if !config.ResourceEnabled(g2v1rDisabled) {
t.Errorf("expected enabled for %v, from %v", g2v1rDisabled, config)
}
}
func TestAnyVersionForGroupEnabled(t *testing.T) {
tests := []struct {
name string