mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-26 21:17:23 +00:00
Merge pull request #19040 from nikhiljindal/serverLibrary
api server library: moving API registration logic to generic api server
This commit is contained in:
commit
af9834ea75
@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
"swaggerVersion": "1.2",
|
"swaggerVersion": "1.2",
|
||||||
"apis": [
|
"apis": [
|
||||||
{
|
|
||||||
"path": "/api/v1",
|
|
||||||
"description": "API at /api/v1"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"path": "/version",
|
"path": "/version",
|
||||||
"description": "git code version from which this is built"
|
"description": "git code version from which this is built"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "/api/v1",
|
||||||
|
"description": "API at /api/v1"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "/api",
|
"path": "/api",
|
||||||
"description": "get available API versions"
|
"description": "get available API versions"
|
||||||
|
@ -78,7 +78,7 @@ func (a *APIInstaller) Install(ws *restful.WebService) (apiResources []unversion
|
|||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
apiResource, err := a.registerResourceHandlers(path, a.group.Storage[path], ws, proxyHandler)
|
apiResource, err := a.registerResourceHandlers(path, a.group.Storage[path], ws, proxyHandler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors = append(errors, err)
|
errors = append(errors, fmt.Errorf("error in registering resource: %s, %v", path, err))
|
||||||
}
|
}
|
||||||
if apiResource != nil {
|
if apiResource != nil {
|
||||||
apiResources = append(apiResources, *apiResource)
|
apiResources = append(apiResources, *apiResource)
|
||||||
|
@ -18,6 +18,7 @@ package genericapiserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/pprof"
|
"net/http/pprof"
|
||||||
@ -27,7 +28,9 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kubernetes/pkg/admission"
|
"k8s.io/kubernetes/pkg/admission"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/latest"
|
||||||
"k8s.io/kubernetes/pkg/api/rest"
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
"k8s.io/kubernetes/pkg/auth/authenticator"
|
"k8s.io/kubernetes/pkg/auth/authenticator"
|
||||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||||
@ -128,6 +131,21 @@ type APIGroupVersionOverride struct {
|
|||||||
ResourceOverrides map[string]bool
|
ResourceOverrides map[string]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Info about an API group.
|
||||||
|
type APIGroupInfo struct {
|
||||||
|
GroupMeta latest.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.
|
||||||
|
// If nil, defaults to groupMeta.GroupVersion.
|
||||||
|
// TODO: Remove this when https://github.com/kubernetes/kubernetes/issues/19018 is fixed.
|
||||||
|
OptionsExternalVersion *unversioned.GroupVersion
|
||||||
|
}
|
||||||
|
|
||||||
// Config is a structure used to configure a GenericAPIServer.
|
// Config is a structure used to configure a GenericAPIServer.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
StorageDestinations StorageDestinations
|
StorageDestinations StorageDestinations
|
||||||
@ -229,8 +247,8 @@ type GenericAPIServer struct {
|
|||||||
enableSwaggerSupport bool
|
enableSwaggerSupport bool
|
||||||
enableProfiling bool
|
enableProfiling bool
|
||||||
enableWatchCache bool
|
enableWatchCache bool
|
||||||
ApiPrefix string
|
APIPrefix string
|
||||||
ApiGroupPrefix string
|
APIGroupPrefix string
|
||||||
corsAllowedOriginList []string
|
corsAllowedOriginList []string
|
||||||
authenticator authenticator.Request
|
authenticator authenticator.Request
|
||||||
authorizer authorizer.Authorizer
|
authorizer authorizer.Authorizer
|
||||||
@ -351,8 +369,8 @@ func New(c *Config) *GenericAPIServer {
|
|||||||
enableSwaggerSupport: c.EnableSwaggerSupport,
|
enableSwaggerSupport: c.EnableSwaggerSupport,
|
||||||
enableProfiling: c.EnableProfiling,
|
enableProfiling: c.EnableProfiling,
|
||||||
enableWatchCache: c.EnableWatchCache,
|
enableWatchCache: c.EnableWatchCache,
|
||||||
ApiPrefix: c.APIPrefix,
|
APIPrefix: c.APIPrefix,
|
||||||
ApiGroupPrefix: c.APIGroupPrefix,
|
APIGroupPrefix: c.APIGroupPrefix,
|
||||||
corsAllowedOriginList: c.CorsAllowedOriginList,
|
corsAllowedOriginList: c.CorsAllowedOriginList,
|
||||||
authenticator: c.Authenticator,
|
authenticator: c.Authenticator,
|
||||||
authorizer: c.Authorizer,
|
authorizer: c.Authorizer,
|
||||||
@ -397,8 +415,8 @@ func New(c *Config) *GenericAPIServer {
|
|||||||
|
|
||||||
func (s *GenericAPIServer) NewRequestInfoResolver() *apiserver.RequestInfoResolver {
|
func (s *GenericAPIServer) NewRequestInfoResolver() *apiserver.RequestInfoResolver {
|
||||||
return &apiserver.RequestInfoResolver{
|
return &apiserver.RequestInfoResolver{
|
||||||
sets.NewString(strings.Trim(s.ApiPrefix, "/"), strings.Trim(s.ApiGroupPrefix, "/")), // all possible API prefixes
|
sets.NewString(strings.Trim(s.APIPrefix, "/"), strings.Trim(s.APIGroupPrefix, "/")), // all possible API prefixes
|
||||||
sets.NewString(strings.Trim(s.ApiPrefix, "/")), // APIPrefixes that won't have groups (legacy)
|
sets.NewString(strings.Trim(s.APIPrefix, "/")), // APIPrefixes that won't have groups (legacy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,6 +522,102 @@ func (s *GenericAPIServer) init(c *Config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exposes the given group versions in API.
|
||||||
|
func (s *GenericAPIServer) InstallAPIGroups(groupsInfo []APIGroupInfo) error {
|
||||||
|
for _, apiGroupInfo := range groupsInfo {
|
||||||
|
if err := s.installAPIGroup(&apiGroupInfo); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GenericAPIServer) installAPIGroup(apiGroupInfo *APIGroupInfo) error {
|
||||||
|
apiPrefix := s.APIGroupPrefix
|
||||||
|
if apiGroupInfo.IsLegacyGroup {
|
||||||
|
apiPrefix = s.APIPrefix
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install REST handlers for all the versions in this group.
|
||||||
|
apiVersions := []string{}
|
||||||
|
for _, groupVersion := range apiGroupInfo.GroupMeta.GroupVersions {
|
||||||
|
apiVersions = append(apiVersions, groupVersion.Version)
|
||||||
|
|
||||||
|
apiGroupVersion, err := s.getAPIGroupVersion(apiGroupInfo, groupVersion, apiPrefix)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if apiGroupInfo.OptionsExternalVersion != nil {
|
||||||
|
apiGroupVersion.OptionsExternalVersion = apiGroupInfo.OptionsExternalVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := apiGroupVersion.InstallREST(s.HandlerContainer); err != nil {
|
||||||
|
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.HandlerContainer, apiPrefix, apiVersions)
|
||||||
|
} else {
|
||||||
|
// Add a handler at /apis/<groupName> to enumerate all versions supported by this group.
|
||||||
|
apiVersionsForDiscovery := []unversioned.GroupVersionForDiscovery{}
|
||||||
|
for _, groupVersion := range apiGroupInfo.GroupMeta.GroupVersions {
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
apiserver.AddGroupWebService(s.HandlerContainer, apiPrefix+"/"+apiGroup.Name, apiGroup)
|
||||||
|
}
|
||||||
|
apiserver.InstallServiceErrorHandler(s.HandlerContainer, s.NewRequestInfoResolver(), apiVersions)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GenericAPIServer) getAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupVersion unversioned.GroupVersion, apiPrefix string) (*apiserver.APIGroupVersion, error) {
|
||||||
|
storage := make(map[string]rest.Storage)
|
||||||
|
for k, v := range apiGroupInfo.VersionedResourcesStorageMap[groupVersion.Version] {
|
||||||
|
storage[strings.ToLower(k)] = v
|
||||||
|
}
|
||||||
|
version, err := s.newAPIGroupVersion(apiGroupInfo.GroupMeta, groupVersion)
|
||||||
|
version.Root = apiPrefix
|
||||||
|
version.Storage = storage
|
||||||
|
return version, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GenericAPIServer) newAPIGroupVersion(groupMeta latest.GroupMeta, groupVersion unversioned.GroupVersion) (*apiserver.APIGroupVersion, error) {
|
||||||
|
versionInterface, err := groupMeta.InterfacesFor(groupVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &apiserver.APIGroupVersion{
|
||||||
|
RequestInfoResolver: s.NewRequestInfoResolver(),
|
||||||
|
|
||||||
|
Creater: api.Scheme,
|
||||||
|
Convertor: api.Scheme,
|
||||||
|
Typer: api.Scheme,
|
||||||
|
|
||||||
|
GroupVersion: groupVersion,
|
||||||
|
Linker: groupMeta.SelfLinker,
|
||||||
|
Mapper: groupMeta.RESTMapper,
|
||||||
|
Codec: versionInterface.Codec,
|
||||||
|
|
||||||
|
Admit: s.AdmissionControl,
|
||||||
|
Context: s.RequestContextMapper,
|
||||||
|
|
||||||
|
MinRequestTimeout: s.MinRequestTimeout,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// InstallSwaggerAPI installs the /swaggerapi/ endpoint to allow schema discovery
|
// InstallSwaggerAPI installs the /swaggerapi/ endpoint to allow schema discovery
|
||||||
// and traversal. It is optional to allow consumers of the Kubernetes GenericAPIServer to
|
// and traversal. It is optional to allow consumers of the Kubernetes GenericAPIServer to
|
||||||
// register their own web services into the Kubernetes mux prior to initialization
|
// register their own web services into the Kubernetes mux prior to initialization
|
||||||
|
@ -21,8 +21,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/latest"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
|
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
|
||||||
"k8s.io/kubernetes/pkg/util"
|
"k8s.io/kubernetes/pkg/util"
|
||||||
@ -57,8 +62,8 @@ func TestNew(t *testing.T) {
|
|||||||
assert.Equal(s.enableUISupport, config.EnableUISupport)
|
assert.Equal(s.enableUISupport, config.EnableUISupport)
|
||||||
assert.Equal(s.enableSwaggerSupport, config.EnableSwaggerSupport)
|
assert.Equal(s.enableSwaggerSupport, config.EnableSwaggerSupport)
|
||||||
assert.Equal(s.enableProfiling, config.EnableProfiling)
|
assert.Equal(s.enableProfiling, config.EnableProfiling)
|
||||||
assert.Equal(s.ApiPrefix, config.APIPrefix)
|
assert.Equal(s.APIPrefix, config.APIPrefix)
|
||||||
assert.Equal(s.ApiGroupPrefix, config.APIGroupPrefix)
|
assert.Equal(s.APIGroupPrefix, config.APIGroupPrefix)
|
||||||
assert.Equal(s.corsAllowedOriginList, config.CorsAllowedOriginList)
|
assert.Equal(s.corsAllowedOriginList, config.CorsAllowedOriginList)
|
||||||
assert.Equal(s.authenticator, config.Authenticator)
|
assert.Equal(s.authenticator, config.Authenticator)
|
||||||
assert.Equal(s.authorizer, config.Authorizer)
|
assert.Equal(s.authorizer, config.Authorizer)
|
||||||
@ -80,6 +85,54 @@ func TestNew(t *testing.T) {
|
|||||||
assert.Equal(s.ProxyTransport.(*http.Transport).TLSClientConfig, config.ProxyTLSClientConfig)
|
assert.Equal(s.ProxyTransport.(*http.Transport).TLSClientConfig, config.ProxyTLSClientConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verifies that AddGroupVersions works as expected.
|
||||||
|
func TestInstallAPIGroups(t *testing.T) {
|
||||||
|
_, etcdserver, config, assert := setUp(t)
|
||||||
|
defer etcdserver.Terminate(t)
|
||||||
|
|
||||||
|
config.ProxyDialer = func(network, addr string) (net.Conn, error) { return nil, nil }
|
||||||
|
config.ProxyTLSClientConfig = &tls.Config{}
|
||||||
|
config.APIPrefix = "/apiPrefix"
|
||||||
|
config.APIGroupPrefix = "/apiGroupPrefix"
|
||||||
|
|
||||||
|
s := New(&config)
|
||||||
|
apiGroupMeta := latest.GroupOrDie(api.GroupName)
|
||||||
|
extensionsGroupMeta := latest.GroupOrDie(extensions.GroupName)
|
||||||
|
apiGroupsInfo := []APIGroupInfo{
|
||||||
|
{
|
||||||
|
// legacy group version
|
||||||
|
GroupMeta: *apiGroupMeta,
|
||||||
|
VersionedResourcesStorageMap: map[string]map[string]rest.Storage{},
|
||||||
|
IsLegacyGroup: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// extensions group version
|
||||||
|
GroupMeta: *extensionsGroupMeta,
|
||||||
|
VersionedResourcesStorageMap: map[string]map[string]rest.Storage{},
|
||||||
|
OptionsExternalVersion: &apiGroupMeta.GroupVersion,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
s.InstallAPIGroups(apiGroupsInfo)
|
||||||
|
|
||||||
|
server := httptest.NewServer(s.HandlerContainer.ServeMux)
|
||||||
|
validPaths := []string{
|
||||||
|
// "/api"
|
||||||
|
config.APIPrefix,
|
||||||
|
// "/api/v1"
|
||||||
|
config.APIPrefix + "/" + apiGroupMeta.GroupVersion.Version,
|
||||||
|
// "/apis/extensions"
|
||||||
|
config.APIGroupPrefix + "/" + extensionsGroupMeta.GroupVersion.Group,
|
||||||
|
// "/apis/extensions/v1beta1"
|
||||||
|
config.APIGroupPrefix + "/" + extensionsGroupMeta.GroupVersion.String(),
|
||||||
|
}
|
||||||
|
for _, path := range validPaths {
|
||||||
|
_, err := http.Get(server.URL + path)
|
||||||
|
if !assert.NoError(err) {
|
||||||
|
t.Errorf("unexpected error: %v, for path: %s", err, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestNewHandlerContainer verifies that NewHandlerContainer uses the
|
// TestNewHandlerContainer verifies that NewHandlerContainer uses the
|
||||||
// mux provided
|
// mux provided
|
||||||
func TestNewHandlerContainer(t *testing.T) {
|
func TestNewHandlerContainer(t *testing.T) {
|
||||||
|
@ -30,8 +30,6 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/latest"
|
"k8s.io/kubernetes/pkg/api/latest"
|
||||||
"k8s.io/kubernetes/pkg/api/rest"
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
apiutil "k8s.io/kubernetes/pkg/api/util"
|
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||||
@ -159,14 +157,8 @@ func New(c *Config) *Master {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Master) InstallAPIs(c *Config) {
|
func (m *Master) InstallAPIs(c *Config) {
|
||||||
apiVersions := []string{}
|
apiGroupsInfo := []genericapiserver.APIGroupInfo{}
|
||||||
// Install v1 unless disabled.
|
|
||||||
if !m.ApiGroupVersionOverrides["api/v1"].Disable {
|
|
||||||
if err := m.api_v1(c).InstallREST(m.HandlerContainer); err != nil {
|
|
||||||
glog.Fatalf("Unable to setup API v1: %v", err)
|
|
||||||
}
|
|
||||||
apiVersions = append(apiVersions, "v1")
|
|
||||||
}
|
|
||||||
// Run the tunnel.
|
// Run the tunnel.
|
||||||
healthzChecks := []healthz.HealthzChecker{}
|
healthzChecks := []healthz.HealthzChecker{}
|
||||||
if m.tunneler != nil {
|
if m.tunneler != nil {
|
||||||
@ -180,12 +172,24 @@ func (m *Master) InstallAPIs(c *Config) {
|
|||||||
|
|
||||||
// TODO(nikhiljindal): Refactor generic parts of support services (like /versions) to genericapiserver.
|
// TODO(nikhiljindal): Refactor generic parts of support services (like /versions) to genericapiserver.
|
||||||
apiserver.InstallSupport(m.MuxHelper, m.RootWebService, c.EnableProfiling, healthzChecks...)
|
apiserver.InstallSupport(m.MuxHelper, m.RootWebService, c.EnableProfiling, healthzChecks...)
|
||||||
|
|
||||||
|
// Install v1 unless disabled.
|
||||||
|
if !m.ApiGroupVersionOverrides["api/v1"].Disable {
|
||||||
|
// Install v1 API.
|
||||||
|
m.initV1ResourcesStorage(c)
|
||||||
|
apiGroupInfo := genericapiserver.APIGroupInfo{
|
||||||
|
GroupMeta: *latest.GroupOrDie(api.GroupName),
|
||||||
|
VersionedResourcesStorageMap: map[string]map[string]rest.Storage{
|
||||||
|
"v1": m.v1ResourcesStorage,
|
||||||
|
},
|
||||||
|
IsLegacyGroup: true,
|
||||||
|
}
|
||||||
|
apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo)
|
||||||
|
}
|
||||||
|
|
||||||
// Install root web services
|
// Install root web services
|
||||||
m.HandlerContainer.Add(m.RootWebService)
|
m.HandlerContainer.Add(m.RootWebService)
|
||||||
|
|
||||||
apiserver.AddApiWebService(m.HandlerContainer, c.APIPrefix, apiVersions)
|
|
||||||
apiserver.InstallServiceErrorHandler(m.HandlerContainer, m.NewRequestInfoResolver(), apiVersions)
|
|
||||||
|
|
||||||
// allGroups records all supported groups at /apis
|
// allGroups records all supported groups at /apis
|
||||||
allGroups := []unversioned.APIGroup{}
|
allGroups := []unversioned.APIGroup{}
|
||||||
// Install extensions unless disabled.
|
// Install extensions unless disabled.
|
||||||
@ -193,33 +197,41 @@ func (m *Master) InstallAPIs(c *Config) {
|
|||||||
m.thirdPartyStorage = c.StorageDestinations.APIGroups[extensions.GroupName].Default
|
m.thirdPartyStorage = c.StorageDestinations.APIGroups[extensions.GroupName].Default
|
||||||
m.thirdPartyResources = map[string]thirdPartyEntry{}
|
m.thirdPartyResources = map[string]thirdPartyEntry{}
|
||||||
|
|
||||||
expVersion := m.experimental(c)
|
extensionResources := m.getExtensionResources(c)
|
||||||
|
extensionsGroupMeta := latest.GroupOrDie(extensions.GroupName)
|
||||||
if err := expVersion.InstallREST(m.HandlerContainer); err != nil {
|
// Update the prefered version as per StorageVersions in the config.
|
||||||
glog.Fatalf("Unable to setup experimental api: %v", err)
|
storageVersion, found := c.StorageVersions[extensionsGroupMeta.GroupVersion.Group]
|
||||||
}
|
|
||||||
g, err := latest.Group(extensions.GroupName)
|
|
||||||
if err != nil {
|
|
||||||
glog.Fatalf("Unable to setup experimental api: %v", err)
|
|
||||||
}
|
|
||||||
expAPIVersions := []unversioned.GroupVersionForDiscovery{
|
|
||||||
{
|
|
||||||
GroupVersion: expVersion.GroupVersion.String(),
|
|
||||||
Version: expVersion.GroupVersion.Version,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
storageVersion, found := c.StorageVersions[g.GroupVersion.Group]
|
|
||||||
if !found {
|
if !found {
|
||||||
glog.Fatalf("Couldn't find storage version of group %v", g.GroupVersion.Group)
|
glog.Fatalf("Couldn't find storage version of group %v", extensionsGroupMeta.GroupVersion.Group)
|
||||||
|
}
|
||||||
|
preferedGroupVersion, err := unversioned.ParseGroupVersion(storageVersion)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("Error in parsing group version %s: %v", storageVersion, err)
|
||||||
|
}
|
||||||
|
extensionsGroupMeta.GroupVersion = preferedGroupVersion
|
||||||
|
|
||||||
|
apiGroupInfo := genericapiserver.APIGroupInfo{
|
||||||
|
GroupMeta: *extensionsGroupMeta,
|
||||||
|
VersionedResourcesStorageMap: map[string]map[string]rest.Storage{
|
||||||
|
"v1beta1": extensionResources,
|
||||||
|
},
|
||||||
|
OptionsExternalVersion: &latest.GroupOrDie(api.GroupName).GroupVersion,
|
||||||
|
}
|
||||||
|
apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo)
|
||||||
|
|
||||||
|
extensionsGVForDiscovery := unversioned.GroupVersionForDiscovery{
|
||||||
|
GroupVersion: extensionsGroupMeta.GroupVersion.String(),
|
||||||
|
Version: extensionsGroupMeta.GroupVersion.Version,
|
||||||
}
|
}
|
||||||
group := unversioned.APIGroup{
|
group := unversioned.APIGroup{
|
||||||
Name: g.GroupVersion.Group,
|
Name: extensionsGroupMeta.GroupVersion.Group,
|
||||||
Versions: expAPIVersions,
|
Versions: []unversioned.GroupVersionForDiscovery{extensionsGVForDiscovery},
|
||||||
PreferredVersion: unversioned.GroupVersionForDiscovery{GroupVersion: storageVersion, Version: apiutil.GetVersion(storageVersion)},
|
PreferredVersion: extensionsGVForDiscovery,
|
||||||
}
|
}
|
||||||
apiserver.AddGroupWebService(m.HandlerContainer, c.APIGroupPrefix+"/"+latest.GroupOrDie(extensions.GroupName).GroupVersion.Group, group)
|
|
||||||
allGroups = append(allGroups, group)
|
allGroups = append(allGroups, group)
|
||||||
apiserver.InstallServiceErrorHandler(m.HandlerContainer, m.NewRequestInfoResolver(), []string{expVersion.GroupVersion.String()})
|
}
|
||||||
|
if err := m.InstallAPIGroups(apiGroupsInfo); err != nil {
|
||||||
|
glog.Fatalf("Error in registering group versions: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should be done after all groups are registered
|
// This should be done after all groups are registered
|
||||||
@ -398,39 +410,6 @@ func (m *Master) getServersToValidate(c *Config) map[string]apiserver.Server {
|
|||||||
return serversToValidate
|
return serversToValidate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Master) defaultAPIGroupVersion() *apiserver.APIGroupVersion {
|
|
||||||
return &apiserver.APIGroupVersion{
|
|
||||||
Root: m.ApiPrefix,
|
|
||||||
RequestInfoResolver: m.NewRequestInfoResolver(),
|
|
||||||
|
|
||||||
Mapper: latest.GroupOrDie(api.GroupName).RESTMapper,
|
|
||||||
|
|
||||||
Creater: api.Scheme,
|
|
||||||
Convertor: api.Scheme,
|
|
||||||
Typer: api.Scheme,
|
|
||||||
Linker: latest.GroupOrDie(api.GroupName).SelfLinker,
|
|
||||||
|
|
||||||
Admit: m.AdmissionControl,
|
|
||||||
Context: m.RequestContextMapper,
|
|
||||||
|
|
||||||
MinRequestTimeout: m.MinRequestTimeout,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// api_v1 returns the resources and codec for API version v1.
|
|
||||||
func (m *Master) api_v1(c *Config) *apiserver.APIGroupVersion {
|
|
||||||
m.initV1ResourcesStorage(c)
|
|
||||||
storage := make(map[string]rest.Storage)
|
|
||||||
for k, v := range m.v1ResourcesStorage {
|
|
||||||
storage[strings.ToLower(k)] = v
|
|
||||||
}
|
|
||||||
version := m.defaultAPIGroupVersion()
|
|
||||||
version.Storage = storage
|
|
||||||
version.GroupVersion = unversioned.GroupVersion{Version: "v1"}
|
|
||||||
version.Codec = v1.Codec
|
|
||||||
return version
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasThirdPartyResource returns true if a particular third party resource currently installed.
|
// HasThirdPartyResource returns true if a particular third party resource currently installed.
|
||||||
func (m *Master) HasThirdPartyResource(rsrc *extensions.ThirdPartyResource) (bool, error) {
|
func (m *Master) HasThirdPartyResource(rsrc *extensions.ThirdPartyResource) (bool, error) {
|
||||||
_, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind(rsrc)
|
_, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind(rsrc)
|
||||||
@ -575,8 +554,8 @@ func (m *Master) thirdpartyapi(group, kind, version string) *apiserver.APIGroupV
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// experimental returns the resources and codec for the experimental api
|
// getExperimentalResources returns the resources for extenstions api
|
||||||
func (m *Master) experimental(c *Config) *apiserver.APIGroupVersion {
|
func (m *Master) getExtensionResources(c *Config) map[string]rest.Storage {
|
||||||
// All resources except these are disabled by default.
|
// All resources except these are disabled by default.
|
||||||
enabledResources := sets.NewString("jobs", "horizontalpodautoscalers", "ingresses")
|
enabledResources := sets.NewString("jobs", "horizontalpodautoscalers", "ingresses")
|
||||||
resourceOverrides := m.ApiGroupVersionOverrides["extensions/v1beta1"].ResourceOverrides
|
resourceOverrides := m.ApiGroupVersionOverrides["extensions/v1beta1"].ResourceOverrides
|
||||||
@ -640,30 +619,7 @@ func (m *Master) experimental(c *Config) *apiserver.APIGroupVersion {
|
|||||||
storage["ingresses"] = ingressStorage
|
storage["ingresses"] = ingressStorage
|
||||||
storage["ingresses/status"] = ingressStatusStorage
|
storage["ingresses/status"] = ingressStatusStorage
|
||||||
}
|
}
|
||||||
|
return storage
|
||||||
extensionsGroup := latest.GroupOrDie(extensions.GroupName)
|
|
||||||
optionsExternalVersion := latest.GroupOrDie(api.GroupName).GroupVersion
|
|
||||||
|
|
||||||
return &apiserver.APIGroupVersion{
|
|
||||||
Root: m.ApiGroupPrefix,
|
|
||||||
RequestInfoResolver: m.NewRequestInfoResolver(),
|
|
||||||
|
|
||||||
Creater: api.Scheme,
|
|
||||||
Convertor: api.Scheme,
|
|
||||||
Typer: api.Scheme,
|
|
||||||
|
|
||||||
Mapper: extensionsGroup.RESTMapper,
|
|
||||||
Codec: extensionsGroup.Codec,
|
|
||||||
Linker: extensionsGroup.SelfLinker,
|
|
||||||
Storage: storage,
|
|
||||||
GroupVersion: extensionsGroup.GroupVersion,
|
|
||||||
OptionsExternalVersion: &optionsExternalVersion,
|
|
||||||
|
|
||||||
Admit: m.AdmissionControl,
|
|
||||||
Context: m.RequestContextMapper,
|
|
||||||
|
|
||||||
MinRequestTimeout: m.MinRequestTimeout,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// findExternalAddress returns ExternalIP of provided node with fallback to LegacyHostIP.
|
// findExternalAddress returns ExternalIP of provided node with fallback to LegacyHostIP.
|
||||||
|
@ -30,11 +30,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/latest"
|
|
||||||
"k8s.io/kubernetes/pkg/api/testapi"
|
"k8s.io/kubernetes/pkg/api/testapi"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
apiutil "k8s.io/kubernetes/pkg/api/util"
|
apiutil "k8s.io/kubernetes/pkg/api/util"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/client"
|
"k8s.io/kubernetes/pkg/kubelet/client"
|
||||||
@ -102,8 +100,8 @@ 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(master.enableCoreControllers, config.EnableCoreControllers)
|
assert.Equal(master.enableCoreControllers, config.EnableCoreControllers)
|
||||||
assert.Equal(master.tunneler, config.Tunneler)
|
assert.Equal(master.tunneler, config.Tunneler)
|
||||||
assert.Equal(master.ApiPrefix, config.APIPrefix)
|
assert.Equal(master.APIPrefix, config.APIPrefix)
|
||||||
assert.Equal(master.ApiGroupPrefix, config.APIGroupPrefix)
|
assert.Equal(master.APIGroupPrefix, config.APIGroupPrefix)
|
||||||
assert.Equal(master.ApiGroupVersionOverrides, config.APIGroupVersionOverrides)
|
assert.Equal(master.ApiGroupVersionOverrides, config.APIGroupVersionOverrides)
|
||||||
assert.Equal(master.RequestContextMapper, config.RequestContextMapper)
|
assert.Equal(master.RequestContextMapper, config.RequestContextMapper)
|
||||||
assert.Equal(master.MasterCount, config.MasterCount)
|
assert.Equal(master.MasterCount, config.MasterCount)
|
||||||
@ -160,35 +158,6 @@ func TestFindExternalAddress(t *testing.T) {
|
|||||||
assert.Error(err, "expected findExternalAddress to fail on a node with missing ip information")
|
assert.Error(err, "expected findExternalAddress to fail on a node with missing ip information")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestApi_v1 verifies that the unexported api_v1 function does indeed
|
|
||||||
// utilize the correct Version and Codec.
|
|
||||||
func TestApi_v1(t *testing.T) {
|
|
||||||
_, etcdserver, config, assert := setUp(t)
|
|
||||||
defer etcdserver.Terminate(t)
|
|
||||||
|
|
||||||
// config.KubeletClient = client.FakeKubeletClient{}
|
|
||||||
|
|
||||||
config.ProxyDialer = func(network, addr string) (net.Conn, error) { return nil, nil }
|
|
||||||
config.ProxyTLSClientConfig = &tls.Config{}
|
|
||||||
|
|
||||||
s := genericapiserver.New(config.Config)
|
|
||||||
master := &Master{
|
|
||||||
GenericAPIServer: s,
|
|
||||||
tunneler: config.Tunneler,
|
|
||||||
}
|
|
||||||
|
|
||||||
version := master.api_v1(&config)
|
|
||||||
assert.Equal(unversioned.GroupVersion{Version: "v1"}, version.GroupVersion, "Version was not v1: %s", version.GroupVersion)
|
|
||||||
assert.Equal(v1.Codec, version.Codec, "version.Codec was not for v1: %s", version.Codec)
|
|
||||||
// Verify that version storage has all the resources.
|
|
||||||
for k, v := range master.v1ResourcesStorage {
|
|
||||||
k = strings.ToLower(k)
|
|
||||||
val, ok := version.Storage[k]
|
|
||||||
assert.True(ok, "ok: %s", ok)
|
|
||||||
assert.Equal(val, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestNewBootstrapController verifies master fields are properly copied into controller
|
// TestNewBootstrapController verifies master fields are properly copied into controller
|
||||||
func TestNewBootstrapController(t *testing.T) {
|
func TestNewBootstrapController(t *testing.T) {
|
||||||
// Tests a subset of inputs to ensure they are set properly in the controller
|
// Tests a subset of inputs to ensure they are set properly in the controller
|
||||||
@ -248,36 +217,6 @@ func TestControllerServicePorts(t *testing.T) {
|
|||||||
assert.Equal(1010, controller.ExtraServicePorts[1].Port)
|
assert.Equal(1010, controller.ExtraServicePorts[1].Port)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestDefaultAPIGroupVersion verifies that the unexported defaultAPIGroupVersion
|
|
||||||
// creates the expected APIGroupVersion based off of master.
|
|
||||||
func TestDefaultAPIGroupVersion(t *testing.T) {
|
|
||||||
master, etcdserver, _, assert := setUp(t)
|
|
||||||
defer etcdserver.Terminate(t)
|
|
||||||
|
|
||||||
apiGroup := master.defaultAPIGroupVersion()
|
|
||||||
|
|
||||||
assert.Equal(apiGroup.Root, master.ApiPrefix)
|
|
||||||
assert.Equal(apiGroup.Admit, master.AdmissionControl)
|
|
||||||
assert.Equal(apiGroup.Context, master.RequestContextMapper)
|
|
||||||
assert.Equal(apiGroup.MinRequestTimeout, master.MinRequestTimeout)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestExpapi verifies that the unexported exapi creates
|
|
||||||
// the an experimental unversioned.APIGroupVersion.
|
|
||||||
func TestExpapi(t *testing.T) {
|
|
||||||
master, etcdserver, config, assert := setUp(t)
|
|
||||||
defer etcdserver.Terminate(t)
|
|
||||||
|
|
||||||
extensionsGroupMeta := latest.GroupOrDie(extensions.GroupName)
|
|
||||||
|
|
||||||
expAPIGroup := master.experimental(&config)
|
|
||||||
assert.Equal(expAPIGroup.Root, master.ApiGroupPrefix)
|
|
||||||
assert.Equal(expAPIGroup.Mapper, extensionsGroupMeta.RESTMapper)
|
|
||||||
assert.Equal(expAPIGroup.Codec, extensionsGroupMeta.Codec)
|
|
||||||
assert.Equal(expAPIGroup.Linker, extensionsGroupMeta.SelfLinker)
|
|
||||||
assert.Equal(expAPIGroup.GroupVersion, extensionsGroupMeta.GroupVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestGetNodeAddresses verifies that proper results are returned
|
// TestGetNodeAddresses verifies that proper results are returned
|
||||||
// when requesting node addresses.
|
// when requesting node addresses.
|
||||||
func TestGetNodeAddresses(t *testing.T) {
|
func TestGetNodeAddresses(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user