2014-06-16 06:29:07 +00:00
/ *
Copyright 2014 Google Inc . 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 master
import (
2014-11-11 07:11:45 +00:00
"bytes"
2014-11-02 20:52:31 +00:00
"fmt"
2014-09-18 23:03:34 +00:00
"net"
2014-10-23 23:55:14 +00:00
"net/http"
2015-03-13 15:44:11 +00:00
"net/http/pprof"
2014-11-02 20:52:31 +00:00
"net/url"
2014-11-11 07:11:45 +00:00
rt "runtime"
2014-10-28 00:56:33 +00:00
"strconv"
2014-10-23 23:55:14 +00:00
"strings"
2014-06-16 06:29:07 +00:00
"time"
2015-01-06 16:44:43 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
2014-11-02 20:52:31 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
2014-09-11 23:01:29 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
2014-09-11 17:02:53 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
2014-09-11 17:04:13 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
2015-01-08 17:42:20 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
2014-06-16 06:29:07 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
2014-10-27 21:18:02 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator"
2014-11-03 15:57:08 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authorizer"
2014-10-23 23:55:14 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/handlers"
2014-06-16 06:29:07 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
2014-06-17 17:50:42 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
2014-12-16 03:45:27 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/master/ports"
2014-08-11 07:34:59 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/controller"
2014-08-14 19:48:34 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/endpoint"
2014-08-11 07:34:59 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/etcd"
2014-10-09 22:46:41 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/event"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
2015-01-22 21:52:40 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/limitrange"
2014-08-11 07:34:59 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/minion"
2015-01-19 21:50:00 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/namespace"
2014-08-11 07:34:59 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod"
2015-02-11 23:37:12 +00:00
podetcd "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod/etcd"
2015-03-13 19:15:04 +00:00
resourcequotaetcd "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/resourcequota/etcd"
2015-02-18 01:24:50 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/secret"
2014-08-11 07:34:59 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/service"
2014-09-11 23:01:29 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
2014-10-23 20:56:18 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/ui"
2014-06-16 06:29:07 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
2014-10-23 23:55:14 +00:00
2014-11-11 07:11:45 +00:00
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful/swagger"
2014-10-23 23:55:14 +00:00
"github.com/golang/glog"
2014-06-16 06:29:07 +00:00
)
2014-07-27 02:16:39 +00:00
// Config is a structure used to configure a Master.
type Config struct {
2015-01-30 23:53:04 +00:00
Client * client . Client
Cloud cloudprovider . Interface
EtcdHelper tools . EtcdHelper
EventTTL time . Duration
MinionRegexp string
KubeletClient client . KubeletClient
PortalNet * net . IPNet
EnableLogsSupport bool
EnableUISupport bool
// allow downstream consumers to disable swagger
EnableSwaggerSupport bool
// allow v1beta3 to be conditionally enabled
EnableV1Beta3 bool
// allow downstream consumers to disable the index route
EnableIndex bool
2015-03-13 15:44:11 +00:00
EnableProfiling bool
2015-01-08 15:25:14 +00:00
APIPrefix string
CorsAllowedOriginList util . StringList
Authenticator authenticator . Request
Authorizer authorizer . Authorizer
AdmissionControl admission . Interface
MasterServiceNamespace string
2014-10-28 00:56:33 +00:00
2015-02-11 22:09:25 +00:00
// Map requests to contexts. Exported so downstream consumers can provider their own mappers
RequestContextMapper api . RequestContextMapper
2014-12-15 20:29:55 +00:00
// If specified, all web services will be registered into this container
RestfulContainer * restful . Container
2014-10-28 23:49:52 +00:00
// Number of masters running; all masters must be started with the
// same value for this field. (Numbers > 1 currently untested.)
MasterCount int
2014-10-28 00:56:33 +00:00
// The port on PublicAddress where a read-only server will be installed.
// Defaults to 7080 if not set.
ReadOnlyPort int
// The port on PublicAddress where a read-write server will be installed.
2015-02-07 00:33:28 +00:00
// Defaults to 6443 if not set.
2014-10-28 00:56:33 +00:00
ReadWritePort int
2015-01-20 03:25:06 +00:00
// If nil, the first result from net.InterfaceAddrs will be used.
PublicAddress net . IP
2015-01-28 22:39:57 +00:00
// Control the interval that pod, node IP, and node heath status caches
// expire.
CacheTimeout time . Duration
2015-02-13 22:58:42 +00:00
// The name of the cluster.
ClusterName string
2015-02-25 13:33:08 +00:00
// If true we will periodically probe pods statuses.
SyncPodStatus bool
2014-07-27 02:16:39 +00:00
}
2014-06-16 06:29:07 +00:00
// Master contains state for a Kubernetes cluster master/api server.
type Master struct {
2014-10-23 23:55:14 +00:00
// "Inputs", Copied from Config
2015-02-12 00:07:54 +00:00
client * client . Client
portalNet * net . IPNet
cacheTimeout time . Duration
2014-12-15 20:29:55 +00:00
2014-10-23 23:55:14 +00:00
mux apiserver . Mux
2015-01-16 00:18:47 +00:00
muxHelper * apiserver . MuxHelper
2014-11-11 07:11:45 +00:00
handlerContainer * restful . Container
rootWebService * restful . WebService
2014-10-23 23:55:14 +00:00
enableLogsSupport bool
enableUISupport bool
2014-12-15 20:29:55 +00:00
enableSwaggerSupport bool
2015-03-13 15:44:11 +00:00
enableProfiling bool
2014-10-23 23:55:14 +00:00
apiPrefix string
corsAllowedOriginList util . StringList
2014-11-19 15:31:43 +00:00
authenticator authenticator . Request
2014-11-02 06:50:00 +00:00
authorizer authorizer . Authorizer
2015-01-07 19:33:21 +00:00
admissionControl admission . Interface
2014-10-28 23:49:52 +00:00
masterCount int
2015-01-08 17:42:20 +00:00
v1beta3 bool
2015-02-11 22:09:25 +00:00
requestContextMapper api . RequestContextMapper
2014-10-28 00:56:33 +00:00
2015-01-20 03:25:06 +00:00
publicIP net . IP
publicReadOnlyPort int
publicReadWritePort int
serviceReadOnlyIP net . IP
serviceReadOnlyPort int
serviceReadWriteIP net . IP
serviceReadWritePort int
masterServices * util . Runner
2014-11-06 17:11:31 +00:00
2015-02-12 00:07:54 +00:00
// storage contains the RESTful endpoints exposed by this master
storage map [ string ] apiserver . RESTStorage
// registries are internal client APIs for accessing the storage layer
// TODO: define the internal typed interface in a way that clients can
// also be replaced
nodeRegistry minion . Registry
namespaceRegistry generic . Registry
serviceRegistry service . Registry
endpointRegistry endpoint . Registry
2014-11-06 17:11:31 +00:00
// "Outputs"
Handler http . Handler
InsecureHandler http . Handler
2014-06-16 06:29:07 +00:00
}
2014-09-11 23:01:29 +00:00
// NewEtcdHelper returns an EtcdHelper for the provided arguments or an error if the version
// is incorrect.
2014-09-26 01:11:01 +00:00
func NewEtcdHelper ( client tools . EtcdGetSet , version string ) ( helper tools . EtcdHelper , err error ) {
2014-09-11 23:01:29 +00:00
if version == "" {
version = latest . Version
}
2014-09-25 22:08:09 +00:00
versionInterfaces , err := latest . InterfacesFor ( version )
2014-09-11 23:01:29 +00:00
if err != nil {
return helper , err
}
2014-10-27 03:01:17 +00:00
return tools . EtcdHelper { client , versionInterfaces . Codec , tools . RuntimeVersionAdapter { versionInterfaces . MetadataAccessor } } , nil
2014-09-11 23:01:29 +00:00
}
2014-10-28 00:56:33 +00:00
// setDefaults fills in any fields not set that are required to have valid data.
func setDefaults ( c * Config ) {
2014-10-29 19:27:35 +00:00
if c . PortalNet == nil {
defaultNet := "10.0.0.0/24"
glog . Warningf ( "Portal net unspecified. Defaulting to %v." , defaultNet )
_ , portalNet , err := net . ParseCIDR ( defaultNet )
if err != nil {
glog . Fatalf ( "Unable to parse CIDR: %v" , err )
}
c . PortalNet = portalNet
}
2014-10-28 23:49:52 +00:00
if c . MasterCount == 0 {
// Clearly, there will be at least one master.
c . MasterCount = 1
}
2014-10-28 00:56:33 +00:00
if c . ReadOnlyPort == 0 {
c . ReadOnlyPort = 7080
}
2015-02-07 00:33:28 +00:00
if c . ReadWritePort == 0 {
c . ReadWritePort = 6443
}
2015-01-28 22:39:57 +00:00
if c . CacheTimeout == 0 {
c . CacheTimeout = 5 * time . Second
}
2015-01-20 03:25:06 +00:00
for c . PublicAddress == nil {
2014-10-28 23:49:52 +00:00
// Find and use the first non-loopback address.
// TODO: potentially it'd be useful to skip the docker interface if it
// somehow is first in the list.
2014-10-28 00:56:33 +00:00
addrs , err := net . InterfaceAddrs ( )
if err != nil {
glog . Fatalf ( "Unable to get network interfaces: error='%v'" , err )
}
found := false
for i := range addrs {
ip , _ , err := net . ParseCIDR ( addrs [ i ] . String ( ) )
if err != nil {
glog . Errorf ( "Error parsing '%v': %v" , addrs [ i ] , err )
continue
}
if ip . IsLoopback ( ) {
glog . Infof ( "'%v' (%v) is a loopback address, ignoring." , ip , addrs [ i ] )
continue
}
found = true
2015-01-20 03:25:06 +00:00
c . PublicAddress = ip
2014-10-28 00:56:33 +00:00
glog . Infof ( "Will report %v as public IP address." , ip )
break
}
if ! found {
2015-01-18 07:32:34 +00:00
glog . Errorf ( "Unable to find suitable network address in list: '%v'\n" +
2014-11-05 20:07:33 +00:00
"Will try again in 5 seconds. Set the public address directly to avoid this wait." , addrs )
time . Sleep ( 5 * time . Second )
2014-10-28 00:56:33 +00:00
}
}
2015-02-11 22:09:25 +00:00
if c . RequestContextMapper == nil {
c . RequestContextMapper = api . NewRequestContextMapper ( )
}
2014-10-28 00:56:33 +00:00
}
2014-10-28 20:02:19 +00:00
// New returns a new instance of Master from the given config.
// Certain config fields will be set to a default value if unset,
// including:
// PortalNet
// MasterCount
// ReadOnlyPort
// ReadWritePort
// PublicAddress
// Certain config fields must be specified, including:
// KubeletClient
// Public fields:
// Handler -- The returned master has a field TopHandler which is an
// http.Handler which handles all the endpoints provided by the master,
// including the API, the UI, and miscelaneous debugging endpoints. All
// these are subject to authorization and authentication.
2014-11-06 17:11:31 +00:00
// InsecureHandler -- an http.Handler which handles all the same
// endpoints as Handler, but no authorization and authentication is done.
2014-10-28 20:02:19 +00:00
// Public methods:
// HandleWithAuth -- Allows caller to add an http.Handler for an endpoint
// that uses the same authentication and authorization (if any is configured)
// as the master's built-in endpoints.
// If the caller wants to add additional endpoints not using the master's
// auth, then the caller should create a handler for those endpoints, which delegates the
// any unhandled paths to "Handler".
2014-07-27 02:16:39 +00:00
func New ( c * Config ) * Master {
2014-10-28 00:56:33 +00:00
setDefaults ( c )
2014-11-03 22:50:41 +00:00
if c . KubeletClient == nil {
glog . Fatalf ( "master.New() called with config.KubeletClient == nil" )
}
2014-12-15 20:29:55 +00:00
2015-01-20 03:25:06 +00:00
// Select the first two valid IPs from portalNet to use as the master service portalIPs
serviceReadOnlyIP , err := service . GetIndexedIP ( c . PortalNet , 1 )
if err != nil {
glog . Fatalf ( "Failed to generate service read-only IP for master service: %v" , err )
}
serviceReadWriteIP , err := service . GetIndexedIP ( c . PortalNet , 2 )
if err != nil {
glog . Fatalf ( "Failed to generate service read-write IP for master service: %v" , err )
}
glog . Infof ( "Setting master service IPs based on PortalNet subnet to %q (read-only) and %q (read-write)." , serviceReadOnlyIP , serviceReadWriteIP )
2014-06-16 06:29:07 +00:00
m := & Master {
2014-10-23 23:55:14 +00:00
client : c . Client ,
portalNet : c . PortalNet ,
2014-11-11 07:11:45 +00:00
rootWebService : new ( restful . WebService ) ,
2014-10-23 23:55:14 +00:00
enableLogsSupport : c . EnableLogsSupport ,
enableUISupport : c . EnableUISupport ,
2014-12-15 20:29:55 +00:00
enableSwaggerSupport : c . EnableSwaggerSupport ,
2015-03-13 15:44:11 +00:00
enableProfiling : c . EnableProfiling ,
2014-10-23 23:55:14 +00:00
apiPrefix : c . APIPrefix ,
corsAllowedOriginList : c . CorsAllowedOriginList ,
2014-11-19 15:31:43 +00:00
authenticator : c . Authenticator ,
2014-11-02 06:50:00 +00:00
authorizer : c . Authorizer ,
2015-01-06 16:44:43 +00:00
admissionControl : c . AdmissionControl ,
2015-01-08 17:42:20 +00:00
v1beta3 : c . EnableV1Beta3 ,
2015-02-11 22:09:25 +00:00
requestContextMapper : c . RequestContextMapper ,
2015-01-28 22:39:57 +00:00
cacheTimeout : c . CacheTimeout ,
2014-10-16 21:18:16 +00:00
2015-01-20 03:25:06 +00:00
masterCount : c . MasterCount ,
publicIP : c . PublicAddress ,
publicReadOnlyPort : c . ReadOnlyPort ,
publicReadWritePort : c . ReadWritePort ,
serviceReadOnlyIP : serviceReadOnlyIP ,
// TODO: serviceReadOnlyPort should be passed in as an argument, it may not always be 80
serviceReadOnlyPort : 80 ,
serviceReadWriteIP : serviceReadWriteIP ,
// TODO: serviceReadWritePort should be passed in as an argument, it may not always be 443
serviceReadWritePort : 443 ,
2014-06-16 06:29:07 +00:00
}
2014-12-15 20:29:55 +00:00
if c . RestfulContainer != nil {
m . mux = c . RestfulContainer . ServeMux
m . handlerContainer = c . RestfulContainer
} else {
mux := http . NewServeMux ( )
m . mux = mux
m . handlerContainer = NewHandlerContainer ( mux )
}
2015-01-31 00:08:59 +00:00
// Use CurlyRouter to be able to use regular expressions in paths. Regular expressions are required in paths for example for proxy (where the path is proxy/{kind}/{name}/{*})
m . handlerContainer . Router ( restful . CurlyRouter { } )
2015-01-16 00:18:47 +00:00
m . muxHelper = & apiserver . MuxHelper { m . mux , [ ] string { } }
2014-12-15 20:29:55 +00:00
2014-10-28 23:49:52 +00:00
m . masterServices = util . NewRunner ( m . serviceWriterLoop , m . roServiceWriterLoop )
2014-10-08 23:14:37 +00:00
m . init ( c )
2014-06-16 06:29:07 +00:00
return m
}
2014-10-28 20:02:19 +00:00
// HandleWithAuth adds an http.Handler for pattern to an http.ServeMux
// Applies the same authentication and authorization (if any is configured)
// to the request is used for the master's built-in endpoints.
func ( m * Master ) HandleWithAuth ( pattern string , handler http . Handler ) {
// TODO: Add a way for plugged-in endpoints to translate their
// URLs into attributes that an Authorizer can understand, and have
// sensible policy defaults for plugged-in endpoints. This will be different
// for generic endpoints versus REST object endpoints.
2014-11-11 07:11:45 +00:00
// TODO: convert to go-restful
2015-01-16 00:18:47 +00:00
m . muxHelper . Handle ( pattern , handler )
2014-10-28 20:02:19 +00:00
}
// HandleFuncWithAuth adds an http.Handler for pattern to an http.ServeMux
// Applies the same authentication and authorization (if any is configured)
// to the request is used for the master's built-in endpoints.
func ( m * Master ) HandleFuncWithAuth ( pattern string , handler func ( http . ResponseWriter , * http . Request ) ) {
2014-11-11 07:11:45 +00:00
// TODO: convert to go-restful
2015-01-16 00:18:47 +00:00
m . muxHelper . HandleFunc ( pattern , handler )
2014-10-28 20:02:19 +00:00
}
2014-11-11 07:11:45 +00:00
func NewHandlerContainer ( mux * http . ServeMux ) * restful . Container {
container := restful . NewContainer ( )
container . ServeMux = mux
container . RecoverHandler ( logStackOnRecover )
return container
}
//TODO: Unify with RecoverPanics?
func logStackOnRecover ( panicReason interface { } , httpWriter http . ResponseWriter ) {
var buffer bytes . Buffer
buffer . WriteString ( fmt . Sprintf ( "recover from panic situation: - %v\r\n" , panicReason ) )
for i := 2 ; ; i += 1 {
_ , file , line , ok := rt . Caller ( i )
if ! ok {
break
}
buffer . WriteString ( fmt . Sprintf ( " %s:%d\r\n" , file , line ) )
}
glog . Errorln ( buffer . String ( ) )
}
2014-10-08 23:14:37 +00:00
// init initializes master.
func ( m * Master ) init ( c * Config ) {
2015-03-13 08:58:00 +00:00
podStorage , bindingStorage , podStatusStorage := podetcd . NewREST ( c . EtcdHelper )
2015-02-11 23:37:12 +00:00
podRegistry := pod . NewRegistry ( podStorage )
2015-02-12 00:07:54 +00:00
eventRegistry := event . NewEtcdRegistry ( c . EtcdHelper , uint64 ( c . EventTTL . Seconds ( ) ) )
limitRangeRegistry := limitrange . NewEtcdRegistry ( c . EtcdHelper )
2015-03-13 19:15:04 +00:00
resourceQuotaStorage , resourceQuotaStatusStorage := resourcequotaetcd . NewREST ( c . EtcdHelper )
2015-02-18 01:24:50 +00:00
secretRegistry := secret . NewEtcdRegistry ( c . EtcdHelper )
2015-02-12 00:07:54 +00:00
m . namespaceRegistry = namespace . NewEtcdRegistry ( c . EtcdHelper )
// TODO: split me up into distinct storage registries
registry := etcd . NewRegistry ( c . EtcdHelper , podRegistry )
m . serviceRegistry = registry
m . endpointRegistry = registry
m . nodeRegistry = registry
nodeStorage := minion . NewREST ( m . nodeRegistry )
// TODO: unify the storage -> registry and storage -> client patterns
nodeStorageClient := RESTStorageToNodes ( nodeStorage )
2014-12-21 02:49:10 +00:00
podCache := NewPodCache (
c . KubeletClient ,
2015-02-12 00:07:54 +00:00
nodeStorageClient . Nodes ( ) ,
2015-02-11 23:37:12 +00:00
podRegistry ,
2014-12-21 02:49:10 +00:00
)
2015-02-25 13:33:08 +00:00
if c . SyncPodStatus {
go util . Forever ( func ( ) { podCache . UpdateAllContainers ( ) } , m . cacheTimeout )
}
2015-01-29 06:15:23 +00:00
go util . Forever ( func ( ) { podCache . GarbageCollectPodStatus ( ) } , time . Minute * 30 )
2014-12-19 01:47:59 +00:00
2015-02-11 23:37:12 +00:00
// TODO: refactor podCache to sit on top of podStorage via status calls
podStorage = podStorage . WithPodStatus ( podCache )
2014-11-11 07:11:45 +00:00
// TODO: Factor out the core API registration
2014-06-16 06:29:07 +00:00
m . storage = map [ string ] apiserver . RESTStorage {
2015-03-04 20:55:41 +00:00
"pods" : podStorage ,
"pods/status" : podStatusStorage ,
"pods/binding" : bindingStorage ,
"bindings" : bindingStorage ,
2015-02-11 23:37:12 +00:00
2015-02-12 00:07:54 +00:00
"replicationControllers" : controller . NewREST ( registry , podRegistry ) ,
2015-02-13 22:58:42 +00:00
"services" : service . NewREST ( m . serviceRegistry , c . Cloud , m . nodeRegistry , m . portalNet , c . ClusterName ) ,
2014-09-08 21:40:56 +00:00
"endpoints" : endpoint . NewREST ( m . endpointRegistry ) ,
2015-02-12 00:07:54 +00:00
"minions" : nodeStorage ,
"nodes" : nodeStorage ,
"events" : event . NewREST ( eventRegistry ) ,
2014-08-15 23:01:33 +00:00
2015-03-13 19:15:04 +00:00
"limitRanges" : limitrange . NewREST ( limitRangeRegistry ) ,
"resourceQuotas" : resourceQuotaStorage ,
"resourceQuotas/status" : resourceQuotaStatusStorage ,
"namespaces" : namespace . NewREST ( m . namespaceRegistry ) ,
"secrets" : secret . NewREST ( secretRegistry ) ,
2014-06-16 06:29:07 +00:00
}
2014-10-28 00:56:33 +00:00
2015-01-07 23:43:38 +00:00
apiVersions := [ ] string { "v1beta1" , "v1beta2" }
2015-03-04 20:57:05 +00:00
if err := m . api_v1beta1 ( ) . InstallREST ( m . handlerContainer ) ; err != nil {
2015-01-15 19:18:17 +00:00
glog . Fatalf ( "Unable to setup API v1beta1: %v" , err )
}
2015-03-04 20:57:05 +00:00
if err := m . api_v1beta2 ( ) . InstallREST ( m . handlerContainer ) ; err != nil {
2015-01-15 19:18:17 +00:00
glog . Fatalf ( "Unable to setup API v1beta2: %v" , err )
}
2015-01-08 17:42:20 +00:00
if c . EnableV1Beta3 {
2015-03-04 20:57:05 +00:00
if err := m . api_v1beta3 ( ) . InstallREST ( m . handlerContainer ) ; err != nil {
2015-01-15 19:18:17 +00:00
glog . Fatalf ( "Unable to setup API v1beta3: %v" , err )
}
2015-01-07 23:43:38 +00:00
apiVersions = [ ] string { "v1beta1" , "v1beta2" , "v1beta3" }
2015-01-08 17:42:20 +00:00
}
2014-11-11 07:11:45 +00:00
2015-01-16 00:18:47 +00:00
apiserver . InstallSupport ( m . muxHelper , m . rootWebService )
2015-01-07 23:43:38 +00:00
apiserver . AddApiWebService ( m . handlerContainer , c . APIPrefix , apiVersions )
// Register root handler.
// We do not register this using restful Webservice since we do not want to surface this in api docs.
2015-01-30 23:53:04 +00:00
// Allow master to be embedded in contexts which already have something registered at the root
if c . EnableIndex {
m . mux . HandleFunc ( "/" , apiserver . IndexHandler ( m . handlerContainer , m . muxHelper ) )
}
2014-11-11 07:11:45 +00:00
// TODO: use go-restful
2015-01-16 00:18:47 +00:00
apiserver . InstallValidator ( m . muxHelper , func ( ) map [ string ] apiserver . Server { return m . getServersToValidate ( c ) } )
2014-10-23 20:56:18 +00:00
if c . EnableLogsSupport {
2015-01-16 00:18:47 +00:00
apiserver . InstallLogsSupport ( m . muxHelper )
2014-10-23 20:56:18 +00:00
}
if c . EnableUISupport {
2015-01-16 00:18:47 +00:00
ui . InstallSupport ( m . muxHelper , m . enableSwaggerSupport )
2014-10-23 20:56:18 +00:00
}
2014-10-23 23:55:14 +00:00
2015-03-13 15:44:11 +00:00
if c . EnableProfiling {
m . mux . HandleFunc ( "/debug/pprof/" , pprof . Index )
m . mux . HandleFunc ( "/debug/pprof/profile" , pprof . Profile )
m . mux . HandleFunc ( "/debug/pprof/symbol" , pprof . Symbol )
}
2014-11-11 07:11:45 +00:00
2014-10-23 23:55:14 +00:00
handler := http . Handler ( m . mux . ( * http . ServeMux ) )
2014-11-11 07:11:45 +00:00
// TODO: handle CORS and auth using go-restful
// See github.com/emicklei/go-restful/blob/master/examples/restful-CORS-filter.go, and
// github.com/emicklei/go-restful/blob/master/examples/restful-basic-authentication.go
2014-10-23 23:55:14 +00:00
if len ( c . CorsAllowedOriginList ) > 0 {
allowedOriginRegexps , err := util . CompileRegexps ( c . CorsAllowedOriginList )
if err != nil {
glog . Fatalf ( "Invalid CORS allowed origin, --cors_allowed_origins flag was set to %v - %v" , strings . Join ( c . CorsAllowedOriginList , "," ) , err )
}
handler = apiserver . CORS ( handler , allowedOriginRegexps , nil , nil , "true" )
}
2014-11-06 17:11:31 +00:00
m . InsecureHandler = handler
2015-02-11 22:09:25 +00:00
attributeGetter := apiserver . NewRequestAttributeGetter ( m . requestContextMapper , latest . RESTMapper , "api" )
2014-11-02 06:50:00 +00:00
handler = apiserver . WithAuthorizationCheck ( handler , attributeGetter , m . authorizer )
2014-10-16 21:18:16 +00:00
// Install Authenticator
2015-02-11 22:09:25 +00:00
if c . Authenticator != nil {
authenticatedHandler , err := handlers . NewRequestAuthenticator ( m . requestContextMapper , c . Authenticator , handlers . Unauthorized , handler )
if err != nil {
glog . Fatalf ( "Could not initialize authenticator: %v" , err )
}
handler = authenticatedHandler
2014-10-23 23:55:14 +00:00
}
2014-11-11 07:11:45 +00:00
// Install root web services
m . handlerContainer . Add ( m . rootWebService )
2014-12-15 20:29:55 +00:00
// TODO: Make this optional? Consumers of master depend on this currently.
m . Handler = handler
if m . enableSwaggerSupport {
m . InstallSwaggerAPI ( )
}
2015-02-11 22:09:25 +00:00
// After all wrapping is done, put a context filter around both handlers
if handler , err := api . NewRequestContextFilter ( m . requestContextMapper , m . Handler ) ; err != nil {
glog . Fatalf ( "Could not initialize request context filter: %v" , err )
} else {
m . Handler = handler
}
if handler , err := api . NewRequestContextFilter ( m . requestContextMapper , m . InsecureHandler ) ; err != nil {
glog . Fatalf ( "Could not initialize request context filter: %v" , err )
} else {
m . InsecureHandler = handler
}
2014-12-15 20:29:55 +00:00
// TODO: Attempt clean shutdown?
m . masterServices . Start ( )
}
// InstallSwaggerAPI installs the /swaggerapi/ endpoint to allow schema discovery
// and traversal. It is optional to allow consumers of the Kubernetes master to
// register their own web services into the Kubernetes mux prior to initialization
// of swagger, so that other resource types show up in the documentation.
func ( m * Master ) InstallSwaggerAPI ( ) {
2015-03-11 23:14:14 +00:00
webServicesUrl := ""
// Use the secure read write port, if available.
if m . publicReadWritePort != 0 {
webServicesUrl = "https://" + net . JoinHostPort ( m . publicIP . String ( ) , strconv . Itoa ( m . publicReadWritePort ) )
} else {
// Use the read only port.
webServicesUrl = "http://" + net . JoinHostPort ( m . publicIP . String ( ) , strconv . Itoa ( m . publicReadOnlyPort ) )
}
2014-11-11 07:11:45 +00:00
// Enable swagger UI and discovery API
swaggerConfig := swagger . Config {
2015-03-11 23:14:14 +00:00
WebServicesUrl : webServicesUrl ,
WebServices : m . handlerContainer . RegisteredWebServices ( ) ,
2014-12-20 00:16:54 +00:00
ApiPath : "/swaggerapi/" ,
SwaggerPath : "/swaggerui/" ,
2015-01-05 23:50:19 +00:00
SwaggerFilePath : "/swagger-ui/" ,
2014-11-11 07:11:45 +00:00
}
swagger . RegisterSwaggerService ( swaggerConfig , m . handlerContainer )
2014-06-16 06:29:07 +00:00
}
2014-11-02 20:52:31 +00:00
func ( m * Master ) getServersToValidate ( c * Config ) map [ string ] apiserver . Server {
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
}
for ix , machine := range c . EtcdHelper . Client . GetCluster ( ) {
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
port = 4001
}
serversToValidate [ fmt . Sprintf ( "etcd-%d" , ix ) ] = apiserver . Server { Addr : addr , Port : port , Path : "/v2/keys/" }
}
2015-02-12 00:07:54 +00:00
nodes , err := m . nodeRegistry . ListMinions ( api . NewDefaultContext ( ) )
2014-11-02 20:52:31 +00:00
if err != nil {
glog . Errorf ( "Failed to list minions: %v" , err )
}
for ix , node := range nodes . Items {
2014-12-16 03:45:27 +00:00
serversToValidate [ fmt . Sprintf ( "node-%d" , ix ) ] = apiserver . Server { Addr : node . Name , Port : ports . KubeletPort , Path : "/healthz" }
2014-11-02 20:52:31 +00:00
}
return serversToValidate
}
2015-03-04 20:57:05 +00:00
func ( m * Master ) defaultAPIGroupVersion ( ) * apiserver . APIGroupVersion {
return & apiserver . APIGroupVersion {
Root : m . apiPrefix ,
Mapper : latest . RESTMapper ,
Creater : api . Scheme ,
Typer : api . Scheme ,
Linker : latest . SelfLinker ,
Admit : m . admissionControl ,
Context : m . requestContextMapper ,
}
}
2015-01-15 00:35:16 +00:00
// api_v1beta1 returns the resources and codec for API version v1beta1.
2015-03-04 20:57:05 +00:00
func ( m * Master ) api_v1beta1 ( ) * apiserver . APIGroupVersion {
2014-08-09 21:12:55 +00:00
storage := make ( map [ string ] apiserver . RESTStorage )
for k , v := range m . storage {
storage [ k ] = v
2014-06-16 06:29:07 +00:00
}
2015-03-04 20:57:05 +00:00
version := m . defaultAPIGroupVersion ( )
version . Storage = storage
version . Version = "v1beta1"
version . Codec = v1beta1 . Codec
return version
2014-06-24 01:28:06 +00:00
}
2014-09-11 17:04:13 +00:00
2015-01-15 00:35:16 +00:00
// api_v1beta2 returns the resources and codec for API version v1beta2.
2015-03-04 20:57:05 +00:00
func ( m * Master ) api_v1beta2 ( ) * apiserver . APIGroupVersion {
2014-09-11 17:04:13 +00:00
storage := make ( map [ string ] apiserver . RESTStorage )
for k , v := range m . storage {
storage [ k ] = v
}
2015-03-04 20:57:05 +00:00
version := m . defaultAPIGroupVersion ( )
version . Storage = storage
version . Version = "v1beta2"
version . Codec = v1beta2 . Codec
return version
2014-09-11 17:04:13 +00:00
}
2015-01-08 17:42:20 +00:00
2015-01-15 00:35:16 +00:00
// api_v1beta3 returns the resources and codec for API version v1beta3.
2015-03-04 20:57:05 +00:00
func ( m * Master ) api_v1beta3 ( ) * apiserver . APIGroupVersion {
2015-01-08 17:42:20 +00:00
storage := make ( map [ string ] apiserver . RESTStorage )
for k , v := range m . storage {
if k == "minions" {
continue
}
storage [ strings . ToLower ( k ) ] = v
}
2015-03-04 20:57:05 +00:00
version := m . defaultAPIGroupVersion ( )
version . Storage = storage
version . Version = "v1beta3"
version . Codec = v1beta3 . Codec
return version
2015-01-08 17:42:20 +00:00
}