Browse code

make admission plugins enablable or disabable based on config

deads2k authored on 2016/05/20 02:42:41
Showing 10 changed files
... ...
@@ -137,3 +137,21 @@ func captureSurroundingJSONForError(prefix string, data []byte, err error) error
137 137
 	}
138 138
 	return err
139 139
 }
140
+
141
+// IsAdmissionPluginActivated returns true if the admission plugin is activated using configapi.DefaultAdmissionConfig
142
+// otherwise it returns a default value
143
+func IsAdmissionPluginActivated(reader io.Reader, defaultValue bool) (bool, error) {
144
+	obj, err := ReadYAML(reader)
145
+	if err != nil {
146
+		return false, err
147
+	}
148
+	if obj == nil {
149
+		return defaultValue, nil
150
+	}
151
+	activationConfig, ok := obj.(*configapi.DefaultAdmissionConfig)
152
+	if !ok {
153
+		return false, fmt.Errorf("unexpected config object: %#v", obj)
154
+	}
155
+
156
+	return !activationConfig.Disable, nil
157
+}
... ...
@@ -53,9 +53,13 @@ func addKnownTypes(scheme *runtime.Scheme) {
53 53
 		&OpenIDIdentityProvider{},
54 54
 
55 55
 		&LDAPSyncConfig{},
56
+
57
+		&DefaultAdmissionConfig{},
56 58
 	)
57 59
 }
58 60
 
61
+func (obj *DefaultAdmissionConfig) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
62
+
59 63
 func (obj *LDAPSyncConfig) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
60 64
 
61 65
 func (obj *OpenIDIdentityProvider) GetObjectKind() unversioned.ObjectKind        { return &obj.TypeMeta }
... ...
@@ -1202,3 +1202,13 @@ type ServiceServingCert struct {
1202 1202
 	// If this value is nil, then certs are not signed automatically.
1203 1203
 	Signer *CertInfo
1204 1204
 }
1205
+
1206
+// DefaultAdmissionConfig can be used to enable or disable various admission plugins.
1207
+// When this type is present as the `configuration` object under `pluginConfig` and *if* the admission plugin supports it,
1208
+// this will cause an "off by default" admission plugin to be enabled
1209
+type DefaultAdmissionConfig struct {
1210
+	unversioned.TypeMeta
1211
+
1212
+	// Disable turns off an admission plugin that is enabled by default.
1213
+	Disable bool
1214
+}
... ...
@@ -36,9 +36,13 @@ func addKnownTypes(scheme *runtime.Scheme) {
36 36
 		&OpenIDIdentityProvider{},
37 37
 
38 38
 		&LDAPSyncConfig{},
39
+
40
+		&DefaultAdmissionConfig{},
39 41
 	)
40 42
 }
41 43
 
44
+func (obj *DefaultAdmissionConfig) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
45
+
42 46
 func (obj *LDAPSyncConfig) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
43 47
 
44 48
 func (obj *OpenIDIdentityProvider) GetObjectKind() unversioned.ObjectKind        { return &obj.TypeMeta }
... ...
@@ -135,6 +135,15 @@ func (DNSConfig) SwaggerDoc() map[string]string {
135 135
 	return map_DNSConfig
136 136
 }
137 137
 
138
+var map_DefaultAdmissionConfig = map[string]string{
139
+	"":        "DefaultAdmissionConfig can be used to enable or disable various admission plugins. When this type is present as the `configuration` object under `pluginConfig` and *if* the admission plugin supports it, this will cause an \"off by default\" admission plugin to be enabled",
140
+	"Disable": "Disable turns off an admission plugin that is enabled by default.",
141
+}
142
+
143
+func (DefaultAdmissionConfig) SwaggerDoc() map[string]string {
144
+	return map_DefaultAdmissionConfig
145
+}
146
+
138 147
 var map_DenyAllPasswordIdentityProvider = map[string]string{
139 148
 	"": "DenyAllPasswordIdentityProvider provides no identities for users",
140 149
 }
... ...
@@ -1207,3 +1207,13 @@ type ServiceServingCert struct {
1207 1207
 	// If this value is nil, then certs are not signed automatically.
1208 1208
 	Signer *CertInfo `json:"signer"`
1209 1209
 }
1210
+
1211
+// DefaultAdmissionConfig can be used to enable or disable various admission plugins.
1212
+// When this type is present as the `configuration` object under `pluginConfig` and *if* the admission plugin supports it,
1213
+// this will cause an "off by default" admission plugin to be enabled
1214
+type DefaultAdmissionConfig struct {
1215
+	unversioned.TypeMeta `json:",inline"`
1216
+
1217
+	// Disable turns off an admission plugin that is enabled by default.
1218
+	Disable bool
1219
+}
... ...
@@ -47,7 +47,7 @@ import (
47 47
 )
48 48
 
49 49
 // AdmissionPlugins is the full list of admission control plugins to enable in the order they must run
