Merge pull request #12001 from uluyol/os-exp-hack

Add (stopgap) support for an experimental API prefix.
This commit is contained in:
Mike Danese 2015-07-31 10:15:06 -07:00
commit e58ea24d0b
31 changed files with 529 additions and 110 deletions

View File

@ -42,6 +42,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record" "github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/nodecontroller" "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/nodecontroller"
replicationControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/controller/replication" replicationControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/controller/replication"
explatest "github.com/GoogleCloudPlatform/kubernetes/pkg/expapi/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/cadvisor" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/cadvisor"
@ -132,10 +133,14 @@ func startComponents(firstManifestURL, secondManifestURL, apiVersion string) (st
cl := client.NewOrDie(&client.Config{Host: apiServer.URL, Version: apiVersion}) cl := client.NewOrDie(&client.Config{Host: apiServer.URL, Version: apiVersion})
etcdStorage, err := master.NewEtcdStorage(etcdClient, "", etcdtest.PathPrefix()) etcdStorage, err := master.NewEtcdStorage(etcdClient, latest.InterfacesFor, latest.Version, etcdtest.PathPrefix())
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, explatest.InterfacesFor, explatest.Version, etcdtest.PathPrefix())
if err != nil {
glog.Fatalf("Unable to get etcd storage for experimental: %v", err)
}
// Master // Master
host, port, err := net.SplitHostPort(strings.TrimLeft(apiServer.URL, "http://")) host, port, err := net.SplitHostPort(strings.TrimLeft(apiServer.URL, "http://"))
@ -155,11 +160,13 @@ func startComponents(firstManifestURL, secondManifestURL, apiVersion string) (st
// Create a master and install handlers into mux. // Create a master and install handlers into mux.
m := master.New(&master.Config{ m := master.New(&master.Config{
DatabaseStorage: etcdStorage, DatabaseStorage: etcdStorage,
ExpDatabaseStorage: expEtcdStorage,
KubeletClient: fakeKubeletClient{}, KubeletClient: fakeKubeletClient{},
EnableCoreControllers: true, EnableCoreControllers: true,
EnableLogsSupport: false, EnableLogsSupport: false,
EnableProfiling: true, EnableProfiling: true,
APIPrefix: "/api", APIPrefix: "/api",
ExpAPIPrefix: "/experimental",
Authorizer: apiserver.NewAlwaysAllowAuthorizer(), Authorizer: apiserver.NewAlwaysAllowAuthorizer(),
AdmissionControl: admit.NewAlwaysAdmit(), AdmissionControl: admit.NewAlwaysAdmit(),
ReadWritePort: portNumber, ReadWritePort: portNumber,

View File

@ -32,10 +32,13 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission" "github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/capabilities" "github.com/GoogleCloudPlatform/kubernetes/pkg/capabilities"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider" "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
explatest "github.com/GoogleCloudPlatform/kubernetes/pkg/expapi/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/master" "github.com/GoogleCloudPlatform/kubernetes/pkg/master"
"github.com/GoogleCloudPlatform/kubernetes/pkg/master/ports" "github.com/GoogleCloudPlatform/kubernetes/pkg/master/ports"
"github.com/GoogleCloudPlatform/kubernetes/pkg/storage" "github.com/GoogleCloudPlatform/kubernetes/pkg/storage"
@ -71,7 +74,9 @@ type APIServer struct {
TLSPrivateKeyFile string TLSPrivateKeyFile string
CertDirectory string CertDirectory string
APIPrefix string APIPrefix string
ExpAPIPrefix string
StorageVersion string StorageVersion string
ExpStorageVersion string
CloudProvider string CloudProvider string
CloudConfigFile string CloudConfigFile string
EventTTL time.Duration EventTTL time.Duration
@ -115,6 +120,7 @@ func NewAPIServer() *APIServer {
APIRate: 10.0, APIRate: 10.0,
APIBurst: 200, APIBurst: 200,
APIPrefix: "/api", APIPrefix: "/api",
ExpAPIPrefix: "/experimental",
EventTTL: 1 * time.Hour, EventTTL: 1 * time.Hour,
AuthorizationMode: "AlwaysAllow", AuthorizationMode: "AlwaysAllow",
AdmissionControl: "AlwaysAdmit", AdmissionControl: "AlwaysAdmit",
@ -172,6 +178,7 @@ func (s *APIServer) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&s.CertDirectory, "cert-dir", s.CertDirectory, "The directory where the TLS certs are located (by default /var/run/kubernetes). "+ fs.StringVar(&s.CertDirectory, "cert-dir", s.CertDirectory, "The directory where the TLS certs are located (by default /var/run/kubernetes). "+
"If --tls-cert-file and --tls-private-key-file are provided, this flag will be ignored.") "If --tls-cert-file and --tls-private-key-file are provided, this flag will be ignored.")
fs.StringVar(&s.APIPrefix, "api-prefix", s.APIPrefix, "The prefix for API requests on the server. Default '/api'.") fs.StringVar(&s.APIPrefix, "api-prefix", s.APIPrefix, "The prefix for API requests on the server. Default '/api'.")
fs.StringVar(&s.ExpAPIPrefix, "experimental-prefix", s.ExpAPIPrefix, "The prefix for experimental API requests on the server. Default '/experimental'.")
fs.StringVar(&s.StorageVersion, "storage-version", s.StorageVersion, "The version to store resources with. Defaults to server preferred") fs.StringVar(&s.StorageVersion, "storage-version", s.StorageVersion, "The version to store resources with. Defaults to server preferred")
fs.StringVar(&s.CloudProvider, "cloud-provider", s.CloudProvider, "The provider for cloud services. Empty string for no provider.") fs.StringVar(&s.CloudProvider, "cloud-provider", s.CloudProvider, "The provider for cloud services. Empty string for no provider.")
fs.StringVar(&s.CloudConfigFile, "cloud-config", s.CloudConfigFile, "The path to the cloud provider configuration file. Empty string for no configuration file.") fs.StringVar(&s.CloudConfigFile, "cloud-config", s.CloudConfigFile, "The path to the cloud provider configuration file. Empty string for no configuration file.")
@ -217,7 +224,7 @@ func (s *APIServer) verifyClusterIPFlags() {
} }
} }
func newEtcd(etcdConfigFile string, etcdServerList util.StringList, storageVersion string, pathPrefix string) (etcdStorage storage.Interface, err error) { func newEtcd(etcdConfigFile string, etcdServerList util.StringList, interfacesFunc meta.VersionInterfacesFunc, defaultVersion, storageVersion, pathPrefix string) (etcdStorage storage.Interface, err error) {
var client tools.EtcdClient var client tools.EtcdClient
if etcdConfigFile != "" { if etcdConfigFile != "" {
client, err = etcd.NewClientFromFile(etcdConfigFile) client, err = etcd.NewClientFromFile(etcdConfigFile)
@ -237,7 +244,10 @@ func newEtcd(etcdConfigFile string, etcdServerList util.StringList, storageVersi
client = etcdClient client = etcdClient
} }
return master.NewEtcdStorage(client, storageVersion, pathPrefix) if storageVersion == "" {
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.
@ -292,6 +302,10 @@ func (s *APIServer) Run(_ []string) error {
disableV1 := disableAllAPIs disableV1 := disableAllAPIs
disableV1 = !s.getRuntimeConfigValue("api/v1", !disableV1) disableV1 = !s.getRuntimeConfigValue("api/v1", !disableV1)
// "experimental/v1={true|false} allows users to enable/disable the experimental API.
// This takes preference over api/all, if specified.
enableExp := s.getRuntimeConfigValue("experimental/v1", false)
// TODO: expose same flags as client.BindClientConfigFlags but for a server // TODO: expose same flags as client.BindClientConfigFlags but for a server
clientConfig := &client.Config{ clientConfig := &client.Config{
Host: net.JoinHostPort(s.InsecureBindAddress.String(), strconv.Itoa(s.InsecurePort)), Host: net.JoinHostPort(s.InsecureBindAddress.String(), strconv.Itoa(s.InsecurePort)),
@ -302,10 +316,14 @@ 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, s.StorageVersion, s.EtcdPathPrefix) etcdStorage, err := newEtcd(s.EtcdConfigFile, s.EtcdServerList, latest.InterfacesFor, latest.Version, s.StorageVersion, s.EtcdPathPrefix)
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)
} }
expEtcdStorage, err := newEtcd(s.EtcdConfigFile, s.EtcdServerList, explatest.InterfacesFor, explatest.Version, s.ExpStorageVersion, s.EtcdPathPrefix)
if err != nil {
glog.Fatalf("Invalid experimental storage version or misconfigured etcd: %v", err)
}
n := net.IPNet(s.ServiceClusterIPRange) n := net.IPNet(s.ServiceClusterIPRange)
@ -360,7 +378,9 @@ func (s *APIServer) Run(_ []string) error {
} }
} }
config := &master.Config{ config := &master.Config{
DatabaseStorage: etcdStorage, DatabaseStorage: etcdStorage,
ExpDatabaseStorage: expEtcdStorage,
EventTTL: s.EventTTL, EventTTL: s.EventTTL,
KubeletClient: kubeletClient, KubeletClient: kubeletClient,
ServiceClusterIPRange: &n, ServiceClusterIPRange: &n,
@ -371,6 +391,7 @@ func (s *APIServer) Run(_ []string) error {
EnableProfiling: s.EnableProfiling, EnableProfiling: s.EnableProfiling,
EnableIndex: true, EnableIndex: true,
APIPrefix: s.APIPrefix, APIPrefix: s.APIPrefix,
ExpAPIPrefix: s.ExpAPIPrefix,
CorsAllowedOriginList: s.CorsAllowedOriginList, CorsAllowedOriginList: s.CorsAllowedOriginList,
ReadWritePort: s.SecurePort, ReadWritePort: s.SecurePort,
PublicAddress: net.IP(s.AdvertiseAddress), PublicAddress: net.IP(s.AdvertiseAddress),
@ -379,6 +400,7 @@ func (s *APIServer) Run(_ []string) error {
Authorizer: authorizer, Authorizer: authorizer,
AdmissionControl: admissionController, AdmissionControl: admissionController,
DisableV1: disableV1, DisableV1: disableV1,
EnableExp: enableExp,
MasterServiceNamespace: s.MasterServiceNamespace, MasterServiceNamespace: s.MasterServiceNamespace,
ClusterName: s.ClusterName, ClusterName: s.ClusterName,
ExternalHost: s.ExternalHost, ExternalHost: s.ExternalHost,

View File

@ -30,12 +30,14 @@ import (
kubeletapp "github.com/GoogleCloudPlatform/kubernetes/cmd/kubelet/app" kubeletapp "github.com/GoogleCloudPlatform/kubernetes/cmd/kubelet/app"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/nodecontroller" "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/nodecontroller"
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/servicecontroller" "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/servicecontroller"
"github.com/GoogleCloudPlatform/kubernetes/pkg/controller/replication" "github.com/GoogleCloudPlatform/kubernetes/pkg/controller/replication"
explatest "github.com/GoogleCloudPlatform/kubernetes/pkg/expapi/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/cadvisor" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/cadvisor"
kubecontainer "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/container" kubecontainer "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/container"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
@ -79,14 +81,19 @@ func (h *delegateHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
func runApiServer(etcdClient tools.EtcdClient, addr net.IP, port int, masterServiceNamespace string) { func runApiServer(etcdClient tools.EtcdClient, addr net.IP, port int, masterServiceNamespace string) {
handler := delegateHandler{} handler := delegateHandler{}
etcdStorage, err := master.NewEtcdStorage(etcdClient, "", master.DefaultEtcdPathPrefix) etcdStorage, err := master.NewEtcdStorage(etcdClient, latest.InterfacesFor, latest.Version, master.DefaultEtcdPathPrefix)
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, explatest.InterfacesFor, explatest.Version, master.DefaultEtcdPathPrefix)
if err != nil {
glog.Fatalf("Unable to get etcd storage for experimental: %v", err)
}
// Create a master and install handlers into mux. // Create a master and install handlers into mux.
m := master.New(&master.Config{ m := master.New(&master.Config{
DatabaseStorage: etcdStorage, DatabaseStorage: etcdStorage,
ExpDatabaseStorage: expEtcdStorage,
KubeletClient: &client.HTTPKubeletClient{ KubeletClient: &client.HTTPKubeletClient{
Client: http.DefaultClient, Client: http.DefaultClient,
Config: &client.KubeletConfig{Port: 10250}, Config: &client.KubeletConfig{Port: 10250},
@ -96,6 +103,7 @@ func runApiServer(etcdClient tools.EtcdClient, addr net.IP, port int, masterServ
EnableSwaggerSupport: true, EnableSwaggerSupport: true,
EnableProfiling: *enableProfiling, EnableProfiling: *enableProfiling,
APIPrefix: "/api", APIPrefix: "/api",
ExpAPIPrefix: "/experimental",
Authorizer: apiserver.NewAlwaysAllowAuthorizer(), Authorizer: apiserver.NewAlwaysAllowAuthorizer(),
ReadWritePort: port, ReadWritePort: port,

View File

@ -63,6 +63,8 @@ var RESTMapper meta.RESTMapper
// userResources is a group of resources mostly used by a kubectl user // userResources is a group of resources mostly used by a kubectl user
var userResources = []string{"rc", "svc", "pods", "pvc"} var userResources = []string{"rc", "svc", "pods", "pvc"}
const importPrefix = "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
func init() { func init() {
// Use the first API version in the list of registered versions as the latest. // Use the first API version in the list of registered versions as the latest.
Version = registered.RegisteredVersions[0] Version = registered.RegisteredVersions[0]
@ -75,28 +77,14 @@ func init() {
Versions = append(Versions, versions[i]) Versions = append(Versions, versions[i])
} }
mapper := meta.NewDefaultRESTMapper(
versions,
func(version string) (*meta.VersionInterfaces, bool) {
interfaces, err := InterfacesFor(version)
if err != nil {
return nil, false
}
return interfaces, true
},
)
// the list of kinds that are scoped at the root of the api hierarchy // the list of kinds that are scoped at the root of the api hierarchy
// if a kind is not enumerated here, it is assumed to have a namespace scope // if a kind is not enumerated here, it is assumed to have a namespace scope
kindToRootScope := map[string]bool{ rootScoped := util.NewStringSet(
"Node": true, "Node",
"Minion": true, "Minion",
"Namespace": true, "Namespace",
"PersistentVolume": true, "PersistentVolume",
} )
// setup aliases for groups of resources
mapper.AddResourceAlias("all", userResources...)
// these kinds should be excluded from the list of resources // these kinds should be excluded from the list of resources
ignoredKinds := util.NewStringSet( ignoredKinds := util.NewStringSet(
@ -107,20 +95,11 @@ func init() {
"PodExecOptions", "PodExecOptions",
"PodProxyOptions") "PodProxyOptions")
// enumerate all supported versions, get the kinds, and register with the mapper how to address our resources. mapper := api.NewDefaultRESTMapper(versions, InterfacesFor, importPrefix, ignoredKinds, rootScoped)
for _, version := range versions { // setup aliases for groups of resources
for kind := range api.Scheme.KnownTypes(version) { mapper.AddResourceAlias("all", userResources...)
if ignoredKinds.Has(kind) {
continue
}
scope := meta.RESTScopeNamespace
if kindToRootScope[kind] {
scope = meta.RESTScopeRoot
}
mapper.Add(scope, kind, version, false)
}
}
RESTMapper = mapper RESTMapper = mapper
api.RegisterRESTMapper(RESTMapper)
} }
// InterfacesFor returns the default Codec and ResourceVersioner for a given version // InterfacesFor returns the default Codec and ResourceVersioner for a given version

57
pkg/api/mapper.go Normal file
View File

@ -0,0 +1,57 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api
import (
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
var RESTMapper meta.RESTMapper
func init() {
RESTMapper = meta.MultiRESTMapper{}
}
func RegisterRESTMapper(m meta.RESTMapper) {
RESTMapper = append(RESTMapper.(meta.MultiRESTMapper), m)
}
func NewDefaultRESTMapper(versions []string, interfacesFunc meta.VersionInterfacesFunc, importPathPrefix string,
ignoredKinds, rootScoped util.StringSet) *meta.DefaultRESTMapper {
mapper := meta.NewDefaultRESTMapper(versions, interfacesFunc)
// enumerate all supported versions, get the kinds, and register with the mapper how to address our resources.
for _, version := range versions {
for kind, oType := range Scheme.KnownTypes(version) {
// TODO: Remove import path prefix check.
// We check the import path prefix because we currently stuff both "api" and "experimental" objects
// into the same group within Scheme since Scheme has no notion of groups yet.
if !strings.HasPrefix(oType.PkgPath(), importPathPrefix) || ignoredKinds.Has(kind) {
continue
}
scope := meta.RESTScopeNamespace
if rootScoped.Has(kind) {
scope = meta.RESTScopeRoot
}
mapper.Add(scope, kind, version, false)
}
}
return mapper
}

View File

@ -83,8 +83,8 @@ type DefaultRESTMapper struct {
} }
// VersionInterfacesFunc returns the appropriate codec, typer, and metadata accessor for a // VersionInterfacesFunc returns the appropriate codec, typer, and metadata accessor for a
// given api version, or false if no such api version exists. // given api version, or an error if no such api version exists.
type VersionInterfacesFunc func(apiVersion string) (*VersionInterfaces, bool) type VersionInterfacesFunc func(apiVersion string) (*VersionInterfaces, error)
// NewDefaultRESTMapper initializes a mapping between Kind and APIVersion // NewDefaultRESTMapper initializes a mapping between Kind and APIVersion
// to a resource name and back based on the objects in a runtime.Scheme // to a resource name and back based on the objects in a runtime.Scheme
@ -226,8 +226,8 @@ func (m *DefaultRESTMapper) RESTMapping(kind string, versions ...string) (*RESTM
return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported scope", version, kind) return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported scope", version, kind)
} }
interfaces, ok := m.interfacesFunc(version) interfaces, err := m.interfacesFunc(version)
if !ok { if err != nil {
return nil, fmt.Errorf("the provided version %q has no relevant versions", version) return nil, fmt.Errorf("the provided version %q has no relevant versions", version)
} }

View File

@ -17,6 +17,7 @@ limitations under the License.
package meta package meta
import ( import (
"errors"
"testing" "testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
@ -54,12 +55,14 @@ var validCodec = fakeCodec{}
var validAccessor = resourceAccessor{} var validAccessor = resourceAccessor{}
var validConvertor = fakeConvertor{} var validConvertor = fakeConvertor{}
func fakeInterfaces(version string) (*VersionInterfaces, bool) { func fakeInterfaces(version string) (*VersionInterfaces, error) {
return &VersionInterfaces{Codec: validCodec, ObjectConvertor: validConvertor, MetadataAccessor: validAccessor}, true return &VersionInterfaces{Codec: validCodec, ObjectConvertor: validConvertor, MetadataAccessor: validAccessor}, nil
} }
func unmatchedVersionInterfaces(version string) (*VersionInterfaces, bool) { var unmatchedErr = errors.New("no version")
return nil, false
func unmatchedVersionInterfaces(version string) (*VersionInterfaces, error) {
return nil, unmatchedErr
} }
func TestRESTMapperVersionAndKindForResource(t *testing.T) { func TestRESTMapperVersionAndKindForResource(t *testing.T) {

View File

@ -88,16 +88,7 @@ func interfacesFor(version string) (*meta.VersionInterfaces, error) {
} }
func newMapper() *meta.DefaultRESTMapper { func newMapper() *meta.DefaultRESTMapper {
return meta.NewDefaultRESTMapper( return meta.NewDefaultRESTMapper(versions, interfacesFor)
versions,
func(version string) (*meta.VersionInterfaces, bool) {
interfaces, err := interfacesFor(version)
if err != nil {
return nil, false
}
return interfaces, true
},
)
} }
func addTestTypes() { func addTestTypes() {

19
pkg/expapi/deep_copy.go Normal file
View File

@ -0,0 +1,19 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package expapi
func addDeepCopyFuncs() {}

View File

@ -0,0 +1,75 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package latest
import (
"fmt"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/registered"
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/expapi"
"github.com/GoogleCloudPlatform/kubernetes/pkg/expapi/v1"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
var (
Version string
Versions []string
accessor = meta.NewAccessor()
Codec runtime.Codec
SelfLinker = runtime.SelfLinker(accessor)
RESTMapper meta.RESTMapper
)
const importPrefix = "github.com/GoogleCloudPlatform/kubernetes/pkg/expapi"
func init() {
Version = registered.RegisteredVersions[0]
Codec = runtime.CodecFor(api.Scheme, Version)
// Put the registered versions in Versions in reverse order.
for i := len(registered.RegisteredVersions) - 1; i >= 0; i-- {
Versions = append(Versions, registered.RegisteredVersions[i])
}
// the list of kinds that are scoped at the root of the api hierarchy
// if a kind is not enumerated here, it is assumed to have a namespace scope
rootScoped := util.NewStringSet()
ignoredKinds := util.NewStringSet()
RESTMapper = api.NewDefaultRESTMapper(Versions, InterfacesFor, importPrefix, ignoredKinds, rootScoped)
api.RegisterRESTMapper(RESTMapper)
}
// InterfacesFor returns the default Codec and ResourceVersioner for a given version
// string, or an error if the version is not known.
func InterfacesFor(version string) (*meta.VersionInterfaces, error) {
switch version {
case "v1":
return &meta.VersionInterfaces{
Codec: v1.Codec,
ObjectConvertor: api.Scheme,
MetadataAccessor: accessor,
}, nil
default:
return nil, fmt.Errorf("unsupported storage version: %s (valid: %s)", version, strings.Join(Versions, ", "))
}
}

19
pkg/expapi/register.go Normal file
View File

@ -0,0 +1,19 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package expapi
func init() {}

29
pkg/expapi/types.go Normal file
View File

@ -0,0 +1,29 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
This file (together with pkg/expapi/v1/types.go) contain the experimental
types in kubernetes. These API objects are experimental, meaning that the
APIs may be broken at any time by the kubernetes team.
DISCLAIMER: The implementation of the experimental API group itself is
a temporary one meant as a stopgap solution until kubernetes has proper
support for multiple API groups. The transition may require changes
beyond registration differences. In other words, experimental API group
support is experimental.
*/
package expapi

View File

@ -0,0 +1,19 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
func addConversionFuncs() {}

View File

@ -0,0 +1,19 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
func addDeepCopyFuncs() {}

19
pkg/expapi/v1/defaults.go Normal file
View File

@ -0,0 +1,19 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
func addDefaultingFuncs() {}

30
pkg/expapi/v1/register.go Normal file
View File

@ -0,0 +1,30 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)
var Codec = runtime.CodecFor(api.Scheme, "v1")
func init() {
addDeepCopyFuncs()
addConversionFuncs()
addDefaultingFuncs()
}

17
pkg/expapi/v1/types.go Normal file
View File

@ -0,0 +1,17 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1

View File

@ -18,6 +18,7 @@ package cmd
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@ -64,6 +65,15 @@ func (*internalType) IsAnAPIObject() {}
func (*externalType) IsAnAPIObject() {} func (*externalType) IsAnAPIObject() {}
func (*ExternalType2) IsAnAPIObject() {} func (*ExternalType2) IsAnAPIObject() {}
var versionErr = errors.New("not a version")
func versionErrIfFalse(b bool) error {
if b {
return nil
}
return versionErr
}
func newExternalScheme() (*runtime.Scheme, meta.RESTMapper, runtime.Codec) { func newExternalScheme() (*runtime.Scheme, meta.RESTMapper, runtime.Codec) {
scheme := runtime.NewScheme() scheme := runtime.NewScheme()
scheme.AddKnownTypeWithName("", "Type", &internalType{}) scheme.AddKnownTypeWithName("", "Type", &internalType{})
@ -73,12 +83,12 @@ func newExternalScheme() (*runtime.Scheme, meta.RESTMapper, runtime.Codec) {
codec := runtime.CodecFor(scheme, "unlikelyversion") codec := runtime.CodecFor(scheme, "unlikelyversion")
validVersion := testapi.Version() validVersion := testapi.Version()
mapper := meta.NewDefaultRESTMapper([]string{"unlikelyversion", validVersion}, func(version string) (*meta.VersionInterfaces, bool) { mapper := meta.NewDefaultRESTMapper([]string{"unlikelyversion", validVersion}, func(version string) (*meta.VersionInterfaces, error) {
return &meta.VersionInterfaces{ return &meta.VersionInterfaces{
Codec: runtime.CodecFor(scheme, version), Codec: runtime.CodecFor(scheme, version),
ObjectConvertor: scheme, ObjectConvertor: scheme,
MetadataAccessor: meta.NewAccessor(), MetadataAccessor: meta.NewAccessor(),
}, (version == validVersion || version == "unlikelyversion") }, versionErrIfFalse(version == validVersion || version == "unlikelyversion")
}) })
for _, version := range []string{"unlikelyversion", validVersion} { for _, version := range []string{"unlikelyversion", validVersion} {
for kind := range scheme.KnownTypes(version) { for kind := range scheme.KnownTypes(version) {

View File

@ -36,6 +36,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission" "github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
@ -43,6 +44,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authorizer" "github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authorizer"
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/handlers" "github.com/GoogleCloudPlatform/kubernetes/pkg/auth/handlers"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
explatest "github.com/GoogleCloudPlatform/kubernetes/pkg/expapi/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/healthz" "github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
@ -89,22 +91,25 @@ const (
// Config is a structure used to configure a Master. // Config is a structure used to configure a Master.
type Config struct { type Config struct {
DatabaseStorage storage.Interface DatabaseStorage storage.Interface
EventTTL time.Duration ExpDatabaseStorage storage.Interface
MinionRegexp string EventTTL time.Duration
KubeletClient client.KubeletClient MinionRegexp 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
EnableUISupport bool EnableUISupport bool
// allow downstream consumers to disable swagger // allow downstream consumers to disable swagger
EnableSwaggerSupport bool EnableSwaggerSupport bool
// allow v1 to be conditionally disabled // allow api versions to be conditionally disabled
DisableV1 bool DisableV1 bool
EnableExp bool
// allow downstream consumers to disable the index route // allow downstream consumers to disable the index route
EnableIndex bool EnableIndex bool
EnableProfiling bool EnableProfiling bool
APIPrefix string APIPrefix string
ExpAPIPrefix string
CorsAllowedOriginList util.StringList CorsAllowedOriginList util.StringList
Authenticator authenticator.Request Authenticator authenticator.Request
// TODO(roberthbailey): Remove once the server no longer supports http basic auth. // TODO(roberthbailey): Remove once the server no longer supports http basic auth.
@ -181,12 +186,14 @@ type Master struct {
enableSwaggerSupport bool enableSwaggerSupport bool
enableProfiling bool enableProfiling bool
apiPrefix string apiPrefix string
expAPIPrefix string
corsAllowedOriginList util.StringList corsAllowedOriginList util.StringList
authenticator authenticator.Request authenticator authenticator.Request
authorizer authorizer.Authorizer authorizer authorizer.Authorizer
admissionControl admission.Interface admissionControl admission.Interface
masterCount int masterCount int
v1 bool v1 bool
exp bool
requestContextMapper api.RequestContextMapper requestContextMapper api.RequestContextMapper
// External host is the name that should be used in external (public internet) URLs for this master // External host is the name that should be used in external (public internet) URLs for this master
@ -227,11 +234,8 @@ type Master struct {
// NewEtcdStorage returns a storage.Interface for the provided arguments or an error if the version // NewEtcdStorage returns a storage.Interface for the provided arguments or an error if the version
// is incorrect. // is incorrect.
func NewEtcdStorage(client tools.EtcdClient, version string, prefix string) (etcdStorage storage.Interface, err error) { func NewEtcdStorage(client tools.EtcdClient, interfacesFunc meta.VersionInterfacesFunc, version, prefix string) (etcdStorage storage.Interface, err error) {
if version == "" { versionInterfaces, err := interfacesFunc(version)
version = latest.Version
}
versionInterfaces, err := latest.InterfacesFor(version)
if err != nil { if err != nil {
return etcdStorage, err return etcdStorage, err
} }
@ -337,11 +341,13 @@ func New(c *Config) *Master {
enableSwaggerSupport: c.EnableSwaggerSupport, enableSwaggerSupport: c.EnableSwaggerSupport,
enableProfiling: c.EnableProfiling, enableProfiling: c.EnableProfiling,
apiPrefix: c.APIPrefix, apiPrefix: c.APIPrefix,
expAPIPrefix: c.ExpAPIPrefix,
corsAllowedOriginList: c.CorsAllowedOriginList, corsAllowedOriginList: c.CorsAllowedOriginList,
authenticator: c.Authenticator, authenticator: c.Authenticator,
authorizer: c.Authorizer, authorizer: c.Authorizer,
admissionControl: c.AdmissionControl, admissionControl: c.AdmissionControl,
v1: !c.DisableV1, v1: !c.DisableV1,
exp: c.EnableExp,
requestContextMapper: c.RequestContextMapper, requestContextMapper: c.RequestContextMapper,
cacheTimeout: c.CacheTimeout, cacheTimeout: c.CacheTimeout,
@ -566,6 +572,16 @@ func (m *Master) init(c *Config) {
requestInfoResolver := &apiserver.APIRequestInfoResolver{util.NewStringSet(strings.TrimPrefix(defaultVersion.Root, "/")), defaultVersion.Mapper} requestInfoResolver := &apiserver.APIRequestInfoResolver{util.NewStringSet(strings.TrimPrefix(defaultVersion.Root, "/")), defaultVersion.Mapper}
apiserver.InstallServiceErrorHandler(m.handlerContainer, requestInfoResolver, apiVersions) apiserver.InstallServiceErrorHandler(m.handlerContainer, requestInfoResolver, apiVersions)
if m.exp {
expVersion := m.expapi(c)
if err := expVersion.InstallREST(m.handlerContainer); err != nil {
glog.Fatalf("Unable to setup experimental api: %v", err)
}
apiserver.AddApiWebService(m.handlerContainer, c.ExpAPIPrefix, []string{expVersion.Version})
expRequestInfoResolver := &apiserver.APIRequestInfoResolver{util.NewStringSet(strings.TrimPrefix(expVersion.Root, "/")), expVersion.Mapper}
apiserver.InstallServiceErrorHandler(m.handlerContainer, expRequestInfoResolver, []string{expVersion.Version})
}
// 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
@ -760,6 +776,30 @@ func (m *Master) api_v1() *apiserver.APIGroupVersion {
return version return version
} }
// expapi returns the resources and codec for the experimental api
func (m *Master) expapi(c *Config) *apiserver.APIGroupVersion {
storage := map[string]rest.Storage{}
return &apiserver.APIGroupVersion{
Root: m.expAPIPrefix,
Creater: api.Scheme,
Convertor: api.Scheme,
Typer: api.Scheme,
Mapper: explatest.RESTMapper,
Codec: explatest.Codec,
Linker: explatest.SelfLinker,
Storage: storage,
Version: explatest.Version,
Admit: m.admissionControl,
Context: m.requestContextMapper,
ProxyDialerFn: m.dialer,
MinRequestTimeout: m.minRequestTimeout,
}
}
// findExternalAddress returns ExternalIP of provided node with fallback to LegacyHostIP. // findExternalAddress returns ExternalIP of provided node with fallback to LegacyHostIP.
func findExternalAddress(node *api.Node) (string, error) { func findExternalAddress(node *api.Node) (string, error) {
var fallback string var fallback string

View File

@ -21,6 +21,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
explatest "github.com/GoogleCloudPlatform/kubernetes/pkg/expapi/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
etcdstorage "github.com/GoogleCloudPlatform/kubernetes/pkg/storage/etcd" etcdstorage "github.com/GoogleCloudPlatform/kubernetes/pkg/storage/etcd"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools" "github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
@ -33,6 +34,7 @@ func TestGetServersToValidate(t *testing.T) {
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"}
config.DatabaseStorage = etcdstorage.NewEtcdStorage(fakeClient, latest.Codec, etcdtest.PathPrefix()) config.DatabaseStorage = etcdstorage.NewEtcdStorage(fakeClient, latest.Codec, etcdtest.PathPrefix())
config.ExpDatabaseStorage = etcdstorage.NewEtcdStorage(fakeClient, explatest.Codec, etcdtest.PathPrefix())
master.nodeRegistry = registrytest.NewMinionRegistry([]string{"node1", "node2"}, api.NodeResources{}) master.nodeRegistry = registrytest.NewMinionRegistry([]string{"node1", "node2"}, api.NodeResources{})

View File

@ -21,7 +21,6 @@ import (
"time" "time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/testclient" "github.com/GoogleCloudPlatform/kubernetes/pkg/client/testclient"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
) )
@ -138,7 +137,7 @@ func TestSyncNamespaceThatIsActive(t *testing.T) {
func TestRunStop(t *testing.T) { func TestRunStop(t *testing.T) {
o := testclient.NewObjects(api.Scheme, api.Scheme) o := testclient.NewObjects(api.Scheme, api.Scheme)
client := &testclient.Fake{ReactFn: testclient.ObjectReaction(o, latest.RESTMapper)} client := &testclient.Fake{ReactFn: testclient.ObjectReaction(o, api.RESTMapper)}
nsMgr := NewNamespaceManager(client, 1*time.Second) nsMgr := NewNamespaceManager(client, 1*time.Second)
if nsMgr.StopEverything != nil { if nsMgr.StopEverything != nil {

View File

@ -23,7 +23,6 @@ import (
"testing" "testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/testclient" "github.com/GoogleCloudPlatform/kubernetes/pkg/client/testclient"
"github.com/GoogleCloudPlatform/kubernetes/pkg/types" "github.com/GoogleCloudPlatform/kubernetes/pkg/types"
@ -238,7 +237,7 @@ func TestNewBuilder(t *testing.T) {
o := testclient.NewObjects(api.Scheme, api.Scheme) o := testclient.NewObjects(api.Scheme, api.Scheme)
o.Add(item.pv) o.Add(item.pv)
o.Add(item.claim) o.Add(item.claim)
client := &testclient.Fake{ReactFn: testclient.ObjectReaction(o, latest.RESTMapper)} client := &testclient.Fake{ReactFn: testclient.ObjectReaction(o, api.RESTMapper)}
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(testProbeVolumePlugins(), newTestHost(t, client)) plugMgr.InitPlugins(testProbeVolumePlugins(), newTestHost(t, client))
@ -295,7 +294,7 @@ func TestNewBuilderClaimNotBound(t *testing.T) {
o := testclient.NewObjects(api.Scheme, api.Scheme) o := testclient.NewObjects(api.Scheme, api.Scheme)
o.Add(pv) o.Add(pv)
o.Add(claim) o.Add(claim)
client := &testclient.Fake{ReactFn: testclient.ObjectReaction(o, latest.RESTMapper)} client := &testclient.Fake{ReactFn: testclient.ObjectReaction(o, api.RESTMapper)}
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(testProbeVolumePlugins(), newTestHost(t, client)) plugMgr.InitPlugins(testProbeVolumePlugins(), newTestHost(t, client))

View File

@ -23,7 +23,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/testclient" "github.com/GoogleCloudPlatform/kubernetes/pkg/client/testclient"
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume" "github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
@ -32,7 +31,7 @@ import (
func TestRunStop(t *testing.T) { func TestRunStop(t *testing.T) {
o := testclient.NewObjects(api.Scheme, api.Scheme) o := testclient.NewObjects(api.Scheme, api.Scheme)
client := &testclient.Fake{ReactFn: testclient.ObjectReaction(o, latest.RESTMapper)} client := &testclient.Fake{ReactFn: testclient.ObjectReaction(o, api.RESTMapper)}
binder := NewPersistentVolumeClaimBinder(client, 1*time.Second) binder := NewPersistentVolumeClaimBinder(client, 1*time.Second)
if len(binder.stopChannels) != 0 { if len(binder.stopChannels) != 0 {
@ -119,7 +118,7 @@ func TestExampleObjects(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
client := &testclient.Fake{ReactFn: testclient.ObjectReaction(o, latest.RESTMapper)} client := &testclient.Fake{ReactFn: testclient.ObjectReaction(o, api.RESTMapper)}
if reflect.TypeOf(scenario.expected) == reflect.TypeOf(&api.PersistentVolumeClaim{}) { if reflect.TypeOf(scenario.expected) == reflect.TypeOf(&api.PersistentVolumeClaim{}) {
pvc, err := client.PersistentVolumeClaims("ns").Get("doesntmatter") pvc, err := client.PersistentVolumeClaims("ns").Get("doesntmatter")
@ -179,7 +178,7 @@ func TestBindingWithExamples(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
client := &testclient.Fake{ReactFn: testclient.ObjectReaction(o, latest.RESTMapper)} client := &testclient.Fake{ReactFn: testclient.ObjectReaction(o, api.RESTMapper)}
pv, err := client.PersistentVolumes().Get("any") pv, err := client.PersistentVolumes().Get("any")
pv.Spec.PersistentVolumeReclaimPolicy = api.PersistentVolumeReclaimRecycle pv.Spec.PersistentVolumeReclaimPolicy = api.PersistentVolumeReclaimRecycle
@ -282,7 +281,7 @@ func TestMissingFromIndex(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
client := &testclient.Fake{ReactFn: testclient.ObjectReaction(o, latest.RESTMapper)} client := &testclient.Fake{ReactFn: testclient.ObjectReaction(o, api.RESTMapper)}
pv, err := client.PersistentVolumes().Get("any") pv, err := client.PersistentVolumes().Get("any")
if err != nil { if err != nil {

View File

@ -22,7 +22,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission" "github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache" "github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
@ -48,11 +47,11 @@ type provision struct {
} }
func (p *provision) Admit(a admission.Attributes) (err error) { func (p *provision) Admit(a admission.Attributes) (err error) {
defaultVersion, kind, err := latest.RESTMapper.VersionAndKindForResource(a.GetResource()) defaultVersion, kind, err := api.RESTMapper.VersionAndKindForResource(a.GetResource())
if err != nil { if err != nil {
return admission.NewForbidden(a, err) return admission.NewForbidden(a, err)
} }
mapping, err := latest.RESTMapper.RESTMapping(kind, defaultVersion) mapping, err := api.RESTMapper.RESTMapping(kind, defaultVersion)
if err != nil { if err != nil {
return admission.NewForbidden(a, err) return admission.NewForbidden(a, err)
} }

View File

@ -23,7 +23,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission" "github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache" "github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
@ -49,11 +48,11 @@ type exists struct {
} }
func (e *exists) Admit(a admission.Attributes) (err error) { func (e *exists) Admit(a admission.Attributes) (err error) {
defaultVersion, kind, err := latest.RESTMapper.VersionAndKindForResource(a.GetResource()) defaultVersion, kind, err := api.RESTMapper.VersionAndKindForResource(a.GetResource())
if err != nil { if err != nil {
return admission.NewForbidden(a, err) return admission.NewForbidden(a, err)
} }
mapping, err := latest.RESTMapper.RESTMapping(kind, defaultVersion) mapping, err := api.RESTMapper.RESTMapping(kind, defaultVersion)
if err != nil { if err != nil {
return admission.NewForbidden(a, err) return admission.NewForbidden(a, err)
} }

View File

@ -23,7 +23,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission" "github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache" "github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
@ -59,11 +58,11 @@ func (l *lifecycle) Admit(a admission.Attributes) (err error) {
return nil return nil
} }
defaultVersion, kind, err := latest.RESTMapper.VersionAndKindForResource(a.GetResource()) defaultVersion, kind, err := api.RESTMapper.VersionAndKindForResource(a.GetResource())
if err != nil { if err != nil {
return admission.NewForbidden(a, err) return admission.NewForbidden(a, err)
} }
mapping, err := latest.RESTMapper.RESTMapping(kind, defaultVersion) mapping, err := api.RESTMapper.RESTMapping(kind, defaultVersion)
if err != nil { if err != nil {
return admission.NewForbidden(a, err) return admission.NewForbidden(a, err)
} }

View File

@ -22,6 +22,7 @@ import (
"fmt" "fmt"
"math/rand" "math/rand"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
"github.com/GoogleCloudPlatform/kubernetes/pkg/master" "github.com/GoogleCloudPlatform/kubernetes/pkg/master"
"github.com/GoogleCloudPlatform/kubernetes/pkg/storage" "github.com/GoogleCloudPlatform/kubernetes/pkg/storage"
@ -42,7 +43,7 @@ func NewEtcdClient() *etcd.Client {
} }
func NewEtcdStorage() (storage.Interface, error) { func NewEtcdStorage() (storage.Interface, error) {
return master.NewEtcdStorage(NewEtcdClient(), testapi.Version(), etcdtest.PathPrefix()) return master.NewEtcdStorage(NewEtcdClient(), latest.InterfacesFor, testapi.Version(), etcdtest.PathPrefix())
} }
func RequireEtcd() { func RequireEtcd() {

View File

@ -26,11 +26,13 @@ import (
"time" "time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record" "github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
"github.com/GoogleCloudPlatform/kubernetes/pkg/controller/replication" "github.com/GoogleCloudPlatform/kubernetes/pkg/controller/replication"
explatest "github.com/GoogleCloudPlatform/kubernetes/pkg/expapi/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
@ -128,19 +130,27 @@ func startMasterOrDie(masterConfig *master.Config) (*master.Master, *httptest.Se
var etcdStorage storage.Interface var etcdStorage storage.Interface
var err error var err error
if masterConfig == nil { if masterConfig == nil {
etcdStorage, err = master.NewEtcdStorage(NewEtcdClient(), "", etcdtest.PathPrefix()) etcdClient := NewEtcdClient()
etcdStorage, err = master.NewEtcdStorage(etcdClient, latest.InterfacesFor, latest.Version, etcdtest.PathPrefix())
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, explatest.InterfacesFor, explatest.Version, etcdtest.PathPrefix())
if err != nil {
glog.Fatalf("Failed to create etcd storage for master %v", err)
}
masterConfig = &master.Config{ masterConfig = &master.Config{
DatabaseStorage: etcdStorage, DatabaseStorage: etcdStorage,
KubeletClient: client.FakeKubeletClient{}, ExpDatabaseStorage: expEtcdStorage,
EnableLogsSupport: false, KubeletClient: client.FakeKubeletClient{},
EnableProfiling: true, EnableLogsSupport: false,
EnableUISupport: false, EnableProfiling: true,
APIPrefix: "/api", EnableUISupport: false,
Authorizer: apiserver.NewAlwaysAllowAuthorizer(), APIPrefix: "/api",
AdmissionControl: admit.NewAlwaysAdmit(), ExpAPIPrefix: "/experimental",
Authorizer: apiserver.NewAlwaysAllowAuthorizer(),
AdmissionControl: admit.NewAlwaysAdmit(),
} }
} else { } else {
etcdStorage = masterConfig.DatabaseStorage etcdStorage = masterConfig.DatabaseStorage
@ -258,20 +268,28 @@ 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) {
etcdStorage, err := master.NewEtcdStorage(NewEtcdClient(), testapi.Version(), etcdtest.PathPrefix()) etcdClient := NewEtcdClient()
etcdStorage, err := master.NewEtcdStorage(etcdClient, latest.InterfacesFor, testapi.Version(), etcdtest.PathPrefix())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expEtcdStorage, err := master.NewEtcdStorage(etcdClient, explatest.InterfacesFor, explatest.Version, etcdtest.PathPrefix())
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
m := master.New(&master.Config{ m := master.New(&master.Config{
DatabaseStorage: etcdStorage, DatabaseStorage: etcdStorage,
KubeletClient: client.FakeKubeletClient{}, ExpDatabaseStorage: expEtcdStorage,
EnableLogsSupport: false, KubeletClient: client.FakeKubeletClient{},
EnableProfiling: true, EnableLogsSupport: false,
EnableUISupport: false, EnableProfiling: true,
APIPrefix: "/api", EnableUISupport: false,
Authorizer: apiserver.NewAlwaysAllowAuthorizer(), APIPrefix: "/api",
AdmissionControl: admit.NewAlwaysAdmit(), ExpAPIPrefix: "/experimental",
EnableExp: true,
Authorizer: apiserver.NewAlwaysAllowAuthorizer(),
AdmissionControl: admit.NewAlwaysAdmit(),
}) })
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {

View File

@ -0,0 +1,39 @@
// +build integration,!no-etcd
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package integration
import (
"net/http"
"testing"
"github.com/GoogleCloudPlatform/kubernetes/test/integration/framework"
)
func TestExperimentalPrefix(t *testing.T) {
_, s := framework.RunAMaster(t)
defer s.Close()
resp, err := http.Get(s.URL + "/experimental/")
if err != nil {
t.Fatalf("unexpected error getting experimental prefix: %v", err)
}
if resp.StatusCode != http.StatusOK {
t.Fatalf("got status %v instead of 200 OK", resp.StatusCode)
}
}

View File

@ -33,6 +33,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator" "github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator"
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator/bearertoken" "github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator/bearertoken"
@ -340,7 +341,7 @@ func startServiceAccountTestServer(t *testing.T) (*client.Client, client.Config,
deleteAllEtcdKeys() deleteAllEtcdKeys()
// Etcd // Etcd
etcdStorage, err := master.NewEtcdStorage(newEtcdClient(), testapi.Version(), etcdtest.PathPrefix()) etcdStorage, err := master.NewEtcdStorage(newEtcdClient(), latest.InterfacesFor, testapi.Version(), etcdtest.PathPrefix())
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }

View File

@ -25,6 +25,7 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
@ -67,7 +68,7 @@ func deleteAllEtcdKeys() {
} }
func runAMaster(t *testing.T) (*master.Master, *httptest.Server) { func runAMaster(t *testing.T) (*master.Master, *httptest.Server) {
etcdStorage, err := master.NewEtcdStorage(newEtcdClient(), testapi.Version(), etcdtest.PathPrefix()) etcdStorage, err := master.NewEtcdStorage(newEtcdClient(), latest.InterfacesFor, testapi.Version(), etcdtest.PathPrefix())
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }