Browse code

Merge pull request #2908 from smarterclayton/configure_master

Merged by openshift-bot

OpenShift Bot authored on 2015/06/09 03:52:21
Showing 14 changed files
... ...
@@ -228,7 +228,7 @@ func GetClientCertCAPool(options MasterConfig) (*x509.CertPool, error) {
228 228
 
229 229
 // GetAPIServerCertCAPool returns the cert pool containing the roots for the API server cert
230 230
 func GetAPIServerCertCAPool(options MasterConfig) (*x509.CertPool, error) {
231
-	if !UseTLS(options.ServingInfo) {
231
+	if !UseTLS(options.ServingInfo.ServingInfo) {
232 232
 		return x509.NewCertPool(), nil
233 233
 	}
234 234
 
... ...
@@ -236,7 +236,7 @@ func GetAPIServerCertCAPool(options MasterConfig) (*x509.CertPool, error) {
236 236
 }
237 237
 
238 238
 func getOAuthClientCertCAs(options MasterConfig) ([]*x509.Certificate, error) {
239
-	if !UseTLS(options.ServingInfo) {
239
+	if !UseTLS(options.ServingInfo.ServingInfo) {
240 240
 		return nil, nil
241 241
 	}
242 242
 
... ...
@@ -264,7 +264,7 @@ func getOAuthClientCertCAs(options MasterConfig) ([]*x509.Certificate, error) {
264 264
 }
265 265
 
266 266
 func getAPIClientCertCAs(options MasterConfig) ([]*x509.Certificate, error) {
267
-	if !UseTLS(options.ServingInfo) {
267
+	if !UseTLS(options.ServingInfo.ServingInfo) {
268 268
 		return nil, nil
269 269
 	}
270 270
 
... ...
@@ -86,7 +86,7 @@ type MasterConfig struct {
86 86
 	api.TypeMeta
87 87
 
88 88
 	// ServingInfo describes how to start serving
89
-	ServingInfo ServingInfo
89
+	ServingInfo HTTPServingInfo
90 90
 
91 91
 	// CORSAllowedOrigins
92 92
 	CORSAllowedOrigins []string
... ...
@@ -262,6 +262,15 @@ type ServingInfo struct {
262 262
 	ClientCA string
263 263
 }
264 264
 
265
+type HTTPServingInfo struct {
266
+	ServingInfo
267
+	// MaxRequestsInFlight is the number of concurrent requests allowed to the server. If zero, no limit.
268
+	MaxRequestsInFlight int
269
+	// RequestTimeoutSeconds is the number of seconds before requests are timed out. The default is 60 minutes, if
270
+	// -1 there is no limit on requests.
271
+	RequestTimeoutSeconds int
272
+}
273
+
265 274
 type MasterClients struct {
266 275
 	// OpenShiftLoopbackKubeConfig is a .kubeconfig filename for system components to loopback to this master
267 276
 	OpenShiftLoopbackKubeConfig string
... ...
@@ -275,7 +284,7 @@ type DNSConfig struct {
275 275
 }
276 276
 
277 277
 type AssetConfig struct {
278
-	ServingInfo ServingInfo
278
+	ServingInfo HTTPServingInfo
279 279
 
280 280
 	// PublicURL is where you can find the asset server (TODO do we really need this?)
281 281
 	PublicURL string
... ...
@@ -515,6 +524,8 @@ type KubernetesMasterConfig struct {
515 515
 	MasterCount int
516 516
 	// ServicesSubnet is the subnet to use for assigning service IPs
517 517
 	ServicesSubnet string
518
+	// ServicesNodePortRange is the range to use for assigning service public ports on a host.
519
+	ServicesNodePortRange string
518 520
 	// StaticNodeNames is the list of nodes that are statically known
519 521
 	StaticNodeNames []string
520 522
 	// SchedulerConfigFile points to a file that describes how to set up the scheduler. If empty, you get the default scheduling rules.
... ...
@@ -522,6 +533,10 @@ type KubernetesMasterConfig struct {
522 522
 	// PodEvictionTimeout controls grace period for deleting pods on failed nodes.
523 523
 	// It takes valid time duration string. If empty, you get the default pod eviction timeout.
524 524
 	PodEvictionTimeout string
525
+	// APIServerArguments are key value pairs that will be passed directly to the Kube apiserver that match the apiservers's
526
+	// command line arguments.  These are not migrated, but if you reference a value that does not exist the server will not
527
+	// start. These values may override other settings in KubernetesMasterConfig which may cause invalid configurations.
528
+	APIServerArguments ExtendedArguments
525 529
 }
526 530
 
527 531
 type CertInfo struct {
... ...
@@ -15,6 +15,9 @@ func init() {
15 15
 			if len(obj.Controllers) == 0 {
16 16
 				obj.Controllers = ControllersAll
17 17
 			}
18
+			if obj.ServingInfo.RequestTimeoutSeconds == 0 {
19
+				obj.ServingInfo.RequestTimeoutSeconds = 60 * 60
20
+			}
18 21
 		},
19 22
 		func(obj *KubernetesMasterConfig) {
20 23
 			if obj.MasterCount == 0 {
... ...
@@ -23,19 +26,22 @@ func init() {
23 23
 			if len(obj.APILevels) == 0 {
24 24
 				obj.APILevels = newer.DefaultKubernetesAPILevels
25 25
 			}
26
+			if len(obj.ServicesNodePortRange) == 0 {
27
+				obj.ServicesNodePortRange = "30000-32767"
28
+			}
26 29
 			if len(obj.PodEvictionTimeout) == 0 {
27 30
 				obj.PodEvictionTimeout = "5m"
28 31
 			}
29 32
 		},
30 33
 		func(obj *EtcdStorageConfig) {
31 34
 			if len(obj.KubernetesStorageVersion) == 0 {
32
-				obj.KubernetesStorageVersion = "v1beta3"
35
+				obj.KubernetesStorageVersion = "v1"
33 36
 			}
34 37
 			if len(obj.KubernetesStoragePrefix) == 0 {
35 38
 				obj.KubernetesStoragePrefix = "kubernetes.io"
36 39
 			}
37 40
 			if len(obj.OpenShiftStorageVersion) == 0 {
38
-				obj.OpenShiftStorageVersion = "v1beta3"
41
+				obj.OpenShiftStorageVersion = "v1"
39 42
 			}
40 43
 			if len(obj.OpenShiftStoragePrefix) == 0 {
41 44
 				obj.OpenShiftStoragePrefix = "openshift.io"
... ...
@@ -76,7 +76,7 @@ type MasterConfig struct {
76 76
 	v1.TypeMeta `json:",inline"`
77 77
 
78 78
 	// ServingInfo describes how to start serving
79
-	ServingInfo ServingInfo `json:"servingInfo"`
79
+	ServingInfo HTTPServingInfo `json:"servingInfo"`
80 80
 
81 81
 	// CORSAllowedOrigins
82 82
 	CORSAllowedOrigins []string `json:"corsAllowedOrigins"`
... ...
@@ -251,6 +251,15 @@ type ServingInfo struct {
251 251
 	ClientCA string `json:"clientCA"`
252 252
 }
253 253
 
254
+type HTTPServingInfo struct {
255
+	ServingInfo `json:",inline"`
256
+	// MaxRequestsInFlight is the number of concurrent requests allowed to the server. If zero, no limit.
257
+	MaxRequestsInFlight int `json:"maxRequestsInFlight"`
258
+	// RequestTimeoutSeconds is the number of seconds before requests are timed out. The default is 60 minutes, if
259
+	// -1 there is no limit on requests.
260
+	RequestTimeoutSeconds int `json:"requestTimeoutSeconds"`
261
+}
262
+
254 263
 type MasterClients struct {
255 264
 	// OpenShiftLoopbackKubeConfig is a .kubeconfig filename for system components to loopback to this master
256 265
 	OpenShiftLoopbackKubeConfig string `json:"openshiftLoopbackKubeConfig"`
... ...
@@ -264,7 +273,7 @@ type DNSConfig struct {
264 264
 }
265 265
 
266 266
 type AssetConfig struct {
267
-	ServingInfo ServingInfo `json:"servingInfo"`
267
+	ServingInfo HTTPServingInfo `json:"servingInfo"`
268 268
 
269 269
 	// PublicURL is where you can find the asset server (TODO do we really need this?)
270 270
 	PublicURL string `json:"publicURL"`
... ...
@@ -491,11 +500,17 @@ type KubernetesMasterConfig struct {
491 491
 	APILevels []string `json:"apiLevels"`
492 492
 	MasterIP  string   `json:"masterIP"`
493 493
 	// MasterCount is the number of expected masters that should be running. This value defaults to 1 and may be set to a positive integer.
494
-	MasterCount         int      `json:"masterCount"`
495
-	ServicesSubnet      string   `json:"servicesSubnet"`
496
-	StaticNodeNames     []string `json:"staticNodeNames"`
497
-	SchedulerConfigFile string   `json:"schedulerConfigFile"`
498
-	PodEvictionTimeout  string   `json:"podEvictionTimeout"`
494
+	MasterCount    int    `json:"masterCount"`
495
+	ServicesSubnet string `json:"servicesSubnet"`
496
+	// ServicesNodePortRange is the range to use for assigning service public ports on a host.
497
+	ServicesNodePortRange string   `json:"servicesNodePortRange"`
498
+	StaticNodeNames       []string `json:"staticNodeNames"`
499
+	SchedulerConfigFile   string   `json:"schedulerConfigFile"`
500
+	PodEvictionTimeout    string   `json:"podEvictionTimeout"`
501
+	// APIServerArguments are key value pairs that will be passed directly to the Kube apiserver that match the apiservers's
502
+	// command line arguments.  These are not migrated, but if you reference a value that does not exist the server will not
503
+	// start. These values may override other settings in KubernetesMasterConfig which may cause invalid configurations.
504
+	APIServerArguments ExtendedArguments `json:"apiServerArguments"`
499 505
 }
500 506
 
501 507
 type CertInfo struct {
... ...
@@ -55,6 +55,8 @@ assetConfig:
55 55
     certFile: ""
56 56
     clientCA: ""
57 57
     keyFile: ""
58
+    maxRequestsInFlight: 0
59
+    requestTimeoutSeconds: 0
58 60
 corsAllowedOrigins: null
59 61
 dnsConfig:
60 62
   bindAddress: ""
... ...
@@ -93,10 +95,12 @@ kubeletClientInfo:
93 93
   port: 0
94 94
 kubernetesMasterConfig:
95 95
   apiLevels: null
96
+  apiServerArguments: null
96 97
   masterCount: 0
97 98
   masterIP: ""
98 99
   podEvictionTimeout: ""
99 100
   schedulerConfigFile: ""
101
+  servicesNodePortRange: ""
100 102
   servicesSubnet: ""
101 103
   staticNodeNames: null
102 104
 masterClients:
... ...
@@ -212,6 +216,8 @@ servingInfo:
212 212
   certFile: ""
213 213
   clientCA: ""
214 214
   keyFile: ""
215
+  maxRequestsInFlight: 0
216
+  requestTimeoutSeconds: 0
215 217
 `
216 218
 )
217 219
 
... ...
@@ -19,6 +19,7 @@ import (
19 19
 	"github.com/openshift/origin/pkg/util/labelselector"
20 20
 )
21 21
 
22
+// TODO: this should just be two return arrays, no need to be clever
22 23
 type ValidationResults struct {
23 24
 	Warnings fielderrors.ValidationErrorList
24 25
 	Errors   fielderrors.ValidationErrorList
... ...
@@ -52,6 +53,8 @@ func (r ValidationResults) Prefix(prefix string) ValidationResults {
52 52
 func ValidateMasterConfig(config *api.MasterConfig) ValidationResults {
53 53
 	validationResults := ValidationResults{}
54 54
 
55
+	validationResults.AddErrors(ValidateHTTPServingInfo(config.ServingInfo).Prefix("servingInfo")...)
56
+
55 57
 	if _, urlErrs := ValidateURL(config.MasterPublicURL, "masterPublicURL"); len(urlErrs) > 0 {
56 58
 		validationResults.AddErrors(urlErrs...)
57 59
 	}
... ...
@@ -128,7 +131,7 @@ func ValidateMasterConfig(config *api.MasterConfig) ValidationResults {
128 128
 
129 129
 	validationResults.Append(ValidateServiceAccountConfig(config.ServiceAccountConfig, builtInKubernetes).Prefix("serviceAccountConfig"))
130 130
 
131
-	validationResults.AddErrors(ValidateServingInfo(config.ServingInfo).Prefix("servingInfo")...)
131
+	validationResults.AddErrors(ValidateHTTPServingInfo(config.ServingInfo).Prefix("servingInfo")...)
132 132
 
133 133
 	validationResults.AddErrors(ValidateProjectConfig(config.ProjectConfig).Prefix("projectConfig")...)
134 134
 
... ...
@@ -227,7 +230,7 @@ func ValidateServiceAccountConfig(config api.ServiceAccountConfig, builtInKubern
227 227
 func ValidateAssetConfig(config *api.AssetConfig) fielderrors.ValidationErrorList {
228 228
 	allErrs := fielderrors.ValidationErrorList{}
229 229
 
230
-	allErrs = append(allErrs, ValidateServingInfo(config.ServingInfo).Prefix("servingInfo")...)
230
+	allErrs = append(allErrs, ValidateHTTPServingInfo(config.ServingInfo).Prefix("servingInfo")...)
231 231
 
232 232
 	if len(config.LogoutURL) > 0 {
233 233
 		_, urlErrs := ValidateURL(config.LogoutURL, "logoutURL")
... ...
@@ -294,6 +297,12 @@ func ValidateKubernetesMasterConfig(config *api.KubernetesMasterConfig) Validati
294 294
 		}
295 295
 	}
296 296
 
297
+	if len(config.ServicesNodePortRange) > 0 {
298
+		if _, err := util.ParsePortRange(strings.TrimSpace(config.ServicesNodePortRange)); err != nil {
299
+			validationResults.AddErrors(fielderrors.NewFieldInvalid("servicesNodePortRange", config.ServicesNodePortRange, "must be a valid port range (e.g. 30000-32000)"))
300
+		}
301
+	}
302
+
297 303
 	if len(config.SchedulerConfigFile) > 0 {
298 304
 		validationResults.AddErrors(ValidateFile(config.SchedulerConfigFile, "schedulerConfigFile")...)
299 305
 	}
... ...
@@ -65,6 +65,20 @@ func ValidateServingInfo(info api.ServingInfo) fielderrors.ValidationErrorList {
65 65
 	return allErrs
66 66
 }
67 67
 
68
+func ValidateHTTPServingInfo(info api.HTTPServingInfo) fielderrors.ValidationErrorList {
69
+	allErrs := ValidateServingInfo(info.ServingInfo)
70
+
71
+	if info.MaxRequestsInFlight < 0 {
72
+		allErrs = append(allErrs, fielderrors.NewFieldInvalid("maxRequestsInFlight", info.MaxRequestsInFlight, "must be zero (no limit) or greater"))
73
+	}
74
+
75
+	if info.RequestTimeoutSeconds < 0 {
76
+		allErrs = append(allErrs, fielderrors.NewFieldInvalid("requestTimeoutSeconds", info.RequestTimeoutSeconds, "must be zero (no limit) or greater"))
77
+	}
78
+
79
+	return allErrs
80
+}
81
+
68 82
 func ValidateKubeConfig(path string, field string) fielderrors.ValidationErrorList {
69 83
 	allErrs := fielderrors.ValidationErrorList{}
70 84
 
... ...
@@ -3,7 +3,6 @@ package kubernetes
3 3
 import (
4 4
 	"fmt"
5 5
 	"io/ioutil"
6
-	"net"
7 6
 	"os"
8 7
 	"time"
9 8
 
... ...
@@ -11,7 +10,6 @@ import (
11 11
 	"github.com/golang/glog"
12 12
 
13 13
 	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
14
-	kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
15 14
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
16 15
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/nodecontroller"
17 16
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/controller"
... ...
@@ -27,7 +25,6 @@ import (
27 27
 	"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/factory"
28 28
 
29 29
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/namespace"
30
-	configapi "github.com/openshift/origin/pkg/cmd/server/api"
31 30
 )
32 31
 
33 32
 const (
... ...
@@ -36,58 +33,20 @@ const (
36 36
 	KubeAPIPrefixV1      = "/api/v1"
37 37
 )
38 38
 
39
-// TODO: Longer term we should read this from some config store, rather than a flag.
40
-func (c *MasterConfig) EnsurePortalFlags() {
41
-	if c.PortalNet == nil {
42
-		glog.Fatal("No --portal-net specified")
43
-	}
44
-}
45
-
46 39
 // InstallAPI starts a Kubernetes master and registers the supported REST APIs
47 40
 // into the provided mux, then returns an array of strings indicating what
48 41
 // endpoints were started (these are format strings that will expect to be sent
49 42
 // a single string value).
50 43
 func (c *MasterConfig) InstallAPI(container *restful.Container) []string {
51
-	kubeletClient, err := kclient.NewKubeletClient(c.KubeletClientConfig)
52
-	if err != nil {
53
-		glog.Fatalf("Unable to configure Kubelet client: %v", err)
54
-	}
55
-
56
-	masterConfig := &master.Config{
57
-		PublicAddress: net.ParseIP(c.Options.MasterIP),
58
-		ReadWritePort: c.MasterPort,
59
-		ReadOnlyPort:  c.MasterPort,
60
-
61
-		EtcdHelper: c.EtcdHelper,
62
-
63
-		EventTTL: 2 * time.Hour,
64
-
65
-		PortalNet: c.PortalNet,
66
-
67
-		RequestContextMapper: c.RequestContextMapper,
68
-
69
-		RestfulContainer: container,
70
-		KubeletClient:    kubeletClient,
71
-		APIPrefix:        KubeAPIPrefix,
72
-
73
-		EnableCoreControllers: true,
74
-
75
-		MasterCount: c.Options.MasterCount,
76
-
77
-		Authorizer:       c.Authorizer,
78
-		AdmissionControl: c.AdmissionControl,
79
-
80
-		DisableV1Beta3: !configapi.HasKubernetesAPILevel(c.Options, "v1beta3"),
81
-		EnableV1:       configapi.HasKubernetesAPILevel(c.Options, "v1"),
82
-	}
83
-	_ = master.New(masterConfig)
44
+	c.Master.RestfulContainer = container
45
+	_ = master.New(c.Master)
84 46
 
85 47
 	messages := []string{}
86
-	if !masterConfig.DisableV1Beta3 {
87
-		messages = append(messages, fmt.Sprintf("Started Kubernetes API at %%s%s", KubeAPIPrefixV1Beta3))
48
+	if !c.Master.DisableV1Beta3 {
49
+		messages = append(messages, fmt.Sprintf("Started Kubernetes API at %%s%s (deprecated)", KubeAPIPrefixV1Beta3))
88 50
 	}
89
-	if masterConfig.EnableV1 {
90
-		messages = append(messages, fmt.Sprintf("Started Kubernetes API at %%s%s (experimental)", KubeAPIPrefixV1))
51
+	if c.Master.EnableV1 {
52
+		messages = append(messages, fmt.Sprintf("Started Kubernetes API at %%s%s", KubeAPIPrefixV1))
91 53
 	}
92 54
 
93 55
 	return messages
... ...
@@ -5,37 +5,30 @@ import (
5 5
 	"fmt"
6 6
 	"net"
7 7
 	"strconv"
8
+	"strings"
9
+	"time"
8 10
 
11
+	"github.com/GoogleCloudPlatform/kubernetes/cmd/kube-apiserver/app"
9 12
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
10 13
 	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
11 14
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
12
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authorizer"
13 15
 	kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
14 16
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/master"
15
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
17
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
18
+	kerrors "github.com/GoogleCloudPlatform/kubernetes/pkg/util/errors"
16 19
 
17 20
 	"github.com/openshift/origin/pkg/cmd/flagtypes"
18 21
 	configapi "github.com/openshift/origin/pkg/cmd/server/api"
19 22
 	"github.com/openshift/origin/pkg/cmd/server/etcd"
23
+	cmdflags "github.com/openshift/origin/pkg/cmd/util/flags"
20 24
 )
21 25
 
22 26
 // MasterConfig defines the required values to start a Kubernetes master
23 27
 type MasterConfig struct {
24 28
 	Options configapi.KubernetesMasterConfig
25 29
 
26
-	MasterPort int
27
-
28
-	// TODO: remove, not used
29
-	PortalNet *net.IPNet
30
-
31
-	RequestContextMapper kapi.RequestContextMapper
32
-
33
-	EtcdHelper          tools.EtcdHelper
34
-	KubeClient          *kclient.Client
35
-	KubeletClientConfig *kclient.KubeletConfig
36
-
37
-	Authorizer       authorizer.Authorizer
38
-	AdmissionControl admission.Interface
30
+	Master     *master.Config
31
+	KubeClient *kclient.Client
39 32
 }
40 33
 
41 34
 func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextMapper kapi.RequestContextMapper, kubeClient *kclient.Client) (*MasterConfig, error) {
... ...
@@ -54,13 +47,13 @@ func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextM
54 54
 	}
55 55
 
56 56
 	kubeletClientConfig := configapi.GetKubeletClientConfig(options)
57
-
58
-	portalNet := net.IPNet(flagtypes.DefaultIPNet(options.KubernetesMasterConfig.ServicesSubnet))
57
+	kubeletClient, err := kclient.NewKubeletClient(kubeletClientConfig)
58
+	if err != nil {
59
+		return nil, fmt.Errorf("unable to configure Kubelet client: %v", err)
60
+	}
59 61
 
60 62
 	// in-order list of plug-ins that should intercept admission decisions
61 63
 	// TODO: Push node environment support to upstream in future
62
-	admissionControlPluginNames := []string{"NamespaceExists", "NamespaceLifecycle", "OriginPodNodeEnvironment", "LimitRanger", "ServiceAccount", "ResourceQuota"}
63
-	admissionController := admission.NewFromPlugins(kubeClient, admissionControlPluginNames, "")
64 64
 
65 65
 	_, portString, err := net.SplitHostPort(options.ServingInfo.BindAddress)
66 66
 	if err != nil {
... ...
@@ -71,17 +64,61 @@ func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextM
71 71
 		return nil, err
72 72
 	}
73 73
 
74
-	kmaster := &MasterConfig{
75
-		Options: *options.KubernetesMasterConfig,
74
+	portRange, err := util.ParsePortRange(options.KubernetesMasterConfig.ServicesNodePortRange)
75
+	if err != nil {
76
+		return nil, err
77
+	}
78
+
79
+	server := app.NewAPIServer()
80
+	server.EventTTL = 2 * time.Hour
81
+	server.PortalNet = util.IPNet(flagtypes.DefaultIPNet(options.KubernetesMasterConfig.ServicesSubnet))
82
+	server.ServiceNodePorts = *portRange
83
+	server.AdmissionControl = strings.Join([]string{
84
+		"NamespaceExists", "NamespaceLifecycle", "OriginPodNodeEnvironment", "LimitRanger", "ServiceAccount", "ResourceQuota",
85
+	}, ",")
86
+
87
+	// resolve extended arguments
88
+	// TODO: this should be done in config validation (along with the above) so we can provide
89
+	// proper errors
90
+	if err := cmdflags.Resolve(options.KubernetesMasterConfig.APIServerArguments, server.AddFlags); len(err) > 0 {
91
+		return nil, kerrors.NewAggregate(err)
92
+	}
93
+
94
+	admissionController := admission.NewFromPlugins(kubeClient, strings.Split(server.AdmissionControl, ","), server.AdmissionControlConfigFile)
95
+
96
+	m := &master.Config{
97
+		PublicAddress: net.ParseIP(options.KubernetesMasterConfig.MasterIP),
98
+		ReadWritePort: port,
99
+		ReadOnlyPort:  port,
100
+
101
+		EtcdHelper: ketcdHelper,
102
+
103
+		EventTTL: server.EventTTL,
104
+		//MinRequestTimeout: server.MinRequestTimeout,
105
+
106
+		PortalNet:        (*net.IPNet)(&server.PortalNet),
107
+		ServiceNodePorts: server.ServiceNodePorts,
76 108
 
77
-		MasterPort:           port,
78
-		PortalNet:            &portalNet,
79 109
 		RequestContextMapper: requestContextMapper,
80
-		EtcdHelper:           ketcdHelper,
81
-		KubeClient:           kubeClient,
82
-		KubeletClientConfig:  kubeletClientConfig,
83
-		Authorizer:           apiserver.NewAlwaysAllowAuthorizer(),
84
-		AdmissionControl:     admissionController,
110
+
111
+		KubeletClient: kubeletClient,
112
+		APIPrefix:     KubeAPIPrefix,
113
+
114
+		EnableCoreControllers: true,
115
+
116
+		MasterCount: options.KubernetesMasterConfig.MasterCount,
117
+
118
+		Authorizer:       apiserver.NewAlwaysAllowAuthorizer(),
119
+		AdmissionControl: admissionController,
120
+
121
+		DisableV1Beta3: !configapi.HasKubernetesAPILevel(*options.KubernetesMasterConfig, "v1beta3"),
122
+		EnableV1:       configapi.HasKubernetesAPILevel(*options.KubernetesMasterConfig, "v1"),
123
+	}
124
+
125
+	kmaster := &MasterConfig{
126
+		Options:    *options.KubernetesMasterConfig,
127
+		Master:     m,
128
+		KubeClient: kubeClient,
85 129
 	}
86 130
 
87 131
 	return kmaster, nil
... ...
@@ -58,15 +58,20 @@ func (c *AssetConfig) Run() {
58 58
 		})
59 59
 	}
60 60
 
61
+	timeout := c.Options.ServingInfo.RequestTimeoutSeconds
62
+	if timeout == -1 {
63
+		timeout = 0
64
+	}
65
+
61 66
 	server := &http.Server{
62 67
 		Addr:           c.Options.ServingInfo.BindAddress,
63 68
 		Handler:        mux,
64
-		ReadTimeout:    5 * time.Minute,
65
-		WriteTimeout:   5 * time.Minute,
69
+		ReadTimeout:    time.Duration(timeout) * time.Second,
70
+		WriteTimeout:   time.Duration(timeout) * time.Second,
66 71
 		MaxHeaderBytes: 1 << 20,
67 72
 	}
68 73
 
69
-	isTLS := configapi.UseTLS(c.Options.ServingInfo)
74
+	isTLS := configapi.UseTLS(c.Options.ServingInfo.ServingInfo)
70 75
 
71 76
 	go util.Forever(func() {
72 77
 		if isTLS {
... ...
@@ -494,11 +494,22 @@ func (c *MasterConfig) Run(protected []APIInstaller, unprotected []APIInstaller)
494 494
 		handler = contextHandler
495 495
 	}
496 496
 
497
+	if c.Options.ServingInfo.MaxRequestsInFlight > 0 {
498
+		longRunningRE := regexp.MustCompile("[.*\\/watch$][^\\/proxy.*]")
499
+		sem := make(chan bool, c.Options.ServingInfo.MaxRequestsInFlight)
500
+		handler = apiserver.MaxInFlightLimit(sem, longRunningRE, handler)
501
+	}
502
+
503
+	timeout := c.Options.ServingInfo.RequestTimeoutSeconds
504
+	if timeout == -1 {
505
+		timeout = 0
506
+	}
507
+
497 508
 	server := &http.Server{
498 509
 		Addr:           c.Options.ServingInfo.BindAddress,
499 510
 		Handler:        handler,
500
-		ReadTimeout:    5 * time.Minute,
501
-		WriteTimeout:   5 * time.Minute,
511
+		ReadTimeout:    time.Duration(timeout) * time.Second,
512
+		WriteTimeout:   time.Duration(timeout) * time.Second,
502 513
 		MaxHeaderBytes: 1 << 20,
503 514
 	}
504 515
 
... ...
@@ -161,7 +161,7 @@ func BuildMasterConfig(options configapi.MasterConfig) (*MasterConfig, error) {
161 161
 
162 162
 		AdmissionControl: admissionController,
163 163
 
164
-		TLS: configapi.UseTLS(options.ServingInfo),
164
+		TLS: configapi.UseTLS(options.ServingInfo.ServingInfo),
165 165
 
166 166
 		ControllerPlug: plug.NewPlug(!options.PauseControllers),
167 167
 
... ...
@@ -226,7 +226,7 @@ func newAuthenticator(config configapi.MasterConfig, etcdHelper tools.EtcdHelper
226 226
 		authenticators = append(authenticators, paramtoken.New("access_token", tokenAuthenticator, true))
227 227
 	}
228 228
 
229
-	if configapi.UseTLS(config.ServingInfo) {
229
+	if configapi.UseTLS(config.ServingInfo.ServingInfo) {
230 230
 		// build cert authenticator
231 231
 		// TODO: add "system:" prefix in authenticator, limit cert to username
232 232
 		// TODO: add "system:" prefix to groups in authenticator, limit cert to group name
... ...
@@ -150,8 +150,10 @@ func (args MasterArgs) BuildSerializeableMasterConfig() (*configapi.MasterConfig
150 150
 	etcdClientInfo := admin.DefaultMasterEtcdClientCertInfo(args.ConfigDir.Value())
151 151
 
152 152
 	config := &configapi.MasterConfig{
153
-		ServingInfo: configapi.ServingInfo{
154
-			BindAddress: args.ListenArg.ListenAddr.URL.Host,
153
+		ServingInfo: configapi.HTTPServingInfo{
154
+			ServingInfo: configapi.ServingInfo{
155
+				BindAddress: args.ListenArg.ListenAddr.URL.Host,
156
+			},
155 157
 		},
156 158
 		CORSAllowedOrigins: corsAllowedOrigins.List(),
157 159
 		MasterPublicURL:    masterPublicAddr.String(),
... ...
@@ -164,8 +166,10 @@ func (args MasterArgs) BuildSerializeableMasterConfig() (*configapi.MasterConfig
164 164
 		PauseControllers: args.PauseControllers,
165 165
 
166 166
 		AssetConfig: &configapi.AssetConfig{
167
-			ServingInfo: configapi.ServingInfo{
168
-				BindAddress: args.GetAssetBindAddress(),
167
+			ServingInfo: configapi.HTTPServingInfo{
168
+				ServingInfo: configapi.ServingInfo{
169
+					BindAddress: args.GetAssetBindAddress(),
170
+				},
169 171
 			},
170 172
 
171 173
 			LogoutURL:       "",
... ...
@@ -357,7 +357,6 @@ func StartMaster(openshiftMasterConfig *configapi.MasterConfig) error {
357 357
 		if err != nil {
358 358
 			return err
359 359
 		}
360
-		kubeConfig.EnsurePortalFlags()
361 360
 
362 361
 		openshiftConfig.Run([]origin.APIInstaller{kubeConfig}, unprotectedInstallers)
363 362
 		go daemon.SdNotify("READY=1")