Merge pull request #13955 from caesarxuchao/API-discovery
Auto commit by PR queue bot
This commit is contained in:
commit
6c30a0e170
@ -9,6 +9,10 @@
|
|||||||
"path": "/api",
|
"path": "/api",
|
||||||
"description": "get available API versions"
|
"description": "get available API versions"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "/apis",
|
||||||
|
"description": "get available API versions"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "/version",
|
"path": "/version",
|
||||||
"description": "git code version from which this is built"
|
"description": "git code version from which this is built"
|
||||||
|
@ -10950,6 +10950,25 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/api/v1",
|
||||||
|
"description": "API at /api/v1 version v1",
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"type": "void",
|
||||||
|
"method": "GET",
|
||||||
|
"summary": "get available resources",
|
||||||
|
"nickname": "getAPIResources",
|
||||||
|
"parameters": [],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"models": {
|
"models": {
|
||||||
|
@ -132,11 +132,14 @@ func startComponents(firstManifestURL, secondManifestURL string) (string, string
|
|||||||
// We will fix this by supporting multiple group versions in Config
|
// We will fix this by supporting multiple group versions in Config
|
||||||
cl.ExperimentalClient = client.NewExperimentalOrDie(&client.Config{Host: apiServer.URL, Version: testapi.Experimental.Version()})
|
cl.ExperimentalClient = client.NewExperimentalOrDie(&client.Config{Host: apiServer.URL, Version: testapi.Experimental.Version()})
|
||||||
|
|
||||||
|
storageVersions := make(map[string]string)
|
||||||
etcdStorage, err := master.NewEtcdStorage(etcdClient, latest.GroupOrDie("").InterfacesFor, testapi.Default.Version(), etcdtest.PathPrefix())
|
etcdStorage, err := master.NewEtcdStorage(etcdClient, latest.GroupOrDie("").InterfacesFor, testapi.Default.Version(), etcdtest.PathPrefix())
|
||||||
|
storageVersions[""] = testapi.Default.Version()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Unable to get etcd storage: %v", err)
|
glog.Fatalf("Unable to get etcd storage: %v", err)
|
||||||
}
|
}
|
||||||
expEtcdStorage, err := master.NewEtcdStorage(etcdClient, latest.GroupOrDie("experimental").InterfacesFor, testapi.Experimental.Version(), etcdtest.PathPrefix())
|
expEtcdStorage, err := master.NewEtcdStorage(etcdClient, latest.GroupOrDie("experimental").InterfacesFor, testapi.Experimental.Version(), etcdtest.PathPrefix())
|
||||||
|
storageVersions["experimental"] = testapi.Experimental.Version()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Unable to get etcd storage for experimental: %v", err)
|
glog.Fatalf("Unable to get etcd storage for experimental: %v", err)
|
||||||
}
|
}
|
||||||
@ -171,6 +174,7 @@ func startComponents(firstManifestURL, secondManifestURL string) (string, string
|
|||||||
ReadWritePort: portNumber,
|
ReadWritePort: portNumber,
|
||||||
PublicAddress: publicAddress,
|
PublicAddress: publicAddress,
|
||||||
CacheTimeout: 2 * time.Second,
|
CacheTimeout: 2 * time.Second,
|
||||||
|
StorageVersions: storageVersions,
|
||||||
})
|
})
|
||||||
handler.delegate = m.Handler
|
handler.delegate = m.Handler
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -245,7 +246,10 @@ func (s *APIServer) verifyClusterIPFlags() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newEtcd(etcdConfigFile string, etcdServerList []string, interfacesFunc meta.VersionInterfacesFunc, defaultVersion, storageVersion, pathPrefix string) (etcdStorage storage.Interface, err error) {
|
func newEtcd(etcdConfigFile string, etcdServerList []string, interfacesFunc meta.VersionInterfacesFunc, storageVersion, pathPrefix string) (etcdStorage storage.Interface, err error) {
|
||||||
|
if storageVersion == "" {
|
||||||
|
return etcdStorage, fmt.Errorf("storageVersion is required to create a etcd storage")
|
||||||
|
}
|
||||||
var client tools.EtcdClient
|
var client tools.EtcdClient
|
||||||
if etcdConfigFile != "" {
|
if etcdConfigFile != "" {
|
||||||
client, err = etcd.NewClientFromFile(etcdConfigFile)
|
client, err = etcd.NewClientFromFile(etcdConfigFile)
|
||||||
@ -264,11 +268,8 @@ func newEtcd(etcdConfigFile string, etcdServerList []string, interfacesFunc meta
|
|||||||
etcdClient.SetTransport(transport)
|
etcdClient.SetTransport(transport)
|
||||||
client = etcdClient
|
client = etcdClient
|
||||||
}
|
}
|
||||||
|
etcdStorage, err = master.NewEtcdStorage(client, interfacesFunc, storageVersion, pathPrefix)
|
||||||
if storageVersion == "" {
|
return etcdStorage, err
|
||||||
storageVersion = defaultVersion
|
|
||||||
}
|
|
||||||
return master.NewEtcdStorage(client, interfacesFunc, storageVersion, pathPrefix)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run runs the specified APIServer. This should never exit.
|
// Run runs the specified APIServer. This should never exit.
|
||||||
@ -341,7 +342,16 @@ func (s *APIServer) Run(_ []string) error {
|
|||||||
glog.Fatalf("Invalid server address: %v", err)
|
glog.Fatalf("Invalid server address: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
etcdStorage, err := newEtcd(s.EtcdConfigFile, s.EtcdServerList, latest.GroupOrDie("").InterfacesFor, latest.GroupOrDie("").Version, s.StorageVersion, s.EtcdPathPrefix)
|
g, err := latest.Group("")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
storageVersions := make(map[string]string)
|
||||||
|
if s.StorageVersion == "" {
|
||||||
|
s.StorageVersion = g.Version
|
||||||
|
}
|
||||||
|
etcdStorage, err := newEtcd(s.EtcdConfigFile, s.EtcdServerList, g.InterfacesFor, s.StorageVersion, s.EtcdPathPrefix)
|
||||||
|
storageVersions[""] = s.StorageVersion
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Invalid storage version or misconfigured etcd: %v", err)
|
glog.Fatalf("Invalid storage version or misconfigured etcd: %v", err)
|
||||||
}
|
}
|
||||||
@ -352,10 +362,14 @@ func (s *APIServer) Run(_ []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("experimental API is enabled in runtime config, but not enabled in the environment variable KUBE_API_VERSIONS. Error: %v", err)
|
glog.Fatalf("experimental API is enabled in runtime config, but not enabled in the environment variable KUBE_API_VERSIONS. Error: %v", err)
|
||||||
}
|
}
|
||||||
expEtcdStorage, err = newEtcd(s.EtcdConfigFile, s.EtcdServerList, g.InterfacesFor, g.Version, s.ExpStorageVersion, s.EtcdPathPrefix)
|
if s.ExpStorageVersion == "" {
|
||||||
|
s.ExpStorageVersion = g.Version
|
||||||
|
}
|
||||||
|
expEtcdStorage, err = newEtcd(s.EtcdConfigFile, s.EtcdServerList, g.InterfacesFor, s.ExpStorageVersion, s.EtcdPathPrefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Invalid experimental storage version or misconfigured etcd: %v", err)
|
glog.Fatalf("Invalid experimental storage version or misconfigured etcd: %v", err)
|
||||||
}
|
}
|
||||||
|
storageVersions["experimental"] = s.StorageVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
n := s.ServiceClusterIPRange
|
n := s.ServiceClusterIPRange
|
||||||
@ -427,6 +441,7 @@ func (s *APIServer) Run(_ []string) error {
|
|||||||
config := &master.Config{
|
config := &master.Config{
|
||||||
DatabaseStorage: etcdStorage,
|
DatabaseStorage: etcdStorage,
|
||||||
ExpDatabaseStorage: expEtcdStorage,
|
ExpDatabaseStorage: expEtcdStorage,
|
||||||
|
StorageVersions: storageVersions,
|
||||||
|
|
||||||
EventTTL: s.EventTTL,
|
EventTTL: s.EventTTL,
|
||||||
KubeletClient: kubeletClient,
|
KubeletClient: kubeletClient,
|
||||||
|
@ -22,16 +22,64 @@ import (
|
|||||||
|
|
||||||
// This file contains API types that are unversioned.
|
// This file contains API types that are unversioned.
|
||||||
|
|
||||||
// APIVersions lists the api versions that are available, to allow
|
// APIVersions lists the versions that are available, to allow clients to
|
||||||
// version negotiation. APIVersions isn't just an unnamed array of
|
// discover the API at /api, which is the root path of the legacy v1 API.
|
||||||
// strings in order to allow for future evolution, though unversioned
|
|
||||||
type APIVersions struct {
|
type APIVersions struct {
|
||||||
|
// versions are the api versions that are available.
|
||||||
Versions []string `json:"versions"`
|
Versions []string `json:"versions"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// APIGroupList is a list of APIGroup, to allow clients to discover the API at
|
||||||
|
// /apis.
|
||||||
|
type APIGroupList struct {
|
||||||
|
// groups is a list of APIGroup.
|
||||||
|
Groups []APIGroup `json:"groups"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIGroup contains the name, the supported versions, and the preferred version
|
||||||
|
// of a group.
|
||||||
|
type APIGroup struct {
|
||||||
|
// name is the name of the group.
|
||||||
|
Name string `json:"name"`
|
||||||
|
// versions are the versions supported in this group.
|
||||||
|
Versions []GroupVersion `json:"versions"`
|
||||||
|
// preferredVersion is the version preferred by the API server, which
|
||||||
|
// probably is the storage version.
|
||||||
|
PreferredVersion GroupVersion `json:"preferredVersion,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupVersion contains the "group/version" and "version" string of a version.
|
||||||
|
// It is made a struct to keep extensiblity.
|
||||||
|
type GroupVersion struct {
|
||||||
|
// groupVersion specifies the API group and version in the form "group/version"
|
||||||
|
GroupVersion string `json:"groupVersion"`
|
||||||
|
// version specifies the version in the form of "version". This is to save
|
||||||
|
// the clients the trouble of splitting the GroupVersion.
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIResource specifies the name of a resource and whether it is namespaced.
|
||||||
|
type APIResource struct {
|
||||||
|
// name is the name of the resource.
|
||||||
|
Name string `json:"name"`
|
||||||
|
// namespaced indicates if a resource is namespaced or not.
|
||||||
|
Namespaced bool `json:"namespaced"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIResourceList is a list of APIResource, it is used to expose the name of the
|
||||||
|
// resources supported in a specific group and version, and if the resource
|
||||||
|
// is namespaced.
|
||||||
|
type APIResourceList struct {
|
||||||
|
// groupVersion is the group and version this APIResourceList is for.
|
||||||
|
GroupVersion string `json:"groupVersion"`
|
||||||
|
// resources contains the name of the resources and if they are namespaced.
|
||||||
|
APIResources []APIResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
// RootPaths lists the paths available at root.
|
// RootPaths lists the paths available at root.
|
||||||
// For example: "/healthz", "/api".
|
// For example: "/healthz", "/apis".
|
||||||
type RootPaths struct {
|
type RootPaths struct {
|
||||||
|
// paths are the paths available at root.
|
||||||
Paths []string `json:"paths"`
|
Paths []string `json:"paths"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,6 +168,7 @@ type ThirdPartyResourceList struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// An APIVersion represents a single concrete version of an object model.
|
// An APIVersion represents a single concrete version of an object model.
|
||||||
|
// TODO: we should consider merge this struct with GroupVersion in unversioned.go
|
||||||
type APIVersion struct {
|
type APIVersion struct {
|
||||||
// Name of this version (e.g. 'v1').
|
// Name of this version (e.g. 'v1').
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
|
@ -61,8 +61,8 @@ type documentable interface {
|
|||||||
var errEmptyName = errors.NewBadRequest("name must be provided")
|
var errEmptyName = errors.NewBadRequest("name must be provided")
|
||||||
|
|
||||||
// Installs handlers for API resources.
|
// Installs handlers for API resources.
|
||||||
func (a *APIInstaller) Install(ws *restful.WebService) []error {
|
func (a *APIInstaller) Install(ws *restful.WebService) (apiResources []api.APIResource, errors []error) {
|
||||||
errors := make([]error, 0)
|
errors = make([]error, 0)
|
||||||
|
|
||||||
proxyHandler := (&ProxyHandler{a.prefix + "/proxy/", a.group.Storage, a.group.Codec, a.group.Context, a.info, a.proxyDialerFn})
|
proxyHandler := (&ProxyHandler{a.prefix + "/proxy/", a.group.Storage, a.group.Codec, a.group.Context, a.info, a.proxyDialerFn})
|
||||||
|
|
||||||
@ -75,11 +75,15 @@ func (a *APIInstaller) Install(ws *restful.WebService) []error {
|
|||||||
}
|
}
|
||||||
sort.Strings(paths)
|
sort.Strings(paths)
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
if err := a.registerResourceHandlers(path, a.group.Storage[path], ws, proxyHandler); err != nil {
|
apiResource, err := a.registerResourceHandlers(path, a.group.Storage[path], ws, proxyHandler)
|
||||||
|
if err != nil {
|
||||||
errors = append(errors, err)
|
errors = append(errors, err)
|
||||||
}
|
}
|
||||||
|
if apiResource != nil {
|
||||||
|
apiResources = append(apiResources, *apiResource)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return errors
|
return apiResources, errors
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWebService creates a new restful webservice with the api installer's prefix and version.
|
// NewWebService creates a new restful webservice with the api installer's prefix and version.
|
||||||
@ -95,7 +99,7 @@ func (a *APIInstaller) NewWebService() *restful.WebService {
|
|||||||
return ws
|
return ws
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storage, ws *restful.WebService, proxyHandler http.Handler) error {
|
func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storage, ws *restful.WebService, proxyHandler http.Handler) (*api.APIResource, error) {
|
||||||
admit := a.group.Admit
|
admit := a.group.Admit
|
||||||
context := a.group.Context
|
context := a.group.Context
|
||||||
|
|
||||||
@ -112,40 +116,40 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
resource = parts[0]
|
resource = parts[0]
|
||||||
default:
|
default:
|
||||||
// TODO: support deeper paths
|
// TODO: support deeper paths
|
||||||
return fmt.Errorf("api_installer allows only one or two segment paths (resource or resource/subresource)")
|
return nil, fmt.Errorf("api_installer allows only one or two segment paths (resource or resource/subresource)")
|
||||||
}
|
}
|
||||||
hasSubresource := len(subresource) > 0
|
hasSubresource := len(subresource) > 0
|
||||||
|
|
||||||
object := storage.New()
|
object := storage.New()
|
||||||
_, kind, err := a.group.Typer.ObjectVersionAndKind(object)
|
_, kind, err := a.group.Typer.ObjectVersionAndKind(object)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
versionedPtr, err := a.group.Creater.New(a.group.Version, kind)
|
versionedPtr, err := a.group.Creater.New(a.group.Version, kind)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
versionedObject := indirectArbitraryPointer(versionedPtr)
|
versionedObject := indirectArbitraryPointer(versionedPtr)
|
||||||
|
|
||||||
mapping, err := a.group.Mapper.RESTMapping(kind, a.group.Version)
|
mapping, err := a.group.Mapper.RESTMapping(kind, a.group.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// subresources must have parent resources, and follow the namespacing rules of their parent
|
// subresources must have parent resources, and follow the namespacing rules of their parent
|
||||||
if hasSubresource {
|
if hasSubresource {
|
||||||
parentStorage, ok := a.group.Storage[resource]
|
parentStorage, ok := a.group.Storage[resource]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("subresources can only be declared when the parent is also registered: %s needs %s", path, resource)
|
return nil, fmt.Errorf("subresources can only be declared when the parent is also registered: %s needs %s", path, resource)
|
||||||
}
|
}
|
||||||
parentObject := parentStorage.New()
|
parentObject := parentStorage.New()
|
||||||
_, parentKind, err := a.group.Typer.ObjectVersionAndKind(parentObject)
|
_, parentKind, err := a.group.Typer.ObjectVersionAndKind(parentObject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
parentMapping, err := a.group.Mapper.RESTMapping(parentKind, a.group.Version)
|
parentMapping, err := a.group.Mapper.RESTMapping(parentKind, a.group.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
mapping.Scope = parentMapping.Scope
|
mapping.Scope = parentMapping.Scope
|
||||||
}
|
}
|
||||||
@ -178,14 +182,14 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
_, listKind, err := a.group.Typer.ObjectVersionAndKind(list)
|
_, listKind, err := a.group.Typer.ObjectVersionAndKind(list)
|
||||||
versionedListPtr, err := a.group.Creater.New(a.group.Version, listKind)
|
versionedListPtr, err := a.group.Creater.New(a.group.Version, listKind)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
versionedList = indirectArbitraryPointer(versionedListPtr)
|
versionedList = indirectArbitraryPointer(versionedListPtr)
|
||||||
}
|
}
|
||||||
|
|
||||||
versionedListOptions, err := a.group.Creater.New(serverVersion, "ListOptions")
|
versionedListOptions, err := a.group.Creater.New(serverVersion, "ListOptions")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var versionedDeleterObject interface{}
|
var versionedDeleterObject interface{}
|
||||||
@ -193,7 +197,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
case isGracefulDeleter:
|
case isGracefulDeleter:
|
||||||
objectPtr, err := a.group.Creater.New(serverVersion, "DeleteOptions")
|
objectPtr, err := a.group.Creater.New(serverVersion, "DeleteOptions")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
versionedDeleterObject = indirectArbitraryPointer(objectPtr)
|
versionedDeleterObject = indirectArbitraryPointer(objectPtr)
|
||||||
isDeleter = true
|
isDeleter = true
|
||||||
@ -203,7 +207,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
|
|
||||||
versionedStatusPtr, err := a.group.Creater.New(serverVersion, "Status")
|
versionedStatusPtr, err := a.group.Creater.New(serverVersion, "Status")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
versionedStatus := indirectArbitraryPointer(versionedStatusPtr)
|
versionedStatus := indirectArbitraryPointer(versionedStatusPtr)
|
||||||
var (
|
var (
|
||||||
@ -217,11 +221,11 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
getOptions, getSubpath, getSubpathKey = getterWithOptions.NewGetOptions()
|
getOptions, getSubpath, getSubpathKey = getterWithOptions.NewGetOptions()
|
||||||
_, getOptionsKind, err = a.group.Typer.ObjectVersionAndKind(getOptions)
|
_, getOptionsKind, err = a.group.Typer.ObjectVersionAndKind(getOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
versionedGetOptions, err = a.group.Creater.New(serverVersion, getOptionsKind)
|
versionedGetOptions, err = a.group.Creater.New(serverVersion, getOptionsKind)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
isGetter = true
|
isGetter = true
|
||||||
}
|
}
|
||||||
@ -238,7 +242,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
if connectOptions != nil {
|
if connectOptions != nil {
|
||||||
_, connectOptionsKind, err = a.group.Typer.ObjectVersionAndKind(connectOptions)
|
_, connectOptionsKind, err = a.group.Typer.ObjectVersionAndKind(connectOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
versionedConnectOptions, err = a.group.Creater.New(serverVersion, connectOptionsKind)
|
versionedConnectOptions, err = a.group.Creater.New(serverVersion, connectOptionsKind)
|
||||||
}
|
}
|
||||||
@ -262,6 +266,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
params := []*restful.Parameter{}
|
params := []*restful.Parameter{}
|
||||||
actions := []action{}
|
actions := []action{}
|
||||||
|
|
||||||
|
var apiResource api.APIResource
|
||||||
// Get the list of actions for the given scope.
|
// Get the list of actions for the given scope.
|
||||||
switch scope.Name() {
|
switch scope.Name() {
|
||||||
case meta.RESTScopeNameRoot:
|
case meta.RESTScopeNameRoot:
|
||||||
@ -276,6 +281,8 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
resourcePath = itemPath
|
resourcePath = itemPath
|
||||||
resourceParams = nameParams
|
resourceParams = nameParams
|
||||||
}
|
}
|
||||||
|
apiResource.Name = path
|
||||||
|
apiResource.Namespaced = false
|
||||||
namer := rootScopeNaming{scope, a.group.Linker, gpath.Join(a.prefix, itemPath)}
|
namer := rootScopeNaming{scope, a.group.Linker, gpath.Join(a.prefix, itemPath)}
|
||||||
|
|
||||||
// Handler for standard REST verbs (GET, PUT, POST and DELETE).
|
// Handler for standard REST verbs (GET, PUT, POST and DELETE).
|
||||||
@ -314,6 +321,8 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
resourcePath = itemPath
|
resourcePath = itemPath
|
||||||
resourceParams = nameParams
|
resourceParams = nameParams
|
||||||
}
|
}
|
||||||
|
apiResource.Name = path
|
||||||
|
apiResource.Namespaced = true
|
||||||
namer := scopeNaming{scope, a.group.Linker, gpath.Join(a.prefix, itemPath), false}
|
namer := scopeNaming{scope, a.group.Linker, gpath.Join(a.prefix, itemPath), false}
|
||||||
|
|
||||||
actions = appendIf(actions, action{"LIST", resourcePath, resourceParams, namer}, isLister)
|
actions = appendIf(actions, action{"LIST", resourcePath, resourceParams, namer}, isLister)
|
||||||
@ -344,7 +353,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported restscope: %s", scope.Name())
|
return nil, fmt.Errorf("unsupported restscope: %s", scope.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Routes for the actions.
|
// Create Routes for the actions.
|
||||||
@ -404,7 +413,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
Writes(versionedObject)
|
Writes(versionedObject)
|
||||||
if isGetterWithOptions {
|
if isGetterWithOptions {
|
||||||
if err := addObjectParams(ws, route, versionedGetOptions); err != nil {
|
if err := addObjectParams(ws, route, versionedGetOptions); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addParams(route, action.Params)
|
addParams(route, action.Params)
|
||||||
@ -423,7 +432,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
Returns(http.StatusOK, "OK", versionedList).
|
Returns(http.StatusOK, "OK", versionedList).
|
||||||
Writes(versionedList)
|
Writes(versionedList)
|
||||||
if err := addObjectParams(ws, route, versionedListOptions); err != nil {
|
if err := addObjectParams(ws, route, versionedListOptions); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
case isLister && isWatcher:
|
case isLister && isWatcher:
|
||||||
@ -529,7 +538,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
Returns(http.StatusOK, "OK", watchjson.WatchEvent{}).
|
Returns(http.StatusOK, "OK", watchjson.WatchEvent{}).
|
||||||
Writes(watchjson.WatchEvent{})
|
Writes(watchjson.WatchEvent{})
|
||||||
if err := addObjectParams(ws, route, versionedListOptions); err != nil {
|
if err := addObjectParams(ws, route, versionedListOptions); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
addParams(route, action.Params)
|
addParams(route, action.Params)
|
||||||
ws.Route(route)
|
ws.Route(route)
|
||||||
@ -548,7 +557,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
Returns(http.StatusOK, "OK", watchjson.WatchEvent{}).
|
Returns(http.StatusOK, "OK", watchjson.WatchEvent{}).
|
||||||
Writes(watchjson.WatchEvent{})
|
Writes(watchjson.WatchEvent{})
|
||||||
if err := addObjectParams(ws, route, versionedListOptions); err != nil {
|
if err := addObjectParams(ws, route, versionedListOptions); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
addParams(route, action.Params)
|
addParams(route, action.Params)
|
||||||
ws.Route(route)
|
ws.Route(route)
|
||||||
@ -576,18 +585,18 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
Writes("string")
|
Writes("string")
|
||||||
if versionedConnectOptions != nil {
|
if versionedConnectOptions != nil {
|
||||||
if err := addObjectParams(ws, route, versionedConnectOptions); err != nil {
|
if err := addObjectParams(ws, route, versionedConnectOptions); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addParams(route, action.Params)
|
addParams(route, action.Params)
|
||||||
ws.Route(route)
|
ws.Route(route)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unrecognized action verb: %s", action.Verb)
|
return nil, fmt.Errorf("unrecognized action verb: %s", action.Verb)
|
||||||
}
|
}
|
||||||
// Note: update GetAttribs() when adding a custom handler.
|
// Note: update GetAttribs() when adding a custom handler.
|
||||||
}
|
}
|
||||||
return nil
|
return &apiResource, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// rootScopeNaming reads only names from a request and ignores namespaces. It implements ScopeNamer
|
// rootScopeNaming reads only names from a request and ignores namespaces. It implements ScopeNamer
|
||||||
|
@ -118,7 +118,9 @@ const (
|
|||||||
func (g *APIGroupVersion) InstallREST(container *restful.Container) error {
|
func (g *APIGroupVersion) InstallREST(container *restful.Container) error {
|
||||||
installer := g.newInstaller()
|
installer := g.newInstaller()
|
||||||
ws := installer.NewWebService()
|
ws := installer.NewWebService()
|
||||||
registrationErrors := installer.Install(ws)
|
apiResources, registrationErrors := installer.Install(ws)
|
||||||
|
// TODO: g.Version only contains "version" now, it will contain "group/version" in the near future.
|
||||||
|
AddSupportedResourcesWebService(ws, g.Version, apiResources)
|
||||||
container.Add(ws)
|
container.Add(ws)
|
||||||
return errors.NewAggregate(registrationErrors)
|
return errors.NewAggregate(registrationErrors)
|
||||||
}
|
}
|
||||||
@ -141,8 +143,10 @@ func (g *APIGroupVersion) UpdateREST(container *restful.Container) error {
|
|||||||
if ws == nil {
|
if ws == nil {
|
||||||
return apierrors.NewInternalError(fmt.Errorf("unable to find an existing webservice for prefix %s", installer.prefix))
|
return apierrors.NewInternalError(fmt.Errorf("unable to find an existing webservice for prefix %s", installer.prefix))
|
||||||
}
|
}
|
||||||
|
apiResources, registrationErrors := installer.Install(ws)
|
||||||
return errors.NewAggregate(installer.Install(ws))
|
// TODO: g.Version only contains "version" now, it will contain "group/version" in the near future.
|
||||||
|
AddSupportedResourcesWebService(ws, g.Version, apiResources)
|
||||||
|
return errors.NewAggregate(registrationErrors)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newInstaller is a helper to create the installer. Used by InstallREST and UpdateREST.
|
// newInstaller is a helper to create the installer. Used by InstallREST and UpdateREST.
|
||||||
@ -232,7 +236,7 @@ func serviceErrorHandler(requestResolver *APIRequestInfoResolver, apiVersions []
|
|||||||
errorJSON(apierrors.NewGenericServerResponse(serviceErr.Code, "", "", "", "", 0, false), codec, response.ResponseWriter)
|
errorJSON(apierrors.NewGenericServerResponse(serviceErr.Code, "", "", "", "", 0, false), codec, response.ResponseWriter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds a service to return the supported api versions.
|
// Adds a service to return the supported api versions at the legacy /api.
|
||||||
func AddApiWebService(container *restful.Container, apiPrefix string, versions []string) {
|
func AddApiWebService(container *restful.Container, apiPrefix string, versions []string) {
|
||||||
// TODO: InstallREST should register each version automatically
|
// TODO: InstallREST should register each version automatically
|
||||||
|
|
||||||
@ -248,6 +252,46 @@ func AddApiWebService(container *restful.Container, apiPrefix string, versions [
|
|||||||
container.Add(ws)
|
container.Add(ws)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adds a service to return the supported api versions at /apis.
|
||||||
|
func AddApisWebService(container *restful.Container, apiPrefix string, groups []api.APIGroup) {
|
||||||
|
rootAPIHandler := RootAPIHandler(groups)
|
||||||
|
ws := new(restful.WebService)
|
||||||
|
ws.Path(apiPrefix)
|
||||||
|
ws.Doc("get available API versions")
|
||||||
|
ws.Route(ws.GET("/").To(rootAPIHandler).
|
||||||
|
Doc("get available API versions").
|
||||||
|
Operation("getAPIVersions").
|
||||||
|
Produces(restful.MIME_JSON).
|
||||||
|
Consumes(restful.MIME_JSON))
|
||||||
|
container.Add(ws)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a service to return the supported versions, preferred version, and name
|
||||||
|
// of a group. E.g., a such web service will be registered at /apis/experimental.
|
||||||
|
func AddGroupWebService(container *restful.Container, path string, group api.APIGroup) {
|
||||||
|
groupHandler := GroupHandler(group)
|
||||||
|
ws := new(restful.WebService)
|
||||||
|
ws.Path(path)
|
||||||
|
ws.Doc("get information of a group")
|
||||||
|
ws.Route(ws.GET("/").To(groupHandler).
|
||||||
|
Doc("get information of a group").
|
||||||
|
Operation("getAPIGroup").
|
||||||
|
Produces(restful.MIME_JSON).
|
||||||
|
Consumes(restful.MIME_JSON))
|
||||||
|
container.Add(ws)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a service to return the supported resources, E.g., a such web service
|
||||||
|
// will be registered at /apis/experimental/v1.
|
||||||
|
func AddSupportedResourcesWebService(ws *restful.WebService, groupVersion string, apiResources []api.APIResource) {
|
||||||
|
resourceHandler := SupportedResourcesHandler(groupVersion, apiResources)
|
||||||
|
ws.Route(ws.GET("/").To(resourceHandler).
|
||||||
|
Doc("get available resources").
|
||||||
|
Operation("getAPIResources").
|
||||||
|
Produces(restful.MIME_JSON).
|
||||||
|
Consumes(restful.MIME_JSON))
|
||||||
|
}
|
||||||
|
|
||||||
// handleVersion writes the server's version information.
|
// handleVersion writes the server's version information.
|
||||||
func handleVersion(req *restful.Request, resp *restful.Response) {
|
func handleVersion(req *restful.Request, resp *restful.Response) {
|
||||||
// TODO: use restful's Response methods
|
// TODO: use restful's Response methods
|
||||||
@ -262,6 +306,31 @@ func APIVersionHandler(versions ...string) restful.RouteFunction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RootAPIHandler returns a handler which will list the provided groups and versions as available.
|
||||||
|
func RootAPIHandler(groups []api.APIGroup) restful.RouteFunction {
|
||||||
|
return func(req *restful.Request, resp *restful.Response) {
|
||||||
|
// TODO: use restful's Response methods
|
||||||
|
writeRawJSON(http.StatusOK, api.APIGroupList{Groups: groups}, resp.ResponseWriter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupHandler returns a handler which will return the api.GroupAndVersion of
|
||||||
|
// the group.
|
||||||
|
func GroupHandler(group api.APIGroup) restful.RouteFunction {
|
||||||
|
return func(req *restful.Request, resp *restful.Response) {
|
||||||
|
// TODO: use restful's Response methods
|
||||||
|
writeRawJSON(http.StatusOK, group, resp.ResponseWriter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SupportedResourcesHandler returns a handler which will list the provided resources as available.
|
||||||
|
func SupportedResourcesHandler(groupVersion string, apiResources []api.APIResource) restful.RouteFunction {
|
||||||
|
return func(req *restful.Request, resp *restful.Response) {
|
||||||
|
// TODO: use restful's Response methods
|
||||||
|
writeRawJSON(http.StatusOK, api.APIResourceList{GroupVersion: groupVersion, APIResources: apiResources}, resp.ResponseWriter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// write renders a returned runtime.Object to the response as a stream or an encoded object. If the object
|
// write renders a returned runtime.Object to the response as a stream or an encoded object. If the object
|
||||||
// returned by the response implements rest.ResourceStreamer that interface will be used to render the
|
// returned by the response implements rest.ResourceStreamer that interface will be used to render the
|
||||||
// response. The Accept header and current API version will be passed in, and the output will be copied
|
// response. The Accept header and current API version will be passed in, and the output will be copied
|
||||||
|
@ -100,9 +100,11 @@ const (
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
DatabaseStorage storage.Interface
|
DatabaseStorage storage.Interface
|
||||||
ExpDatabaseStorage storage.Interface
|
ExpDatabaseStorage storage.Interface
|
||||||
EventTTL time.Duration
|
// StorageVersions is a map between groups and their storage versions
|
||||||
NodeRegexp string
|
StorageVersions map[string]string
|
||||||
KubeletClient client.KubeletClient
|
EventTTL time.Duration
|
||||||
|
NodeRegexp string
|
||||||
|
KubeletClient client.KubeletClient
|
||||||
// allow downstream consumers to disable the core controller loops
|
// allow downstream consumers to disable the core controller loops
|
||||||
EnableCoreControllers bool
|
EnableCoreControllers bool
|
||||||
EnableLogsSupport bool
|
EnableLogsSupport bool
|
||||||
@ -570,16 +572,42 @@ func (m *Master) init(c *Config) {
|
|||||||
requestInfoResolver := &apiserver.APIRequestInfoResolver{APIPrefixes: sets.NewString(strings.TrimPrefix(defaultVersion.Root, "/")), RestMapper: defaultVersion.Mapper}
|
requestInfoResolver := &apiserver.APIRequestInfoResolver{APIPrefixes: sets.NewString(strings.TrimPrefix(defaultVersion.Root, "/")), RestMapper: defaultVersion.Mapper}
|
||||||
apiserver.InstallServiceErrorHandler(m.handlerContainer, requestInfoResolver, apiVersions)
|
apiserver.InstallServiceErrorHandler(m.handlerContainer, requestInfoResolver, apiVersions)
|
||||||
|
|
||||||
|
// allGroups records all supported groups at /apis
|
||||||
|
allGroups := []api.APIGroup{}
|
||||||
if m.exp {
|
if m.exp {
|
||||||
expVersion := m.experimental(c)
|
expVersion := m.experimental(c)
|
||||||
if err := expVersion.InstallREST(m.handlerContainer); err != nil {
|
if err := expVersion.InstallREST(m.handlerContainer); err != nil {
|
||||||
glog.Fatalf("Unable to setup experimental api: %v", err)
|
glog.Fatalf("Unable to setup experimental api: %v", err)
|
||||||
}
|
}
|
||||||
apiserver.AddApiWebService(m.handlerContainer, c.APIGroupPrefix+"/"+latest.GroupOrDie("experimental").Group+"/", []string{expVersion.Version})
|
g, err := latest.Group("experimental")
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("Unable to setup experimental api: %v", err)
|
||||||
|
}
|
||||||
|
expAPIVersions := []api.GroupVersion{
|
||||||
|
{
|
||||||
|
GroupVersion: g.Group + "/" + expVersion.Version,
|
||||||
|
Version: expVersion.Version,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
storageVersion, found := c.StorageVersions[g.Group]
|
||||||
|
if !found {
|
||||||
|
glog.Fatalf("Couldn't find storage version of group %v", g.Group)
|
||||||
|
}
|
||||||
|
group := api.APIGroup{
|
||||||
|
Name: g.Group,
|
||||||
|
Versions: expAPIVersions,
|
||||||
|
PreferredVersion: api.GroupVersion{GroupVersion: g.Group + "/" + storageVersion, Version: storageVersion},
|
||||||
|
}
|
||||||
|
apiserver.AddGroupWebService(m.handlerContainer, c.APIGroupPrefix+"/"+latest.GroupOrDie("experimental").Group+"/", group)
|
||||||
|
allGroups = append(allGroups, group)
|
||||||
expRequestInfoResolver := &apiserver.APIRequestInfoResolver{APIPrefixes: sets.NewString(strings.TrimPrefix(expVersion.Root, "/")), RestMapper: expVersion.Mapper}
|
expRequestInfoResolver := &apiserver.APIRequestInfoResolver{APIPrefixes: sets.NewString(strings.TrimPrefix(expVersion.Root, "/")), RestMapper: expVersion.Mapper}
|
||||||
apiserver.InstallServiceErrorHandler(m.handlerContainer, expRequestInfoResolver, []string{expVersion.Version})
|
apiserver.InstallServiceErrorHandler(m.handlerContainer, expRequestInfoResolver, []string{expVersion.Version})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This should be done after all groups are registered
|
||||||
|
// TODO: replace the hardcoded "apis".
|
||||||
|
apiserver.AddApisWebService(m.handlerContainer, "/apis", allGroups)
|
||||||
|
|
||||||
// Register root handler.
|
// Register root handler.
|
||||||
// We do not register this using restful Webservice since we do not want to surface this in api docs.
|
// We do not register this using restful Webservice since we do not want to surface this in api docs.
|
||||||
// Allow master to be embedded in contexts which already have something registered at the root
|
// Allow master to be embedded in contexts which already have something registered at the root
|
||||||
@ -784,7 +812,15 @@ func (m *Master) InstallThirdPartyAPI(rsrc *experimental.ThirdPartyResource) err
|
|||||||
glog.Fatalf("Unable to setup thirdparty api: %v", err)
|
glog.Fatalf("Unable to setup thirdparty api: %v", err)
|
||||||
}
|
}
|
||||||
thirdPartyAPIPrefix := makeThirdPartyPath(group) + "/"
|
thirdPartyAPIPrefix := makeThirdPartyPath(group) + "/"
|
||||||
apiserver.AddApiWebService(m.handlerContainer, thirdPartyAPIPrefix, []string{rsrc.Versions[0].Name})
|
groupVersion := api.GroupVersion{
|
||||||
|
GroupVersion: group + "/" + rsrc.Versions[0].Name,
|
||||||
|
Version: rsrc.Versions[0].Name,
|
||||||
|
}
|
||||||
|
apiGroup := api.APIGroup{
|
||||||
|
Name: group,
|
||||||
|
Versions: []api.GroupVersion{groupVersion},
|
||||||
|
}
|
||||||
|
apiserver.AddGroupWebService(m.handlerContainer, thirdPartyAPIPrefix, apiGroup)
|
||||||
thirdPartyRequestInfoResolver := &apiserver.APIRequestInfoResolver{APIPrefixes: sets.NewString(strings.TrimPrefix(group, "/")), RestMapper: thirdparty.Mapper}
|
thirdPartyRequestInfoResolver := &apiserver.APIRequestInfoResolver{APIPrefixes: sets.NewString(strings.TrimPrefix(group, "/")), RestMapper: thirdparty.Mapper}
|
||||||
apiserver.InstallServiceErrorHandler(m.handlerContainer, thirdPartyRequestInfoResolver, []string{thirdparty.Version})
|
apiserver.InstallServiceErrorHandler(m.handlerContainer, thirdPartyRequestInfoResolver, []string{thirdparty.Version})
|
||||||
return nil
|
return nil
|
||||||
|
@ -59,9 +59,12 @@ func setUp(t *testing.T) (Master, Config, *assert.Assertions) {
|
|||||||
config := Config{}
|
config := Config{}
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
fakeClient := tools.NewFakeEtcdClient(t)
|
||||||
fakeClient.Machines = []string{"http://machine1:4001", "http://machine2", "http://machine3:4003"}
|
fakeClient.Machines = []string{"http://machine1:4001", "http://machine2", "http://machine3:4003"}
|
||||||
|
storageVersions := make(map[string]string)
|
||||||
config.DatabaseStorage = etcdstorage.NewEtcdStorage(fakeClient, testapi.Default.Codec(), etcdtest.PathPrefix())
|
config.DatabaseStorage = etcdstorage.NewEtcdStorage(fakeClient, testapi.Default.Codec(), etcdtest.PathPrefix())
|
||||||
|
storageVersions[""] = testapi.Default.Version()
|
||||||
config.ExpDatabaseStorage = etcdstorage.NewEtcdStorage(fakeClient, testapi.Experimental.Codec(), etcdtest.PathPrefix())
|
config.ExpDatabaseStorage = etcdstorage.NewEtcdStorage(fakeClient, testapi.Experimental.Codec(), etcdtest.PathPrefix())
|
||||||
|
storageVersions["experimental"] = testapi.Experimental.Version()
|
||||||
|
config.StorageVersions = storageVersions
|
||||||
master.nodeRegistry = registrytest.NewNodeRegistry([]string{"node1", "node2"}, api.NodeResources{})
|
master.nodeRegistry = registrytest.NewNodeRegistry([]string{"node1", "node2"}, api.NodeResources{})
|
||||||
|
|
||||||
return master, config, assert.New(t)
|
return master, config, assert.New(t)
|
||||||
|
@ -406,6 +406,7 @@ func TestAuthModeAlwaysAllow(t *testing.T) {
|
|||||||
APIPrefix: "/api",
|
APIPrefix: "/api",
|
||||||
Authorizer: apiserver.NewAlwaysAllowAuthorizer(),
|
Authorizer: apiserver.NewAlwaysAllowAuthorizer(),
|
||||||
AdmissionControl: admit.NewAlwaysAdmit(),
|
AdmissionControl: admit.NewAlwaysAdmit(),
|
||||||
|
StorageVersions: map[string]string{"": testapi.Default.Version()},
|
||||||
})
|
})
|
||||||
|
|
||||||
transport := http.DefaultTransport
|
transport := http.DefaultTransport
|
||||||
@ -522,6 +523,7 @@ func TestAuthModeAlwaysDeny(t *testing.T) {
|
|||||||
APIPrefix: "/api",
|
APIPrefix: "/api",
|
||||||
Authorizer: apiserver.NewAlwaysDenyAuthorizer(),
|
Authorizer: apiserver.NewAlwaysDenyAuthorizer(),
|
||||||
AdmissionControl: admit.NewAlwaysAdmit(),
|
AdmissionControl: admit.NewAlwaysAdmit(),
|
||||||
|
StorageVersions: map[string]string{"": testapi.Default.Version()},
|
||||||
})
|
})
|
||||||
|
|
||||||
transport := http.DefaultTransport
|
transport := http.DefaultTransport
|
||||||
@ -590,6 +592,7 @@ func TestAliceNotForbiddenOrUnauthorized(t *testing.T) {
|
|||||||
Authenticator: getTestTokenAuth(),
|
Authenticator: getTestTokenAuth(),
|
||||||
Authorizer: allowAliceAuthorizer{},
|
Authorizer: allowAliceAuthorizer{},
|
||||||
AdmissionControl: admit.NewAlwaysAdmit(),
|
AdmissionControl: admit.NewAlwaysAdmit(),
|
||||||
|
StorageVersions: map[string]string{"": testapi.Default.Version()},
|
||||||
})
|
})
|
||||||
|
|
||||||
previousResourceVersion := make(map[string]float64)
|
previousResourceVersion := make(map[string]float64)
|
||||||
@ -677,6 +680,7 @@ func TestBobIsForbidden(t *testing.T) {
|
|||||||
Authenticator: getTestTokenAuth(),
|
Authenticator: getTestTokenAuth(),
|
||||||
Authorizer: allowAliceAuthorizer{},
|
Authorizer: allowAliceAuthorizer{},
|
||||||
AdmissionControl: admit.NewAlwaysAdmit(),
|
AdmissionControl: admit.NewAlwaysAdmit(),
|
||||||
|
StorageVersions: map[string]string{"": testapi.Default.Version()},
|
||||||
})
|
})
|
||||||
|
|
||||||
transport := http.DefaultTransport
|
transport := http.DefaultTransport
|
||||||
@ -738,6 +742,7 @@ func TestUnknownUserIsUnauthorized(t *testing.T) {
|
|||||||
Authenticator: getTestTokenAuth(),
|
Authenticator: getTestTokenAuth(),
|
||||||
Authorizer: allowAliceAuthorizer{},
|
Authorizer: allowAliceAuthorizer{},
|
||||||
AdmissionControl: admit.NewAlwaysAdmit(),
|
AdmissionControl: admit.NewAlwaysAdmit(),
|
||||||
|
StorageVersions: map[string]string{"": testapi.Default.Version()},
|
||||||
})
|
})
|
||||||
|
|
||||||
transport := http.DefaultTransport
|
transport := http.DefaultTransport
|
||||||
@ -818,6 +823,7 @@ func TestNamespaceAuthorization(t *testing.T) {
|
|||||||
Authenticator: getTestTokenAuth(),
|
Authenticator: getTestTokenAuth(),
|
||||||
Authorizer: a,
|
Authorizer: a,
|
||||||
AdmissionControl: admit.NewAlwaysAdmit(),
|
AdmissionControl: admit.NewAlwaysAdmit(),
|
||||||
|
StorageVersions: map[string]string{"": testapi.Default.Version()},
|
||||||
})
|
})
|
||||||
|
|
||||||
previousResourceVersion := make(map[string]float64)
|
previousResourceVersion := make(map[string]float64)
|
||||||
@ -933,6 +939,7 @@ func TestKindAuthorization(t *testing.T) {
|
|||||||
Authenticator: getTestTokenAuth(),
|
Authenticator: getTestTokenAuth(),
|
||||||
Authorizer: a,
|
Authorizer: a,
|
||||||
AdmissionControl: admit.NewAlwaysAdmit(),
|
AdmissionControl: admit.NewAlwaysAdmit(),
|
||||||
|
StorageVersions: map[string]string{"": testapi.Default.Version()},
|
||||||
})
|
})
|
||||||
|
|
||||||
previousResourceVersion := make(map[string]float64)
|
previousResourceVersion := make(map[string]float64)
|
||||||
@ -1035,6 +1042,7 @@ func TestReadOnlyAuthorization(t *testing.T) {
|
|||||||
Authenticator: getTestTokenAuth(),
|
Authenticator: getTestTokenAuth(),
|
||||||
Authorizer: a,
|
Authorizer: a,
|
||||||
AdmissionControl: admit.NewAlwaysAdmit(),
|
AdmissionControl: admit.NewAlwaysAdmit(),
|
||||||
|
StorageVersions: map[string]string{"": testapi.Default.Version()},
|
||||||
})
|
})
|
||||||
|
|
||||||
transport := http.DefaultTransport
|
transport := http.DefaultTransport
|
||||||
|
@ -130,11 +130,14 @@ func startMasterOrDie(masterConfig *master.Config) (*master.Master, *httptest.Se
|
|||||||
var err error
|
var err error
|
||||||
if masterConfig == nil {
|
if masterConfig == nil {
|
||||||
etcdClient := NewEtcdClient()
|
etcdClient := NewEtcdClient()
|
||||||
|
storageVersions := make(map[string]string)
|
||||||
etcdStorage, err = master.NewEtcdStorage(etcdClient, latest.GroupOrDie("").InterfacesFor, latest.GroupOrDie("").Version, etcdtest.PathPrefix())
|
etcdStorage, err = master.NewEtcdStorage(etcdClient, latest.GroupOrDie("").InterfacesFor, latest.GroupOrDie("").Version, etcdtest.PathPrefix())
|
||||||
|
storageVersions[""] = latest.GroupOrDie("").Version
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Failed to create etcd storage for master %v", err)
|
glog.Fatalf("Failed to create etcd storage for master %v", err)
|
||||||
}
|
}
|
||||||
expEtcdStorage, err := master.NewEtcdStorage(etcdClient, latest.GroupOrDie("experimental").InterfacesFor, latest.GroupOrDie("experimental").Version, etcdtest.PathPrefix())
|
expEtcdStorage, err := master.NewEtcdStorage(etcdClient, latest.GroupOrDie("experimental").InterfacesFor, latest.GroupOrDie("experimental").Version, etcdtest.PathPrefix())
|
||||||
|
storageVersions["experimental"] = latest.GroupOrDie("experimental").Version
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Failed to create etcd storage for master %v", err)
|
glog.Fatalf("Failed to create etcd storage for master %v", err)
|
||||||
}
|
}
|
||||||
@ -142,6 +145,7 @@ func startMasterOrDie(masterConfig *master.Config) (*master.Master, *httptest.Se
|
|||||||
masterConfig = &master.Config{
|
masterConfig = &master.Config{
|
||||||
DatabaseStorage: etcdStorage,
|
DatabaseStorage: etcdStorage,
|
||||||
ExpDatabaseStorage: expEtcdStorage,
|
ExpDatabaseStorage: expEtcdStorage,
|
||||||
|
StorageVersions: storageVersions,
|
||||||
KubeletClient: client.FakeKubeletClient{},
|
KubeletClient: client.FakeKubeletClient{},
|
||||||
EnableExp: true,
|
EnableExp: true,
|
||||||
EnableLogsSupport: false,
|
EnableLogsSupport: false,
|
||||||
@ -270,11 +274,14 @@ func StartPods(numPods int, host string, restClient *client.Client) error {
|
|||||||
// TODO: Merge this into startMasterOrDie.
|
// TODO: Merge this into startMasterOrDie.
|
||||||
func RunAMaster(t *testing.T) (*master.Master, *httptest.Server) {
|
func RunAMaster(t *testing.T) (*master.Master, *httptest.Server) {
|
||||||
etcdClient := NewEtcdClient()
|
etcdClient := NewEtcdClient()
|
||||||
|
storageVersions := make(map[string]string)
|
||||||
etcdStorage, err := master.NewEtcdStorage(etcdClient, latest.GroupOrDie("").InterfacesFor, testapi.Default.Version(), etcdtest.PathPrefix())
|
etcdStorage, err := master.NewEtcdStorage(etcdClient, latest.GroupOrDie("").InterfacesFor, testapi.Default.Version(), etcdtest.PathPrefix())
|
||||||
|
storageVersions[""] = testapi.Default.Version()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
expEtcdStorage, err := master.NewEtcdStorage(etcdClient, latest.GroupOrDie("experimental").InterfacesFor, latest.GroupOrDie("experimental").Version, etcdtest.PathPrefix())
|
expEtcdStorage, err := master.NewEtcdStorage(etcdClient, latest.GroupOrDie("experimental").InterfacesFor, latest.GroupOrDie("experimental").Version, etcdtest.PathPrefix())
|
||||||
|
storageVersions["experimental"] = testapi.Experimental.Version()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -291,6 +298,7 @@ func RunAMaster(t *testing.T) (*master.Master, *httptest.Server) {
|
|||||||
EnableExp: true,
|
EnableExp: true,
|
||||||
Authorizer: apiserver.NewAlwaysAllowAuthorizer(),
|
Authorizer: apiserver.NewAlwaysAllowAuthorizer(),
|
||||||
AdmissionControl: admit.NewAlwaysAdmit(),
|
AdmissionControl: admit.NewAlwaysAdmit(),
|
||||||
|
StorageVersions: storageVersions,
|
||||||
})
|
})
|
||||||
|
|
||||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
@ -75,6 +75,7 @@ func TestUnschedulableNodes(t *testing.T) {
|
|||||||
APIPrefix: "/api",
|
APIPrefix: "/api",
|
||||||
Authorizer: apiserver.NewAlwaysAllowAuthorizer(),
|
Authorizer: apiserver.NewAlwaysAllowAuthorizer(),
|
||||||
AdmissionControl: admit.NewAlwaysAdmit(),
|
AdmissionControl: admit.NewAlwaysAdmit(),
|
||||||
|
StorageVersions: map[string]string{"": testapi.Default.Version()},
|
||||||
})
|
})
|
||||||
|
|
||||||
restClient := client.NewOrDie(&client.Config{Host: s.URL, Version: testapi.Default.Version()})
|
restClient := client.NewOrDie(&client.Config{Host: s.URL, Version: testapi.Default.Version()})
|
||||||
|
@ -68,6 +68,7 @@ func TestSecrets(t *testing.T) {
|
|||||||
APIPrefix: "/api",
|
APIPrefix: "/api",
|
||||||
Authorizer: apiserver.NewAlwaysAllowAuthorizer(),
|
Authorizer: apiserver.NewAlwaysAllowAuthorizer(),
|
||||||
AdmissionControl: admit.NewAlwaysAdmit(),
|
AdmissionControl: admit.NewAlwaysAdmit(),
|
||||||
|
StorageVersions: map[string]string{"": testapi.Default.Version()},
|
||||||
})
|
})
|
||||||
|
|
||||||
framework.DeleteAllEtcdKeys()
|
framework.DeleteAllEtcdKeys()
|
||||||
|
@ -420,6 +420,7 @@ func startServiceAccountTestServer(t *testing.T) (*client.Client, client.Config,
|
|||||||
Authenticator: authenticator,
|
Authenticator: authenticator,
|
||||||
Authorizer: authorizer,
|
Authorizer: authorizer,
|
||||||
AdmissionControl: serviceAccountAdmission,
|
AdmissionControl: serviceAccountAdmission,
|
||||||
|
StorageVersions: map[string]string{"": testapi.Default.Version()},
|
||||||
})
|
})
|
||||||
|
|
||||||
// Start the service account and service account token controllers
|
// Start the service account and service account token controllers
|
||||||
|
@ -81,6 +81,7 @@ func runAMaster(t *testing.T) (*master.Master, *httptest.Server) {
|
|||||||
APIPrefix: "/api",
|
APIPrefix: "/api",
|
||||||
Authorizer: apiserver.NewAlwaysAllowAuthorizer(),
|
Authorizer: apiserver.NewAlwaysAllowAuthorizer(),
|
||||||
AdmissionControl: admit.NewAlwaysAdmit(),
|
AdmissionControl: admit.NewAlwaysAdmit(),
|
||||||
|
StorageVersions: map[string]string{"": testapi.Default.Version()},
|
||||||
})
|
})
|
||||||
|
|
||||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
Loading…
Reference in New Issue
Block a user