Merge pull request #34551 from deads2k/api-23-remove-legacy-prefixy

Automatic merge from submit-queue

Change legacy API resource registration

Updates the legacy API resource registration to emphasize its different-ness and to simplify supporting objects.  The option has to remain in the genericapiserverconfig for multiple prefixes to enable cases where composers/extenders had composed additional groupless APIs. See OpenShift as an example.

However this is now transparent to "normal" composers.

@ncdc since sttts is out.
This commit is contained in:
Kubernetes Submit Queue 2016-10-13 08:23:35 -07:00 committed by GitHub
commit dd529f3c4a
9 changed files with 165 additions and 139 deletions

View File

@ -61,12 +61,11 @@ func installCoreAPIs(s *options.ServerRunOptions, g *genericapiserver.GenericAPI
v1.SchemeGroupVersion.Version: coreResources,
},
OptionsExternalVersion: &registered.GroupOrDie(core.GroupName).GroupVersion,
IsLegacyGroup: true,
Scheme: core.Scheme,
ParameterCodec: core.ParameterCodec,
NegotiatedSerializer: core.Codecs,
}
if err := g.InstallAPIGroup(&apiGroupInfo); err != nil {
if err := g.InstallLegacyAPIGroup(genericapiserver.LegacyAPIPrefix, &apiGroupInfo); err != nil {
glog.Fatalf("Error in registering group version: %+v.\n Error: %v\n", apiGroupInfo, err)
}
}

View File

