... | ... |
@@ -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 { |