50
-var AdmissionPlugins = []string{"RunOnceDuration", lifecycle.PluginName, "PodNodeConstraints", "OriginPodNodeEnvironment", overrideapi.PluginName, serviceadmit.ExternalIPPluginName, "LimitRanger", "ServiceAccount", "SecurityContextConstraint", "BuildDefaults", "BuildOverrides", "ResourceQuota", "SCCExecRestrictions"}
50
+var AdmissionPlugins = []string{"RunOnceDuration", lifecycle.PluginName, "PodNodeConstraints", "OriginPodNodeEnvironment", overrideapi.PluginName, serviceadmit.ExternalIPPluginName, "LimitRanger", "ServiceAccount", "SecurityContextConstraint", "BuildDefaults", "BuildOverrides", "AlwaysPullImages", "ResourceQuota", "SCCExecRestrictions"}
51 51
 
52 52
 // MasterConfig defines the required values to start a Kubernetes master
53 53
 type MasterConfig struct {
54 54
new file mode 100644
... ...
@@ -0,0 +1,57 @@
0
+package start
1
+
2
+import (
3
+	"io"
4
+
5
+	"k8s.io/kubernetes/pkg/admission"
6
+	"k8s.io/kubernetes/pkg/util/sets"
7
+
8
+	// Admission control plug-ins used by OpenShift
9
+	_ "github.com/openshift/origin/pkg/build/admission/defaults"
10
+	_ "github.com/openshift/origin/pkg/build/admission/overrides"
11
+	_ "github.com/openshift/origin/pkg/build/admission/strategyrestrictions"
12
+	_ "github.com/openshift/origin/pkg/project/admission/lifecycle"
13
+	_ "github.com/openshift/origin/pkg/project/admission/nodeenv"
14
+	_ "github.com/openshift/origin/pkg/project/admission/requestlimit"
15
+	_ "github.com/openshift/origin/pkg/quota/admission/clusterresourceoverride"
16
+	_ "github.com/openshift/origin/pkg/quota/admission/resourcequota"
17
+	_ "github.com/openshift/origin/pkg/quota/admission/runonceduration"
18
+	_ "github.com/openshift/origin/pkg/scheduler/admission/podnodeconstraints"
19
+	_ "github.com/openshift/origin/pkg/security/admission"
20
+	_ "k8s.io/kubernetes/plugin/pkg/admission/admit"
21
+	_ "k8s.io/kubernetes/plugin/pkg/admission/alwayspullimages"
22
+	_ "k8s.io/kubernetes/plugin/pkg/admission/exec"
23
+	_ "k8s.io/kubernetes/plugin/pkg/admission/limitranger"
24
+	_ "k8s.io/kubernetes/plugin/pkg/admission/namespace/exists"
25
+	_ "k8s.io/kubernetes/plugin/pkg/admission/namespace/lifecycle"
26
+	_ "k8s.io/kubernetes/plugin/pkg/admission/resourcequota"
27
+	_ "k8s.io/kubernetes/plugin/pkg/admission/serviceaccount"
28
+
29
+	configlatest "github.com/openshift/origin/pkg/cmd/server/api/latest"
30
+)
31
+
32
+var (
33
+	defaultOnPlugins  = sets.String{}
34
+	defaultOffPlugins = sets.String{}
35
+)
36
+
37
+func init() {
38
+	defaultOffPlugins.Insert("AlwaysPullImages")
39
+	admission.PluginEnabledFn = IsAdmissionPluginActivated
40
+}
41
+
42
+func IsAdmissionPluginActivated(name string, config io.Reader) bool {
43
+	// only intercept if we have an explicit enable or disable.  If the check fails in any way,
44
+	// assume that the config was a different type and let the actual admission plugin check it
45
+	if defaultOnPlugins.Has(name) {
46
+		if enabled, err := configlatest.IsAdmissionPluginActivated(config, true); err == nil && !enabled {
47
+			return false
48
+		}
49
+	} else if defaultOffPlugins.Has(name) {
50
+		if enabled, err := configlatest.IsAdmissionPluginActivated(config, false); err == nil && !enabled {
51
+			return false
52
+		}
53
+	}
54
+
55
+	return true
56
+}
0 57
deleted file mode 100644
... ...
@@ -1,25 +0,0 @@
1
-package start
2
-
3
-import (
4
-
5
-	// Admission control plug-ins used by OpenShift
6
-	_ "github.com/openshift/origin/pkg/build/admission/defaults"
7
-	_ "github.com/openshift/origin/pkg/build/admission/overrides"
8
-	_ "github.com/openshift/origin/pkg/build/admission/strategyrestrictions"
9
-	_ "github.com/openshift/origin/pkg/project/admission/lifecycle"
10
-	_ "github.com/openshift/origin/pkg/project/admission/nodeenv"
11
-	_ "github.com/openshift/origin/pkg/project/admission/requestlimit"
12
-	_ "github.com/openshift/origin/pkg/quota/admission/clusterresourceoverride"
13
-	_ "github.com/openshift/origin/pkg/quota/admission/resourcequota"
14
-	_ "github.com/openshift/origin/pkg/quota/admission/runonceduration"
15
-	_ "github.com/openshift/origin/pkg/scheduler/admission/podnodeconstraints"
16
-	_ "github.com/openshift/origin/pkg/security/admission"
17
-	_ "k8s.io/kubernetes/plugin/pkg/admission/admit"
18
-	_ "k8s.io/kubernetes/plugin/pkg/admission/alwayspullimages"
19
-	_ "k8s.io/kubernetes/plugin/pkg/admission/exec"
20
-	_ "k8s.io/kubernetes/plugin/pkg/admission/limitranger"
21
-	_ "k8s.io/kubernetes/plugin/pkg/admission/namespace/exists"
22
-	_ "k8s.io/kubernetes/plugin/pkg/admission/namespace/lifecycle"
23
-	_ "k8s.io/kubernetes/plugin/pkg/admission/resourcequota"
24
-	_ "k8s.io/kubernetes/plugin/pkg/admission/serviceaccount"
25
-)
... ...
@@ -291,3 +291,92 @@ func TestOpenshiftAdmissionPluginEmbeddedConfig(t *testing.T) {
291 291
 		t.Errorf("Error: %v", err)
292 292
 	}
293 293
 }
