Browse code

enable extensions

deads2k authored on 2015/10/21 21:43:12
Showing 9 changed files
... ...
@@ -5,7 +5,6 @@ import (
5 5
 	"strings"
6 6
 
7 7
 	"k8s.io/kubernetes/pkg/api"
8
-	klatest "k8s.io/kubernetes/pkg/api/latest"
9 8
 	kmeta "k8s.io/kubernetes/pkg/api/meta"
10 9
 	"k8s.io/kubernetes/pkg/runtime"
11 10
 	"k8s.io/kubernetes/pkg/util/sets"
... ...
@@ -96,11 +95,7 @@ func OriginKind(kind, apiVersion string) bool {
96 96
 func init() {
97 97
 	// this keeps us consistent with old code.  We can decide if we want to expand our RESTMapper to cover
98 98
 	// api.RESTMapper, which is different than what you'd get from latest.
99
-	kubeAPIGroup, err := klatest.Group("")
100
-	if err != nil {
101
-		panic(err)
102
-	}
103
-	kubeMapper := kubeAPIGroup.RESTMapper
99
+	kubeMapper := api.RESTMapper
104 100
 
105 101
 	// list of versions we support on the server, in preferred order
106 102
 	versions := []string{"v1", "v1beta3"}
... ...
@@ -498,7 +498,20 @@ func HasOpenShiftAPILevel(config MasterConfig, apiLevel string) bool {
498 498
 	return apiLevelSet.Has(apiLevel)
499 499
 }
500 500
 
501
-func HasKubernetesAPILevel(config KubernetesMasterConfig, apiLevel string) bool {
502
-	apiLevelSet := sets.NewString(config.APILevels...)
503
-	return apiLevelSet.Has(apiLevel)
501
+func GetEnabledAPIVersionsForGroup(config KubernetesMasterConfig, apiGroup string) []string {
502
+	allowedVersions := KubeAPIGroupsToAllowedVersions[apiGroup]
503
+	blacklist := sets.NewString(config.DisabledAPIGroupVersions[apiGroup]...)
504
+
505
+	if blacklist.Has(AllVersions) {
506
+		return []string{}
507
+	}
508
+
509
+	enabledVersions := []string{}
510
+	for _, currVersion := range allowedVersions {
511
+		if !blacklist.Has(currVersion) {
512
+			enabledVersions = append(enabledVersions, currVersion)
513
+		}
514
+	}
515
+
516
+	return enabledVersions
504 517
 }
... ...
@@ -1,6 +1,8 @@
1 1
 package api
2 2
 
3 3
 import (
4
+	"reflect"
5
+
4 6
 	"k8s.io/kubernetes/pkg/api/unversioned"
5 7
 	"k8s.io/kubernetes/pkg/runtime"
6 8
 	"k8s.io/kubernetes/pkg/util/sets"
... ...
@@ -13,6 +15,8 @@ const (
13 13
 	FeatureBuilder    = `Builder`
14 14
 	FeatureS2I        = `S2IBuilder`
15 15
 	FeatureWebConsole = `WebConsole`
16
+
17
+	AllVersions = "*"
16 18
 )
17 19
 
18 20
 var (
... ...
@@ -38,6 +42,14 @@ var (
38 38
 	// exposed externally.
39 39
 	DeadOpenShiftStorageVersionLevels = []string{"v1beta1", "v1beta3"}
40 40
 
41
+	APIGroupKube                   = ""
42
+	APIGroupExtensions             = "extensions"
43
+	KubeAPIGroupsToAllowedVersions = map[string][]string{
44
+		APIGroupKube:       {"v1"},
45
+		APIGroupExtensions: {"v1beta1"},
46
+	}
47
+	KnownKubeAPIGroups = sets.KeySet(reflect.ValueOf(KubeAPIGroupsToAllowedVersions))
48
+
41 49
 	// FeatureAliases maps deprecated names of feature flag to their canonical
42 50
 	// names. Aliases must be lower-cased for O(1) lookup.
43 51
 	FeatureAliases = map[string]string{
... ...
@@ -732,8 +744,9 @@ type EtcdConfig struct {
732 732
 }
733 733
 
734 734
 type KubernetesMasterConfig struct {
735
-	// APILevels is a list of API levels that should be enabled on startup: v1beta3 and v1 as examples
736
-	APILevels []string
735
+	// DisabledAPIGroupVersions is a map of groups to the versions (or *) that should be disabled.
736
+	DisabledAPIGroupVersions map[string][]string
737
+
737 738
 	// MasterIP is the public IP address of kubernetes stuff.  If empty, the first result from net.InterfaceAddrs will be used.
738 739
 	MasterIP string
739 740
 	// MasterCount is the number of expected masters that should be running. This value defaults to 1 and may be set to a positive integer,
... ...
@@ -2,16 +2,17 @@ package v1
2 2
 
3 3
 import (
4 4
 	"k8s.io/kubernetes/pkg/conversion"
5
+	"k8s.io/kubernetes/pkg/util/sets"
5 6
 
6
-	newer "github.com/openshift/origin/pkg/cmd/server/api"
7
+	internal "github.com/openshift/origin/pkg/cmd/server/api"
7 8
 	"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy"
8 9
 )
9 10
 
10 11
 func init() {
11
-	err := newer.Scheme.AddDefaultingFuncs(
12
+	err := internal.Scheme.AddDefaultingFuncs(
12 13
 		func(obj *MasterConfig) {
13 14
 			if len(obj.APILevels) == 0 {
14
-				obj.APILevels = newer.DefaultOpenShiftAPILevels
15
+				obj.APILevels = internal.DefaultOpenShiftAPILevels
15 16
 			}
16 17
 			if len(obj.Controllers) == 0 {
17 18
 				obj.Controllers = ControllersAll
... ...
@@ -53,7 +54,7 @@ func init() {
53 53
 				obj.MasterCount = 1
54 54
 			}
55 55
 			if len(obj.APILevels) == 0 {
56
-				obj.APILevels = newer.DefaultKubernetesAPILevels
56
+				obj.APILevels = internal.DefaultKubernetesAPILevels
57 57
 			}
58 58
 			if len(obj.ServicesNodePortRange) == 0 {
59 59
 				obj.ServicesNodePortRange = "30000-32767"
... ...
@@ -96,7 +97,7 @@ func init() {
96 96
 				obj.KubernetesStoragePrefix = "kubernetes.io"
97 97
 			}
98 98
 			if len(obj.OpenShiftStorageVersion) == 0 {
99
-				obj.OpenShiftStorageVersion = newer.DefaultOpenShiftStorageVersionLevel
99
+				obj.OpenShiftStorageVersion = internal.DefaultOpenShiftStorageVersionLevel
100 100
 			}
101 101
 			if len(obj.OpenShiftStoragePrefix) == 0 {
102 102
 				obj.OpenShiftStoragePrefix = "openshift.io"
... ...
@@ -141,14 +142,49 @@ func init() {
141 141
 		// If one of the conversion functions is malformed, detect it immediately.
142 142
 		panic(err)
143 143
 	}
144
-	err = newer.Scheme.AddConversionFuncs(
145
-		func(in *NodeConfig, out *newer.NodeConfig, s conversion.Scope) error {
144
+	err = internal.Scheme.AddConversionFuncs(
145
+		func(in *NodeConfig, out *internal.NodeConfig, s conversion.Scope) error {
146 146
 			return s.DefaultConvert(in, out, conversion.IgnoreMissingFields)
147 147
 		},
148
-		func(in *newer.NodeConfig, out *NodeConfig, s conversion.Scope) error {
148
+		func(in *internal.NodeConfig, out *NodeConfig, s conversion.Scope) error {
149 149
 			return s.DefaultConvert(in, out, conversion.IgnoreMissingFields)
150 150
 		},
151
-		func(in *ServingInfo, out *newer.ServingInfo, s conversion.Scope) error {
151
+		func(in *KubernetesMasterConfig, out *internal.KubernetesMasterConfig, s conversion.Scope) error {
152
+			if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil {
153
+				return err
154
+			}
155
+
156
+			if out.DisabledAPIGroupVersions == nil {
157
+				out.DisabledAPIGroupVersions = map[string][]string{}
158
+			}
159
+
160
+			// the APILevels (whitelist) needs to be converted into an internal blacklist
161
+			if len(in.APILevels) == 0 {
162
+				out.DisabledAPIGroupVersions[internal.APIGroupKube] = []string{"*"}
163
+
164
+			} else {
165
+				availableLevels := internal.KubeAPIGroupsToAllowedVersions[internal.APIGroupKube]
166
+				whitelistedLevels := sets.NewString(in.APILevels...)
167
+				blacklistedLevels := []string{}
168
+
169
+				for _, curr := range availableLevels {
170
+					if !whitelistedLevels.Has(curr) {
171
+						blacklistedLevels = append(blacklistedLevels, curr)
172
+					}
173
+				}
174
+
175
+				if len(blacklistedLevels) > 0 {
176
+					out.DisabledAPIGroupVersions[internal.APIGroupKube] = blacklistedLevels
177
+				}
178
+			}
179
+
180
+			return nil
181
+		},
182
+		func(in *internal.KubernetesMasterConfig, out *KubernetesMasterConfig, s conversion.Scope) error {
183
+			// internal doesn't have all fields: APILevels
184
+			return s.DefaultConvert(in, out, conversion.IgnoreMissingFields)
185
+		},
186
+		func(in *ServingInfo, out *internal.ServingInfo, s conversion.Scope) error {
152 187
 			if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil {
153 188
 				return err
154 189
 			}
... ...
@@ -156,7 +192,7 @@ func init() {
156 156
 			out.ServerCert.KeyFile = in.KeyFile
157 157
 			return nil
158 158
 		},
159
-		func(in *newer.ServingInfo, out *ServingInfo, s conversion.Scope) error {
159
+		func(in *internal.ServingInfo, out *ServingInfo, s conversion.Scope) error {
160 160
 			if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil {
161 161
 				return err
162 162
 			}
... ...
@@ -164,42 +200,42 @@ func init() {
164 164
 			out.KeyFile = in.ServerCert.KeyFile
165 165
 			return nil
166 166
 		},
167
-		func(in *RemoteConnectionInfo, out *newer.RemoteConnectionInfo, s conversion.Scope) error {
167
+		func(in *RemoteConnectionInfo, out *internal.RemoteConnectionInfo, s conversion.Scope) error {
168 168
 			out.URL = in.URL
169 169
 			out.CA = in.CA
170 170
 			out.ClientCert.CertFile = in.CertFile
171 171
 			out.ClientCert.KeyFile = in.KeyFile
172 172
 			return nil
173 173
 		},
174
-		func(in *newer.RemoteConnectionInfo, out *RemoteConnectionInfo, s conversion.Scope) error {
174
+		func(in *internal.RemoteConnectionInfo, out *RemoteConnectionInfo, s conversion.Scope) error {
175 175
 			out.URL = in.URL
176 176
 			out.CA = in.CA
177 177
 			out.CertFile = in.ClientCert.CertFile
178 178
 			out.KeyFile = in.ClientCert.KeyFile
179 179
 			return nil
180 180
 		},
181
-		func(in *EtcdConnectionInfo, out *newer.EtcdConnectionInfo, s conversion.Scope) error {
181
+		func(in *EtcdConnectionInfo, out *internal.EtcdConnectionInfo, s conversion.Scope) error {
182 182
 			out.URLs = in.URLs
183 183
 			out.CA = in.CA
184 184
 			out.ClientCert.CertFile = in.CertFile
185 185
 			out.ClientCert.KeyFile = in.KeyFile
186 186
 			return nil
187 187
 		},
188
-		func(in *newer.EtcdConnectionInfo, out *EtcdConnectionInfo, s conversion.Scope) error {
188
+		func(in *internal.EtcdConnectionInfo, out *EtcdConnectionInfo, s conversion.Scope) error {
189 189
 			out.URLs = in.URLs
190 190
 			out.CA = in.CA
191 191
 			out.CertFile = in.ClientCert.CertFile
192 192
 			out.KeyFile = in.ClientCert.KeyFile
193 193
 			return nil
194 194
 		},
195
-		func(in *KubeletConnectionInfo, out *newer.KubeletConnectionInfo, s conversion.Scope) error {
195
+		func(in *KubeletConnectionInfo, out *internal.KubeletConnectionInfo, s conversion.Scope) error {
196 196
 			out.Port = in.Port
197 197
 			out.CA = in.CA
198 198
 			out.ClientCert.CertFile = in.CertFile
199 199
 			out.ClientCert.KeyFile = in.KeyFile
200 200
 			return nil
201 201
 		},
202
-		func(in *newer.KubeletConnectionInfo, out *KubeletConnectionInfo, s conversion.Scope) error {
202
+		func(in *internal.KubeletConnectionInfo, out *KubeletConnectionInfo, s conversion.Scope) error {
203 203
 			out.Port = in.Port
204 204
 			out.CA = in.CA
205 205
 			out.CertFile = in.ClientCert.CertFile
... ...
@@ -693,6 +693,9 @@ type EtcdConfig struct {
693 693
 type KubernetesMasterConfig struct {
694 694
 	// APILevels is a list of API levels that should be enabled on startup: v1beta3 and v1 as examples
695 695
 	APILevels []string `json:"apiLevels"`
696
+	// DisabledAPIGroupVersions is a map of groups to the versions (or *) that should be disabled.
697
+	DisabledAPIGroupVersions map[string][]string `json:"disabledAPIGroupVersions"`
698
+
696 699
 	// MasterIP is the public IP address of kubernetes stuff.  If empty, the first result from net.InterfaceAddrs will be used.
697 700
 	MasterIP string `json:"masterIP"`
698 701
 	// MasterCount is the number of expected masters that should be running. This value defaults to 1 and may be set to a positive integer,
... ...
@@ -127,6 +127,7 @@ kubernetesMasterConfig:
127 127
   apiLevels: null
128 128
   apiServerArguments: null
129 129
   controllerArguments: null
130
+  disabledAPIGroupVersions: null
130 131
   masterCount: 0
131 132
   masterIP: ""
132 133
   podEvictionTimeout: ""
... ...
@@ -432,7 +432,24 @@ func ValidateKubernetesMasterConfig(config *api.KubernetesMasterConfig) Validati
432 432
 		}
433 433
 	}
434 434
 
435
-	validationResults.Append(ValidateAPILevels(config.APILevels, api.KnownKubernetesAPILevels, api.DeadKubernetesAPILevels, "apiLevels"))
435
+	for group, versions := range config.DisabledAPIGroupVersions {
436
+		name := "disabledAPIGroupVersions[" + group + "]"
437
+		if !api.KnownKubeAPIGroups.Has(group) {
438
+			validationResults.AddWarnings(fielderrors.NewFieldValueNotSupported(name, group, api.KnownKubeAPIGroups.List()))
439
+			continue
440
+		}
441
+
442
+		allowedVersions := sets.NewString(api.KubeAPIGroupsToAllowedVersions[group]...)
443
+		for i, version := range versions {
444
+			if version == "*" {
445
+				continue
446
+			}
447
+
448
+			if !allowedVersions.Has(version) {
449
+				validationResults.AddWarnings(fielderrors.NewFieldValueNotSupported(fmt.Sprintf("%s[%d]", name, i), version, allowedVersions.List()))
450
+			}
451
+		}
452
+	}
436 453
 
437 454
 	validationResults.AddErrors(ValidateAPIServerExtendedArguments(config.APIServerArguments).Prefix("apiServerArguments")...)
438 455
 	validationResults.AddErrors(ValidateControllerExtendedArguments(config.ControllerArguments).Prefix("controllerArguments")...)
... ...
@@ -31,8 +31,10 @@ import (
31 31
 )
32 32
 
33 33
 const (
34
-	KubeAPIPrefix   = "/api"
35
-	KubeAPIPrefixV1 = "/api/v1"
34
+	KubeAPIPrefix                  = "/api"
35
+	KubeAPIPrefixV1                = KubeAPIPrefix + "/v1"
36
+	KubeAPIGroupPrefix             = "/apis"
37
+	KubeAPIExtensionsPrefixV1beta1 = KubeAPIGroupPrefix + "/extensions/v1beta1"
36 38
 )
37 39
 
38 40
 // InstallAPI starts a Kubernetes master and registers the supported REST APIs
... ...
@@ -48,6 +50,10 @@ func (c *MasterConfig) InstallAPI(container *restful.Container) []string {
48 48
 		messages = append(messages, fmt.Sprintf("Started Kubernetes API at %%s%s", KubeAPIPrefixV1))
49 49
 	}
50 50
 
51
+	if c.Master.EnableExp {
52
+		messages = append(messages, fmt.Sprintf("Started Kubernetes API Extensions at %%s%s", KubeAPIExtensionsPrefixV1beta1))
53
+	}
54
+
51 55
 	return messages
52 56
 }
53 57
 
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"time"
11 11
 
12 12
 	"github.com/golang/glog"
13
+
13 14
 	"k8s.io/kubernetes/cmd/kube-apiserver/app"
14 15
 	cmapp "k8s.io/kubernetes/cmd/kube-controller-manager/app"
15 16
 	"k8s.io/kubernetes/pkg/admission"
... ...
@@ -21,6 +22,7 @@ import (
21 21
 	"k8s.io/kubernetes/pkg/master"
22 22
 	"k8s.io/kubernetes/pkg/util"
23 23
 	kerrors "k8s.io/kubernetes/pkg/util/errors"
24
+	"k8s.io/kubernetes/pkg/util/sets"
24 25
 	saadmit "k8s.io/kubernetes/plugin/pkg/admission/serviceaccount"
25 26
 
26 27
 	"github.com/openshift/origin/pkg/cmd/flagtypes"
... ...
@@ -147,14 +149,32 @@ func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextM
147 147
 		proxyClientCerts = append(proxyClientCerts, clientCert)
148 148
 	}
149 149
 
150
+	// TODO you have to know every APIGroup you're enabling or upstream will panic.  It's alternative to panicing is Fataling
151
+	// It needs a refactor to return errors
150 152
 	storageDestinations := master.NewStorageDestinations()
151
-	storageDestinations.AddAPIGroup("", databaseStorage)
153
+	// storageVersions is a map from API group to allowed versions that must be a version exposed by the REST API or it breaks.
154
+	// We need to fix the upstream to stop using the storage version as a preferred api version.
155
+	storageVersions := map[string]string{}
156
+
157
+	enabledKubeVersions := configapi.GetEnabledAPIVersionsForGroup(*options.KubernetesMasterConfig, configapi.APIGroupKube)
158
+	enabledKubeVersionSet := sets.NewString(enabledKubeVersions...)
159
+	if len(enabledKubeVersions) > 0 {
160
+		storageDestinations.AddAPIGroup(configapi.APIGroupKube, databaseStorage)
161
+		storageVersions[configapi.APIGroupKube] = options.EtcdStorageConfig.KubernetesStorageVersion
162
+	}
163
+
164
+	enabledExtensionsVersions := configapi.GetEnabledAPIVersionsForGroup(*options.KubernetesMasterConfig, configapi.APIGroupExtensions)
165
+	if len(enabledExtensionsVersions) > 0 {
166
+		storageDestinations.AddAPIGroup(configapi.APIGroupExtensions, databaseStorage)
167
+		storageVersions[configapi.APIGroupExtensions] = enabledExtensionsVersions[0]
168
+	}
152 169
 
153 170
 	m := &master.Config{
154 171
 		PublicAddress: net.ParseIP(options.KubernetesMasterConfig.MasterIP),
155 172
 		ReadWritePort: port,
156 173
 
157 174
 		StorageDestinations: storageDestinations,
175
+		StorageVersions:     storageVersions,
158 176
 
159 177
 		EventTTL: server.EventTTL,
160 178
 		//MinRequestTimeout: server.MinRequestTimeout,
... ...
@@ -164,8 +184,9 @@ func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextM
164 164
 
165 165
 		RequestContextMapper: requestContextMapper,
166 166
 
167
-		KubeletClient: kubeletClient,
168
-		APIPrefix:     KubeAPIPrefix,
167
+		KubeletClient:  kubeletClient,
168
+		APIPrefix:      KubeAPIPrefix,
169
+		APIGroupPrefix: KubeAPIGroupPrefix,
169 170
 
170 171
 		EnableCoreControllers: true,
171 172
 
... ...
@@ -174,7 +195,8 @@ func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextM
174 174
 		Authorizer:       apiserver.NewAlwaysAllowAuthorizer(),
175 175
 		AdmissionControl: admissionController,
176 176
 
177
-		DisableV1: !configapi.HasKubernetesAPILevel(*options.KubernetesMasterConfig, "v1"),
177
+		EnableExp: len(enabledExtensionsVersions) > 0,
178
+		DisableV1: !enabledKubeVersionSet.Has("v1"),
178 179
 
179 180
 		// Set the TLS options for proxying to pods and services
180 181
 		// Proxying to nodes uses the kubeletClient TLS config (so can provide a different cert, and verify the node hostname)