From 1a5da9afc804eed6630caa1a17540d1a171b211a Mon Sep 17 00:00:00 2001 From: p0lyn0mial Date: Thu, 25 May 2017 20:32:43 +0200 Subject: [PATCH 1/2] move namespace lifecycle plugin to apiserver --- .../apiserver/pkg/admission/plugin}/namespace/lifecycle/BUILD | 0 .../pkg/admission/plugin}/namespace/lifecycle/admission.go | 0 .../pkg/admission/plugin}/namespace/lifecycle/admission_test.go | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename {plugin/pkg/admission => staging/src/k8s.io/apiserver/pkg/admission/plugin}/namespace/lifecycle/BUILD (100%) rename {plugin/pkg/admission => staging/src/k8s.io/apiserver/pkg/admission/plugin}/namespace/lifecycle/admission.go (100%) rename {plugin/pkg/admission => staging/src/k8s.io/apiserver/pkg/admission/plugin}/namespace/lifecycle/admission_test.go (100%) diff --git a/plugin/pkg/admission/namespace/lifecycle/BUILD b/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/BUILD similarity index 100% rename from plugin/pkg/admission/namespace/lifecycle/BUILD rename to staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/BUILD diff --git a/plugin/pkg/admission/namespace/lifecycle/admission.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission.go similarity index 100% rename from plugin/pkg/admission/namespace/lifecycle/admission.go rename to staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission.go diff --git a/plugin/pkg/admission/namespace/lifecycle/admission_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go similarity index 100% rename from plugin/pkg/admission/namespace/lifecycle/admission_test.go rename to staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go From 77eb2f39500f1fcf66899ea557791e7bca851449 Mon Sep 17 00:00:00 2001 From: p0lyn0mial Date: Thu, 25 May 2017 21:57:00 +0200 Subject: [PATCH 2/2] register all generic admission plugins when AdmissionOptions are created. lifecycle plugin: make use of the libraries under k8s.io/client-go/pkg/api and k8s.io/client-go/kubernetes for the client libraries instead of k8s.io/kubernetes/client/* move registration to AdmissionOptions --- cmd/kube-apiserver/app/BUILD | 1 - cmd/kube-apiserver/app/plugins.go | 2 - federation/cmd/federation-apiserver/app/BUILD | 1 - .../cmd/federation-apiserver/app/plugins.go | 4 +- .../cmd/federation-apiserver/app/server.go | 1 + plugin/BUILD | 1 - .../plugin/namespace/lifecycle/BUILD | 33 +++----- .../plugin/namespace/lifecycle/admission.go | 34 ++++----- .../namespace/lifecycle/admission_test.go | 75 ++++++++++--------- staging/src/k8s.io/apiserver/pkg/server/BUILD | 2 + .../apiserver/pkg/server/options/admission.go | 7 +- .../k8s.io/apiserver/pkg/server/plugins.go | 28 +++++++ 12 files changed, 104 insertions(+), 85 deletions(-) create mode 100644 staging/src/k8s.io/apiserver/pkg/server/plugins.go diff --git a/cmd/kube-apiserver/app/BUILD b/cmd/kube-apiserver/app/BUILD index 5154375b367..218c86814ae 100644 --- a/cmd/kube-apiserver/app/BUILD +++ b/cmd/kube-apiserver/app/BUILD @@ -55,7 +55,6 @@ go_library( "//plugin/pkg/admission/limitranger:go_default_library", "//plugin/pkg/admission/namespace/autoprovision:go_default_library", "//plugin/pkg/admission/namespace/exists:go_default_library", - "//plugin/pkg/admission/namespace/lifecycle:go_default_library", "//plugin/pkg/admission/noderestriction:go_default_library", "//plugin/pkg/admission/persistentvolume/label:go_default_library", "//plugin/pkg/admission/podnodeselector:go_default_library", diff --git a/cmd/kube-apiserver/app/plugins.go b/cmd/kube-apiserver/app/plugins.go index ba20aacfd16..f287a9a47d0 100644 --- a/cmd/kube-apiserver/app/plugins.go +++ b/cmd/kube-apiserver/app/plugins.go @@ -37,7 +37,6 @@ import ( "k8s.io/kubernetes/plugin/pkg/admission/limitranger" "k8s.io/kubernetes/plugin/pkg/admission/namespace/autoprovision" "k8s.io/kubernetes/plugin/pkg/admission/namespace/exists" - "k8s.io/kubernetes/plugin/pkg/admission/namespace/lifecycle" noderestriction "k8s.io/kubernetes/plugin/pkg/admission/noderestriction" "k8s.io/kubernetes/plugin/pkg/admission/persistentvolume/label" "k8s.io/kubernetes/plugin/pkg/admission/podnodeselector" @@ -64,7 +63,6 @@ func registerAllAdmissionPlugins(plugins *admission.Plugins) { limitranger.Register(plugins) autoprovision.Register(plugins) exists.Register(plugins) - lifecycle.Register(plugins) noderestriction.Register(plugins) label.Register(plugins) podnodeselector.Register(plugins) diff --git a/federation/cmd/federation-apiserver/app/BUILD b/federation/cmd/federation-apiserver/app/BUILD index 84177527d91..0966608dce0 100644 --- a/federation/cmd/federation-apiserver/app/BUILD +++ b/federation/cmd/federation-apiserver/app/BUILD @@ -67,7 +67,6 @@ go_library( "//plugin/pkg/admission/admit:go_default_library", "//plugin/pkg/admission/deny:go_default_library", "//plugin/pkg/admission/gc:go_default_library", - "//plugin/pkg/admission/namespace/lifecycle:go_default_library", "//vendor/github.com/go-openapi/spec:go_default_library", "//vendor/github.com/golang/glog:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library", diff --git a/federation/cmd/federation-apiserver/app/plugins.go b/federation/cmd/federation-apiserver/app/plugins.go index fbad2402da5..61c5902eb12 100644 --- a/federation/cmd/federation-apiserver/app/plugins.go +++ b/federation/cmd/federation-apiserver/app/plugins.go @@ -21,14 +21,13 @@ package app // given binary target. import ( // Cloud providers - "k8s.io/apiserver/pkg/admission" _ "k8s.io/kubernetes/pkg/cloudprovider/providers" // Admission policies + "k8s.io/apiserver/pkg/admission" "k8s.io/kubernetes/plugin/pkg/admission/admit" "k8s.io/kubernetes/plugin/pkg/admission/deny" "k8s.io/kubernetes/plugin/pkg/admission/gc" - "k8s.io/kubernetes/plugin/pkg/admission/namespace/lifecycle" ) // registerAllAdmissionPlugins registers all admission plugins @@ -36,5 +35,4 @@ func registerAllAdmissionPlugins(plugins *admission.Plugins) { admit.Register(plugins) deny.Register(plugins) gc.Register(plugins) - lifecycle.Register(plugins) } diff --git a/federation/cmd/federation-apiserver/app/server.go b/federation/cmd/federation-apiserver/app/server.go index dbc7456b93d..6c905060ba0 100644 --- a/federation/cmd/federation-apiserver/app/server.go +++ b/federation/cmd/federation-apiserver/app/server.go @@ -87,6 +87,7 @@ func Run(s *options.ServerRunOptions, stopCh <-chan struct{}) error { func NonBlockingRun(s *options.ServerRunOptions, stopCh <-chan struct{}) error { // register all admission plugins registerAllAdmissionPlugins(s.Admission.Plugins) + // set defaults if err := s.GenericServerRunOptions.DefaultAdvertiseAddress(s.SecureServing); err != nil { return err diff --git a/plugin/BUILD b/plugin/BUILD index 9f7368ddf2b..2af6b49bbce 100644 --- a/plugin/BUILD +++ b/plugin/BUILD @@ -26,7 +26,6 @@ filegroup( "//plugin/pkg/admission/limitranger:all-srcs", "//plugin/pkg/admission/namespace/autoprovision:all-srcs", "//plugin/pkg/admission/namespace/exists:all-srcs", - "//plugin/pkg/admission/namespace/lifecycle:all-srcs", "//plugin/pkg/admission/noderestriction:all-srcs", "//plugin/pkg/admission/persistentvolume/label:all-srcs", "//plugin/pkg/admission/podnodeselector:all-srcs", diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/BUILD b/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/BUILD index 5d0428688ab..10bba641e2b 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/BUILD @@ -13,11 +13,6 @@ go_library( srcs = ["admission.go"], tags = ["automanaged"], deps = [ - "//pkg/api:go_default_library", - "//pkg/client/clientset_generated/internalclientset:go_default_library", - "//pkg/client/informers/informers_generated/internalversion:go_default_library", - "//pkg/client/listers/core/internalversion:go_default_library", - "//pkg/kubeapiserver/admission:go_default_library", "//vendor/github.com/golang/glog:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", @@ -26,6 +21,11 @@ go_library( "//vendor/k8s.io/apimachinery/pkg/util/clock:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apiserver/pkg/admission:go_default_library", + "//vendor/k8s.io/apiserver/pkg/admission/initializer:go_default_library", + "//vendor/k8s.io/client-go/informers:go_default_library", + "//vendor/k8s.io/client-go/kubernetes:go_default_library", + "//vendor/k8s.io/client-go/listers/core/v1:go_default_library", + "//vendor/k8s.io/client-go/pkg/api/v1:go_default_library", ], ) @@ -35,11 +35,6 @@ go_test( library = ":go_default_library", tags = ["automanaged"], deps = [ - "//pkg/api:go_default_library", - "//pkg/client/clientset_generated/internalclientset:go_default_library", - "//pkg/client/clientset_generated/internalclientset/fake:go_default_library", - "//pkg/client/informers/informers_generated/internalversion:go_default_library", - "//pkg/kubeapiserver/admission:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", @@ -47,19 +42,11 @@ go_test( "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//vendor/k8s.io/apiserver/pkg/admission:go_default_library", + "//vendor/k8s.io/apiserver/pkg/admission/initializer:go_default_library", + "//vendor/k8s.io/client-go/informers:go_default_library", + "//vendor/k8s.io/client-go/kubernetes:go_default_library", + "//vendor/k8s.io/client-go/kubernetes/fake:go_default_library", + "//vendor/k8s.io/client-go/pkg/api/v1:go_default_library", "//vendor/k8s.io/client-go/testing:go_default_library", ], ) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [":package-srcs"], - tags = ["automanaged"], -) diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission.go index aab86656a17..e01445621e2 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission.go @@ -30,11 +30,11 @@ import ( "k8s.io/apimachinery/pkg/util/clock" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/admission" - "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion" - corelisters "k8s.io/kubernetes/pkg/client/listers/core/internalversion" - kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" + "k8s.io/apiserver/pkg/admission/initializer" + "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes" + corelisters "k8s.io/client-go/listers/core/v1" + "k8s.io/client-go/pkg/api/v1" ) const ( @@ -61,7 +61,7 @@ func Register(plugins *admission.Plugins) { // It enforces life-cycle constraints around a Namespace depending on its Phase type lifecycle struct { *admission.Handler - client internalclientset.Interface + client kubernetes.Interface immortalNamespaces sets.String namespaceLister corelisters.NamespaceLister // forceLiveLookupCache holds a list of entries for namespaces that we have a strong reason to believe are stale in our local cache. @@ -73,11 +73,11 @@ type forceLiveLookupEntry struct { expiry time.Time } -var _ = kubeapiserveradmission.WantsInternalKubeInformerFactory(&lifecycle{}) -var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&lifecycle{}) +var _ = initializer.WantsExternalKubeInformerFactory(&lifecycle{}) +var _ = initializer.WantsExternalKubeClientSet(&lifecycle{}) -func makeNamespaceKey(namespace string) *api.Namespace { - return &api.Namespace{ +func makeNamespaceKey(namespace string) *v1.Namespace { + return &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: namespace, Namespace: "", @@ -87,14 +87,14 @@ func makeNamespaceKey(namespace string) *api.Namespace { func (l *lifecycle) Admit(a admission.Attributes) error { // prevent deletion of immortal namespaces - if a.GetOperation() == admission.Delete && a.GetKind().GroupKind() == api.Kind("Namespace") && l.immortalNamespaces.Has(a.GetName()) { + if a.GetOperation() == admission.Delete && a.GetKind().GroupKind() == v1.SchemeGroupVersion.WithKind("Namespace").GroupKind() && l.immortalNamespaces.Has(a.GetName()) { return errors.NewForbidden(a.GetResource().GroupResource(), a.GetName(), fmt.Errorf("this namespace may not be deleted")) } // if we're here, then we've already passed authentication, so we're allowed to do what we're trying to do // if we're here, then the API server has found a route, which means that if we have a non-empty namespace // its a namespaced resource. - if len(a.GetNamespace()) == 0 || a.GetKind().GroupKind() == api.Kind("Namespace") { + if len(a.GetNamespace()) == 0 || a.GetKind().GroupKind() == v1.SchemeGroupVersion.WithKind("Namespace").GroupKind() { // if a namespace is deleted, we want to prevent all further creates into it // while it is undergoing termination. to reduce incidences where the cache // is slow to update, we add the namespace into a force live lookup list to ensure @@ -151,7 +151,7 @@ func (l *lifecycle) Admit(a admission.Attributes) error { forceLiveLookup := false if _, ok := l.forceLiveLookupCache.Get(a.GetNamespace()); ok { // we think the namespace was marked for deletion, but our current local cache says otherwise, we will force a live lookup. - forceLiveLookup = exists && namespace.Status.Phase == api.NamespaceActive + forceLiveLookup = exists && namespace.Status.Phase == v1.NamespaceActive } // refuse to operate on non-existent namespaces @@ -169,7 +169,7 @@ func (l *lifecycle) Admit(a admission.Attributes) error { // ensure that we're not trying to create objects in terminating namespaces if a.GetOperation() == admission.Create { - if namespace.Status.Phase != api.NamespaceTerminating { + if namespace.Status.Phase != v1.NamespaceTerminating { return nil } @@ -194,13 +194,13 @@ func newLifecycleWithClock(immortalNamespaces sets.String, clock utilcache.Clock }, nil } -func (l *lifecycle) SetInternalKubeInformerFactory(f informers.SharedInformerFactory) { - namespaceInformer := f.Core().InternalVersion().Namespaces() +func (l *lifecycle) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) { + namespaceInformer := f.Core().V1().Namespaces() l.namespaceLister = namespaceInformer.Lister() l.SetReadyFunc(namespaceInformer.Informer().HasSynced) } -func (l *lifecycle) SetInternalKubeClientSet(client internalclientset.Interface) { +func (l *lifecycle) SetExternalKubeClientSet(client kubernetes.Interface) { l.client = client } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go index 39ce5f0da17..7b2e2b06413 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go @@ -28,12 +28,12 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apiserver/pkg/admission" + kubeadmission "k8s.io/apiserver/pkg/admission/initializer" + informers "k8s.io/client-go/informers" + clientset "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/pkg/api/v1" core "k8s.io/client-go/testing" - "k8s.io/kubernetes/pkg/api" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" - informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion" - kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" ) // newHandlerForTest returns a configured handler for testing. @@ -48,29 +48,32 @@ func newHandlerForTestWithClock(c clientset.Interface, cacheClock clock.Clock) ( if err != nil { return nil, f, err } - pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil, nil, nil, nil) + pluginInitializer, err := kubeadmission.New(c, f, nil) + if err != nil { + return handler, f, err + } pluginInitializer.Initialize(handler) err = admission.Validate(handler) return handler, f, err } // newMockClientForTest creates a mock client that returns a client configured for the specified list of namespaces with the specified phase. -func newMockClientForTest(namespaces map[string]api.NamespacePhase) *fake.Clientset { +func newMockClientForTest(namespaces map[string]v1.NamespacePhase) *fake.Clientset { mockClient := &fake.Clientset{} mockClient.AddReactor("list", "namespaces", func(action core.Action) (bool, runtime.Object, error) { - namespaceList := &api.NamespaceList{ + namespaceList := &v1.NamespaceList{ ListMeta: metav1.ListMeta{ ResourceVersion: fmt.Sprintf("%d", len(namespaces)), }, } index := 0 for name, phase := range namespaces { - namespaceList.Items = append(namespaceList.Items, api.Namespace{ + namespaceList.Items = append(namespaceList.Items, v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: name, ResourceVersion: fmt.Sprintf("%d", index), }, - Status: api.NamespaceStatus{ + Status: v1.NamespaceStatus{ Phase: phase, }, }) @@ -82,19 +85,19 @@ func newMockClientForTest(namespaces map[string]api.NamespacePhase) *fake.Client } // newPod returns a new pod for the specified namespace -func newPod(namespace string) api.Pod { - return api.Pod{ +func newPod(namespace string) v1.Pod { + return v1.Pod{ ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: namespace}, - Spec: api.PodSpec{ - Volumes: []api.Volume{{Name: "vol"}}, - Containers: []api.Container{{Name: "ctr", Image: "image"}}, + Spec: v1.PodSpec{ + Volumes: []v1.Volume{{Name: "vol"}}, + Containers: []v1.Container{{Name: "ctr", Image: "image"}}, }, } } func TestAccessReviewCheckOnMissingNamespace(t *testing.T) { namespace := "test" - mockClient := newMockClientForTest(map[string]api.NamespacePhase{}) + mockClient := newMockClientForTest(map[string]v1.NamespacePhase{}) mockClient.AddReactor("get", "namespaces", func(action core.Action) (bool, runtime.Object, error) { return true, nil, fmt.Errorf("nope, out of luck") }) @@ -113,7 +116,7 @@ func TestAccessReviewCheckOnMissingNamespace(t *testing.T) { // TestAdmissionNamespaceDoesNotExist verifies pod is not admitted if namespace does not exist. func TestAdmissionNamespaceDoesNotExist(t *testing.T) { namespace := "test" - mockClient := newMockClientForTest(map[string]api.NamespacePhase{}) + mockClient := newMockClientForTest(map[string]v1.NamespacePhase{}) mockClient.AddReactor("get", "namespaces", func(action core.Action) (bool, runtime.Object, error) { return true, nil, fmt.Errorf("nope, out of luck") }) @@ -124,7 +127,7 @@ func TestAdmissionNamespaceDoesNotExist(t *testing.T) { informerFactory.Start(wait.NeverStop) pod := newPod(namespace) - err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, nil)) if err == nil { actions := "" for _, action := range mockClient.Actions() { @@ -137,8 +140,8 @@ func TestAdmissionNamespaceDoesNotExist(t *testing.T) { // TestAdmissionNamespaceActive verifies a resource is admitted when the namespace is active. func TestAdmissionNamespaceActive(t *testing.T) { namespace := "test" - mockClient := newMockClientForTest(map[string]api.NamespacePhase{ - namespace: api.NamespaceActive, + mockClient := newMockClientForTest(map[string]v1.NamespacePhase{ + namespace: v1.NamespaceActive, }) handler, informerFactory, err := newHandlerForTest(mockClient) @@ -148,7 +151,7 @@ func TestAdmissionNamespaceActive(t *testing.T) { informerFactory.Start(wait.NeverStop) pod := newPod(namespace) - err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, nil)) if err != nil { t.Errorf("unexpected error returned from admission handler") } @@ -157,8 +160,8 @@ func TestAdmissionNamespaceActive(t *testing.T) { // TestAdmissionNamespaceTerminating verifies a resource is not created when the namespace is active. func TestAdmissionNamespaceTerminating(t *testing.T) { namespace := "test" - mockClient := newMockClientForTest(map[string]api.NamespacePhase{ - namespace: api.NamespaceTerminating, + mockClient := newMockClientForTest(map[string]v1.NamespacePhase{ + namespace: v1.NamespaceTerminating, }) handler, informerFactory, err := newHandlerForTest(mockClient) @@ -169,31 +172,31 @@ func TestAdmissionNamespaceTerminating(t *testing.T) { pod := newPod(namespace) // verify create operations in the namespace cause an error - err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, nil)) 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, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, nil)) + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Update, nil)) 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, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Delete, nil)) + err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Delete, nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } // verify delete of namespace default can never proceed - err = handler.Admit(admission.NewAttributesRecord(nil, nil, api.Kind("Namespace").WithVersion("version"), "", metav1.NamespaceDefault, api.Resource("namespaces").WithVersion("version"), "", admission.Delete, nil)) + err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), "", metav1.NamespaceDefault, v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, nil)) if err == nil { t.Errorf("Expected an error that this namespace can never be deleted") } // verify delete of namespace other than default can proceed - err = handler.Admit(admission.NewAttributesRecord(nil, nil, api.Kind("Namespace").WithVersion("version"), "", "other", api.Resource("namespaces").WithVersion("version"), "", admission.Delete, nil)) + err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), "", "other", v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, nil)) if err != nil { t.Errorf("Did not expect an error %v", err) } @@ -203,11 +206,11 @@ func TestAdmissionNamespaceTerminating(t *testing.T) { func TestAdmissionNamespaceForceLiveLookup(t *testing.T) { namespace := "test" getCalls := int64(0) - phases := map[string]api.NamespacePhase{namespace: api.NamespaceActive} + phases := map[string]v1.NamespacePhase{namespace: v1.NamespaceActive} mockClient := newMockClientForTest(phases) mockClient.AddReactor("get", "namespaces", func(action core.Action) (bool, runtime.Object, error) { getCalls++ - return true, &api.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}, Status: api.NamespaceStatus{Phase: phases[namespace]}}, nil + return true, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}, Status: v1.NamespaceStatus{Phase: phases[namespace]}}, nil }) fakeClock := clock.NewFakeClock(time.Now()) @@ -220,7 +223,7 @@ func TestAdmissionNamespaceForceLiveLookup(t *testing.T) { pod := newPod(namespace) // verify create operations in the namespace is allowed - err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, nil)) if err != nil { t.Errorf("Unexpected error rejecting creates in an active namespace") } @@ -230,7 +233,7 @@ func TestAdmissionNamespaceForceLiveLookup(t *testing.T) { getCalls = 0 // verify delete of namespace can proceed - err = handler.Admit(admission.NewAttributesRecord(nil, nil, api.Kind("Namespace").WithVersion("version"), "", namespace, api.Resource("namespaces").WithVersion("version"), "", admission.Delete, nil)) + err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), "", namespace, v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, nil)) if err != nil { t.Errorf("Expected namespace deletion to be allowed") } @@ -240,10 +243,10 @@ func TestAdmissionNamespaceForceLiveLookup(t *testing.T) { getCalls = 0 // simulate the phase changing - phases[namespace] = api.NamespaceTerminating + phases[namespace] = v1.NamespaceTerminating // verify create operations in the namespace cause an error - err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, nil)) if err == nil { t.Errorf("Expected error rejecting creates in a namespace right after deleting it") } @@ -256,7 +259,7 @@ func TestAdmissionNamespaceForceLiveLookup(t *testing.T) { fakeClock.Step(forceLiveLookupTTL) // verify create operations in the namespace cause an error - err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, nil)) if err == nil { t.Errorf("Expected error rejecting creates in a namespace right after deleting it") } @@ -269,7 +272,7 @@ func TestAdmissionNamespaceForceLiveLookup(t *testing.T) { fakeClock.Step(time.Millisecond) // verify create operations in the namespace don't force a live lookup after the timeout - handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, nil)) if getCalls != 0 { t.Errorf("Expected no live lookup of the namespace at t=forceLiveLookupTTL+1ms, got %d", getCalls) } diff --git a/staging/src/k8s.io/apiserver/pkg/server/BUILD b/staging/src/k8s.io/apiserver/pkg/server/BUILD index 1526f24adbd..d430499a62b 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/server/BUILD @@ -52,6 +52,7 @@ go_library( "handler.go", "healthz.go", "hooks.go", + "plugins.go", "serve.go", ], tags = ["automanaged"], @@ -76,6 +77,7 @@ go_library( "//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library", "//vendor/k8s.io/apimachinery/pkg/version:go_default_library", "//vendor/k8s.io/apiserver/pkg/admission:go_default_library", + "//vendor/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/apiserver/install:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/audit:go_default_library", diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/admission.go b/staging/src/k8s.io/apiserver/pkg/server/options/admission.go index 6d2003bd673..760f4fc3da7 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/admission.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/admission.go @@ -35,11 +35,16 @@ type AdmissionOptions struct { } // NewAdmissionOptions creates a new instance of AdmissionOptions +// Note: +// In addition it calls RegisterAllAdmissionPlugins to register +// all generic admission plugins. func NewAdmissionOptions() *AdmissionOptions { - return &AdmissionOptions{ + options := &AdmissionOptions{ Plugins: &admission.Plugins{}, PluginNames: []string{}, } + server.RegisterAllAdmissionPlugins(options.Plugins) + return options } // AddFlags adds flags related to admission for a specific APIServer to the specified FlagSet diff --git a/staging/src/k8s.io/apiserver/pkg/server/plugins.go b/staging/src/k8s.io/apiserver/pkg/server/plugins.go new file mode 100644 index 00000000000..404e8afc4c8 --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/server/plugins.go @@ -0,0 +1,28 @@ +/* +Copyright 2017 The Kubernetes Authors. + +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 server + +// This file exists to force the desired plugin implementations to be linked into genericapi pkg. +import ( + "k8s.io/apiserver/pkg/admission" + "k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle" +) + +// RegisterAllAdmissionPlugins registers all admission plugins +func RegisterAllAdmissionPlugins(plugins *admission.Plugins) { + lifecycle.Register(plugins) +}