@ -56,6 +56,11 @@ import (
"k8s.io/kubernetes/pkg/util/sets"
)
const (
// LegacyAPIPrefix is where the the legacy APIs will be located
LegacyAPIPrefix = "/api"
)
// Config is a structure used to configure a GenericAPIServer.
type Config struct {
// Destination for audit logs
@ -73,7 +78,6 @@ type Config struct {
EnableProfiling bool
EnableVersion bool
EnableGarbageCollection bool
APIPrefix string
APIGroupPrefix string
CorsAllowedOriginList []string
Authenticator authenticator.Request
@ -168,6 +172,10 @@ type Config struct {
// Build the handler chains by decorating the apiHandler.
BuildHandlerChainsFunc func(apiHandler http.Handler, c *Config) (secure, insecure http.Handler)
// LegacyAPIGroupPrefixes is used to set up URL parsing for authorization and for validating requests
// to InstallLegacyAPIGroup
LegacyAPIGroupPrefixes sets.String
}
type ServingInfo struct {
@ -227,7 +235,6 @@ func NewConfig(options *options.ServerRunOptions) *Config {
return &Config{
APIGroupPrefix: options.APIGroupPrefix,
APIPrefix: options.APIPrefix,
CorsAllowedOriginList: options.CorsAllowedOriginList,
AuditWriter: auditWriter,
EnableGarbageCollection: options.EnableGarbageCollection,
@ -261,8 +268,9 @@ func NewConfig(options *options.ServerRunOptions) *Config {
},
},
},
MaxRequestsInFlight: options.MaxRequestsInFlight,
LongRunningFunc: genericfilters.BasicLongRunningRequestCheck(longRunningRE, map[string]string{"watch": "true"}),
MaxRequestsInFlight: options.MaxRequestsInFlight,
LongRunningFunc: genericfilters.BasicLongRunningRequestCheck(longRunningRE, map[string]string{"watch": "true"}),
LegacyAPIGroupPrefixes: sets.NewString(LegacyAPIPrefix),
}
}
@ -363,13 +371,13 @@ func (c completedConfig) New() (*GenericAPIServer, error) {
}
s := &GenericAPIServer{
ServiceClusterIPRange: c.ServiceClusterIPRange,
LoopbackClientConfig: c.LoopbackClientConfig,
legacyAPIPrefix: c.APIPrefix,
apiPrefix: c.APIGroupPrefix,
admissionControl: c.AdmissionControl,
requestContextMapper: c.RequestContextMapper,
Serializer: c.Serializer,
ServiceClusterIPRange: c.ServiceClusterIPRange,
LoopbackClientConfig: c.LoopbackClientConfig,
apiPrefix: c.APIGroupPrefix,
legacyAPIGroupPrefixes: c.LegacyAPIGroupPrefixes,
admissionControl: c.AdmissionControl,
requestContextMapper: c.RequestContextMapper,
Serializer: c.Serializer,
minRequestTimeout: time.Duration(c.MinRequestTimeout) * time.Second,
enableSwaggerSupport: c.EnableSwaggerSupport,
@ -498,8 +506,15 @@ func DefaultAndValidateRunOptions(options *options.ServerRunOptions) {
}
func NewRequestInfoResolver(c *Config) *request.RequestInfoFactory {
apiPrefixes := sets.NewString(strings.Trim(c.APIGroupPrefix, "/")) // all possible API prefixes
legacyAPIPrefixes := sets.String{} // APIPrefixes that won't have groups (legacy)
for legacyAPIPrefix := range c.LegacyAPIGroupPrefixes {
apiPrefixes.Insert(strings.Trim(legacyAPIPrefix, "/"))
legacyAPIPrefixes.Insert(strings.Trim(legacyAPIPrefix, "/"))
}
return &request.RequestInfoFactory{
APIPrefixes: sets.NewString(strings.Trim(c.APIPrefix, "/"), strings.Trim(c.APIGroupPrefix, "/")), // all possible API prefixes
GrouplessAPIPrefixes: sets.NewString(strings.Trim(c.APIPrefix, "/")), // APIPrefixes that won't have groups (legacy)
APIPrefixes: apiPrefixes,
GrouplessAPIPrefixes: legacyAPIPrefixes,
}
}

View File

@ -49,6 +49,7 @@ import (
certutil "k8s.io/kubernetes/pkg/util/cert"
utilnet "k8s.io/kubernetes/pkg/util/net"
utilruntime "k8s.io/kubernetes/pkg/util/runtime"
"k8s.io/kubernetes/pkg/util/sets"
)
// Info about an API group.
@ -56,8 +57,6 @@ type APIGroupInfo struct {
GroupMeta apimachinery.GroupMeta
// Info about the resources in this group. Its a map from version to resource to the storage.
VersionedResourcesStorageMap map[string]map[string]rest.Storage
// True, if this is the legacy group ("/v1").
IsLegacyGroup bool
// OptionsExternalVersion controls the APIVersion used for common objects in the
// schema like api.Status, api.DeleteOptions, and api.ListOptions. Other implementors may
// define a version "v1beta1" but want to use the Kubernetes "v1" internal objects.
@ -102,13 +101,13 @@ type GenericAPIServer struct {
// TODO eventually we should be able to factor this out to take place during initialization.
enableSwaggerSupport bool
// legacyAPIPrefix is the prefix used for legacy API groups that existed before we had API groups
// usuallly /api
legacyAPIPrefix string
// apiPrefix is the prefix where API groups live, usually /apis
apiPrefix string
// legacyAPIGroupPrefixes is used to set up URL parsing for authorization and for validating requests
// to InstallLegacyAPIGroup
legacyAPIGroupPrefixes sets.String
// admissionControl is used to build the RESTStorage that backs an API Group.
admissionControl admission.Interface
@ -294,18 +293,9 @@ func (s *GenericAPIServer) Run() {
select {}
}
// Exposes the given api group in the API.
func (s *GenericAPIServer) InstallAPIGroup(apiGroupInfo *APIGroupInfo) error {
apiPrefix := s.apiPrefix
if apiGroupInfo.IsLegacyGroup {
apiPrefix = s.legacyAPIPrefix
}
// Install REST handlers for all the versions in this group.
apiVersions := []string{}
// installAPIResources is a private method for installing the REST storage backing each api groupversionresource
func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *APIGroupInfo) error {
for _, groupVersion := range apiGroupInfo.GroupMeta.GroupVersions {
apiVersions = append(apiVersions, groupVersion.Version)
apiGroupVersion, err := s.getAPIGroupVersion(apiGroupInfo, groupVersion, apiPrefix)
if err != nil {
return err
@ -318,51 +308,77 @@ func (s *GenericAPIServer) InstallAPIGroup(apiGroupInfo *APIGroupInfo) error {
return fmt.Errorf("Unable to setup API %v: %v", apiGroupInfo, err)
}
}
// Install the version handler.
if apiGroupInfo.IsLegacyGroup {
// Add a handler at /api to enumerate the supported api versions.
apiserver.AddApiWebService(s.Serializer, s.HandlerContainer.Container, apiPrefix, func(req *restful.Request) *unversioned.APIVersions {
apiVersionsForDiscovery := unversioned.APIVersions{
ServerAddressByClientCIDRs: s.getServerAddressByClientCIDRs(req.Request),
Versions: apiVersions,
}
return &apiVersionsForDiscovery
})
} else {
// Do not register empty group or empty version. Doing so claims /apis/ for the wrong entity to be returned.
// Catching these here places the error much closer to its origin
if len(apiGroupInfo.GroupMeta.GroupVersion.Group) == 0 {
return fmt.Errorf("cannot register handler with an empty group for %#v", *apiGroupInfo)
}
if len(apiGroupInfo.GroupMeta.GroupVersion.Version) == 0 {
return fmt.Errorf("cannot register handler with an empty version for %#v", *apiGroupInfo)
}
// Add a handler at /apis/<groupName> to enumerate all versions supported by this group.
apiVersionsForDiscovery := []unversioned.GroupVersionForDiscovery{}
for _, groupVersion := range apiGroupInfo.GroupMeta.GroupVersions {
// Check the config to make sure that we elide versions that don't have any resources
if len(apiGroupInfo.VersionedResourcesStorageMap[groupVersion.Version]) == 0 {
continue
}
apiVersionsForDiscovery = append(apiVersionsForDiscovery, unversioned.GroupVersionForDiscovery{
GroupVersion: groupVersion.String(),
Version: groupVersion.Version,
})
}
preferedVersionForDiscovery := unversioned.GroupVersionForDiscovery{
GroupVersion: apiGroupInfo.GroupMeta.GroupVersion.String(),
Version: apiGroupInfo.GroupMeta.GroupVersion.Version,
}
apiGroup := unversioned.APIGroup{
Name: apiGroupInfo.GroupMeta.GroupVersion.Group,
Versions: apiVersionsForDiscovery,
PreferredVersion: preferedVersionForDiscovery,
}
return nil
}
s.AddAPIGroupForDiscovery(apiGroup)
s.HandlerContainer.Add(apiserver.NewGroupWebService(s.Serializer, apiPrefix+"/"+apiGroup.Name, apiGroup))
func (s *GenericAPIServer) InstallLegacyAPIGroup(apiPrefix string, apiGroupInfo *APIGroupInfo) error {
if !s.legacyAPIGroupPrefixes.Has(apiPrefix) {
return fmt.Errorf("%q is not in the allowed legacy API prefixes: %v", apiPrefix, s.legacyAPIGroupPrefixes.List())
}
if err := s.installAPIResources(apiPrefix, apiGroupInfo); err != nil {
return err
}
// setup discovery
apiVersions := []string{}
for _, groupVersion := range apiGroupInfo.GroupMeta.GroupVersions {
apiVersions = append(apiVersions, groupVersion.Version)
}
// Install the version handler.
// Add a handler at /<apiPrefix> to enumerate the supported api versions.
apiserver.AddApiWebService(s.Serializer, s.HandlerContainer.Container, apiPrefix, func(req *restful.Request) *unversioned.APIVersions {
apiVersionsForDiscovery := unversioned.APIVersions{
ServerAddressByClientCIDRs: s.getServerAddressByClientCIDRs(req.Request),
Versions: apiVersions,
}
return &apiVersionsForDiscovery
})
return nil
}
// Exposes the given api group in the API.
func (s *GenericAPIServer) InstallAPIGroup(apiGroupInfo *APIGroupInfo) error {
// Do not register empty group or empty version. Doing so claims /apis/ for the wrong entity to be returned.
// Catching these here places the error much closer to its origin
if len(apiGroupInfo.GroupMeta.GroupVersion.Group) == 0 {
return fmt.Errorf("cannot register handler with an empty group for %#v", *apiGroupInfo)
}
if len(apiGroupInfo.GroupMeta.GroupVersion.Version) == 0 {
return fmt.Errorf("cannot register handler with an empty version for %#v", *apiGroupInfo)
}
if err := s.installAPIResources(s.apiPrefix, apiGroupInfo); err != nil {
return err
}
// setup discovery
// Install the version handler.
// Add a handler at /apis/<groupName> to enumerate all versions supported by this group.
apiVersionsForDiscovery := []unversioned.GroupVersionForDiscovery{}
for _, groupVersion := range apiGroupInfo.GroupMeta.GroupVersions {
// Check the config to make sure that we elide versions that don't have any resources
if len(apiGroupInfo.VersionedResourcesStorageMap[groupVersion.Version]) == 0 {
continue
}
apiVersionsForDiscovery = append(apiVersionsForDiscovery, unversioned.GroupVersionForDiscovery{
GroupVersion: groupVersion.String(),
Version: groupVersion.Version,
})
}
preferedVersionForDiscovery := unversioned.GroupVersionForDiscovery{
GroupVersion: apiGroupInfo.GroupMeta.GroupVersion.String(),
Version: apiGroupInfo.GroupMeta.GroupVersion.Version,
}
apiGroup := unversioned.APIGroup{
Name: apiGroupInfo.GroupMeta.GroupVersion.Group,
Versions: apiVersionsForDiscovery,
PreferredVersion: preferedVersionForDiscovery,
}
s.AddAPIGroupForDiscovery(apiGroup)
s.HandlerContainer.Add(apiserver.NewGroupWebService(s.Serializer, s.apiPrefix+"/"+apiGroup.Name, apiGroup))
return nil
}

View File

@ -41,6 +41,7 @@ import (
ipallocator "k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
utilnet "k8s.io/kubernetes/pkg/util/net"
"k8s.io/kubernetes/pkg/util/sets"
"github.com/stretchr/testify/assert"
)
@ -55,7 +56,7 @@ func setUp(t *testing.T) (*etcdtesting.EtcdTestServer, Config, *assert.Assertion
config.ProxyDialer = func(network, addr string) (net.Conn, error) { return nil, nil }
config.ProxyTLSClientConfig = &tls.Config{}
config.Serializer = api.Codecs
config.APIPrefix = "/api"
config.LegacyAPIGroupPrefixes = sets.NewString("/api")
config.APIGroupPrefix = "/apis"
return etcdServer, config, assert.New(t)
@ -79,7 +80,7 @@ func TestNew(t *testing.T) {
// Verify many of the variables match their config counterparts
assert.Equal(s.enableSwaggerSupport, config.EnableSwaggerSupport)
assert.Equal(s.legacyAPIPrefix, config.APIPrefix)
assert.Equal(s.legacyAPIGroupPrefixes, config.LegacyAPIGroupPrefixes)
assert.Equal(s.apiPrefix, config.APIGroupPrefix)
assert.Equal(s.admissionControl, config.AdmissionControl)
assert.Equal(s.RequestContextMapper(), config.RequestContextMapper)
@ -105,7 +106,7 @@ func TestInstallAPIGroups(t *testing.T) {
etcdserver, config, assert := setUp(t)
defer etcdserver.Terminate(t)
config.APIPrefix = "/apiPrefix"
config.LegacyAPIGroupPrefixes = sets.NewString("/apiPrefix")
config.APIGroupPrefix = "/apiGroupPrefix"
s, err := config.Complete().New()
@ -115,15 +116,15 @@ func TestInstallAPIGroups(t *testing.T) {
apiGroupMeta := registered.GroupOrDie(api.GroupName)
extensionsGroupMeta := registered.GroupOrDie(extensions.GroupName)
s.InstallLegacyAPIGroup("/apiPrefix", &APIGroupInfo{
// legacy group version
GroupMeta: *apiGroupMeta,
VersionedResourcesStorageMap: map[string]map[string]rest.Storage{},
ParameterCodec: api.ParameterCodec,
NegotiatedSerializer: api.Codecs,
})
apiGroupsInfo := []APIGroupInfo{
{
// legacy group version
GroupMeta: *apiGroupMeta,
VersionedResourcesStorageMap: map[string]map[string]rest.Storage{},
IsLegacyGroup: true,
ParameterCodec: api.ParameterCodec,
NegotiatedSerializer: api.Codecs,
},
{
// extensions group version
GroupMeta: *extensionsGroupMeta,
@ -141,9 +142,9 @@ func TestInstallAPIGroups(t *testing.T) {
defer server.Close()
validPaths := []string{
// "/api"
config.APIPrefix,
config.LegacyAPIGroupPrefixes.List()[0],
// "/api/v1"
config.APIPrefix + "/" + apiGroupMeta.GroupVersion.Version,
config.LegacyAPIGroupPrefixes.List()[0] + "/" + apiGroupMeta.GroupVersion.Version,
// "/apis/extensions"
config.APIGroupPrefix + "/" + extensionsGroupMeta.GroupVersion.Group,
// "/apis/extensions/v1beta1"
@ -224,7 +225,7 @@ func TestNotRestRoutesHaveAuth(t *testing.T) {
authz := mockAuthorizer{}
config.APIPrefix = "/apiPrefix"
config.LegacyAPIGroupPrefixes = sets.NewString("/apiPrefix")
config.APIGroupPrefix = "/apiGroupPrefix"
config.Authorizer = &authz

View File

@ -56,7 +56,6 @@ var AuthorizationModeChoices = []string{ModeAlwaysAllow, ModeAlwaysDeny, ModeABA
// ServerRunOptions contains the options while running a generic api server.
type ServerRunOptions struct {
APIGroupPrefix string
APIPrefix string
AdmissionControl string
AdmissionControlConfigFile string
AdvertiseAddress net.IP
@ -125,7 +124,6 @@ type ServerRunOptions struct {
func NewServerRunOptions() *ServerRunOptions {
return &ServerRunOptions{
APIGroupPrefix: "/apis",
APIPrefix: "/api",
AdmissionControl: "AlwaysAdmit",
AnonymousAuth: true,
AuthorizationMode: "AlwaysAllow",

View File

@ -135,8 +135,6 @@ type Master struct {
// nodeClient is used to back the tunneler
nodeClient coreclient.NodeInterface
restOptionsFactory restOptionsFactory
}
// thirdPartyEntry combines objects storage and API group into one struct
@ -209,31 +207,33 @@ func (c completedConfig) New() (*Master, error) {
nodeClient: coreclient.NewForConfigOrDie(c.GenericConfig.LoopbackClientConfig).Nodes(),
disableThirdPartyControllerForTesting: c.disableThirdPartyControllerForTesting,
}
restOptionsFactory: restOptionsFactory{
deleteCollectionWorkers: c.DeleteCollectionWorkers,
enableGarbageCollection: c.GenericConfig.EnableGarbageCollection,
storageFactory: c.StorageFactory,
},
restOptionsFactory := restOptionsFactory{
deleteCollectionWorkers: c.DeleteCollectionWorkers,
enableGarbageCollection: c.GenericConfig.EnableGarbageCollection,
storageFactory: c.StorageFactory,
}
if c.EnableWatchCache {
m.restOptionsFactory.storageDecorator = registry.StorageWithCacher
restOptionsFactory.storageDecorator = registry.StorageWithCacher
} else {
m.restOptionsFactory.storageDecorator = generic.UndecoratedStorage
restOptionsFactory.storageDecorator = generic.UndecoratedStorage
}
// install legacy rest storage
// because of other hacks, this always has to come first
legacyRESTStorageProvider := corerest.LegacyRESTStorageProvider{
StorageFactory: c.StorageFactory,
ProxyTransport: s.ProxyTransport,
KubeletClient: c.KubeletClient,
EventTTL: c.EventTTL,
ServiceClusterIPRange: c.GenericConfig.ServiceClusterIPRange,
ServiceNodePortRange: c.GenericConfig.ServiceNodePortRange,
ComponentStatusServerFunc: func() map[string]apiserver.Server { return getServersToValidate(c.StorageFactory) },
LoopbackClientConfig: c.GenericConfig.LoopbackClientConfig,
if c.GenericConfig.APIResourceConfigSource.AnyResourcesForVersionEnabled(apiv1.SchemeGroupVersion) {
legacyRESTStorageProvider := corerest.LegacyRESTStorageProvider{
StorageFactory: c.StorageFactory,
ProxyTransport: s.ProxyTransport,
KubeletClient: c.KubeletClient,
EventTTL: c.EventTTL,
ServiceClusterIPRange: c.GenericConfig.ServiceClusterIPRange,
ServiceNodePortRange: c.GenericConfig.ServiceNodePortRange,
ComponentStatusServerFunc: func() map[string]apiserver.Server { return getServersToValidate(c.StorageFactory) },
LoopbackClientConfig: c.GenericConfig.LoopbackClientConfig,
}
m.InstallLegacyAPI(c.Config, restOptionsFactory.NewFor, legacyRESTStorageProvider)
}
// Add some hardcoded storage for now. Append to the map.
@ -253,13 +253,31 @@ func (c completedConfig) New() (*Master, error) {
c.RESTStorageProviders[policy.GroupName] = policyrest.RESTStorageProvider{}
c.RESTStorageProviders[rbac.GroupName] = &rbacrest.RESTStorageProvider{AuthorizerRBACSuperUser: c.GenericConfig.AuthorizerRBACSuperUser}
c.RESTStorageProviders[storage.GroupName] = storagerest.RESTStorageProvider{}
m.InstallAPIs(c.Config, legacyRESTStorageProvider)
m.InstallAPIs(c.Config, restOptionsFactory.NewFor)
m.InstallGeneralEndpoints(c.Config)
return m, nil
}
func (m *Master) InstallLegacyAPI(c *Config, restOptionsGetter genericapiserver.RESTOptionsGetter, legacyRESTStorageProvider corerest.LegacyRESTStorageProvider) {
legacyRESTStorage, apiGroupInfo, err := legacyRESTStorageProvider.NewLegacyRESTStorage(restOptionsGetter)
if err != nil {
glog.Fatalf("Error building core storage: %v", err)
}
if c.EnableCoreControllers {
bootstrapController := c.NewBootstrapController(legacyRESTStorage)
if err := m.GenericAPIServer.AddPostStartHook("bootstrap-controller", bootstrapController.PostStartHook); err != nil {
glog.Fatalf("Error registering PostStartHook %q: %v", "bootstrap-controller", err)
}
}
if err := m.GenericAPIServer.InstallLegacyAPIGroup(genericapiserver.LegacyAPIPrefix, &apiGroupInfo); err != nil {
glog.Fatalf("Error in registering group versions: %v", err)
}
}
// TODO this needs to be refactored so we have a way to add general health checks to genericapiserver
// TODO profiling should be generic
func (m *Master) InstallGeneralEndpoints(c *Config) {
@ -283,30 +301,9 @@ func (m *Master) InstallGeneralEndpoints(c *Config) {
}
func (m *Master) InstallAPIs(c *Config, legacyRESTStorageProvider corerest.LegacyRESTStorageProvider) {
restOptionsGetter := func(resource unversioned.GroupResource) generic.RESTOptions {
return m.restOptionsFactory.NewFor(resource)
}
func (m *Master) InstallAPIs(c *Config, restOptionsGetter genericapiserver.RESTOptionsGetter) {
apiGroupsInfo := []genericapiserver.APIGroupInfo{}
// Install v1 unless disabled.
if c.GenericConfig.APIResourceConfigSource.AnyResourcesForVersionEnabled(apiv1.SchemeGroupVersion) {
legacyRESTStorage, apiGroupInfo, err := legacyRESTStorageProvider.NewLegacyRESTStorage(restOptionsGetter)
if err != nil {
glog.Fatalf("Error building core storage: %v", err)
}
if c.EnableCoreControllers {
bootstrapController := c.NewBootstrapController(legacyRESTStorage)
if err := m.GenericAPIServer.AddPostStartHook("bootstrap-controller", bootstrapController.PostStartHook); err != nil {
glog.Fatalf("Error registering PostStartHook %q: %v", "bootstrap-controller", err)
}
}
apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo)
}
// Install third party resource support if requested
// TODO seems like this bit ought to be unconditional and the REST API is controlled by the config
if c.GenericConfig.APIResourceConfigSource.ResourceEnabled(extensionsapiv1beta1.SchemeGroupVersion.WithResource("thirdpartyresources")) {

View File

@ -92,7 +92,7 @@ func setUp(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert.
config.GenericConfig.PublicAddress = net.ParseIP("192.168.10.4")
config.GenericConfig.Serializer = api.Codecs
config.KubeletClient = client.FakeKubeletClient{}
config.GenericConfig.APIPrefix = "/api"
config.GenericConfig.LegacyAPIGroupPrefixes = sets.NewString("/api")
config.GenericConfig.APIGroupPrefix = "/apis"
config.GenericConfig.APIResourceConfigSource = DefaultAPIResourceConfigSource()
config.GenericConfig.ProxyDialer = func(network, addr string) (net.Conn, error) { return nil, nil }

View File

@ -96,11 +96,10 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi
apiGroupInfo := genericapiserver.APIGroupInfo{
GroupMeta: *registered.GroupOrDie(api.GroupName),
VersionedResourcesStorageMap: map[string]map[string]rest.Storage{},
IsLegacyGroup: true,
Scheme: api.Scheme,
ParameterCodec: api.ParameterCodec,
NegotiatedSerializer: api.Codecs,
SubresourceGroupVersionKind: map[string]unversioned.GroupVersionKind{},
Scheme: api.Scheme,
ParameterCodec: api.ParameterCodec,
NegotiatedSerializer: api.Codecs,
SubresourceGroupVersionKind: map[string]unversioned.GroupVersionKind{},
}
if autoscalingGroupVersion := (unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}); registered.IsEnabledVersion(autoscalingGroupVersion) {
apiGroupInfo.SubresourceGroupVersionKind["replicationcontrollers/scale"] = autoscalingGroupVersion.WithKind("Scale")

View File

@ -61,6 +61,7 @@ import (
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage/storagebackend"
utilnet "k8s.io/kubernetes/pkg/util/net"
"k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/util/wait"
"k8s.io/kubernetes/pkg/watch"
"k8s.io/kubernetes/plugin/pkg/admission/admit"
@ -348,7 +349,7 @@ func NewMasterConfig() *master.Config {
return &master.Config{
GenericConfig: &genericapiserver.Config{
APIResourceConfigSource: master.DefaultAPIResourceConfigSource(),
APIPrefix: "/api",
LegacyAPIGroupPrefixes: sets.NewString("/api"),
APIGroupPrefix: "/apis",
Authorizer: authorizer.NewAlwaysAllowAuthorizer(),
AdmissionControl: admit.NewAlwaysAdmit(),