Browse code

make api levels configuratable

deads2k authored on 2015/05/29 03:59:00
Showing 11 changed files
... ...
@@ -11,6 +11,7 @@ import (
11 11
 	kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
12 12
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
13 13
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
14
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
14 15
 
15 16
 	"github.com/openshift/origin/pkg/client"
16 17
 	cmdutil "github.com/openshift/origin/pkg/cmd/util"
... ...
@@ -334,3 +335,13 @@ func IsOAuthIdentityProvider(provider IdentityProvider) bool {
334 334
 
335 335
 	return false
336 336
 }
337
+
338
+func HasOpenShiftAPILevel(config MasterConfig, apiLevel string) bool {
339
+	apiLevelSet := util.NewStringSet(config.APILevels...)
340
+	return apiLevelSet.Has(apiLevel)
341
+}
342
+
343
+func HasKubernetesAPILevel(config KubernetesMasterConfig, apiLevel string) bool {
344
+	apiLevelSet := util.NewStringSet(config.APILevels...)
345
+	return apiLevelSet.Has(apiLevel)
346
+}
... ...
@@ -6,6 +6,15 @@ import (
6 6
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
7 7
 )
8 8
 
9
+var (
10
+	KnownKubernetesAPILevels   = []string{"v1beta1", "v1beta2", "v1beta3", "v1"}
11
+	KnownOpenShiftAPILevels    = []string{"v1beta1", "v1beta3", "v1"}
12
+	DefaultKubernetesAPILevels = []string{"v1beta1", "v1beta2", "v1beta3", "v1"}
13
+	DefaultOpenShiftAPILevels  = []string{"v1beta1", "v1beta3", "v1"}
14
+	DeadKubernetesAPILevels    = []string{}
15
+	DeadOpenShiftAPILevels     = []string{}
16
+)
17
+
9 18
 // NodeConfig is the fully specified config starting an OpenShift node
10 19
 type NodeConfig struct {
11 20
 	api.TypeMeta
... ...
@@ -51,6 +60,9 @@ type MasterConfig struct {
51 51
 	// CORSAllowedOrigins
52 52
 	CORSAllowedOrigins []string
53 53
 
54
+	// APILevels is a list of API levels that should be enabled on startup: v1beta1, v1beta3, v1 as examples
55
+	APILevels []string
56
+
54 57
 	// MasterPublicURL is how clients can access the OpenShift API server
55 58
 	MasterPublicURL string
56 59
 
... ...
@@ -432,6 +444,8 @@ type EtcdConfig struct {
432 432
 }
433 433
 
434 434
 type KubernetesMasterConfig struct {
435
+	// APILevels is a list of API levels that should be enabled on startup: v1beta1, v1beta2, v1beta3, v1 as examples
436
+	APILevels []string
435 437
 	// MasterIP is the public IP address of kubernetes stuff.  If empty, the first result from net.InterfaceAddrs will be used.
436 438
 	MasterIP string
437 439
 	// MasterCount is the number of expected masters that should be running. This value defaults to 1 and may be set to a positive integer.
... ...
@@ -8,10 +8,18 @@ import (
8 8
 
9 9
 func init() {
10 10
 	err := newer.Scheme.AddDefaultingFuncs(
11
+		func(obj *MasterConfig) {
12
+			if len(obj.APILevels) == 0 {
13
+				obj.APILevels = newer.DefaultOpenShiftAPILevels
14
+			}
15
+		},
11 16
 		func(obj *KubernetesMasterConfig) {
12 17
 			if obj.MasterCount == 0 {
13 18
 				obj.MasterCount = 1
14 19
 			}
20
+			if len(obj.APILevels) == 0 {
21
+				obj.APILevels = newer.DefaultKubernetesAPILevels
22
+			}
15 23
 		},
16 24
 		func(obj *EtcdStorageConfig) {
17 25
 			if len(obj.KubernetesStorageVersion) == 0 {
... ...
@@ -50,6 +50,9 @@ type MasterConfig struct {
50 50
 	// CORSAllowedOrigins
51 51
 	CORSAllowedOrigins []string `json:"corsAllowedOrigins"`
52 52
 
53
+	// APILevels is a list of API levels that should be enabled on startup: v1beta1, v1beta3, v1 as examples
54
+	APILevels []string `json:"apiLevels"`
55
+
53 56
 	// MasterPublicURL is how clients can access the OpenShift API server
54 57
 	MasterPublicURL string `json:"masterPublicURL"`
55 58
 
... ...
@@ -421,7 +424,9 @@ type EtcdConfig struct {
421 421
 }
422 422
 
423 423
 type KubernetesMasterConfig struct {
424
-	MasterIP string `json:"masterIP"`
424
+	// APILevels is a list of API levels that should be enabled on startup: v1beta1, v1beta2, v1beta3, v1 as examples
425
+	APILevels []string `json:"apiLevels"`
426
+	MasterIP  string   `json:"masterIP"`
425 427
 	// MasterCount is the number of expected masters that should be running. This value defaults to 1 and may be set to a positive integer.
426 428
 	MasterCount         int      `json:"masterCount"`
427 429
 	ServicesSubnet      string   `json:"servicesSubnet"`
... ...
@@ -42,7 +42,8 @@ volumeDirectory: ""
42 42
 	// Before modifying this constant, ensure any changes have corresponding issues filed for:
43 43
 	// - documentation: https://github.com/openshift/openshift-docs/
44 44
 	// - install: https://github.com/openshift/openshift-ansible/
45
-	expectedSerializedMasterConfig = `apiVersion: v1
45
+	expectedSerializedMasterConfig = `apiLevels: null
46
+apiVersion: v1
46 47
 assetConfig:
47 48
   logoutURL: ""
48 49
   masterPublicURL: ""
... ...
@@ -89,6 +90,7 @@ kubeletClientInfo:
89 89
   keyFile: ""
90 90
   port: 0
91 91
 kubernetesMasterConfig:
92
+  apiLevels: null
92 93
   masterCount: 0
93 94
   masterIP: ""
94 95
   schedulerConfigFile: ""
... ...
@@ -1,19 +1,17 @@
1 1
 package validation
2 2
 
3 3
 import (
4
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/fielderrors"
5
-
6 4
 	"github.com/openshift/origin/pkg/cmd/server/api"
7 5
 )
8 6
 
9
-func ValidateAllInOneConfig(master *api.MasterConfig, node *api.NodeConfig) fielderrors.ValidationErrorList {
10
-	allErrs := fielderrors.ValidationErrorList{}
7
+func ValidateAllInOneConfig(master *api.MasterConfig, node *api.NodeConfig) ValidationResults {
8
+	validationResults := ValidationResults{}
11 9
 
12
-	allErrs = append(allErrs, ValidateMasterConfig(master).Prefix("masterConfig")...)
10
+	validationResults.Append(ValidateMasterConfig(master).Prefix("masterConfig"))
13 11
 
14
-	allErrs = append(allErrs, ValidateNodeConfig(node).Prefix("nodeConfig")...)
12
+	validationResults.AddErrors(ValidateNodeConfig(node).Prefix("nodeConfig")...)
15 13
 
16 14
 	// Validation between the configs
17 15
 
18
-	return allErrs
16
+	return validationResults
19 17
 }
... ...
@@ -16,26 +16,56 @@ import (
16 16
 	"github.com/openshift/origin/pkg/util/labelselector"
17 17
 )
18 18
 
19
-func ValidateMasterConfig(config *api.MasterConfig) fielderrors.ValidationErrorList {
20
-	allErrs := fielderrors.ValidationErrorList{}
19
+type ValidationResults struct {
20
+	Warnings fielderrors.ValidationErrorList
21
+	Errors   fielderrors.ValidationErrorList
22
+}
23
+
24
+func (r *ValidationResults) Append(additionalResults ValidationResults) {
25
+	r.AddErrors(additionalResults.Errors...)
26
+	r.AddWarnings(additionalResults.Warnings...)
27
+}
28
+
29
+func (r *ValidationResults) AddErrors(errors ...error) {
30
+	if len(errors) == 0 {
31
+		return
32
+	}
33
+	r.Errors = append(r.Errors, errors...)
34
+}
35
+
36
+func (r *ValidationResults) AddWarnings(warnings ...error) {
37
+	if len(warnings) == 0 {
38
+		return
39
+	}
40
+	r.Warnings = append(r.Warnings, warnings...)
41
+}
42
+
43
+func (r ValidationResults) Prefix(prefix string) ValidationResults {
44
+	r.Warnings = r.Warnings.Prefix(prefix)
45
+	r.Errors = r.Errors.Prefix(prefix)
46
+	return r
47
+}
48
+
49
+func ValidateMasterConfig(config *api.MasterConfig) ValidationResults {
50
+	validationResults := ValidationResults{}
21 51
 
22 52
 	if _, urlErrs := ValidateURL(config.MasterPublicURL, "masterPublicURL"); len(urlErrs) > 0 {
23
-		allErrs = append(allErrs, urlErrs...)
53
+		validationResults.AddErrors(urlErrs...)
24 54
 	}
25 55
 
26 56
 	if config.AssetConfig != nil {
27
-		allErrs = append(allErrs, ValidateAssetConfig(config.AssetConfig).Prefix("assetConfig")...)
57
+		validationResults.AddErrors(ValidateAssetConfig(config.AssetConfig).Prefix("assetConfig")...)
28 58
 		colocated := config.AssetConfig.ServingInfo.BindAddress == config.ServingInfo.BindAddress
29 59
 		if colocated {
30 60
 			publicURL, _ := url.Parse(config.AssetConfig.PublicURL)
31 61
 			if publicURL.Path == "/" {
32
-				allErrs = append(allErrs, fielderrors.NewFieldInvalid("assetConfig.publicURL", config.AssetConfig.PublicURL, "path can not be / when colocated with master API"))
62
+				validationResults.AddErrors(fielderrors.NewFieldInvalid("assetConfig.publicURL", config.AssetConfig.PublicURL, "path can not be / when colocated with master API"))
33 63
 			}
34 64
 		}
35 65
 
36 66
 		if config.OAuthConfig != nil {
37 67
 			if config.OAuthConfig.AssetPublicURL != config.AssetConfig.PublicURL {
38
-				allErrs = append(allErrs,
68
+				validationResults.AddErrors(
39 69
 					fielderrors.NewFieldInvalid("assetConfig.publicURL", config.AssetConfig.PublicURL, "must match oauthConfig.assetPublicURL"),
40 70
 					fielderrors.NewFieldInvalid("oauthConfig.assetPublicURL", config.OAuthConfig.AssetPublicURL, "must match assetConfig.publicURL"),
41 71
 				)
... ...
@@ -47,60 +77,83 @@ func ValidateMasterConfig(config *api.MasterConfig) fielderrors.ValidationErrorL
47 47
 	}
48 48
 
49 49
 	if config.DNSConfig != nil {
50
-		allErrs = append(allErrs, ValidateHostPort(config.DNSConfig.BindAddress, "bindAddress").Prefix("dnsConfig")...)
50
+		validationResults.AddErrors(ValidateHostPort(config.DNSConfig.BindAddress, "bindAddress").Prefix("dnsConfig")...)
51 51
 	}
52 52
 
53 53
 	if config.EtcdConfig != nil {
54 54
 		etcdConfigErrs := ValidateEtcdConfig(config.EtcdConfig).Prefix("etcdConfig")
55
-		allErrs = append(allErrs, etcdConfigErrs...)
55
+		validationResults.AddErrors(etcdConfigErrs...)
56 56
 
57 57
 		if len(etcdConfigErrs) == 0 {
58 58
 			// Validate the etcdClientInfo with the internal etcdConfig
59
-			allErrs = append(allErrs, ValidateEtcdConnectionInfo(config.EtcdClientInfo, config.EtcdConfig).Prefix("etcdClientInfo")...)
59
+			validationResults.AddErrors(ValidateEtcdConnectionInfo(config.EtcdClientInfo, config.EtcdConfig).Prefix("etcdClientInfo")...)
60 60
 		} else {
61 61
 			// Validate the etcdClientInfo by itself
62
-			allErrs = append(allErrs, ValidateEtcdConnectionInfo(config.EtcdClientInfo, nil).Prefix("etcdClientInfo")...)
62
+			validationResults.AddErrors(ValidateEtcdConnectionInfo(config.EtcdClientInfo, nil).Prefix("etcdClientInfo")...)
63 63
 		}
64 64
 	} else {
65 65
 		// Validate the etcdClientInfo by itself
66
-		allErrs = append(allErrs, ValidateEtcdConnectionInfo(config.EtcdClientInfo, nil).Prefix("etcdClientInfo")...)
66
+		validationResults.AddErrors(ValidateEtcdConnectionInfo(config.EtcdClientInfo, nil).Prefix("etcdClientInfo")...)
67 67
 	}
68
-	allErrs = append(allErrs, ValidateEtcdStorageConfig(config.EtcdStorageConfig).Prefix("etcdStorageConfig")...)
68
+	validationResults.AddErrors(ValidateEtcdStorageConfig(config.EtcdStorageConfig).Prefix("etcdStorageConfig")...)
69 69
 
70
-	allErrs = append(allErrs, ValidateImageConfig(config.ImageConfig).Prefix("imageConfig")...)
70
+	validationResults.AddErrors(ValidateImageConfig(config.ImageConfig).Prefix("imageConfig")...)
71 71
 
72
-	allErrs = append(allErrs, ValidateKubeletConnectionInfo(config.KubeletClientInfo).Prefix("kubeletClientInfo")...)
72
+	validationResults.AddErrors(ValidateKubeletConnectionInfo(config.KubeletClientInfo).Prefix("kubeletClientInfo")...)
73 73
 
74 74
 	builtInKubernetes := config.KubernetesMasterConfig != nil
75 75
 	if config.KubernetesMasterConfig != nil {
76
-		allErrs = append(allErrs, ValidateKubernetesMasterConfig(config.KubernetesMasterConfig).Prefix("kubernetesMasterConfig")...)
76
+		validationResults.Append(ValidateKubernetesMasterConfig(config.KubernetesMasterConfig).Prefix("kubernetesMasterConfig"))
77 77
 	}
78 78
 	if (config.KubernetesMasterConfig == nil) && (len(config.MasterClients.ExternalKubernetesKubeConfig) == 0) {
79
-		allErrs = append(allErrs, fielderrors.NewFieldInvalid("kubernetesMasterConfig", config.KubernetesMasterConfig, "either kubernetesMasterConfig or masterClients.externalKubernetesKubeConfig must have a value"))
79
+		validationResults.AddErrors(fielderrors.NewFieldInvalid("kubernetesMasterConfig", config.KubernetesMasterConfig, "either kubernetesMasterConfig or masterClients.externalKubernetesKubeConfig must have a value"))
80 80
 	}
81 81
 	if (config.KubernetesMasterConfig != nil) && (len(config.MasterClients.ExternalKubernetesKubeConfig) != 0) {
82
-		allErrs = append(allErrs, fielderrors.NewFieldInvalid("kubernetesMasterConfig", config.KubernetesMasterConfig, "kubernetesMasterConfig and masterClients.externalKubernetesKubeConfig are mutually exclusive"))
82
+		validationResults.AddErrors(fielderrors.NewFieldInvalid("kubernetesMasterConfig", config.KubernetesMasterConfig, "kubernetesMasterConfig and masterClients.externalKubernetesKubeConfig are mutually exclusive"))
83 83
 	}
84 84
 
85
-	allErrs = append(allErrs, ValidateKubeConfig(config.MasterClients.DeployerKubeConfig, "deployerKubeConfig").Prefix("masterClients")...)
86
-	allErrs = append(allErrs, ValidateKubeConfig(config.MasterClients.OpenShiftLoopbackKubeConfig, "openShiftLoopbackKubeConfig").Prefix("masterClients")...)
85
+	validationResults.AddErrors(ValidateKubeConfig(config.MasterClients.DeployerKubeConfig, "deployerKubeConfig").Prefix("masterClients")...)
86
+	validationResults.AddErrors(ValidateKubeConfig(config.MasterClients.OpenShiftLoopbackKubeConfig, "openShiftLoopbackKubeConfig").Prefix("masterClients")...)
87 87
 
88 88
 	if len(config.MasterClients.ExternalKubernetesKubeConfig) > 0 {
89
-		allErrs = append(allErrs, ValidateKubeConfig(config.MasterClients.ExternalKubernetesKubeConfig, "externalKubernetesKubeConfig").Prefix("masterClients")...)
89
+		validationResults.AddErrors(ValidateKubeConfig(config.MasterClients.ExternalKubernetesKubeConfig, "externalKubernetesKubeConfig").Prefix("masterClients")...)
90 90
 	}
91 91
 
92
-	allErrs = append(allErrs, ValidatePolicyConfig(config.PolicyConfig).Prefix("policyConfig")...)
92
+	validationResults.AddErrors(ValidatePolicyConfig(config.PolicyConfig).Prefix("policyConfig")...)
93 93
 	if config.OAuthConfig != nil {
94
-		allErrs = append(allErrs, ValidateOAuthConfig(config.OAuthConfig).Prefix("oauthConfig")...)
94
+		validationResults.AddErrors(ValidateOAuthConfig(config.OAuthConfig).Prefix("oauthConfig")...)
95 95
 	}
96 96
 
97
-	allErrs = append(allErrs, ValidateServiceAccountConfig(config.ServiceAccountConfig, builtInKubernetes).Prefix("serviceAccountConfig")...)
97
+	validationResults.AddErrors(ValidateServiceAccountConfig(config.ServiceAccountConfig, builtInKubernetes).Prefix("serviceAccountConfig")...)
98 98
 
99
-	allErrs = append(allErrs, ValidateServingInfo(config.ServingInfo).Prefix("servingInfo")...)
99
+	validationResults.AddErrors(ValidateServingInfo(config.ServingInfo).Prefix("servingInfo")...)
100 100
 
101
-	allErrs = append(allErrs, ValidateProjectConfig(config.ProjectConfig).Prefix("projectConfig")...)
101
+	validationResults.AddErrors(ValidateProjectConfig(config.ProjectConfig).Prefix("projectConfig")...)
102 102
 
103
-	return allErrs
103
+	validationResults.Append(ValidateAPILevels(config.APILevels, api.KnownOpenShiftAPILevels, api.DeadOpenShiftAPILevels, "apiLevels"))
104
+
105
+	return validationResults
106
+}
107
+
108
+func ValidateAPILevels(apiLevels []string, knownAPILevels, deadAPILevels []string, name string) ValidationResults {
109
+	validationResults := ValidationResults{}
110
+
111
+	if len(apiLevels) == 0 {
112
+		validationResults.AddErrors(fielderrors.NewFieldRequired(name))
113
+	}
114
+
115
+	deadLevels := util.NewStringSet(deadAPILevels...)
116
+	knownLevels := util.NewStringSet(knownAPILevels...)
117
+	for i, apiLevel := range apiLevels {
118
+		if deadLevels.Has(apiLevel) {
119
+			validationResults.AddWarnings(fielderrors.NewFieldInvalid(fmt.Sprintf(name+"[%d]", i), apiLevel, "unsupported level"))
120
+		}
121
+		if !knownLevels.Has(apiLevel) {
122
+			validationResults.AddWarnings(fielderrors.NewFieldInvalid(fmt.Sprintf(name+"[%d]", i), apiLevel, "unknown level"))
123
+		}
124
+	}
125
+
126
+	return validationResults
104 127
 }
105 128
 
106 129
 func ValidateEtcdStorageConfig(config api.EtcdStorageConfig) fielderrors.ValidationErrorList {
... ...
@@ -219,34 +272,36 @@ func ValidateKubeletConnectionInfo(config api.KubeletConnectionInfo) fielderrors
219 219
 	return allErrs
220 220
 }
221 221
 
222
-func ValidateKubernetesMasterConfig(config *api.KubernetesMasterConfig) fielderrors.ValidationErrorList {
223
-	allErrs := fielderrors.ValidationErrorList{}
222
+func ValidateKubernetesMasterConfig(config *api.KubernetesMasterConfig) ValidationResults {
223
+	validationResults := ValidationResults{}
224 224
 
225 225
 	if len(config.MasterIP) > 0 {
226
-		allErrs = append(allErrs, ValidateSpecifiedIP(config.MasterIP, "masterIP")...)
226
+		validationResults.AddErrors(ValidateSpecifiedIP(config.MasterIP, "masterIP")...)
227 227
 	}
228 228
 
229 229
 	if config.MasterCount < 1 {
230
-		allErrs = append(allErrs, fielderrors.NewFieldInvalid("masterCount", config.MasterCount, "must be a positive integer"))
230
+		validationResults.AddErrors(fielderrors.NewFieldInvalid("masterCount", config.MasterCount, "must be a positive integer"))
231 231
 	}
232 232
 
233 233
 	if len(config.ServicesSubnet) > 0 {
234 234
 		if _, _, err := net.ParseCIDR(strings.TrimSpace(config.ServicesSubnet)); err != nil {
235
-			allErrs = append(allErrs, fielderrors.NewFieldInvalid("servicesSubnet", config.ServicesSubnet, "must be a valid CIDR notation IP range (e.g. 172.30.0.0/16)"))
235
+			validationResults.AddErrors(fielderrors.NewFieldInvalid("servicesSubnet", config.ServicesSubnet, "must be a valid CIDR notation IP range (e.g. 172.30.0.0/16)"))
236 236
 		}
237 237
 	}
238 238
 
239 239
 	if len(config.SchedulerConfigFile) > 0 {
240
-		allErrs = append(allErrs, ValidateFile(config.SchedulerConfigFile, "schedulerConfigFile")...)
240
+		validationResults.AddErrors(ValidateFile(config.SchedulerConfigFile, "schedulerConfigFile")...)
241 241
 	}
242 242
 
243 243
 	for i, nodeName := range config.StaticNodeNames {
244 244
 		if len(nodeName) == 0 {
245
-			allErrs = append(allErrs, fielderrors.NewFieldInvalid(fmt.Sprintf("staticNodeName[%d]", i), nodeName, "may not be empty"))
245
+			validationResults.AddErrors(fielderrors.NewFieldInvalid(fmt.Sprintf("staticNodeName[%d]", i), nodeName, "may not be empty"))
246 246
 		}
247 247
 	}
248 248
 
249
-	return allErrs
249
+	validationResults.Append(ValidateAPILevels(config.APILevels, api.KnownKubernetesAPILevels, api.DeadKubernetesAPILevels, "apiLevels"))
250
+
251
+	return validationResults
250 252
 }
251 253
 
252 254
 func ValidatePolicyConfig(config api.PolicyConfig) fielderrors.ValidationErrorList {
... ...
@@ -3,6 +3,7 @@ package kubernetes
3 3
 import (
4 4
 	"fmt"
5 5
 	"io/ioutil"
6
+	"net"
6 7
 	"os"
7 8
 	"time"
8 9
 
... ...
@@ -26,6 +27,7 @@ import (
26 26
 	"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/factory"
27 27
 
28 28
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/namespace"
29
+	configapi "github.com/openshift/origin/pkg/cmd/server/api"
29 30
 )
30 31
 
31 32
 const (
... ...
@@ -54,7 +56,7 @@ func (c *MasterConfig) InstallAPI(container *restful.Container) []string {
54 54
 	}
55 55
 
56 56
 	masterConfig := &master.Config{
57
-		PublicAddress: c.MasterIP,
57
+		PublicAddress: net.ParseIP(c.Options.MasterIP),
58 58
 		ReadWritePort: c.MasterPort,
59 59
 		ReadOnlyPort:  c.MasterPort,
60 60
 
... ...
@@ -70,14 +72,17 @@ func (c *MasterConfig) InstallAPI(container *restful.Container) []string {
70 70
 		KubeletClient:    kubeletClient,
71 71
 		APIPrefix:        KubeAPIPrefix,
72 72
 
73
-		EnableV1: true,
74
-
75 73
 		EnableCoreControllers: true,
76 74
 
77
-		MasterCount: c.MasterCount,
75
+		MasterCount: c.Options.MasterCount,
78 76
 
79 77
 		Authorizer:       c.Authorizer,
80 78
 		AdmissionControl: c.AdmissionControl,
79
+
80
+		DisableV1Beta1: !configapi.HasKubernetesAPILevel(c.Options, "v1beta1"),
81
+		DisableV1Beta2: !configapi.HasKubernetesAPILevel(c.Options, "v1beta2"),
82
+		DisableV1Beta3: !configapi.HasKubernetesAPILevel(c.Options, "v1beta3"),
83
+		EnableV1:       configapi.HasKubernetesAPILevel(c.Options, "v1"),
81 84
 	}
82 85
 	_ = master.New(masterConfig)
83 86
 
... ...
@@ -162,8 +167,8 @@ func (c *MasterConfig) createSchedulerConfig() (*scheduler.Config, error) {
162 162
 	var configData []byte
163 163
 
164 164
 	configFactory := factory.NewConfigFactory(c.KubeClient)
165
-	if _, err := os.Stat(c.SchedulerConfigFile); err == nil {
166
-		configData, err = ioutil.ReadFile(c.SchedulerConfigFile)
165
+	if _, err := os.Stat(c.Options.SchedulerConfigFile); err == nil {
166
+		configData, err = ioutil.ReadFile(c.Options.SchedulerConfigFile)
167 167
 		if err != nil {
168 168
 			return nil, fmt.Errorf("Unable to read scheduler config: %v", err)
169 169
 		}
... ...
@@ -21,12 +21,11 @@ import (
21 21
 
22 22
 // MasterConfig defines the required values to start a Kubernetes master
23 23
 type MasterConfig struct {
24
-	MasterIP    net.IP
25
-	MasterPort  int
26
-	MasterCount int
24
+	Options configapi.KubernetesMasterConfig
25
+
26
+	MasterPort int
27 27
 
28 28
 	// TODO: remove, not used
29
-	NodeHosts []string
30 29
 	PortalNet *net.IPNet
31 30
 
32 31
 	RequestContextMapper kapi.RequestContextMapper
... ...
@@ -37,8 +36,6 @@ type MasterConfig struct {
37 37
 
38 38
 	Authorizer       authorizer.Authorizer
39 39
 	AdmissionControl admission.Interface
40
-
41
-	SchedulerConfigFile string
42 40
 }
43 41
 
44 42
 func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextMapper kapi.RequestContextMapper, kubeClient *kclient.Client) (*MasterConfig, error) {
... ...
@@ -76,10 +73,9 @@ func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextM
76 76
 	}
77 77
 
78 78
 	kmaster := &MasterConfig{
79
-		MasterIP:             net.ParseIP(options.KubernetesMasterConfig.MasterIP),
79
+		Options: *options.KubernetesMasterConfig,
80
+
80 81
 		MasterPort:           port,
81
-		MasterCount:          options.KubernetesMasterConfig.MasterCount,
82
-		NodeHosts:            options.KubernetesMasterConfig.StaticNodeNames,
83 82
 		PortalNet:            &portalNet,
84 83
 		RequestContextMapper: requestContextMapper,
85 84
 		EtcdHelper:           ketcdHelper,
... ...
@@ -87,7 +83,6 @@ func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextM
87 87
 		KubeletClientConfig:  kubeletClientConfig,
88 88
 		Authorizer:           apiserver.NewAlwaysAllowAuthorizer(),
89 89
 		AdmissionControl:     admissionController,
90
-		SchedulerConfigFile:  options.KubernetesMasterConfig.SchedulerConfigFile,
91 90
 	}
92 91
 
93 92
 	return kmaster, nil
... ...
@@ -292,8 +292,6 @@ func (c *MasterConfig) InstallProtectedAPI(container *restful.Container) []strin
292 292
 
293 293
 		"processedTemplates": templateregistry.NewREST(false),
294 294
 		"templates":          templateetcd.NewREST(c.EtcdHelper),
295
-		// DEPRECATED: remove with v1beta1
296
-		"templateConfigs": templateregistry.NewREST(true),
297 295
 
298 296
 		"routes": routeregistry.NewREST(routeEtcd, routeAllocator),
299 297
 
... ...
@@ -326,16 +324,25 @@ func (c *MasterConfig) InstallProtectedAPI(container *restful.Container) []strin
326 326
 		"clusterRoles":          clusterRoleStorage,
327 327
 	}
328 328
 
329
-	if err := c.api_v1beta1(storage).InstallREST(container); err != nil {
330
-		glog.Fatalf("Unable to initialize v1beta1 API: %v", err)
329
+	if configapi.HasOpenShiftAPILevel(c.Options, OpenShiftAPIV1Beta1) {
330
+		// templateConfigs is only available in v1beta1
331
+		storage["templateConfigs"] = templateregistry.NewREST(true)
332
+
333
+		if err := c.api_v1beta1(storage).InstallREST(container); err != nil {
334
+			glog.Fatalf("Unable to initialize v1beta1 API: %v", err)
335
+		}
331 336
 	}
332 337
 
333
-	if err := c.api_v1beta3(storage).InstallREST(container); err != nil {
334
-		glog.Fatalf("Unable to initialize v1beta3 API: %v", err)
338
+	if configapi.HasOpenShiftAPILevel(c.Options, OpenShiftAPIV1Beta3) {
339
+		if err := c.api_v1beta3(storage).InstallREST(container); err != nil {
340
+			glog.Fatalf("Unable to initialize v1beta3 API: %v", err)
341
+		}
335 342
 	}
336 343
 
337
-	if err := c.api_v1(storage).InstallREST(container); err != nil {
338
-		glog.Fatalf("Unable to initialize v1 API: %v", err)
344
+	if configapi.HasOpenShiftAPILevel(c.Options, OpenShiftAPIV1) {
345
+		if err := c.api_v1(storage).InstallREST(container); err != nil {
346
+			glog.Fatalf("Unable to initialize v1 API: %v", err)
347
+		}
339 348
 	}
340 349
 
341 350
 	var root *restful.WebService
... ...
@@ -239,9 +239,14 @@ func (o MasterOptions) RunMaster() error {
239 239
 		return nil
240 240
 	}
241 241
 
242
-	errs := validation.ValidateMasterConfig(masterConfig)
243
-	if len(errs) != 0 {
244
-		return kerrors.NewInvalid("MasterConfig", o.ConfigFile, errs)
242
+	validationResults := validation.ValidateMasterConfig(masterConfig)
243
+	if len(validationResults.Warnings) != 0 {
244
+		for _, warning := range validationResults.Warnings {
245
+			glog.Warningf("%v", warning)
246
+		}
247
+	}
248
+	if len(validationResults.Errors) != 0 {
249
+		return kerrors.NewInvalid("MasterConfig", o.ConfigFile, validationResults.Errors)
245 250
 	}
246 251
 
247 252
 	if err := StartMaster(masterConfig); err != nil {