| ... | ... |
@@ -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 |
+} |