mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Merge pull request #5288 from derekwaynecarr/namespace_lifecycle
NamespaceLifecycle admission control plugin
This commit is contained in:
		@@ -34,6 +34,7 @@ import (
 | 
				
			|||||||
	_ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/limitranger"
 | 
						_ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/limitranger"
 | 
				
			||||||
	_ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/namespace/autoprovision"
 | 
						_ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/namespace/autoprovision"
 | 
				
			||||||
	_ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/namespace/exists"
 | 
						_ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/namespace/exists"
 | 
				
			||||||
 | 
						_ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/namespace/lifecycle"
 | 
				
			||||||
	_ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/resourcedefaults"
 | 
						_ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/resourcedefaults"
 | 
				
			||||||
	_ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/resourcequota"
 | 
						_ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/resourcequota"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										109
									
								
								plugin/pkg/admission/namespace/lifecycle/admission.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								plugin/pkg/admission/namespace/lifecycle/admission.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2015 Google Inc. All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					limitations under the License.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package lifecycle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
 | 
				
			||||||
 | 
						apierrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						admission.RegisterPlugin("NamespaceLifecycle", func(client client.Interface, config io.Reader) (admission.Interface, error) {
 | 
				
			||||||
 | 
							return NewLifecycle(client), nil
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// lifecycle is an implementation of admission.Interface.
 | 
				
			||||||
 | 
					// It enforces life-cycle constraints around a Namespace depending on its Phase
 | 
				
			||||||
 | 
					type lifecycle struct {
 | 
				
			||||||
 | 
						client client.Interface
 | 
				
			||||||
 | 
						store  cache.Store
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (l *lifecycle) Admit(a admission.Attributes) (err error) {
 | 
				
			||||||
 | 
						if a.GetOperation() != "CREATE" {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defaultVersion, kind, err := latest.RESTMapper.VersionAndKindForResource(a.GetResource())
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mapping, err := latest.RESTMapper.RESTMapping(kind, defaultVersion)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if mapping.Scope.Name() != meta.RESTScopeNameNamespace {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						namespaceObj, exists, err := l.store.Get(&api.Namespace{
 | 
				
			||||||
 | 
							ObjectMeta: api.ObjectMeta{
 | 
				
			||||||
 | 
								Name:      a.GetNamespace(),
 | 
				
			||||||
 | 
								Namespace: "",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !exists {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						namespace := namespaceObj.(*api.Namespace)
 | 
				
			||||||
 | 
						if namespace.Status.Phase != api.NamespaceTerminating {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						name := "Unknown"
 | 
				
			||||||
 | 
						obj := a.GetObject()
 | 
				
			||||||
 | 
						if obj != nil {
 | 
				
			||||||
 | 
							name, _ = meta.NewAccessor().Name(obj)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return apierrors.NewForbidden(kind, name, fmt.Errorf("Namespace %s is terminating", a.GetNamespace()))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewLifecycle(c client.Interface) admission.Interface {
 | 
				
			||||||
 | 
						store := cache.NewStore(cache.MetaNamespaceKeyFunc)
 | 
				
			||||||
 | 
						reflector := cache.NewReflector(
 | 
				
			||||||
 | 
							&cache.ListWatch{
 | 
				
			||||||
 | 
								ListFunc: func() (runtime.Object, error) {
 | 
				
			||||||
 | 
									return c.Namespaces().List(labels.Everything())
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								WatchFunc: func(resourceVersion string) (watch.Interface, error) {
 | 
				
			||||||
 | 
									return c.Namespaces().Watch(labels.Everything(), fields.Everything(), resourceVersion)
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							&api.Namespace{},
 | 
				
			||||||
 | 
							store,
 | 
				
			||||||
 | 
							0,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						reflector.Run()
 | 
				
			||||||
 | 
						return &lifecycle{
 | 
				
			||||||
 | 
							client: c,
 | 
				
			||||||
 | 
							store:  store,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										80
									
								
								plugin/pkg/admission/namespace/lifecycle/admission_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								plugin/pkg/admission/namespace/lifecycle/admission_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2015 Google Inc. All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					limitations under the License.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package lifecycle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TestAdmission
 | 
				
			||||||
 | 
					func TestAdmission(t *testing.T) {
 | 
				
			||||||
 | 
						namespaceObj := &api.Namespace{
 | 
				
			||||||
 | 
							ObjectMeta: api.ObjectMeta{
 | 
				
			||||||
 | 
								Name:      "test",
 | 
				
			||||||
 | 
								Namespace: "",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							Status: api.NamespaceStatus{
 | 
				
			||||||
 | 
								Phase: api.NamespaceActive,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						store := cache.NewStore(cache.MetaNamespaceIndexFunc)
 | 
				
			||||||
 | 
						store.Add(namespaceObj)
 | 
				
			||||||
 | 
						mockClient := &client.Fake{}
 | 
				
			||||||
 | 
						handler := &lifecycle{
 | 
				
			||||||
 | 
							client: mockClient,
 | 
				
			||||||
 | 
							store:  store,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pod := api.Pod{
 | 
				
			||||||
 | 
							ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespaceObj.Namespace},
 | 
				
			||||||
 | 
							Spec: api.PodSpec{
 | 
				
			||||||
 | 
								Volumes:    []api.Volume{{Name: "vol"}},
 | 
				
			||||||
 | 
								Containers: []api.Container{{Name: "ctr", Image: "image"}},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err := handler.Admit(admission.NewAttributesRecord(&pod, namespaceObj.Namespace, "pods", "CREATE"))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected error returned from admission handler: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// change namespace state to terminating
 | 
				
			||||||
 | 
						namespaceObj.Status.Phase = api.NamespaceTerminating
 | 
				
			||||||
 | 
						store.Add(namespaceObj)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// verify create operations in the namespace cause an error
 | 
				
			||||||
 | 
						err = handler.Admit(admission.NewAttributesRecord(&pod, namespaceObj.Namespace, "pods", "CREATE"))
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Errorf("Expected error rejecting creates in a namespace when it is terminating")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// verify update operations in the namespace can proceed
 | 
				
			||||||
 | 
						err = handler.Admit(admission.NewAttributesRecord(&pod, namespaceObj.Namespace, "pods", "UPDATE"))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected error returned from admission handler: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// verify delete operations in the namespace can proceed
 | 
				
			||||||
 | 
						err = handler.Admit(admission.NewAttributesRecord(nil, namespaceObj.Namespace, "pods", "DELETE"))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected error returned from admission handler: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user