2014-06-16 06:29:07 +00:00
|
|
|
/*
|
2016-06-03 00:25:58 +00:00
|
|
|
Copyright 2014 The Kubernetes Authors.
|
2014-06-16 06:29:07 +00:00
|
|
|
|
|
|
|
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 master
|
|
|
|
|
|
|
|
import (
|
2014-11-02 20:52:31 +00:00
|
|
|
"fmt"
|
2014-09-18 23:03:34 +00:00
|
|
|
"net"
|
2014-11-02 20:52:31 +00:00
|
|
|
"net/url"
|
2014-10-28 00:56:33 +00:00
|
|
|
"strconv"
|
2014-10-23 23:55:14 +00:00
|
|
|
"strings"
|
2015-06-04 18:58:38 +00:00
|
|
|
"sync"
|
2014-06-16 06:29:07 +00:00
|
|
|
"time"
|
|
|
|
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api"
|
2016-05-09 21:47:02 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api/meta"
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api/rest"
|
2015-10-09 01:33:33 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
2016-03-22 16:45:23 +00:00
|
|
|
apiv1 "k8s.io/kubernetes/pkg/api/v1"
|
2016-01-13 22:40:56 +00:00
|
|
|
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
2016-04-15 22:30:15 +00:00
|
|
|
appsapi "k8s.io/kubernetes/pkg/apis/apps/v1alpha1"
|
2016-07-19 18:47:53 +00:00
|
|
|
authenticationv1beta1 "k8s.io/kubernetes/pkg/apis/authentication/v1beta1"
|
2016-02-03 18:08:10 +00:00
|
|
|
"k8s.io/kubernetes/pkg/apis/authorization"
|
|
|
|
authorizationapiv1beta1 "k8s.io/kubernetes/pkg/apis/authorization/v1beta1"
|
2016-02-15 14:00:40 +00:00
|
|
|
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
2016-03-22 16:45:23 +00:00
|
|
|
autoscalingapiv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1"
|
2016-02-17 17:11:31 +00:00
|
|
|
"k8s.io/kubernetes/pkg/apis/batch"
|
2016-03-22 16:45:23 +00:00
|
|
|
batchapiv1 "k8s.io/kubernetes/pkg/apis/batch/v1"
|
2016-04-14 01:45:43 +00:00
|
|
|
"k8s.io/kubernetes/pkg/apis/certificates"
|
|
|
|
certificatesapiv1alpha1 "k8s.io/kubernetes/pkg/apis/certificates/v1alpha1"
|
2015-12-08 14:21:04 +00:00
|
|
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
2016-03-22 16:45:23 +00:00
|
|
|
extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
2016-05-07 00:03:43 +00:00
|
|
|
"k8s.io/kubernetes/pkg/apis/policy"
|
|
|
|
policyapiv1alpha1 "k8s.io/kubernetes/pkg/apis/policy/v1alpha1"
|
2016-05-25 21:20:41 +00:00
|
|
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
|
|
|
rbacapi "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1"
|
2016-09-01 15:29:26 +00:00
|
|
|
"k8s.io/kubernetes/pkg/apis/storage"
|
|
|
|
storageapiv1beta1 "k8s.io/kubernetes/pkg/apis/storage/v1beta1"
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/apiserver"
|
2016-09-30 16:06:54 +00:00
|
|
|
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/unversioned"
|
2015-11-16 21:46:00 +00:00
|
|
|
"k8s.io/kubernetes/pkg/genericapiserver"
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/healthz"
|
2015-10-27 13:18:45 +00:00
|
|
|
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/master/ports"
|
2016-09-23 19:10:47 +00:00
|
|
|
|
|
|
|
"k8s.io/kubernetes/pkg/registry/generic"
|
|
|
|
"k8s.io/kubernetes/pkg/registry/generic/registry"
|
|
|
|
"k8s.io/kubernetes/pkg/routes"
|
|
|
|
"k8s.io/kubernetes/pkg/runtime"
|
|
|
|
etcdutil "k8s.io/kubernetes/pkg/storage/etcd/util"
|
|
|
|
"k8s.io/kubernetes/pkg/storage/storagebackend"
|
|
|
|
"k8s.io/kubernetes/pkg/util/sets"
|
|
|
|
|
|
|
|
"github.com/golang/glog"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
|
|
|
|
|
|
// RESTStorage installers
|
|
|
|
appsrest "k8s.io/kubernetes/pkg/registry/apps/rest"
|
|
|
|
authenticationrest "k8s.io/kubernetes/pkg/registry/authentication/rest"
|
|
|
|
authorizationrest "k8s.io/kubernetes/pkg/registry/authorization/rest"
|
|
|
|
autoscalingrest "k8s.io/kubernetes/pkg/registry/autoscaling/rest"
|
|
|
|
batchrest "k8s.io/kubernetes/pkg/registry/batch/rest"
|
|
|
|
certificatesrest "k8s.io/kubernetes/pkg/registry/certificates/rest"
|
2016-09-26 11:51:04 +00:00
|
|
|
corerest "k8s.io/kubernetes/pkg/registry/core/rest"
|
2016-09-23 19:10:47 +00:00
|
|
|
extensionsrest "k8s.io/kubernetes/pkg/registry/extensions/rest"
|
|
|
|
policyrest "k8s.io/kubernetes/pkg/registry/policy/rest"
|
|
|
|
rbacrest "k8s.io/kubernetes/pkg/registry/rbac/rest"
|
|
|
|
storagerest "k8s.io/kubernetes/pkg/registry/storage/rest"
|
|
|
|
|
|
|
|
// direct etcd registry dependencies
|
2016-09-21 13:06:56 +00:00
|
|
|
"k8s.io/kubernetes/pkg/registry/extensions/thirdpartyresourcedata"
|
|
|
|
thirdpartyresourcedataetcd "k8s.io/kubernetes/pkg/registry/extensions/thirdpartyresourcedata/etcd"
|
2014-06-16 06:29:07 +00:00
|
|
|
)
|
|
|
|
|
2016-06-24 15:25:46 +00:00
|
|
|
const (
|
|
|
|
// DefaultEndpointReconcilerInterval is the default amount of time for how often the endpoints for
|
|
|
|
// the kubernetes Service are reconciled.
|
|
|
|
DefaultEndpointReconcilerInterval = 10 * time.Second
|
|
|
|
)
|
|
|
|
|
2014-07-27 02:16:39 +00:00
|
|
|
type Config struct {
|
2016-09-28 18:52:28 +00:00
|
|
|
GenericConfig *genericapiserver.Config
|
2015-10-09 05:18:16 +00:00
|
|
|
|
2016-09-19 18:52:41 +00:00
|
|
|
StorageFactory genericapiserver.StorageFactory
|
|
|
|
EnableWatchCache bool
|
2016-06-24 15:25:46 +00:00
|
|
|
EnableCoreControllers bool
|
|
|
|
EndpointReconcilerConfig EndpointReconcilerConfig
|
|
|
|
DeleteCollectionWorkers int
|
|
|
|
EventTTL time.Duration
|
|
|
|
KubeletClient kubeletclient.KubeletClient
|
2016-09-15 17:41:48 +00:00
|
|
|
// genericapiserver.RESTStorageProviders provides RESTStorage building methods keyed by groupName
|
|
|
|
RESTStorageProviders map[string]genericapiserver.RESTStorageProvider
|
2015-10-09 05:18:16 +00:00
|
|
|
// Used to start and monitor tunneling
|
2016-09-06 11:20:36 +00:00
|
|
|
Tunneler genericapiserver.Tunneler
|
|
|
|
EnableUISupport bool
|
|
|
|
EnableLogsSupport bool
|
2016-03-10 04:06:31 +00:00
|
|
|
|
|
|
|
disableThirdPartyControllerForTesting bool
|
2015-10-29 09:51:32 +00:00
|
|
|
}
|
|
|
|
|
2016-06-24 15:25:46 +00:00
|
|
|
// EndpointReconcilerConfig holds the endpoint reconciler and endpoint reconciliation interval to be
|
|
|
|
// used by the master.
|
|
|
|
type EndpointReconcilerConfig struct {
|
|
|
|
Reconciler EndpointReconciler
|
|
|
|
Interval time.Duration
|
|
|
|
}
|
|
|
|
|
2014-06-16 06:29:07 +00:00
|
|
|
// Master contains state for a Kubernetes cluster master/api server.
|
|
|
|
type Master struct {
|
2016-09-30 16:16:32 +00:00
|
|
|
GenericAPIServer *genericapiserver.GenericAPIServer
|
2015-02-12 00:07:54 +00:00
|
|
|
|
2016-02-18 13:50:43 +00:00
|
|
|
deleteCollectionWorkers int
|
2015-02-12 00:07:54 +00:00
|
|
|
|
2015-08-19 18:02:01 +00:00
|
|
|
// storage for third party objects
|
2016-08-08 22:12:54 +00:00
|
|
|
thirdPartyStorageConfig *storagebackend.Config
|
2015-12-10 00:35:35 +00:00
|
|
|
// map from api path to a tuple of (storage for the objects, APIGroup)
|
2016-07-28 06:18:04 +00:00
|
|
|
thirdPartyResources map[string]*thirdPartyEntry
|
2015-09-09 21:36:19 +00:00
|
|
|
// protects the map
|
2015-11-16 21:46:00 +00:00
|
|
|
thirdPartyResourcesLock sync.RWMutex
|
2016-03-10 04:06:31 +00:00
|
|
|
// Useful for reliable testing. Shouldn't be used otherwise.
|
|
|
|
disableThirdPartyControllerForTesting bool
|
2014-06-16 06:29:07 +00:00
|
|
|
|
2016-09-30 16:06:54 +00:00
|
|
|
// nodeClient is used to back the tunneler
|
|
|
|
nodeClient coreclient.NodeInterface
|
2016-09-19 18:52:41 +00:00
|
|
|
|
|
|
|
restOptionsFactory restOptionsFactory
|
2014-10-28 00:56:33 +00:00
|
|
|
}
|
|
|
|
|
2015-12-10 00:35:35 +00:00
|
|
|
// thirdPartyEntry combines objects storage and API group into one struct
|
|
|
|
// for easy lookup.
|
|
|
|
type thirdPartyEntry struct {
|
2016-07-28 06:18:04 +00:00
|
|
|
// Map from plural resource name to entry
|
|
|
|
storage map[string]*thirdpartyresourcedataetcd.REST
|
2015-12-10 00:35:35 +00:00
|
|
|
group unversioned.APIGroup
|
|
|
|
}
|
|
|
|
|
2016-06-15 20:21:53 +00:00
|
|
|
type RESTOptionsGetter func(resource unversioned.GroupResource) generic.RESTOptions
|
2016-07-27 14:29:31 +00:00
|
|
|
|
|
|
|
type RESTStorageProvider interface {
|
2016-08-26 15:06:27 +00:00
|
|
|
NewRESTStorage(apiResourceConfigSource genericapiserver.APIResourceConfigSource, restOptionsGetter RESTOptionsGetter) (groupInfo genericapiserver.APIGroupInfo, enabled bool)
|
|
|
|
}
|
|
|
|
|
2016-09-28 16:39:31 +00:00
|
|
|
type completedConfig struct {
|
|
|
|
*Config
|
|
|
|
}
|
|
|
|
|
2016-09-27 15:52:31 +00:00
|
|
|
// Complete fills in any fields not set that are required to have valid data. It's mutating the receiver.
|
2016-09-28 16:39:31 +00:00
|
|
|
func (c *Config) Complete() completedConfig {
|
|
|
|
c.GenericConfig.Complete()
|
2016-09-27 15:52:31 +00:00
|
|
|
|
|
|
|
// enable swagger UI only if general UI support is on
|
2016-09-28 16:39:31 +00:00
|
|
|
c.GenericConfig.EnableSwaggerUI = c.GenericConfig.EnableSwaggerUI && c.EnableUISupport
|
|
|
|
|
2016-09-30 16:06:54 +00:00
|
|
|
if c.EndpointReconcilerConfig.Interval == 0 {
|
|
|
|
c.EndpointReconcilerConfig.Interval = DefaultEndpointReconcilerInterval
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.EndpointReconcilerConfig.Reconciler == nil {
|
|
|
|
// use a default endpoint reconciler if nothing is set
|
|
|
|
endpointClient := coreclient.NewForConfigOrDie(c.GenericConfig.LoopbackClientConfig)
|
|
|
|
c.EndpointReconcilerConfig.Reconciler = NewMasterCountEndpointReconciler(c.GenericConfig.MasterCount, endpointClient)
|
|
|
|
}
|
|
|
|
|
2016-09-28 16:39:31 +00:00
|
|
|
return completedConfig{c}
|
|
|
|
}
|
2016-09-27 15:52:31 +00:00
|
|
|
|
2016-09-28 16:39:31 +00:00
|
|
|
// SkipComplete provides a way to construct a server instance without config completion.
|
|
|
|
func (c *Config) SkipComplete() completedConfig {
|
|
|
|
return completedConfig{c}
|
2016-09-27 15:52:31 +00:00
|
|
|
}
|
|
|
|
|
2014-10-28 20:02:19 +00:00
|
|
|
// New returns a new instance of Master from the given config.
|
2015-11-16 21:46:00 +00:00
|
|
|
// Certain config fields will be set to a default value if unset.
|
2014-10-28 20:02:19 +00:00
|
|
|
// Certain config fields must be specified, including:
|
|
|
|
// KubeletClient
|
2016-09-28 16:39:31 +00:00
|
|
|
func (c completedConfig) New() (*Master, error) {
|
2014-11-03 22:50:41 +00:00
|
|
|
if c.KubeletClient == nil {
|
2016-02-03 22:26:11 +00:00
|
|
|
return nil, fmt.Errorf("Master.New() called with config.KubeletClient == nil")
|
2014-11-03 22:50:41 +00:00
|
|
|
}
|
2014-12-15 20:29:55 +00:00
|
|
|
|
2016-09-28 16:39:31 +00:00
|
|
|
s, err := c.Config.GenericConfig.SkipComplete().New() // completion is done in Complete, no need for a second time
|
2016-02-03 22:26:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-11-16 21:46:00 +00:00
|
|
|
|
2016-09-06 11:20:36 +00:00
|
|
|
if c.EnableUISupport {
|
2016-09-28 09:26:50 +00:00
|
|
|
routes.UIRedirect{}.Install(s.HandlerContainer)
|
2016-09-06 11:20:36 +00:00
|
|
|
}
|
|
|
|
if c.EnableLogsSupport {
|
2016-09-28 09:26:50 +00:00
|
|
|
routes.Logs{}.Install(s.HandlerContainer)
|
2016-09-06 11:20:36 +00:00
|
|
|
}
|
|
|
|
|
2014-06-16 06:29:07 +00:00
|
|
|
m := &Master{
|
2016-02-18 13:50:43 +00:00
|
|
|
GenericAPIServer: s,
|
|
|
|
deleteCollectionWorkers: c.DeleteCollectionWorkers,
|
2016-09-30 16:06:54 +00:00
|
|
|
nodeClient: coreclient.NewForConfigOrDie(c.GenericConfig.LoopbackClientConfig).Nodes(),
|
2016-03-10 04:06:31 +00:00
|
|
|
|
|
|
|
disableThirdPartyControllerForTesting: c.disableThirdPartyControllerForTesting,
|
2016-09-19 18:52:41 +00:00
|
|
|
|
|
|
|
restOptionsFactory: restOptionsFactory{
|
|
|
|
deleteCollectionWorkers: c.DeleteCollectionWorkers,
|
2016-09-28 18:52:28 +00:00
|
|
|
enableGarbageCollection: c.GenericConfig.EnableGarbageCollection,
|
2016-09-19 18:52:41 +00:00
|
|
|
storageFactory: c.StorageFactory,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.EnableWatchCache {
|
|
|
|
m.restOptionsFactory.storageDecorator = registry.StorageWithCacher
|
|
|
|
} else {
|
|
|
|
m.restOptionsFactory.storageDecorator = generic.UndecoratedStorage
|
2014-06-16 06:29:07 +00:00
|
|
|
}
|
2016-06-15 20:21:53 +00:00
|
|
|
|
2016-09-30 16:16:32 +00:00
|
|
|
// install legacy rest storage
|
|
|
|
// because of other hacks, this always has to come first
|
|
|
|
legacyRESTStorageProvider := corerest.LegacyRESTStorageProvider{
|
|
|
|
StorageFactory: c.StorageFactory,
|
|
|
|
ProxyTransport: s.ProxyTransport,
|
|
|
|
KubeletClient: c.KubeletClient,
|
|
|
|
EventTTL: c.EventTTL,
|
|
|
|
ServiceClusterIPRange: c.GenericConfig.ServiceClusterIPRange,
|
|
|
|
ServiceNodePortRange: c.GenericConfig.ServiceNodePortRange,
|
|
|
|
ComponentStatusServerFunc: func() map[string]apiserver.Server { return getServersToValidate(c.StorageFactory) },
|
|
|
|
LoopbackClientConfig: c.GenericConfig.LoopbackClientConfig,
|
|
|
|
}
|
|
|
|
|
2016-06-15 20:21:53 +00:00
|
|
|
// Add some hardcoded storage for now. Append to the map.
|
|
|
|
if c.RESTStorageProviders == nil {
|
2016-09-15 17:41:48 +00:00
|
|
|
c.RESTStorageProviders = map[string]genericapiserver.RESTStorageProvider{}
|
2016-06-15 20:21:53 +00:00
|
|
|
}
|
2016-09-23 19:10:47 +00:00
|
|
|
c.RESTStorageProviders[appsapi.GroupName] = appsrest.RESTStorageProvider{}
|
2016-09-28 18:52:28 +00:00
|
|
|
c.RESTStorageProviders[authenticationv1beta1.GroupName] = authenticationrest.RESTStorageProvider{Authenticator: c.GenericConfig.Authenticator}
|
|
|
|
c.RESTStorageProviders[authorization.GroupName] = authorizationrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorizer}
|
2016-09-23 19:10:47 +00:00
|
|
|
c.RESTStorageProviders[autoscaling.GroupName] = autoscalingrest.RESTStorageProvider{}
|
|
|
|
c.RESTStorageProviders[batch.GroupName] = batchrest.RESTStorageProvider{}
|
|
|
|
c.RESTStorageProviders[certificates.GroupName] = certificatesrest.RESTStorageProvider{}
|
|
|
|
c.RESTStorageProviders[extensions.GroupName] = extensionsrest.RESTStorageProvider{
|
2016-07-27 14:29:31 +00:00
|
|
|
ResourceInterface: m,
|
|
|
|
DisableThirdPartyControllerForTesting: m.disableThirdPartyControllerForTesting,
|
|
|
|
}
|
2016-09-23 19:10:47 +00:00
|
|
|
c.RESTStorageProviders[policy.GroupName] = policyrest.RESTStorageProvider{}
|
2016-09-28 18:52:28 +00:00
|
|
|
c.RESTStorageProviders[rbac.GroupName] = &rbacrest.RESTStorageProvider{AuthorizerRBACSuperUser: c.GenericConfig.AuthorizerRBACSuperUser}
|
2016-09-23 19:10:47 +00:00
|
|
|
c.RESTStorageProviders[storage.GroupName] = storagerest.RESTStorageProvider{}
|
2016-09-30 16:16:32 +00:00
|
|
|
m.InstallAPIs(c.Config, legacyRESTStorageProvider)
|
|
|
|
|
|
|
|
m.InstallGeneralEndpoints(c.Config)
|
2014-12-15 20:29:55 +00:00
|
|
|
|
2016-02-03 22:26:11 +00:00
|
|
|
return m, nil
|
2014-06-16 06:29:07 +00:00
|
|
|
}
|
|
|
|
|
2016-09-30 16:16:32 +00:00
|
|
|
// TODO this needs to be refactored so we have a way to add general health checks to genericapiserver
|
|
|
|
// TODO profiling should be generic
|
|
|
|
func (m *Master) InstallGeneralEndpoints(c *Config) {
|
|
|
|
// Run the tunneler.
|
|
|
|
healthzChecks := []healthz.HealthzChecker{}
|
|
|
|
if c.Tunneler != nil {
|
|
|
|
c.Tunneler.Run(m.getNodeAddresses)
|
|
|
|
healthzChecks = append(healthzChecks, healthz.NamedCheck("SSH Tunnel Check", genericapiserver.TunnelSyncHealthChecker(c.Tunneler)))
|
|
|
|
prometheus.NewGaugeFunc(prometheus.GaugeOpts{
|
|
|
|
Name: "apiserver_proxy_tunnel_sync_latency_secs",
|
|
|
|
Help: "The time since the last successful synchronization of the SSH tunnels for proxy requests.",
|
|
|
|
}, func() float64 { return float64(c.Tunneler.SecondsSinceSync()) })
|
|
|
|
}
|
|
|
|
healthz.InstallHandler(&m.GenericAPIServer.HandlerContainer.NonSwaggerRoutes, healthzChecks...)
|
|
|
|
|
|
|
|
if c.GenericConfig.EnableProfiling {
|
|
|
|
routes.MetricsWithReset{}.Install(m.GenericAPIServer.HandlerContainer)
|
|
|
|
} else {
|
|
|
|
routes.DefaultMetrics{}.Install(m.GenericAPIServer.HandlerContainer)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Master) InstallAPIs(c *Config, legacyRESTStorageProvider corerest.LegacyRESTStorageProvider) {
|
2016-09-26 11:51:04 +00:00
|
|
|
restOptionsGetter := func(resource unversioned.GroupResource) generic.RESTOptions {
|
|
|
|
return m.restOptionsFactory.NewFor(resource)
|
|
|
|
}
|
|
|
|
|
2015-12-22 21:22:28 +00:00
|
|
|
apiGroupsInfo := []genericapiserver.APIGroupInfo{}
|
|
|
|
|
|
|
|
// Install v1 unless disabled.
|
2016-09-28 18:52:28 +00:00
|
|
|
if c.GenericConfig.APIResourceConfigSource.AnyResourcesForVersionEnabled(apiv1.SchemeGroupVersion) {
|
2016-09-30 16:16:32 +00:00
|
|
|
legacyRESTStorage, apiGroupInfo, err := legacyRESTStorageProvider.NewLegacyRESTStorage(restOptionsGetter)
|
2016-09-26 11:51:04 +00:00
|
|
|
if err != nil {
|
|
|
|
glog.Fatalf("Error building core storage: %v", err)
|
2016-02-24 19:22:34 +00:00
|
|
|
}
|
2016-09-30 16:06:54 +00:00
|
|
|
|
|
|
|
if c.EnableCoreControllers {
|
|
|
|
bootstrapController := c.NewBootstrapController(legacyRESTStorage)
|
|
|
|
if err := m.GenericAPIServer.AddPostStartHook("bootstrap-controller", bootstrapController.PostStartHook); err != nil {
|
|
|
|
glog.Fatalf("Error registering PostStartHook %q: %v", "bootstrap-controller", err)
|
|
|
|
}
|
|
|
|
}
|
2016-09-26 11:51:04 +00:00
|
|
|
|
2015-12-22 21:22:28 +00:00
|
|
|
apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo)
|
|
|
|
}
|
|
|
|
|
2016-07-27 14:29:31 +00:00
|
|
|
// Install third party resource support if requested
|
|
|
|
// TODO seems like this bit ought to be unconditional and the REST API is controlled by the config
|
2016-09-28 18:52:28 +00:00
|
|
|
if c.GenericConfig.APIResourceConfigSource.ResourceEnabled(extensionsapiv1beta1.SchemeGroupVersion.WithResource("thirdpartyresources")) {
|
2016-03-16 14:17:04 +00:00
|
|
|
var err error
|
2016-08-08 22:12:54 +00:00
|
|
|
m.thirdPartyStorageConfig, err = c.StorageFactory.NewConfig(extensions.Resource("thirdpartyresources"))
|
2016-03-16 14:17:04 +00:00
|
|
|
if err != nil {
|
|
|
|
glog.Fatalf("Error getting third party storage: %v", err)
|
|
|
|
}
|
2016-07-28 06:18:04 +00:00
|
|
|
m.thirdPartyResources = map[string]*thirdPartyEntry{}
|
2015-12-22 21:22:28 +00:00
|
|
|
}
|
2016-02-15 14:00:40 +00:00
|
|
|
|
2016-06-15 20:21:53 +00:00
|
|
|
// stabilize order.
|
|
|
|
// TODO find a better way to configure priority of groups
|
|
|
|
for _, group := range sets.StringKeySet(c.RESTStorageProviders).List() {
|
2016-09-28 18:52:28 +00:00
|
|
|
if !c.GenericConfig.APIResourceConfigSource.AnyResourcesForGroupEnabled(group) {
|
2016-09-07 12:57:54 +00:00
|
|
|
glog.V(1).Infof("Skipping disabled API group %q.", group)
|
2016-06-15 20:21:53 +00:00
|
|
|
continue
|
2016-05-07 00:03:43 +00:00
|
|
|
}
|
2016-06-15 20:21:53 +00:00
|
|
|
restStorageBuilder := c.RESTStorageProviders[group]
|
2016-09-28 18:52:28 +00:00
|
|
|
apiGroupInfo, enabled := restStorageBuilder.NewRESTStorage(c.GenericConfig.APIResourceConfigSource, restOptionsGetter)
|
2016-06-15 20:21:53 +00:00
|
|
|
if !enabled {
|
2016-09-07 12:57:54 +00:00
|
|
|
glog.Warningf("Problem initializing API group %q, skipping.", group)
|
2016-06-15 20:21:53 +00:00
|
|
|
continue
|
2016-04-15 22:30:15 +00:00
|
|
|
}
|
2016-09-07 12:57:54 +00:00
|
|
|
glog.V(1).Infof("Enabling API group %q.", group)
|
2016-04-14 01:45:43 +00:00
|
|
|
|
2016-09-15 17:41:48 +00:00
|
|
|
if postHookProvider, ok := restStorageBuilder.(genericapiserver.PostStartHookProvider); ok {
|
2016-08-26 15:06:27 +00:00
|
|
|
name, hook, err := postHookProvider.PostStartHook()
|
|
|
|
if err != nil {
|
|
|
|
glog.Fatalf("Error building PostStartHook: %v", err)
|
|
|
|
}
|
|
|
|
if err := m.GenericAPIServer.AddPostStartHook(name, hook); err != nil {
|
|
|
|
glog.Fatalf("Error registering PostStartHook %q: %v", name, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-25 21:20:41 +00:00
|
|
|
apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo)
|
|
|
|
}
|
|
|
|
|
2016-09-22 11:02:52 +00:00
|
|
|
for i := range apiGroupsInfo {
|
2016-09-30 16:16:32 +00:00
|
|
|
if err := m.GenericAPIServer.InstallAPIGroup(&apiGroupsInfo[i]); err != nil {
|
2016-09-22 11:02:52 +00:00
|
|
|
glog.Fatalf("Error in registering group versions: %v", err)
|
|
|
|
}
|
2015-10-09 05:18:16 +00:00
|
|
|
}
|
2015-11-16 21:46:00 +00:00
|
|
|
}
|
2015-10-09 05:18:16 +00:00
|
|
|
|
2016-09-26 11:51:04 +00:00
|
|
|
func getServersToValidate(storageFactory genericapiserver.StorageFactory) map[string]apiserver.Server {
|
2014-11-02 20:52:31 +00:00
|
|
|
serversToValidate := map[string]apiserver.Server{
|
2014-12-16 03:45:27 +00:00
|
|
|
"controller-manager": {Addr: "127.0.0.1", Port: ports.ControllerManagerPort, Path: "/healthz"},
|
|
|
|
"scheduler": {Addr: "127.0.0.1", Port: ports.SchedulerPort, Path: "/healthz"},
|
2014-11-02 20:52:31 +00:00
|
|
|
}
|
2015-09-30 07:56:51 +00:00
|
|
|
|
2016-09-26 11:51:04 +00:00
|
|
|
for ix, machine := range storageFactory.Backends() {
|
2014-11-02 20:52:31 +00:00
|
|
|
etcdUrl, err := url.Parse(machine)
|
|
|
|
if err != nil {
|
|
|
|
glog.Errorf("Failed to parse etcd url for validation: %v", err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
var port int
|
|
|
|
var addr string
|
|
|
|
if strings.Contains(etcdUrl.Host, ":") {
|
|
|
|
var portString string
|
|
|
|
addr, portString, err = net.SplitHostPort(etcdUrl.Host)
|
|
|
|
if err != nil {
|
|
|
|
glog.Errorf("Failed to split host/port: %s (%v)", etcdUrl.Host, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
port, _ = strconv.Atoi(portString)
|
|
|
|
} else {
|
|
|
|
addr = etcdUrl.Host
|
2016-08-10 20:39:36 +00:00
|
|
|
port = 2379
|
2014-11-02 20:52:31 +00:00
|
|
|
}
|
2015-12-03 16:09:45 +00:00
|
|
|
// TODO: etcd health checking should be abstracted in the storage tier
|
2016-04-06 03:44:45 +00:00
|
|
|
serversToValidate[fmt.Sprintf("etcd-%d", ix)] = apiserver.Server{
|
|
|
|
Addr: addr,
|
|
|
|
EnableHTTPS: etcdUrl.Scheme == "https",
|
|
|
|
Port: port,
|
|
|
|
Path: "/health",
|
|
|
|
Validate: etcdutil.EtcdHealthCheck,
|
|
|
|
}
|
2014-11-02 20:52:31 +00:00
|
|
|
}
|
|
|
|
return serversToValidate
|
|
|
|
}
|
|
|
|
|
2015-09-09 21:36:19 +00:00
|
|
|
// HasThirdPartyResource returns true if a particular third party resource currently installed.
|
2015-12-08 14:21:04 +00:00
|
|
|
func (m *Master) HasThirdPartyResource(rsrc *extensions.ThirdPartyResource) (bool, error) {
|
2016-07-28 06:18:04 +00:00
|
|
|
kind, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind(rsrc)
|
2015-09-09 21:36:19 +00:00
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
2016-09-23 19:10:47 +00:00
|
|
|
path := extensionsrest.MakeThirdPartyPath(group)
|
2016-07-28 06:18:04 +00:00
|
|
|
m.thirdPartyResourcesLock.Lock()
|
|
|
|
defer m.thirdPartyResourcesLock.Unlock()
|
|
|
|
entry := m.thirdPartyResources[path]
|
|
|
|
if entry == nil {
|
|
|
|
return false, nil
|
2015-09-09 21:36:19 +00:00
|
|
|
}
|
2016-07-28 06:18:04 +00:00
|
|
|
plural, _ := meta.KindToResource(unversioned.GroupVersionKind{
|
|
|
|
Group: group,
|
|
|
|
Version: rsrc.Versions[0].Name,
|
|
|
|
Kind: kind,
|
|
|
|
})
|
|
|
|
_, found := entry.storage[plural.Resource]
|
|
|
|
return found, nil
|
2015-09-09 21:36:19 +00:00
|
|
|
}
|
|
|
|
|
2016-07-28 06:18:04 +00:00
|
|
|
func (m *Master) removeThirdPartyStorage(path, resource string) error {
|
2015-09-09 21:36:19 +00:00
|
|
|
m.thirdPartyResourcesLock.Lock()
|
|
|
|
defer m.thirdPartyResourcesLock.Unlock()
|
2016-07-28 06:18:04 +00:00
|
|
|
entry, found := m.thirdPartyResources[path]
|
|
|
|
if !found {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
storage, found := entry.storage[resource]
|
|
|
|
if !found {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if err := m.removeAllThirdPartyResources(storage); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
delete(entry.storage, resource)
|
|
|
|
if len(entry.storage) == 0 {
|
2015-09-09 21:36:19 +00:00
|
|
|
delete(m.thirdPartyResources, path)
|
2016-09-30 16:16:32 +00:00
|
|
|
m.GenericAPIServer.RemoveAPIGroupForDiscovery(extensionsrest.GetThirdPartyGroupName(path))
|
2016-07-28 06:18:04 +00:00
|
|
|
} else {
|
|
|
|
m.thirdPartyResources[path] = entry
|
2015-09-09 21:36:19 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemoveThirdPartyResource removes all resources matching `path`. Also deletes any stored data
|
|
|
|
func (m *Master) RemoveThirdPartyResource(path string) error {
|
2016-07-28 06:18:04 +00:00
|
|
|
ix := strings.LastIndex(path, "/")
|
|
|
|
if ix == -1 {
|
|
|
|
return fmt.Errorf("expected <api-group>/<resource-plural-name>, saw: %s", path)
|
|
|
|
}
|
|
|
|
resource := path[ix+1:]
|
|
|
|
path = path[0:ix]
|
|
|
|
|
|
|
|
if err := m.removeThirdPartyStorage(path, resource); err != nil {
|
2015-09-09 21:36:19 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-09-30 16:16:32 +00:00
|
|
|
services := m.GenericAPIServer.HandlerContainer.RegisteredWebServices()
|
2015-09-09 21:36:19 +00:00
|
|
|
for ix := range services {
|
|
|
|
root := services[ix].RootPath()
|
|
|
|
if root == path || strings.HasPrefix(root, path+"/") {
|
2016-09-30 16:16:32 +00:00
|
|
|
m.GenericAPIServer.HandlerContainer.Remove(services[ix])
|
2015-09-09 21:36:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Master) removeAllThirdPartyResources(registry *thirdpartyresourcedataetcd.REST) error {
|
|
|
|
ctx := api.NewDefaultContext()
|
2015-10-27 13:47:58 +00:00
|
|
|
existingData, err := registry.List(ctx, nil)
|
2015-09-09 21:36:19 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-12-08 14:21:04 +00:00
|
|
|
list, ok := existingData.(*extensions.ThirdPartyResourceDataList)
|
2015-09-09 21:36:19 +00:00
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("expected a *ThirdPartyResourceDataList, got %#v", list)
|
|
|
|
}
|
|
|
|
for ix := range list.Items {
|
|
|
|
item := &list.Items[ix]
|
|
|
|
if _, err := registry.Delete(ctx, item.Name, nil); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ListThirdPartyResources lists all currently installed third party resources
|
2016-07-28 06:18:04 +00:00
|
|
|
// The format is <path>/<resource-plural-name>
|
2015-09-09 21:36:19 +00:00
|
|
|
func (m *Master) ListThirdPartyResources() []string {
|
|
|
|
m.thirdPartyResourcesLock.RLock()
|
|
|
|
defer m.thirdPartyResourcesLock.RUnlock()
|
|
|
|
result := []string{}
|
|
|
|
for key := range m.thirdPartyResources {
|
2016-07-28 06:18:04 +00:00
|
|
|
for rsrc := range m.thirdPartyResources[key].storage {
|
|
|
|
result = append(result, key+"/"+rsrc)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Master) getExistingThirdPartyResources(path string) []unversioned.APIResource {
|
|
|
|
result := []unversioned.APIResource{}
|
|
|
|
m.thirdPartyResourcesLock.Lock()
|
|
|
|
defer m.thirdPartyResourcesLock.Unlock()
|
|
|
|
entry := m.thirdPartyResources[path]
|
|
|
|
if entry != nil {
|
|
|
|
for key, obj := range entry.storage {
|
|
|
|
result = append(result, unversioned.APIResource{
|
|
|
|
Name: key,
|
|
|
|
Namespaced: true,
|
|
|
|
Kind: obj.Kind(),
|
|
|
|
})
|
|
|
|
}
|
2015-09-09 21:36:19 +00:00
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2016-07-28 06:18:04 +00:00
|
|
|
func (m *Master) hasThirdPartyGroupStorage(path string) bool {
|
2016-07-02 05:42:51 +00:00
|
|
|
m.thirdPartyResourcesLock.Lock()
|
|
|
|
defer m.thirdPartyResourcesLock.Unlock()
|
|
|
|
_, found := m.thirdPartyResources[path]
|
|
|
|
return found
|
|
|
|
}
|
|
|
|
|
2016-07-28 06:18:04 +00:00
|
|
|
func (m *Master) addThirdPartyResourceStorage(path, resource string, storage *thirdpartyresourcedataetcd.REST, apiGroup unversioned.APIGroup) {
|
2015-09-09 21:36:19 +00:00
|
|
|
m.thirdPartyResourcesLock.Lock()
|
|
|
|
defer m.thirdPartyResourcesLock.Unlock()
|
2016-07-28 06:18:04 +00:00
|
|
|
entry, found := m.thirdPartyResources[path]
|
|
|
|
if entry == nil {
|
|
|
|
entry = &thirdPartyEntry{
|
|
|
|
group: apiGroup,
|
|
|
|
storage: map[string]*thirdpartyresourcedataetcd.REST{},
|
|
|
|
}
|
|
|
|
m.thirdPartyResources[path] = entry
|
|
|
|
}
|
|
|
|
entry.storage[resource] = storage
|
|
|
|
if !found {
|
2016-09-30 16:16:32 +00:00
|
|
|
m.GenericAPIServer.AddAPIGroupForDiscovery(apiGroup)
|
2016-07-28 06:18:04 +00:00
|
|
|
}
|
2015-09-09 21:36:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// InstallThirdPartyResource installs a third party resource specified by 'rsrc'. When a resource is
|
|
|
|
// installed a corresponding RESTful resource is added as a valid path in the web service provided by
|
|
|
|
// the master.
|
|
|
|
//
|
|
|
|
// For example, if you install a resource ThirdPartyResource{ Name: "foo.company.com", Versions: {"v1"} }
|
|
|
|
// then the following RESTful resource is created on the server:
|
|
|
|
// http://<host>/apis/company.com/v1/foos/...
|
2015-12-08 14:21:04 +00:00
|
|
|
func (m *Master) InstallThirdPartyResource(rsrc *extensions.ThirdPartyResource) error {
|
2015-08-20 05:08:26 +00:00
|
|
|
kind, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind(rsrc)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-05-09 21:47:02 +00:00
|
|
|
plural, _ := meta.KindToResource(unversioned.GroupVersionKind{
|
|
|
|
Group: group,
|
|
|
|
Version: rsrc.Versions[0].Name,
|
|
|
|
Kind: kind,
|
|
|
|
})
|
2016-09-23 19:10:47 +00:00
|
|
|
path := extensionsrest.MakeThirdPartyPath(group)
|
2016-05-09 21:47:02 +00:00
|
|
|
|
2016-07-28 06:18:04 +00:00
|
|
|
groupVersion := unversioned.GroupVersionForDiscovery{
|
|
|
|
GroupVersion: group + "/" + rsrc.Versions[0].Name,
|
|
|
|
Version: rsrc.Versions[0].Name,
|
|
|
|
}
|
|
|
|
apiGroup := unversioned.APIGroup{
|
|
|
|
Name: group,
|
|
|
|
Versions: []unversioned.GroupVersionForDiscovery{groupVersion},
|
|
|
|
PreferredVersion: groupVersion,
|
|
|
|
}
|
|
|
|
|
2016-05-09 21:47:02 +00:00
|
|
|
thirdparty := m.thirdpartyapi(group, kind, rsrc.Versions[0].Name, plural.Resource)
|
2016-07-02 05:42:51 +00:00
|
|
|
|
|
|
|
// If storage exists, this group has already been added, just update
|
|
|
|
// the group with the new API
|
2016-07-28 06:18:04 +00:00
|
|
|
if m.hasThirdPartyGroupStorage(path) {
|
|
|
|
m.addThirdPartyResourceStorage(path, plural.Resource, thirdparty.Storage[plural.Resource].(*thirdpartyresourcedataetcd.REST), apiGroup)
|
2016-09-30 16:16:32 +00:00
|
|
|
return thirdparty.UpdateREST(m.GenericAPIServer.HandlerContainer.Container)
|
2016-07-02 05:42:51 +00:00
|
|
|
}
|
|
|
|
|
2016-09-30 16:16:32 +00:00
|
|
|
if err := thirdparty.InstallREST(m.GenericAPIServer.HandlerContainer.Container); err != nil {
|
2016-07-02 05:42:51 +00:00
|
|
|
glog.Errorf("Unable to setup thirdparty api: %v", err)
|
2015-08-19 18:02:01 +00:00
|
|
|
}
|
2016-09-30 16:16:32 +00:00
|
|
|
m.GenericAPIServer.HandlerContainer.Add(apiserver.NewGroupWebService(api.Codecs, path, apiGroup))
|
2016-05-09 21:47:02 +00:00
|
|
|
|
2016-07-28 06:18:04 +00:00
|
|
|
m.addThirdPartyResourceStorage(path, plural.Resource, thirdparty.Storage[plural.Resource].(*thirdpartyresourcedataetcd.REST), apiGroup)
|
2015-08-19 18:02:01 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-05-09 21:47:02 +00:00
|
|
|
func (m *Master) thirdpartyapi(group, kind, version, pluralResource string) *apiserver.APIGroupVersion {
|
2016-02-18 13:50:43 +00:00
|
|
|
resourceStorage := thirdpartyresourcedataetcd.NewREST(
|
2016-04-23 19:00:28 +00:00
|
|
|
generic.RESTOptions{
|
2016-08-08 22:12:54 +00:00
|
|
|
StorageConfig: m.thirdPartyStorageConfig,
|
2016-04-23 19:00:28 +00:00
|
|
|
Decorator: generic.UndecoratedStorage,
|
|
|
|
DeleteCollectionWorkers: m.deleteCollectionWorkers,
|
|
|
|
},
|
|
|
|
group,
|
|
|
|
kind,
|
|
|
|
)
|
2015-08-19 18:02:01 +00:00
|
|
|
|
|
|
|
storage := map[string]rest.Storage{
|
2016-05-09 21:47:02 +00:00
|
|
|
pluralResource: resourceStorage,
|
2015-08-19 18:02:01 +00:00
|
|
|
}
|
|
|
|
|
2016-01-13 22:40:56 +00:00
|
|
|
optionsExternalVersion := registered.GroupOrDie(api.GroupName).GroupVersion
|
2015-12-21 05:27:49 +00:00
|
|
|
internalVersion := unversioned.GroupVersion{Group: group, Version: runtime.APIVersionInternal}
|
|
|
|
externalVersion := unversioned.GroupVersion{Group: group, Version: version}
|
2015-11-12 20:20:20 +00:00
|
|
|
|
2016-09-23 19:10:47 +00:00
|
|
|
apiRoot := extensionsrest.MakeThirdPartyPath("")
|
2015-08-19 18:02:01 +00:00
|
|
|
return &apiserver.APIGroupVersion{
|
2016-09-26 15:18:19 +00:00
|
|
|
Root: apiRoot,
|
|
|
|
GroupVersion: externalVersion,
|
2015-08-19 18:02:01 +00:00
|
|
|
|
2015-09-29 21:36:47 +00:00
|
|
|
Creater: thirdpartyresourcedata.NewObjectCreator(group, version, api.Scheme),
|
2015-08-19 18:02:01 +00:00
|
|
|
Convertor: api.Scheme,
|
2016-04-29 01:21:35 +00:00
|
|
|
Copier: api.Scheme,
|
2015-08-19 18:02:01 +00:00
|
|
|
Typer: api.Scheme,
|
|
|
|
|
2016-01-13 22:40:56 +00:00
|
|
|
Mapper: thirdpartyresourcedata.NewMapper(registered.GroupOrDie(extensions.GroupName).RESTMapper, kind, version, group),
|
|
|
|
Linker: registered.GroupOrDie(extensions.GroupName).SelfLinker,
|
2015-12-08 19:40:23 +00:00
|
|
|
Storage: storage,
|
|
|
|
OptionsExternalVersion: &optionsExternalVersion,
|
2015-08-19 18:02:01 +00:00
|
|
|
|
2016-04-20 17:35:09 +00:00
|
|
|
Serializer: thirdpartyresourcedata.NewNegotiatedSerializer(api.Codecs, kind, externalVersion, internalVersion),
|
|
|
|
ParameterCodec: thirdpartyresourcedata.NewThirdPartyParameterCodec(api.ParameterCodec),
|
2015-12-21 05:27:49 +00:00
|
|
|
|
2016-09-30 16:16:32 +00:00
|
|
|
Context: m.GenericAPIServer.RequestContextMapper(),
|
2015-08-19 18:02:01 +00:00
|
|
|
|
2016-09-30 16:16:32 +00:00
|
|
|
MinRequestTimeout: m.GenericAPIServer.MinRequestTimeout(),
|
2016-07-28 06:18:04 +00:00
|
|
|
|
2016-09-23 19:10:47 +00:00
|
|
|
ResourceLister: dynamicLister{m, extensionsrest.MakeThirdPartyPath(group)},
|
2015-08-19 18:02:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-19 18:52:41 +00:00
|
|
|
type restOptionsFactory struct {
|
|
|
|
deleteCollectionWorkers int
|
|
|
|
enableGarbageCollection bool
|
|
|
|
storageFactory genericapiserver.StorageFactory
|
|
|
|
storageDecorator generic.StorageDecorator
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f restOptionsFactory) NewFor(resource unversioned.GroupResource) generic.RESTOptions {
|
|
|
|
storageConfig, err := f.storageFactory.NewConfig(resource)
|
2016-03-16 14:17:04 +00:00
|
|
|
if err != nil {
|
|
|
|
glog.Fatalf("Unable to find storage destination for %v, due to %v", resource, err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
return generic.RESTOptions{
|
2016-08-08 22:12:54 +00:00
|
|
|
StorageConfig: storageConfig,
|
2016-09-19 18:52:41 +00:00
|
|
|
Decorator: f.storageDecorator,
|
|
|
|
DeleteCollectionWorkers: f.deleteCollectionWorkers,
|
|
|
|
EnableGarbageCollection: f.enableGarbageCollection,
|
|
|
|
ResourcePrefix: f.storageFactory.ResourcePrefix(resource),
|
2016-03-16 14:17:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-28 08:10:48 +00:00
|
|
|
// findExternalAddress returns ExternalIP of provided node with fallback to LegacyHostIP.
|
2015-05-28 04:38:21 +00:00
|
|
|
func findExternalAddress(node *api.Node) (string, error) {
|
2015-07-28 08:10:48 +00:00
|
|
|
var fallback string
|
2015-05-28 04:38:21 +00:00
|
|
|
for ix := range node.Status.Addresses {
|
|
|
|
addr := &node.Status.Addresses[ix]
|
|
|
|
if addr.Type == api.NodeExternalIP {
|
|
|
|
return addr.Address, nil
|
|
|
|
}
|
2015-07-28 08:10:48 +00:00
|
|
|
if fallback == "" && addr.Type == api.NodeLegacyHostIP {
|
|
|
|
fallback = addr.Address
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if fallback != "" {
|
|
|
|
return fallback, nil
|
2015-05-28 04:38:21 +00:00
|
|
|
}
|
|
|
|
return "", fmt.Errorf("Couldn't find external address: %v", node)
|
|
|
|
}
|
|
|
|
|
2015-06-02 16:52:35 +00:00
|
|
|
func (m *Master) getNodeAddresses() ([]string, error) {
|
2016-09-30 16:06:54 +00:00
|
|
|
nodes, err := m.nodeClient.List(api.ListOptions{})
|
2015-05-28 04:38:21 +00:00
|
|
|
if err != nil {
|
2015-06-02 16:52:35 +00:00
|
|
|
return nil, err
|
2015-05-28 04:38:21 +00:00
|
|
|
}
|
2015-06-02 16:52:35 +00:00
|
|
|
addrs := []string{}
|
2015-05-28 04:38:21 +00:00
|
|
|
for ix := range nodes.Items {
|
|
|
|
node := &nodes.Items[ix]
|
|
|
|
addr, err := findExternalAddress(node)
|
|
|
|
if err != nil {
|
2015-06-02 16:52:35 +00:00
|
|
|
return nil, err
|
2015-05-28 04:38:21 +00:00
|
|
|
}
|
2015-06-02 16:52:35 +00:00
|
|
|
addrs = append(addrs, addr)
|
2015-05-28 04:38:21 +00:00
|
|
|
}
|
2015-06-02 16:52:35 +00:00
|
|
|
return addrs, nil
|
|
|
|
}
|
2015-05-28 04:38:21 +00:00
|
|
|
|
2016-03-22 16:45:23 +00:00
|
|
|
func DefaultAPIResourceConfigSource() *genericapiserver.ResourceConfig {
|
|
|
|
ret := genericapiserver.NewResourceConfig()
|
2016-06-15 20:21:53 +00:00
|
|
|
ret.EnableVersions(
|
|
|
|
apiv1.SchemeGroupVersion,
|
|
|
|
extensionsapiv1beta1.SchemeGroupVersion,
|
|
|
|
batchapiv1.SchemeGroupVersion,
|
2016-07-19 18:47:53 +00:00
|
|
|
authenticationv1beta1.SchemeGroupVersion,
|
2016-06-15 20:21:53 +00:00
|
|
|
autoscalingapiv1.SchemeGroupVersion,
|
|
|
|
appsapi.SchemeGroupVersion,
|
|
|
|
policyapiv1alpha1.SchemeGroupVersion,
|
|
|
|
rbacapi.SchemeGroupVersion,
|
2016-09-01 15:29:26 +00:00
|
|
|
storageapiv1beta1.SchemeGroupVersion,
|
2016-06-15 20:21:53 +00:00
|
|
|
certificatesapiv1alpha1.SchemeGroupVersion,
|
2016-02-03 18:08:10 +00:00
|
|
|
authorizationapiv1beta1.SchemeGroupVersion,
|
2016-06-15 20:21:53 +00:00
|
|
|
)
|
2016-03-22 16:45:23 +00:00
|
|
|
|
|
|
|
// all extensions resources except these are disabled by default
|
|
|
|
ret.EnableResources(
|
|
|
|
extensionsapiv1beta1.SchemeGroupVersion.WithResource("daemonsets"),
|
|
|
|
extensionsapiv1beta1.SchemeGroupVersion.WithResource("deployments"),
|
|
|
|
extensionsapiv1beta1.SchemeGroupVersion.WithResource("horizontalpodautoscalers"),
|
|
|
|
extensionsapiv1beta1.SchemeGroupVersion.WithResource("ingresses"),
|
|
|
|
extensionsapiv1beta1.SchemeGroupVersion.WithResource("jobs"),
|
2016-07-06 20:30:48 +00:00
|
|
|
extensionsapiv1beta1.SchemeGroupVersion.WithResource("networkpolicies"),
|
2016-03-22 16:45:23 +00:00
|
|
|
extensionsapiv1beta1.SchemeGroupVersion.WithResource("replicasets"),
|
|
|
|
extensionsapiv1beta1.SchemeGroupVersion.WithResource("thirdpartyresources"),
|
|
|
|
)
|
|
|
|
|
|
|
|
return ret
|
|
|
|
}
|