294
+
295
+func TestAlwaysPullImagesOn(t *testing.T) {
296
+	testutil.RequireEtcd(t)
297
+	masterConfig, err := testserver.DefaultMasterOptions()
298
+	if err != nil {
299
+		t.Fatalf("error creating config: %v", err)
300
+	}
301
+	masterConfig.KubernetesMasterConfig.AdmissionConfig.PluginConfig = map[string]configapi.AdmissionPluginConfig{
302
+		"AlwaysPullImages": {
303
+			Configuration: &configapi.DefaultAdmissionConfig{},
304
+		},
305
+	}
306
+	kubeConfigFile, err := testserver.StartConfiguredMaster(masterConfig)
307
+	if err != nil {
308
+		t.Fatalf("error starting server: %v", err)
309
+	}
310
+	kubeClient, err := testutil.GetClusterAdminKubeClient(kubeConfigFile)
311
+	if err != nil {
312
+		t.Fatalf("error getting client: %v", err)
313
+	}
314
+
315
+	ns := &kapi.Namespace{}
316
+	ns.Name = testutil.Namespace()
317
+	_, err = kubeClient.Namespaces().Create(ns)
318
+	if err != nil {
319
+		t.Fatalf("error creating namespace: %v", err)
320
+	}
321
+	if err := testserver.WaitForPodCreationServiceAccounts(kubeClient, testutil.Namespace()); err != nil {
322
+		t.Fatalf("error getting client config: %v", err)
323
+	}
324
+
325
+	testPod := &kapi.Pod{}
326
+	testPod.GenerateName = "test"
327
+	testPod.Spec.Containers = []kapi.Container{
328
+		{
329
+			Name:            "container",
330
+			Image:           "openshift/origin-pod:notlatest",
331
+			ImagePullPolicy: kapi.PullNever,
332
+		},
333
+	}
334
+
335
+	actualPod, err := kubeClient.Pods(testutil.Namespace()).Create(testPod)
336
+	if err != nil {
337
+		t.Fatalf("unexpected error: %v", err)
338
+	}
339
+	if actualPod.Spec.Containers[0].ImagePullPolicy != kapi.PullAlways {
340
+		t.Errorf("expected %v, got %v", kapi.PullAlways, actualPod.Spec.Containers[0].ImagePullPolicy)
341
+	}
342
+}
343
+
344
+func TestAlwaysPullImagesOff(t *testing.T) {
345
+	testutil.RequireEtcd(t)
346
+	_, kubeConfigFile, err := testserver.StartTestMaster()
347
+	if err != nil {
348
+		t.Fatalf("error starting server: %v", err)
349
+	}
350
+	kubeClient, err := testutil.GetClusterAdminKubeClient(kubeConfigFile)
351
+	if err != nil {
352
+		t.Fatalf("error getting client: %v", err)
353
+	}
354
+
355
+	ns := &kapi.Namespace{}
356
+	ns.Name = testutil.Namespace()
357
+	_, err = kubeClient.Namespaces().Create(ns)
358
+	if err != nil {
359
+		t.Fatalf("error creating namespace: %v", err)
360
+	}
361
+	if err := testserver.WaitForPodCreationServiceAccounts(kubeClient, testutil.Namespace()); err != nil {
362
+		t.Fatalf("error getting client config: %v", err)
363
+	}
364
+
365
+	testPod := &kapi.Pod{}
366
+	testPod.GenerateName = "test"
367
+	testPod.Spec.Containers = []kapi.Container{
368
+		{
369
+			Name:            "container",
370
+			Image:           "openshift/origin-pod:notlatest",
371
+			ImagePullPolicy: kapi.PullNever,
372
+		},
373
+	}
374
+
375
+	actualPod, err := kubeClient.Pods(testutil.Namespace()).Create(testPod)
376
+	if err != nil {
377
+		t.Fatalf("unexpected error: %v", err)
378
+	}
379
+	if actualPod.Spec.Containers[0].ImagePullPolicy != kapi.PullNever {
380
+		t.Errorf("expected %v, got %v", kapi.PullNever, actualPod.Spec.Containers[0].ImagePullPolicy)
381
+	}
382
+}