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, v1.SchemeGroupVersion.Version: coreResources,
}, },
OptionsExternalVersion: &registered.GroupOrDie(core.GroupName).GroupVersion, OptionsExternalVersion: &registered.GroupOrDie(core.GroupName).GroupVersion,
IsLegacyGroup: true,
Scheme: core.Scheme, Scheme: core.Scheme,
ParameterCodec: core.ParameterCodec, ParameterCodec: core.ParameterCodec,
NegotiatedSerializer: core.Codecs, 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) 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" "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. // Config is a structure used to configure a GenericAPIServer.
type Config struct { type Config struct {
// Destination for audit logs // Destination for audit logs
@ -73,7 +78,6 @@ type Config struct {
EnableProfiling bool EnableProfiling bool
EnableVersion bool EnableVersion bool
EnableGarbageCollection bool EnableGarbageCollection bool
APIPrefix string
APIGroupPrefix string APIGroupPrefix string
CorsAllowedOriginList []string CorsAllowedOriginList []string
Authenticator authenticator.Request Authenticator authenticator.Request
@ -168,6 +172,10 @@ type Config struct {
// Build the handler chains by decorating the apiHandler. // Build the handler chains by decorating the apiHandler.
BuildHandlerChainsFunc func(apiHandler http.Handler, c *Config) (secure, insecure http.Handler) 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 { type ServingInfo struct {
@ -227,7 +235,6 @@ func NewConfig(options *options.ServerRunOptions) *Config {
return &Config{ return &Config{
APIGroupPrefix: options.APIGroupPrefix, APIGroupPrefix: options.APIGroupPrefix,
APIPrefix: options.APIPrefix,
CorsAllowedOriginList: options.CorsAllowedOriginList, CorsAllowedOriginList: options.CorsAllowedOriginList,
AuditWriter: auditWriter, AuditWriter: auditWriter,
EnableGarbageCollection: options.EnableGarbageCollection, EnableGarbageCollection: options.EnableGarbageCollection,
@ -261,8 +268,9 @@ func NewConfig(options *options.ServerRunOptions) *Config {
}, },
}, },
}, },
MaxRequestsInFlight: options.MaxRequestsInFlight, MaxRequestsInFlight: options.MaxRequestsInFlight,
LongRunningFunc: genericfilters.BasicLongRunningRequestCheck(longRunningRE, map[string]string{"watch": "true"}), 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{ s := &GenericAPIServer{
ServiceClusterIPRange: c.ServiceClusterIPRange, ServiceClusterIPRange: c.ServiceClusterIPRange,
LoopbackClientConfig: c.LoopbackClientConfig, LoopbackClientConfig: c.LoopbackClientConfig,
legacyAPIPrefix: c.APIPrefix, apiPrefix: c.APIGroupPrefix,
apiPrefix: c.APIGroupPrefix, legacyAPIGroupPrefixes: c.LegacyAPIGroupPrefixes,
admissionControl: c.AdmissionControl, admissionControl: c.AdmissionControl,
requestContextMapper: c.RequestContextMapper, requestContextMapper: c.RequestContextMapper,
Serializer: c.Serializer, Serializer: c.Serializer,
minRequestTimeout: time.Duration(c.MinRequestTimeout) * time.Second, minRequestTimeout: time.Duration(c.MinRequestTimeout) * time.Second,
enableSwaggerSupport: c.EnableSwaggerSupport, enableSwaggerSupport: c.EnableSwaggerSupport,
@ -498,8 +506,15 @@ func DefaultAndValidateRunOptions(options *options.ServerRunOptions) {
} }
func NewRequestInfoResolver(c *Config) *request.RequestInfoFactory { 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{ return &request.RequestInfoFactory{
APIPrefixes: sets.NewString(strings.Trim(c.APIPrefix, "/"), strings.Trim(c.APIGroupPrefix, "/")), // all possible API prefixes APIPrefixes: apiPrefixes,
GrouplessAPIPrefixes: sets.NewString(strings.Trim(c.APIPrefix, "/")), // APIPrefixes that won't have groups (legacy) GrouplessAPIPrefixes: legacyAPIPrefixes,
} }
} }

View File

@ -49,6 +49,7 @@ import (
certutil "k8s.io/kubernetes/pkg/util/cert" certutil "k8s.io/kubernetes/pkg/util/cert"
utilnet "k8s.io/kubernetes/pkg/util/net" utilnet "k8s.io/kubernetes/pkg/util/net"
utilruntime "k8s.io/kubernetes/pkg/util/runtime" utilruntime "k8s.io/kubernetes/pkg/util/runtime"
"k8s.io/kubernetes/pkg/util/sets"
) )
// Info about an API group. // Info about an API group.
@ -56,8 +57,6 @@ type APIGroupInfo struct {
GroupMeta apimachinery.GroupMeta GroupMeta apimachinery.GroupMeta
// Info about the resources in this group. Its a map from version to resource to the storage. // Info about the resources in this group. Its a map from version to resource to the storage.
VersionedResourcesStorageMap map[string]map[string]rest.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 // OptionsExternalVersion controls the APIVersion used for common objects in the
// schema like api.Status, api.DeleteOptions, and api.ListOptions. Other implementors may // 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. // 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. // TODO eventually we should be able to factor this out to take place during initialization.
enableSwaggerSupport bool 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 is the prefix where API groups live, usually /apis
apiPrefix string 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 is used to build the RESTStorage that backs an API Group.
admissionControl admission.Interface admissionControl admission.Interface
@ -294,18 +293,9 @@ func (s *GenericAPIServer) Run() {
select {} select {}
} }
// Exposes the given api group in the API. // installAPIResources is a private method for installing the REST storage backing each api groupversionresource
func (s *GenericAPIServer) InstallAPIGroup(apiGroupInfo *APIGroupInfo) error { func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *APIGroupInfo) error {
apiPrefix := s.apiPrefix
if apiGroupInfo.IsLegacyGroup {
apiPrefix = s.legacyAPIPrefix
}
// Install REST handlers for all the versions in this group.
apiVersions := []string{}
for _, groupVersion := range apiGroupInfo.GroupMeta.GroupVersions { for _, groupVersion := range apiGroupInfo.GroupMeta.GroupVersions {
apiVersions = append(apiVersions, groupVersion.Version)
apiGroupVersion, err := s.getAPIGroupVersion(apiGroupInfo, groupVersion, apiPrefix) apiGroupVersion, err := s.getAPIGroupVersion(apiGroupInfo, groupVersion, apiPrefix)
if err != nil { if err != nil {
return err return err
@ -318,51 +308,77 @@ func (s *GenericAPIServer) InstallAPIGroup(apiGroupInfo *APIGroupInfo) error {
return fmt.Errorf("Unable to setup API %v: %v", apiGroupInfo, err) 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. return nil
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) func (s *GenericAPIServer) InstallLegacyAPIGroup(apiPrefix string, apiGroupInfo *APIGroupInfo) error {
s.HandlerContainer.Add(apiserver.NewGroupWebService(s.Serializer, apiPrefix+"/"+apiGroup.Name, apiGroup)) 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 return nil
} }

View File

@ -41,6 +41,7 @@ import (
ipallocator "k8s.io/kubernetes/pkg/registry/core/service/ipallocator" ipallocator "k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing" etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
utilnet "k8s.io/kubernetes/pkg/util/net" utilnet "k8s.io/kubernetes/pkg/util/net"
"k8s.io/kubernetes/pkg/util/sets"
"github.com/stretchr/testify/assert" "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.ProxyDialer = func(network, addr string) (net.Conn, error) { return nil, nil }
config.ProxyTLSClientConfig = &tls.Config{} config.ProxyTLSClientConfig = &tls.Config{}
config.Serializer = api.Codecs config.Serializer = api.Codecs
config.APIPrefix = "/api" config.LegacyAPIGroupPrefixes = sets.NewString("/api")
config.APIGroupPrefix = "/apis" config.APIGroupPrefix = "/apis"
return etcdServer, config, assert.New(t) return etcdServer, config, assert.New(t)
@ -79,7 +80,7 @@ func TestNew(t *testing.T) {
// Verify many of the variables match their config counterparts // Verify many of the variables match their config counterparts
assert.Equal(s.enableSwaggerSupport, config.EnableSwaggerSupport) 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.apiPrefix, config.APIGroupPrefix)
assert.Equal(s.admissionControl, config.AdmissionControl) assert.Equal(s.admissionControl, config.AdmissionControl)
assert.Equal(s.RequestContextMapper(), config.RequestContextMapper) assert.Equal(s.RequestContextMapper(), config.RequestContextMapper)
@ -105,7 +106,7 @@ func TestInstallAPIGroups(t *testing.T) {
etcdserver, config, assert := setUp(t) etcdserver, config, assert := setUp(t)
defer etcdserver.Terminate(t) defer etcdserver.Terminate(t)
config.APIPrefix = "/apiPrefix" config.LegacyAPIGroupPrefixes = sets.NewString("/apiPrefix")
config.APIGroupPrefix = "/apiGroupPrefix" config.APIGroupPrefix = "/apiGroupPrefix"
s, err := config.Complete().New() s, err := config.Complete().New()
@ -115,15 +116,15 @@ func TestInstallAPIGroups(t *testing.T) {
apiGroupMeta := registered.GroupOrDie(api.GroupName) apiGroupMeta := registered.GroupOrDie(api.GroupName)
extensionsGroupMeta := registered.GroupOrDie(extensions.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{ 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 // extensions group version
GroupMeta: *extensionsGroupMeta, GroupMeta: *extensionsGroupMeta,
@ -141,9 +142,9 @@ func TestInstallAPIGroups(t *testing.T) {
defer server.Close() defer server.Close()
validPaths := []string{ validPaths := []string{
// "/api" // "/api"
config.APIPrefix, config.LegacyAPIGroupPrefixes.List()[0],
// "/api/v1" // "/api/v1"
config.APIPrefix + "/" + apiGroupMeta.GroupVersion.Version, config.LegacyAPIGroupPrefixes.List()[0] + "/" + apiGroupMeta.GroupVersion.Version,
// "/apis/extensions" // "/apis/extensions"
config.APIGroupPrefix + "/" + extensionsGroupMeta.GroupVersion.Group, config.APIGroupPrefix + "/" + extensionsGroupMeta.GroupVersion.Group,
// "/apis/extensions/v1beta1" // "/apis/extensions/v1beta1"
@ -224,7 +225,7 @@ func TestNotRestRoutesHaveAuth(t *testing.T) {
authz := mockAuthorizer{} authz := mockAuthorizer{}
config.APIPrefix = "/apiPrefix" config.LegacyAPIGroupPrefixes = sets.NewString("/apiPrefix")
config.APIGroupPrefix = "/apiGroupPrefix" config.APIGroupPrefix = "/apiGroupPrefix"
config.Authorizer = &authz 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. // ServerRunOptions contains the options while running a generic api server.
type ServerRunOptions struct { type ServerRunOptions struct {
APIGroupPrefix string APIGroupPrefix string
APIPrefix string
AdmissionControl string AdmissionControl string
AdmissionControlConfigFile string AdmissionControlConfigFile string
AdvertiseAddress net.IP AdvertiseAddress net.IP
@ -125,7 +124,6 @@ type ServerRunOptions struct {
func NewServerRunOptions() *ServerRunOptions { func NewServerRunOptions() *ServerRunOptions {
return &ServerRunOptions{ return &ServerRunOptions{
APIGroupPrefix: "/apis", APIGroupPrefix: "/apis",
APIPrefix: "/api",
AdmissionControl: "AlwaysAdmit", AdmissionControl: "AlwaysAdmit",
AnonymousAuth: true, AnonymousAuth: true,
AuthorizationMode: "AlwaysAllow", AuthorizationMode: "AlwaysAllow",

View File

@ -135,8 +135,6 @@ type Master struct {
// nodeClient is used to back the tunneler // nodeClient is used to back the tunneler
nodeClient coreclient.NodeInterface nodeClient coreclient.NodeInterface
restOptionsFactory restOptionsFactory
} }
// thirdPartyEntry combines objects storage and API group into one struct // 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(), nodeClient: coreclient.NewForConfigOrDie(c.GenericConfig.LoopbackClientConfig).Nodes(),
disableThirdPartyControllerForTesting: c.disableThirdPartyControllerForTesting, disableThirdPartyControllerForTesting: c.disableThirdPartyControllerForTesting,
}
restOptionsFactory: restOptionsFactory{ restOptionsFactory := restOptionsFactory{
deleteCollectionWorkers: c.DeleteCollectionWorkers, deleteCollectionWorkers: c.DeleteCollectionWorkers,
enableGarbageCollection: c.GenericConfig.EnableGarbageCollection, enableGarbageCollection: c.GenericConfig.EnableGarbageCollection,
storageFactory: c.StorageFactory, storageFactory: c.StorageFactory,
},
} }
if c.EnableWatchCache { if c.EnableWatchCache {
m.restOptionsFactory.storageDecorator = registry.StorageWithCacher restOptionsFactory.storageDecorator = registry.StorageWithCacher
} else { } else {
m.restOptionsFactory.storageDecorator = generic.UndecoratedStorage restOptionsFactory.storageDecorator = generic.UndecoratedStorage
} }
// install legacy rest storage // install legacy rest storage
// because of other hacks, this always has to come first if c.GenericConfig.APIResourceConfigSource.AnyResourcesForVersionEnabled(apiv1.SchemeGroupVersion) {
legacyRESTStorageProvider := corerest.LegacyRESTStorageProvider{ legacyRESTStorageProvider := corerest.LegacyRESTStorageProvider{
StorageFactory: c.StorageFactory, StorageFactory: c.StorageFactory,
ProxyTransport: s.ProxyTransport, ProxyTransport: s.ProxyTransport,
KubeletClient: c.KubeletClient, KubeletClient: c.KubeletClient,
EventTTL: c.EventTTL, EventTTL: c.EventTTL,
ServiceClusterIPRange: c.GenericConfig.ServiceClusterIPRange, ServiceClusterIPRange: c.GenericConfig.ServiceClusterIPRange,
ServiceNodePortRange: c.GenericConfig.ServiceNodePortRange, ServiceNodePortRange: c.GenericConfig.ServiceNodePortRange,
ComponentStatusServerFunc: func() map[string]apiserver.Server { return getServersToValidate(c.StorageFactory) }, ComponentStatusServerFunc: func() map[string]apiserver.Server { return getServersToValidate(c.StorageFactory) },
LoopbackClientConfig: c.GenericConfig.LoopbackClientConfig, LoopbackClientConfig: c.GenericConfig.LoopbackClientConfig,
}
m.InstallLegacyAPI(c.Config, restOptionsFactory.NewFor, legacyRESTStorageProvider)
} }
// Add some hardcoded storage for now. Append to the map. // 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[policy.GroupName] = policyrest.RESTStorageProvider{}
c.RESTStorageProviders[rbac.GroupName] = &rbacrest.RESTStorageProvider{AuthorizerRBACSuperUser: c.GenericConfig.AuthorizerRBACSuperUser} c.RESTStorageProviders[rbac.GroupName] = &rbacrest.RESTStorageProvider{AuthorizerRBACSuperUser: c.GenericConfig.AuthorizerRBACSuperUser}
c.RESTStorageProviders[storage.GroupName] = storagerest.RESTStorageProvider{} c.RESTStorageProviders[storage.GroupName] = storagerest.RESTStorageProvider{}
m.InstallAPIs(c.Config, legacyRESTStorageProvider) m.InstallAPIs(c.Config, restOptionsFactory.NewFor)
m.InstallGeneralEndpoints(c.Config) m.InstallGeneralEndpoints(c.Config)
return m, nil 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 this needs to be refactored so we have a way to add general health checks to genericapiserver
// TODO profiling should be generic // TODO profiling should be generic
func (m *Master) InstallGeneralEndpoints(c *Config) { 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) { func (m *Master) InstallAPIs(c *Config, restOptionsGetter genericapiserver.RESTOptionsGetter) {
restOptionsGetter := func(resource unversioned.GroupResource) generic.RESTOptions {
return m.restOptionsFactory.NewFor(resource)
}
apiGroupsInfo := []genericapiserver.APIGroupInfo{} 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 // 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 // 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")) { 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.PublicAddress = net.ParseIP("192.168.10.4")
config.GenericConfig.Serializer = api.Codecs config.GenericConfig.Serializer = api.Codecs
config.KubeletClient = client.FakeKubeletClient{} config.KubeletClient = client.FakeKubeletClient{}
config.GenericConfig.APIPrefix = "/api" config.GenericConfig.LegacyAPIGroupPrefixes = sets.NewString("/api")
config.GenericConfig.APIGroupPrefix = "/apis" config.GenericConfig.APIGroupPrefix = "/apis"
config.GenericConfig.APIResourceConfigSource = DefaultAPIResourceConfigSource() config.GenericConfig.APIResourceConfigSource = DefaultAPIResourceConfigSource()
config.GenericConfig.ProxyDialer = func(network, addr string) (net.Conn, error) { return nil, nil } 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{ apiGroupInfo := genericapiserver.APIGroupInfo{
GroupMeta: *registered.GroupOrDie(api.GroupName), GroupMeta: *registered.GroupOrDie(api.GroupName),
VersionedResourcesStorageMap: map[string]map[string]rest.Storage{}, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{},
IsLegacyGroup: true, Scheme: api.Scheme,
Scheme: api.Scheme, ParameterCodec: api.ParameterCodec,
ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs,
NegotiatedSerializer: api.Codecs, SubresourceGroupVersionKind: map[string]unversioned.GroupVersionKind{},
SubresourceGroupVersionKind: map[string]unversioned.GroupVersionKind{},
} }
if autoscalingGroupVersion := (unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}); registered.IsEnabledVersion(autoscalingGroupVersion) { if autoscalingGroupVersion := (unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}); registered.IsEnabledVersion(autoscalingGroupVersion) {
apiGroupInfo.SubresourceGroupVersionKind["replicationcontrollers/scale"] = autoscalingGroupVersion.WithKind("Scale") apiGroupInfo.SubresourceGroupVersionKind["replicationcontrollers/scale"] = autoscalingGroupVersion.WithKind("Scale")

View File

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