From 2861509b6dc4580c1a49c8ce5a1cfab894f18f25 Mon Sep 17 00:00:00 2001 From: deads2k Date: Wed, 21 Dec 2016 16:16:16 -0500 Subject: [PATCH] refactored admission to avoid internal client references --- cmd/kube-apiserver/app/BUILD | 1 + cmd/kube-apiserver/app/server.go | 5 +- federation/cmd/federation-apiserver/app/BUILD | 1 + .../cmd/federation-apiserver/app/server.go | 5 +- pkg/admission/BUILD | 15 +--- pkg/admission/chain.go | 20 ----- pkg/admission/init.go | 70 ----------------- pkg/admission/interfaces.go | 12 +++ pkg/admission/plugins.go | 63 ++++++++++++--- pkg/admission/types.go | 40 ---------- pkg/kubeapiserver/admission/BUILD | 32 ++++++++ .../admission/init_test.go | 13 ++-- pkg/kubeapiserver/admission/initializer.go | 77 +++++++++++++++++++ plugin/pkg/admission/admit/BUILD | 5 +- plugin/pkg/admission/admit/admission.go | 4 +- plugin/pkg/admission/alwayspullimages/BUILD | 1 - .../admission/alwayspullimages/admission.go | 4 +- plugin/pkg/admission/antiaffinity/BUILD | 1 - .../pkg/admission/antiaffinity/admission.go | 9 +-- .../admission/antiaffinity/admission_test.go | 4 +- plugin/pkg/admission/deny/BUILD | 5 +- plugin/pkg/admission/deny/admission.go | 4 +- plugin/pkg/admission/exec/BUILD | 1 + plugin/pkg/admission/exec/admission.go | 33 +++++--- plugin/pkg/admission/gc/BUILD | 1 - plugin/pkg/admission/gc/gc_admission.go | 3 +- plugin/pkg/admission/imagepolicy/BUILD | 2 - plugin/pkg/admission/imagepolicy/admission.go | 7 +- .../admission/imagepolicy/admission_test.go | 5 +- plugin/pkg/admission/initialresources/BUILD | 1 - .../admission/initialresources/admission.go | 4 +- plugin/pkg/admission/limitranger/BUILD | 2 + plugin/pkg/admission/limitranger/admission.go | 26 ++++--- .../admission/limitranger/admission_test.go | 10 +-- .../admission/namespace/autoprovision/BUILD | 2 + .../namespace/autoprovision/admission.go | 28 ++++--- .../namespace/autoprovision/admission_test.go | 10 +-- plugin/pkg/admission/namespace/exists/BUILD | 2 + .../admission/namespace/exists/admission.go | 28 ++++--- .../namespace/exists/admission_test.go | 10 +-- .../pkg/admission/namespace/lifecycle/BUILD | 2 + .../namespace/lifecycle/admission.go | 31 +++++--- .../namespace/lifecycle/admission_test.go | 10 +-- .../admission/persistentvolume/label/BUILD | 1 - .../persistentvolume/label/admission.go | 4 +- plugin/pkg/admission/podnodeselector/BUILD | 2 + .../admission/podnodeselector/admission.go | 21 +++-- .../podnodeselector/admission_test.go | 12 +-- plugin/pkg/admission/resourcequota/BUILD | 1 + .../pkg/admission/resourcequota/admission.go | 46 +++++++---- .../admission/resourcequota/admission_test.go | 15 +++- .../security/podsecuritypolicy/BUILD | 3 +- .../security/podsecuritypolicy/admission.go | 52 +++++++------ .../podsecuritypolicy/admission_test.go | 12 +-- .../admission/securitycontext/scdeny/BUILD | 1 - .../securitycontext/scdeny/admission.go | 11 +-- .../securitycontext/scdeny/admission_test.go | 6 +- plugin/pkg/admission/serviceaccount/BUILD | 1 + .../pkg/admission/serviceaccount/admission.go | 70 +++++++++++------ .../serviceaccount/admission_test.go | 54 ++++++++----- .../pkg/admission/storageclass/default/BUILD | 1 + .../storageclass/default/admission.go | 51 ++++++++---- .../storageclass/default/admission_test.go | 3 +- test/integration/quota/quota_test.go | 4 +- .../serviceaccount/service_account_test.go | 3 +- 65 files changed, 559 insertions(+), 424 deletions(-) delete mode 100644 pkg/admission/init.go delete mode 100644 pkg/admission/types.go create mode 100644 pkg/kubeapiserver/admission/BUILD rename pkg/{ => kubeapiserver}/admission/init_test.go (77%) create mode 100644 pkg/kubeapiserver/admission/initializer.go diff --git a/cmd/kube-apiserver/app/BUILD b/cmd/kube-apiserver/app/BUILD index 2d9ac3ca58..5992005982 100644 --- a/cmd/kube-apiserver/app/BUILD +++ b/cmd/kube-apiserver/app/BUILD @@ -30,6 +30,7 @@ go_library( "//pkg/generated/openapi:go_default_library", "//pkg/genericapiserver:go_default_library", "//pkg/genericapiserver/filters:go_default_library", + "//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubeapiserver/authenticator:go_default_library", "//pkg/master:go_default_library", "//pkg/registry/cachesize:go_default_library", diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index f52ec29cbc..7915dc3e92 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -49,6 +49,7 @@ import ( generatedopenapi "k8s.io/kubernetes/pkg/generated/openapi" "k8s.io/kubernetes/pkg/genericapiserver" "k8s.io/kubernetes/pkg/genericapiserver/filters" + kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubeauthenticator "k8s.io/kubernetes/pkg/kubeapiserver/authenticator" "k8s.io/kubernetes/pkg/master" "k8s.io/kubernetes/pkg/registry/cachesize" @@ -266,8 +267,8 @@ func Run(s *options.ServerRunOptions) error { } admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",") - pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer) - admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer) + pluginInitializer := kubeadmission.NewPluginInitializer(client, sharedInformers, apiAuthorizer) + admissionController, err := admission.NewFromPlugins(admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer) if err != nil { return fmt.Errorf("failed to initialize plugins: %v", err) } diff --git a/federation/cmd/federation-apiserver/app/BUILD b/federation/cmd/federation-apiserver/app/BUILD index d487bbbb1b..4182eefd0a 100644 --- a/federation/cmd/federation-apiserver/app/BUILD +++ b/federation/cmd/federation-apiserver/app/BUILD @@ -41,6 +41,7 @@ go_library( "//pkg/generated/openapi:go_default_library", "//pkg/genericapiserver:go_default_library", "//pkg/genericapiserver/filters:go_default_library", + "//pkg/kubeapiserver/admission:go_default_library", "//pkg/registry/batch/job/etcd:go_default_library", "//pkg/registry/cachesize:go_default_library", "//pkg/registry/core/configmap/etcd:go_default_library", diff --git a/federation/cmd/federation-apiserver/app/server.go b/federation/cmd/federation-apiserver/app/server.go index 473dd0fea4..292dc2635b 100644 --- a/federation/cmd/federation-apiserver/app/server.go +++ b/federation/cmd/federation-apiserver/app/server.go @@ -37,6 +37,7 @@ import ( "k8s.io/kubernetes/pkg/generated/openapi" "k8s.io/kubernetes/pkg/genericapiserver" "k8s.io/kubernetes/pkg/genericapiserver/filters" + kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" "k8s.io/kubernetes/pkg/registry/cachesize" "k8s.io/kubernetes/pkg/registry/generic" genericregistry "k8s.io/kubernetes/pkg/registry/generic/registry" @@ -156,8 +157,8 @@ func Run(s *options.ServerRunOptions) error { } admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",") - pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer) - admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer) + pluginInitializer := kubeapiserveradmission.NewPluginInitializer(client, sharedInformers, apiAuthorizer) + admissionController, err := admission.NewFromPlugins(admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer) if err != nil { return fmt.Errorf("failed to initialize plugins: %v", err) } diff --git a/pkg/admission/BUILD b/pkg/admission/BUILD index 978ede4d01..e64710a1ae 100644 --- a/pkg/admission/BUILD +++ b/pkg/admission/BUILD @@ -15,19 +15,14 @@ go_library( "chain.go", "errors.go", "handler.go", - "init.go", "interfaces.go", "plugins.go", - "types.go", ], tags = ["automanaged"], deps = [ "//pkg/api/errors:go_default_library", "//pkg/api/meta:go_default_library", - "//pkg/auth/authorizer:go_default_library", "//pkg/auth/user:go_default_library", - "//pkg/client/clientset_generated/internalclientset:go_default_library", - "//pkg/controller/informers:go_default_library", "//pkg/runtime:go_default_library", "//pkg/runtime/schema:go_default_library", "//pkg/util/errors:go_default_library", @@ -38,14 +33,8 @@ go_library( go_test( name = "go_default_test", - srcs = [ - "chain_test.go", - "init_test.go", - ], + srcs = ["chain_test.go"], library = ":go_default_library", tags = ["automanaged"], - deps = [ - "//pkg/auth/authorizer:go_default_library", - "//pkg/runtime/schema:go_default_library", - ], + deps = ["//pkg/runtime/schema:go_default_library"], ) diff --git a/pkg/admission/chain.go b/pkg/admission/chain.go index a43bf8bb5b..45c7f72f9c 100644 --- a/pkg/admission/chain.go +++ b/pkg/admission/chain.go @@ -16,29 +16,9 @@ limitations under the License. package admission -import clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - // chainAdmissionHandler is an instance of admission.Interface that performs admission control using a chain of admission handlers type chainAdmissionHandler []Interface -// NewFromPlugins returns an admission.Interface that will enforce admission control decisions of all -// the given plugins. -func NewFromPlugins(client clientset.Interface, pluginNames []string, configFilePath string, plugInit PluginInitializer) (Interface, error) { - plugins := []Interface{} - for _, pluginName := range pluginNames { - plugin := InitPlugin(pluginName, client, configFilePath) - if plugin != nil { - plugins = append(plugins, plugin) - } - } - plugInit.Initialize(plugins) - // ensure that plugins have been properly initialized - if err := Validate(plugins); err != nil { - return nil, err - } - return chainAdmissionHandler(plugins), nil -} - // NewChainHandler creates a new chain handler from an array of handlers. Used for testing. func NewChainHandler(handlers ...Interface) Interface { return chainAdmissionHandler(handlers) diff --git a/pkg/admission/init.go b/pkg/admission/init.go deleted file mode 100644 index de4e2db83b..0000000000 --- a/pkg/admission/init.go +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright 2016 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 admission - -import ( - "k8s.io/kubernetes/pkg/auth/authorizer" - "k8s.io/kubernetes/pkg/controller/informers" -) - -// PluginInitializer is used for initialization of shareable resources between admission plugins. -// After initialization the resources have to be set separately -type PluginInitializer interface { - Initialize(plugins []Interface) -} - -type pluginInitializer struct { - informers informers.SharedInformerFactory - authorizer authorizer.Authorizer -} - -// NewPluginInitializer constructs new instance of PluginInitializer -func NewPluginInitializer(sharedInformers informers.SharedInformerFactory, authz authorizer.Authorizer) PluginInitializer { - plugInit := &pluginInitializer{ - informers: sharedInformers, - authorizer: authz, - } - return plugInit -} - -// Initialize checks the initialization interfaces implemented by each plugin -// and provide the appropriate initialization data -func (i *pluginInitializer) Initialize(plugins []Interface) { - for _, plugin := range plugins { - if wantsInformerFactory, ok := plugin.(WantsInformerFactory); ok { - wantsInformerFactory.SetInformerFactory(i.informers) - } - - if wantsAuthorizer, ok := plugin.(WantsAuthorizer); ok { - wantsAuthorizer.SetAuthorizer(i.authorizer) - } - } -} - -// Validate will call the Validate function in each plugin if they implement -// the Validator interface. -func Validate(plugins []Interface) error { - for _, plugin := range plugins { - if validater, ok := plugin.(Validator); ok { - err := validater.Validate() - if err != nil { - return err - } - } - } - return nil -} diff --git a/pkg/admission/interfaces.go b/pkg/admission/interfaces.go index dcc2c02767..a2f4ef0a4b 100644 --- a/pkg/admission/interfaces.go +++ b/pkg/admission/interfaces.go @@ -69,3 +69,15 @@ const ( Delete Operation = "DELETE" Connect Operation = "CONNECT" ) + +// PluginInitializer is used for initialization of shareable resources between admission plugins. +// After initialization the resources have to be set separately +type PluginInitializer interface { + Initialize(plugin Interface) +} + +// Validator holds Validate functions, which are responsible for validation of initialized shared resources +// and should be implemented on admission plugins +type Validator interface { + Validate() error +} diff --git a/pkg/admission/plugins.go b/pkg/admission/plugins.go index 6d739d99c5..3656e9e950 100644 --- a/pkg/admission/plugins.go +++ b/pkg/admission/plugins.go @@ -18,6 +18,7 @@ package admission import ( "bytes" + "fmt" "io" "io/ioutil" "os" @@ -26,15 +27,13 @@ import ( "sync" "github.com/golang/glog" - - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" ) // Factory is a function that returns an Interface for admission decisions. // The config parameter provides an io.Reader handler to the factory in // order to load specific configurations. If no configuration is provided // the parameter is nil. -type Factory func(client clientset.Interface, config io.Reader) (Interface, error) +type Factory func(config io.Reader) (Interface, error) // All registered admission options. var ( @@ -79,7 +78,7 @@ func RegisterPlugin(name string, plugin Factory) { // the name is not known. The error is returned only when the named provider was // known but failed to initialize. The config parameter specifies the io.Reader // handler of the configuration file for the cloud provider, or nil for no configuration. -func getPlugin(name string, client clientset.Interface, config io.Reader) (Interface, bool, error) { +func getPlugin(name string, config io.Reader) (Interface, bool, error) { pluginsMutex.Lock() defer pluginsMutex.Unlock() f, found := plugins[name] @@ -95,7 +94,7 @@ func getPlugin(name string, client clientset.Interface, config io.Reader) (Inter return nil, true, nil } - ret, err := f(client, config2) + ret, err := f(config2) return ret, true, err } @@ -113,8 +112,24 @@ func splitStream(config io.Reader) (io.Reader, io.Reader, error) { return bytes.NewBuffer(configBytes), bytes.NewBuffer(configBytes), nil } +// NewFromPlugins returns an admission.Interface that will enforce admission control decisions of all +// the given plugins. +func NewFromPlugins(pluginNames []string, configFilePath string, pluginInitializer PluginInitializer) (Interface, error) { + plugins := []Interface{} + for _, pluginName := range pluginNames { + plugin, err := InitPlugin(pluginName, configFilePath, pluginInitializer) + if err != nil { + return nil, err + } + if plugin != nil { + plugins = append(plugins, plugin) + } + } + return chainAdmissionHandler(plugins), nil +} + // InitPlugin creates an instance of the named interface. -func InitPlugin(name string, client clientset.Interface, configFilePath string) Interface { +func InitPlugin(name string, configFilePath string, pluginInitializer PluginInitializer) (Interface, error) { var ( config *os.File err error @@ -122,7 +137,7 @@ func InitPlugin(name string, client clientset.Interface, configFilePath string) if name == "" { glog.Info("No admission plugin specified.") - return nil + return nil, nil } if configFilePath != "" { @@ -135,13 +150,39 @@ func InitPlugin(name string, client clientset.Interface, configFilePath string) defer config.Close() } - plugin, found, err := getPlugin(name, client, config) + plugin, found, err := getPlugin(name, config) if err != nil { - glog.Fatalf("Couldn't init admission plugin %q: %v", name, err) + return nil, fmt.Errorf("Couldn't init admission plugin %q: %v", name, err) } if !found { - glog.Fatalf("Unknown admission plugin: %s", name) + return nil, fmt.Errorf("Unknown admission plugin: %s", name) } - return plugin + pluginInitializer.Initialize(plugin) + // ensure that plugins have been properly initialized + if err := Validate(plugin); err != nil { + return nil, err + } + + return plugin, nil +} + +// Validate will call the Validate function in each plugin if they implement +// the Validator interface. +func Validate(plugin Interface) error { + if validater, ok := plugin.(Validator); ok { + err := validater.Validate() + if err != nil { + return err + } + } + return nil +} + +type PluginInitializers []PluginInitializer + +func (pp PluginInitializers) Initialize(plugin Interface) { + for _, p := range pp { + p.Initialize(plugin) + } } diff --git a/pkg/admission/types.go b/pkg/admission/types.go deleted file mode 100644 index 21c943b8d0..0000000000 --- a/pkg/admission/types.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 2016 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 admission - -import ( - "k8s.io/kubernetes/pkg/auth/authorizer" - "k8s.io/kubernetes/pkg/controller/informers" -) - -// Validator holds Validate functions, which are responsible for validation of initialized shared resources -// and should be implemented on admission plugins -type Validator interface { - Validate() error -} - -// WantsInformerFactory defines a function which sets InformerFactory for admission plugins that need it -type WantsInformerFactory interface { - SetInformerFactory(informers.SharedInformerFactory) - Validator -} - -// WantsAuthorizer defines a function which sets Authorizer for admission plugins that need it. -type WantsAuthorizer interface { - SetAuthorizer(authorizer.Authorizer) - Validator -} diff --git a/pkg/kubeapiserver/admission/BUILD b/pkg/kubeapiserver/admission/BUILD new file mode 100644 index 0000000000..e5f23b1b3d --- /dev/null +++ b/pkg/kubeapiserver/admission/BUILD @@ -0,0 +1,32 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", + "go_test", +) + +go_test( + name = "go_default_test", + srcs = ["init_test.go"], + library = ":go_default_library", + tags = ["automanaged"], + deps = [ + "//pkg/admission:go_default_library", + "//pkg/auth/authorizer:go_default_library", + ], +) + +go_library( + name = "go_default_library", + srcs = ["initializer.go"], + tags = ["automanaged"], + deps = [ + "//pkg/admission:go_default_library", + "//pkg/auth/authorizer:go_default_library", + "//pkg/client/clientset_generated/internalclientset:go_default_library", + "//pkg/controller/informers:go_default_library", + ], +) diff --git a/pkg/admission/init_test.go b/pkg/kubeapiserver/admission/init_test.go similarity index 77% rename from pkg/admission/init_test.go rename to pkg/kubeapiserver/admission/init_test.go index 685a77ac96..e06e0cd4ff 100644 --- a/pkg/admission/init_test.go +++ b/pkg/kubeapiserver/admission/init_test.go @@ -19,6 +19,7 @@ package admission import ( "testing" + "k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/auth/authorizer" ) @@ -40,19 +41,19 @@ type WantAuthorizerAdmission struct { func (self *WantAuthorizerAdmission) SetAuthorizer(a authorizer.Authorizer) { self.auth = a } -func (self *WantAuthorizerAdmission) Admit(a Attributes) error { return nil } -func (self *WantAuthorizerAdmission) Handles(o Operation) bool { return false } -func (self *WantAuthorizerAdmission) Validate() error { return nil } +func (self *WantAuthorizerAdmission) Admit(a admission.Attributes) error { return nil } +func (self *WantAuthorizerAdmission) Handles(o admission.Operation) bool { return false } +func (self *WantAuthorizerAdmission) Validate() error { return nil } -var _ Interface = &WantAuthorizerAdmission{} +var _ admission.Interface = &WantAuthorizerAdmission{} var _ WantsAuthorizer = &WantAuthorizerAdmission{} // TestWantsAuthorizer ensures that the authorizer is injected when the WantsAuthorizer // interface is implemented. func TestWantsAuthorizer(t *testing.T) { - initializer := NewPluginInitializer(nil, &TestAuthorizer{}) + initializer := NewPluginInitializer(nil, nil, &TestAuthorizer{}) wantAuthorizerAdmission := &WantAuthorizerAdmission{} - initializer.Initialize([]Interface{wantAuthorizerAdmission}) + initializer.Initialize(wantAuthorizerAdmission) if wantAuthorizerAdmission.auth == nil { t.Errorf("expected authorizer to be initialized but found nil") } diff --git a/pkg/kubeapiserver/admission/initializer.go b/pkg/kubeapiserver/admission/initializer.go new file mode 100644 index 0000000000..92fc7a0888 --- /dev/null +++ b/pkg/kubeapiserver/admission/initializer.go @@ -0,0 +1,77 @@ +/* +Copyright 2016 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 admission + +import ( + "k8s.io/kubernetes/pkg/admission" + "k8s.io/kubernetes/pkg/auth/authorizer" + "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + "k8s.io/kubernetes/pkg/controller/informers" +) + +// TODO add a `WantsToRun` which takes a stopCh. Might make it generic. + +// WantsInformerFactory defines a function which sets InformerFactory for admission plugins that need it +type WantsInternalClientSet interface { + SetInternalClientSet(internalclientset.Interface) + admission.Validator +} + +// WantsInformerFactory defines a function which sets InformerFactory for admission plugins that need it +type WantsInformerFactory interface { + SetInformerFactory(informers.SharedInformerFactory) + admission.Validator +} + +// WantsAuthorizer defines a function which sets Authorizer for admission plugins that need it. +type WantsAuthorizer interface { + SetAuthorizer(authorizer.Authorizer) + admission.Validator +} + +type pluginInitializer struct { + internalClient internalclientset.Interface + informers informers.SharedInformerFactory + authorizer authorizer.Authorizer +} + +var _ admission.PluginInitializer = pluginInitializer{} + +// NewPluginInitializer constructs new instance of PluginInitializer +func NewPluginInitializer(internalClient internalclientset.Interface, sharedInformers informers.SharedInformerFactory, authz authorizer.Authorizer) admission.PluginInitializer { + return pluginInitializer{ + internalClient: internalClient, + informers: sharedInformers, + authorizer: authz, + } +} + +// Initialize checks the initialization interfaces implemented by each plugin +// and provide the appropriate initialization data +func (i pluginInitializer) Initialize(plugin admission.Interface) { + if wants, ok := plugin.(WantsInternalClientSet); ok { + wants.SetInternalClientSet(i.internalClient) + } + + if wants, ok := plugin.(WantsInformerFactory); ok { + wants.SetInformerFactory(i.informers) + } + + if wants, ok := plugin.(WantsAuthorizer); ok { + wants.SetAuthorizer(i.authorizer) + } +} diff --git a/plugin/pkg/admission/admit/BUILD b/plugin/pkg/admission/admit/BUILD index 8ff65a9bad..1d95b71e3c 100644 --- a/plugin/pkg/admission/admit/BUILD +++ b/plugin/pkg/admission/admit/BUILD @@ -12,10 +12,7 @@ go_library( name = "go_default_library", srcs = ["admission.go"], tags = ["automanaged"], - deps = [ - "//pkg/admission:go_default_library", - "//pkg/client/clientset_generated/internalclientset:go_default_library", - ], + deps = ["//pkg/admission:go_default_library"], ) go_test( diff --git a/plugin/pkg/admission/admit/admission.go b/plugin/pkg/admission/admit/admission.go index b7b528aedf..6aab9b0eb3 100644 --- a/plugin/pkg/admission/admit/admission.go +++ b/plugin/pkg/admission/admit/admission.go @@ -19,13 +19,11 @@ package admit import ( "io" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "k8s.io/kubernetes/pkg/admission" ) func init() { - admission.RegisterPlugin("AlwaysAdmit", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { + admission.RegisterPlugin("AlwaysAdmit", func(config io.Reader) (admission.Interface, error) { return NewAlwaysAdmit(), nil }) } diff --git a/plugin/pkg/admission/alwayspullimages/BUILD b/plugin/pkg/admission/alwayspullimages/BUILD index 3421996339..d7628a776e 100644 --- a/plugin/pkg/admission/alwayspullimages/BUILD +++ b/plugin/pkg/admission/alwayspullimages/BUILD @@ -16,7 +16,6 @@ go_library( "//pkg/admission:go_default_library", "//pkg/api:go_default_library", "//pkg/api/errors:go_default_library", - "//pkg/client/clientset_generated/internalclientset:go_default_library", ], ) diff --git a/plugin/pkg/admission/alwayspullimages/admission.go b/plugin/pkg/admission/alwayspullimages/admission.go index c0e36709bf..f42aaf18f8 100644 --- a/plugin/pkg/admission/alwayspullimages/admission.go +++ b/plugin/pkg/admission/alwayspullimages/admission.go @@ -27,15 +27,13 @@ package alwayspullimages import ( "io" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/api" apierrors "k8s.io/kubernetes/pkg/api/errors" ) func init() { - admission.RegisterPlugin("AlwaysPullImages", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { + admission.RegisterPlugin("AlwaysPullImages", func(config io.Reader) (admission.Interface, error) { return NewAlwaysPullImages(), nil }) } diff --git a/plugin/pkg/admission/antiaffinity/BUILD b/plugin/pkg/admission/antiaffinity/BUILD index 156402c3ef..f1fae2d028 100644 --- a/plugin/pkg/admission/antiaffinity/BUILD +++ b/plugin/pkg/admission/antiaffinity/BUILD @@ -20,7 +20,6 @@ go_library( "//pkg/api:go_default_library", "//pkg/api/errors:go_default_library", "//pkg/apis/meta/v1:go_default_library", - "//pkg/client/clientset_generated/internalclientset:go_default_library", "//vendor:github.com/golang/glog", ], ) diff --git a/plugin/pkg/admission/antiaffinity/admission.go b/plugin/pkg/admission/antiaffinity/admission.go index 5757c69a0b..aadbb26cbb 100644 --- a/plugin/pkg/admission/antiaffinity/admission.go +++ b/plugin/pkg/admission/antiaffinity/admission.go @@ -25,26 +25,23 @@ import ( "k8s.io/kubernetes/pkg/api" apierrors "k8s.io/kubernetes/pkg/api/errors" metav1 "k8s.io/kubernetes/pkg/apis/meta/v1" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" ) func init() { - admission.RegisterPlugin("LimitPodHardAntiAffinityTopology", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { - return NewInterPodAntiAffinity(client), nil + admission.RegisterPlugin("LimitPodHardAntiAffinityTopology", func(config io.Reader) (admission.Interface, error) { + return NewInterPodAntiAffinity(), nil }) } // plugin contains the client used by the admission controller type plugin struct { *admission.Handler - client clientset.Interface } // NewInterPodAntiAffinity creates a new instance of the LimitPodHardAntiAffinityTopology admission controller -func NewInterPodAntiAffinity(client clientset.Interface) admission.Interface { +func NewInterPodAntiAffinity() admission.Interface { return &plugin{ Handler: admission.NewHandler(admission.Create, admission.Update), - client: client, } } diff --git a/plugin/pkg/admission/antiaffinity/admission_test.go b/plugin/pkg/admission/antiaffinity/admission_test.go index 4fb05f2e3c..8540b28eae 100644 --- a/plugin/pkg/admission/antiaffinity/admission_test.go +++ b/plugin/pkg/admission/antiaffinity/admission_test.go @@ -27,7 +27,7 @@ import ( // ensures the hard PodAntiAffinity is denied if it defines TopologyKey other than kubernetes.io/hostname. func TestInterPodAffinityAdmission(t *testing.T) { - handler := NewInterPodAntiAffinity(nil) + handler := NewInterPodAntiAffinity() pod := api.Pod{ Spec: api.PodSpec{}, } @@ -226,7 +226,7 @@ func TestInterPodAffinityAdmission(t *testing.T) { } } func TestHandles(t *testing.T) { - handler := NewInterPodAntiAffinity(nil) + handler := NewInterPodAntiAffinity() tests := map[admission.Operation]bool{ admission.Update: true, admission.Create: true, diff --git a/plugin/pkg/admission/deny/BUILD b/plugin/pkg/admission/deny/BUILD index fdcbaeae23..8476899dfa 100644 --- a/plugin/pkg/admission/deny/BUILD +++ b/plugin/pkg/admission/deny/BUILD @@ -12,10 +12,7 @@ go_library( name = "go_default_library", srcs = ["admission.go"], tags = ["automanaged"], - deps = [ - "//pkg/admission:go_default_library", - "//pkg/client/clientset_generated/internalclientset:go_default_library", - ], + deps = ["//pkg/admission:go_default_library"], ) go_test( diff --git a/plugin/pkg/admission/deny/admission.go b/plugin/pkg/admission/deny/admission.go index 7b62ea81b3..f7a93f9674 100644 --- a/plugin/pkg/admission/deny/admission.go +++ b/plugin/pkg/admission/deny/admission.go @@ -20,13 +20,11 @@ import ( "errors" "io" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "k8s.io/kubernetes/pkg/admission" ) func init() { - admission.RegisterPlugin("AlwaysDeny", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { + admission.RegisterPlugin("AlwaysDeny", func(config io.Reader) (admission.Interface, error) { return NewAlwaysDeny(), nil }) } diff --git a/plugin/pkg/admission/exec/BUILD b/plugin/pkg/admission/exec/BUILD index 62d9e9f54d..99aca9e87e 100644 --- a/plugin/pkg/admission/exec/BUILD +++ b/plugin/pkg/admission/exec/BUILD @@ -19,6 +19,7 @@ go_library( "//pkg/api/rest:go_default_library", "//pkg/apis/meta/v1:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", + "//pkg/kubeapiserver/admission:go_default_library", ], ) diff --git a/plugin/pkg/admission/exec/admission.go b/plugin/pkg/admission/exec/admission.go index 10fa862653..97fc2b779e 100644 --- a/plugin/pkg/admission/exec/admission.go +++ b/plugin/pkg/admission/exec/admission.go @@ -20,24 +20,24 @@ import ( "fmt" "io" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/rest" metav1 "k8s.io/kubernetes/pkg/apis/meta/v1" + "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" ) func init() { - admission.RegisterPlugin("DenyEscalatingExec", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { - return NewDenyEscalatingExec(client), nil + admission.RegisterPlugin("DenyEscalatingExec", func(config io.Reader) (admission.Interface, error) { + return NewDenyEscalatingExec(), nil }) // This is for legacy support of the DenyExecOnPrivileged admission controller. Most // of the time DenyEscalatingExec should be preferred. - admission.RegisterPlugin("DenyExecOnPrivileged", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { - return NewDenyExecOnPrivileged(client), nil + admission.RegisterPlugin("DenyExecOnPrivileged", func(config io.Reader) (admission.Interface, error) { + return NewDenyExecOnPrivileged(), nil }) } @@ -45,7 +45,7 @@ func init() { // a pod using host based configurations. type denyExec struct { *admission.Handler - client clientset.Interface + client internalclientset.Interface // these flags control which items will be checked to deny exec/attach hostIPC bool @@ -53,12 +53,13 @@ type denyExec struct { privileged bool } +var _ = kubeapiserveradmission.WantsInternalClientSet(&denyExec{}) + // NewDenyEscalatingExec creates a new admission controller that denies an exec operation on a pod // using host based configurations. -func NewDenyEscalatingExec(client clientset.Interface) admission.Interface { +func NewDenyEscalatingExec() admission.Interface { return &denyExec{ Handler: admission.NewHandler(admission.Connect), - client: client, hostIPC: true, hostPID: true, privileged: true, @@ -68,10 +69,9 @@ func NewDenyEscalatingExec(client clientset.Interface) admission.Interface { // NewDenyExecOnPrivileged creates a new admission controller that is only checking the privileged // option. This is for legacy support of the DenyExecOnPrivileged admission controller. Most // of the time NewDenyEscalatingExec should be preferred. -func NewDenyExecOnPrivileged(client clientset.Interface) admission.Interface { +func NewDenyExecOnPrivileged() admission.Interface { return &denyExec{ Handler: admission.NewHandler(admission.Connect), - client: client, hostIPC: false, hostPID: false, privileged: true, @@ -127,3 +127,14 @@ func isPrivileged(pod *api.Pod) bool { } return false } + +func (d *denyExec) SetInternalClientSet(client internalclientset.Interface) { + d.client = client +} + +func (d *denyExec) Validate() error { + if d.client == nil { + return fmt.Errorf("missing client") + } + return nil +} diff --git a/plugin/pkg/admission/gc/BUILD b/plugin/pkg/admission/gc/BUILD index f6d355c955..46aa6c6a66 100644 --- a/plugin/pkg/admission/gc/BUILD +++ b/plugin/pkg/admission/gc/BUILD @@ -17,7 +17,6 @@ go_library( "//pkg/api:go_default_library", "//pkg/api/meta:go_default_library", "//pkg/auth/authorizer:go_default_library", - "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/runtime:go_default_library", ], ) diff --git a/plugin/pkg/admission/gc/gc_admission.go b/plugin/pkg/admission/gc/gc_admission.go index 2d7d206e19..f797280349 100644 --- a/plugin/pkg/admission/gc/gc_admission.go +++ b/plugin/pkg/admission/gc/gc_admission.go @@ -24,12 +24,11 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/auth/authorizer" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/runtime" ) func init() { - admission.RegisterPlugin("OwnerReferencesPermissionEnforcement", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { + admission.RegisterPlugin("OwnerReferencesPermissionEnforcement", func(config io.Reader) (admission.Interface, error) { return &gcPermissionsEnforcement{ Handler: admission.NewHandler(admission.Create, admission.Update), }, nil diff --git a/plugin/pkg/admission/imagepolicy/BUILD b/plugin/pkg/admission/imagepolicy/BUILD index d3b7b1c8c4..acaf50bfc0 100644 --- a/plugin/pkg/admission/imagepolicy/BUILD +++ b/plugin/pkg/admission/imagepolicy/BUILD @@ -21,7 +21,6 @@ go_library( "//pkg/api:go_default_library", "//pkg/api/errors:go_default_library", "//pkg/apis/imagepolicy/v1alpha1:go_default_library", - "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/restclient:go_default_library", "//pkg/runtime/schema:go_default_library", "//pkg/util/cache:go_default_library", @@ -46,7 +45,6 @@ go_test( "//pkg/apis/imagepolicy/install:go_default_library", "//pkg/apis/imagepolicy/v1alpha1:go_default_library", "//pkg/auth/user:go_default_library", - "//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/unversioned/clientcmd/api/v1:go_default_library", ], ) diff --git a/plugin/pkg/admission/imagepolicy/admission.go b/plugin/pkg/admission/imagepolicy/admission.go index 8f65489f6f..6a027d896a 100644 --- a/plugin/pkg/admission/imagepolicy/admission.go +++ b/plugin/pkg/admission/imagepolicy/admission.go @@ -31,7 +31,6 @@ import ( "k8s.io/kubernetes/pkg/api" apierrors "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/apis/imagepolicy/v1alpha1" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/runtime/schema" "k8s.io/kubernetes/pkg/util/yaml" @@ -47,8 +46,8 @@ var ( ) func init() { - admission.RegisterPlugin("ImagePolicyWebhook", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { - newImagePolicyWebhook, err := NewImagePolicyWebhook(client, config) + admission.RegisterPlugin("ImagePolicyWebhook", func(config io.Reader) (admission.Interface, error) { + newImagePolicyWebhook, err := NewImagePolicyWebhook(config) if err != nil { return nil, err } @@ -211,7 +210,7 @@ func (a *imagePolicyWebhook) admitPod(attributes admission.Attributes, review *v // // For additional HTTP configuration, refer to the kubeconfig documentation // http://kubernetes.io/v1.1/docs/user-guide/kubeconfig-file.html. -func NewImagePolicyWebhook(client clientset.Interface, configFile io.Reader) (admission.Interface, error) { +func NewImagePolicyWebhook(configFile io.Reader) (admission.Interface, error) { var config AdmissionConfig d := yaml.NewYAMLOrJSONDecoder(configFile, 4096) err := d.Decode(&config) diff --git a/plugin/pkg/admission/imagepolicy/admission_test.go b/plugin/pkg/admission/imagepolicy/admission_test.go index 950aceacf8..f94c2cea2b 100644 --- a/plugin/pkg/admission/imagepolicy/admission_test.go +++ b/plugin/pkg/admission/imagepolicy/admission_test.go @@ -32,7 +32,6 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/apis/imagepolicy/v1alpha1" "k8s.io/kubernetes/pkg/auth/user" - "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1" "fmt" @@ -244,7 +243,7 @@ current-context: default } defer configFile.Close() - _, err = NewImagePolicyWebhook(fake.NewSimpleClientset(), configFile) + _, err = NewImagePolicyWebhook(configFile) return err }() if err != nil && !tt.wantErr { @@ -404,7 +403,7 @@ func newImagePolicyWebhook(callbackURL string, clientCert, clientKey, ca []byte, return nil, fmt.Errorf("failed to read test config: %v", err) } defer configFile.Close() - wh, err := NewImagePolicyWebhook(fake.NewSimpleClientset(), configFile) + wh, err := NewImagePolicyWebhook(configFile) return wh.(*imagePolicyWebhook), err } diff --git a/plugin/pkg/admission/initialresources/BUILD b/plugin/pkg/admission/initialresources/BUILD index 2e48daf312..bdcd47482a 100644 --- a/plugin/pkg/admission/initialresources/BUILD +++ b/plugin/pkg/admission/initialresources/BUILD @@ -23,7 +23,6 @@ go_library( "//pkg/api:go_default_library", "//pkg/api/errors:go_default_library", "//pkg/api/resource:go_default_library", - "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/restclient:go_default_library", "//pkg/client/unversioned/clientcmd:go_default_library", "//vendor:cloud.google.com/go/compute/metadata", diff --git a/plugin/pkg/admission/initialresources/admission.go b/plugin/pkg/admission/initialresources/admission.go index 0fcbfa9deb..0183d1dc02 100644 --- a/plugin/pkg/admission/initialresources/admission.go +++ b/plugin/pkg/admission/initialresources/admission.go @@ -24,8 +24,6 @@ import ( "strings" "time" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "github.com/golang/glog" "k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/api" @@ -48,7 +46,7 @@ const ( // WARNING: this feature is experimental and will definitely change. func init() { - admission.RegisterPlugin("InitialResources", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { + admission.RegisterPlugin("InitialResources", func(config io.Reader) (admission.Interface, error) { s, err := newDataSource(*source) if err != nil { return nil, err diff --git a/plugin/pkg/admission/limitranger/BUILD b/plugin/pkg/admission/limitranger/BUILD index cc08e80e2e..fdb56b228c 100644 --- a/plugin/pkg/admission/limitranger/BUILD +++ b/plugin/pkg/admission/limitranger/BUILD @@ -23,6 +23,7 @@ go_library( "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/listers/core/internalversion:go_default_library", "//pkg/controller/informers:go_default_library", + "//pkg/kubeapiserver/admission:go_default_library", "//pkg/labels:go_default_library", "//pkg/runtime:go_default_library", "//pkg/util/errors:go_default_library", @@ -44,6 +45,7 @@ go_test( "//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/testing/core:go_default_library", "//pkg/controller/informers:go_default_library", + "//pkg/kubeapiserver/admission:go_default_library", "//pkg/runtime:go_default_library", "//pkg/util/wait:go_default_library", ], diff --git a/plugin/pkg/admission/limitranger/admission.go b/plugin/pkg/admission/limitranger/admission.go index 87fbd1eb46..c16bf60485 100644 --- a/plugin/pkg/admission/limitranger/admission.go +++ b/plugin/pkg/admission/limitranger/admission.go @@ -25,14 +25,14 @@ import ( lru "github.com/hashicorp/golang-lru" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - coreinternallisters "k8s.io/kubernetes/pkg/client/listers/core/internalversion" - "k8s.io/kubernetes/pkg/controller/informers" - "k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/resource" + "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + coreinternallisters "k8s.io/kubernetes/pkg/client/listers/core/internalversion" + "k8s.io/kubernetes/pkg/controller/informers" + kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/runtime" utilerrors "k8s.io/kubernetes/pkg/util/errors" @@ -43,15 +43,15 @@ const ( ) func init() { - admission.RegisterPlugin("LimitRanger", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { - return NewLimitRanger(client, &DefaultLimitRangerActions{}) + admission.RegisterPlugin("LimitRanger", func(config io.Reader) (admission.Interface, error) { + return NewLimitRanger(&DefaultLimitRangerActions{}) }) } // limitRanger enforces usage limits on a per resource basis in the namespace type limitRanger struct { *admission.Handler - client clientset.Interface + client internalclientset.Interface actions LimitRangerActions lister coreinternallisters.LimitRangeLister @@ -77,6 +77,9 @@ func (l *limitRanger) Validate() error { if l.lister == nil { return fmt.Errorf("missing limitRange lister") } + if l.client == nil { + return fmt.Errorf("missing client") + } return nil } @@ -145,7 +148,7 @@ func (l *limitRanger) Admit(a admission.Attributes) (err error) { } // NewLimitRanger returns an object that enforces limits based on the supplied limit function -func NewLimitRanger(client clientset.Interface, actions LimitRangerActions) (admission.Interface, error) { +func NewLimitRanger(actions LimitRangerActions) (admission.Interface, error) { liveLookupCache, err := lru.New(10000) if err != nil { return nil, err @@ -157,13 +160,18 @@ func NewLimitRanger(client clientset.Interface, actions LimitRangerActions) (adm return &limitRanger{ Handler: admission.NewHandler(admission.Create, admission.Update), - client: client, actions: actions, liveLookupCache: liveLookupCache, liveTTL: time.Duration(30 * time.Second), }, nil } +var _ = kubeapiserveradmission.WantsInternalClientSet(&limitRanger{}) + +func (a *limitRanger) SetInternalClientSet(client internalclientset.Interface) { + a.client = client +} + // defaultContainerResourceRequirements returns the default requirements for a container // the requirement.Limits are taken from the LimitRange defaults (if specified) // the requirement.Requests are taken from the LimitRange default request (if specified) diff --git a/plugin/pkg/admission/limitranger/admission_test.go b/plugin/pkg/admission/limitranger/admission_test.go index 0af782fc89..1d6bc36c81 100644 --- a/plugin/pkg/admission/limitranger/admission_test.go +++ b/plugin/pkg/admission/limitranger/admission_test.go @@ -30,6 +30,7 @@ import ( "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/testing/core" "k8s.io/kubernetes/pkg/controller/informers" + kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/util/wait" ) @@ -589,14 +590,13 @@ func newMockClientForTest(limitRanges []api.LimitRange) *fake.Clientset { // newHandlerForTest returns a handler configured for testing. func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) { f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute) - handler, err := NewLimitRanger(c, &DefaultLimitRangerActions{}) + handler, err := NewLimitRanger(&DefaultLimitRangerActions{}) if err != nil { return nil, f, err } - plugins := []admission.Interface{handler} - pluginInitializer := admission.NewPluginInitializer(f, nil) - pluginInitializer.Initialize(plugins) - err = admission.Validate(plugins) + pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil) + pluginInitializer.Initialize(handler) + err = admission.Validate(handler) return handler, f, err } diff --git a/plugin/pkg/admission/namespace/autoprovision/BUILD b/plugin/pkg/admission/namespace/autoprovision/BUILD index 9e7ba5dce9..a8bbaebc96 100644 --- a/plugin/pkg/admission/namespace/autoprovision/BUILD +++ b/plugin/pkg/admission/namespace/autoprovision/BUILD @@ -19,6 +19,7 @@ go_library( "//pkg/client/cache:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/controller/informers:go_default_library", + "//pkg/kubeapiserver/admission:go_default_library", ], ) @@ -36,6 +37,7 @@ go_test( "//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/testing/core:go_default_library", "//pkg/controller/informers:go_default_library", + "//pkg/kubeapiserver/admission:go_default_library", "//pkg/runtime:go_default_library", "//pkg/util/wait:go_default_library", ], diff --git a/plugin/pkg/admission/namespace/autoprovision/admission.go b/plugin/pkg/admission/namespace/autoprovision/admission.go index 67e9256036..c00d2dc261 100644 --- a/plugin/pkg/admission/namespace/autoprovision/admission.go +++ b/plugin/pkg/admission/namespace/autoprovision/admission.go @@ -17,22 +17,21 @@ limitations under the License. package autoprovision import ( - "io" - - "k8s.io/kubernetes/pkg/client/cache" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "fmt" + "io" "k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/errors" + "k8s.io/kubernetes/pkg/client/cache" + "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/controller/informers" + kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" ) func init() { - admission.RegisterPlugin("NamespaceAutoProvision", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { - return NewProvision(client), nil + admission.RegisterPlugin("NamespaceAutoProvision", func(config io.Reader) (admission.Interface, error) { + return NewProvision(), nil }) } @@ -41,11 +40,12 @@ func init() { // It is useful in deployments that do not want to restrict creation of a namespace prior to its usage. type provision struct { *admission.Handler - client clientset.Interface + client internalclientset.Interface namespaceInformer cache.SharedIndexInformer } -var _ = admission.WantsInformerFactory(&provision{}) +var _ = kubeapiserveradmission.WantsInformerFactory(&provision{}) +var _ = kubeapiserveradmission.WantsInformerFactory(&provision{}) func (p *provision) Admit(a admission.Attributes) (err error) { // if we're here, then we've already passed authentication, so we're allowed to do what we're trying to do @@ -80,13 +80,16 @@ func (p *provision) Admit(a admission.Attributes) (err error) { } // NewProvision creates a new namespace provision admission control handler -func NewProvision(c clientset.Interface) admission.Interface { +func NewProvision() admission.Interface { return &provision{ Handler: admission.NewHandler(admission.Create), - client: c, } } +func (p *provision) SetInternalClientSet(client internalclientset.Interface) { + p.client = client +} + func (p *provision) SetInformerFactory(f informers.SharedInformerFactory) { p.namespaceInformer = f.InternalNamespaces().Informer() p.SetReadyFunc(p.namespaceInformer.HasSynced) @@ -96,5 +99,8 @@ func (p *provision) Validate() error { if p.namespaceInformer == nil { return fmt.Errorf("missing namespaceInformer") } + if p.client == nil { + return fmt.Errorf("missing client") + } return nil } diff --git a/plugin/pkg/admission/namespace/autoprovision/admission_test.go b/plugin/pkg/admission/namespace/autoprovision/admission_test.go index 6459c5b79b..42d77ee3ba 100644 --- a/plugin/pkg/admission/namespace/autoprovision/admission_test.go +++ b/plugin/pkg/admission/namespace/autoprovision/admission_test.go @@ -29,6 +29,7 @@ import ( "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/testing/core" "k8s.io/kubernetes/pkg/controller/informers" + kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/util/wait" ) @@ -36,11 +37,10 @@ import ( // newHandlerForTest returns the admission controller configured for testing. func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) { f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute) - handler := NewProvision(c) - plugins := []admission.Interface{handler} - pluginInitializer := admission.NewPluginInitializer(f, nil) - pluginInitializer.Initialize(plugins) - err := admission.Validate(plugins) + handler := NewProvision() + pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil) + pluginInitializer.Initialize(handler) + err := admission.Validate(handler) return handler, f, err } diff --git a/plugin/pkg/admission/namespace/exists/BUILD b/plugin/pkg/admission/namespace/exists/BUILD index e2defba6ff..75cfc06044 100644 --- a/plugin/pkg/admission/namespace/exists/BUILD +++ b/plugin/pkg/admission/namespace/exists/BUILD @@ -20,6 +20,7 @@ go_library( "//pkg/client/cache:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/controller/informers:go_default_library", + "//pkg/kubeapiserver/admission:go_default_library", ], ) @@ -36,6 +37,7 @@ go_test( "//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/testing/core:go_default_library", "//pkg/controller/informers:go_default_library", + "//pkg/kubeapiserver/admission:go_default_library", "//pkg/runtime:go_default_library", "//pkg/util/wait:go_default_library", ], diff --git a/plugin/pkg/admission/namespace/exists/admission.go b/plugin/pkg/admission/namespace/exists/admission.go index 490bc3e8d0..b39c25ade9 100644 --- a/plugin/pkg/admission/namespace/exists/admission.go +++ b/plugin/pkg/admission/namespace/exists/admission.go @@ -17,23 +17,22 @@ limitations under the License. package exists import ( - "io" - - "k8s.io/kubernetes/pkg/client/cache" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "fmt" + "io" "k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/errors" metav1 "k8s.io/kubernetes/pkg/apis/meta/v1" + "k8s.io/kubernetes/pkg/client/cache" + "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/controller/informers" + kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" ) func init() { - admission.RegisterPlugin("NamespaceExists", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { - return NewExists(client), nil + admission.RegisterPlugin("NamespaceExists", func(config io.Reader) (admission.Interface, error) { + return NewExists(), nil }) } @@ -42,11 +41,12 @@ func init() { // It is useful in deployments that want to enforce pre-declaration of a Namespace resource. type exists struct { *admission.Handler - client clientset.Interface + client internalclientset.Interface namespaceInformer cache.SharedIndexInformer } -var _ = admission.WantsInformerFactory(&exists{}) +var _ = kubeapiserveradmission.WantsInformerFactory(&exists{}) +var _ = kubeapiserveradmission.WantsInternalClientSet(&exists{}) func (e *exists) Admit(a admission.Attributes) (err error) { // if we're here, then we've already passed authentication, so we're allowed to do what we're trying to do @@ -88,13 +88,16 @@ func (e *exists) Admit(a admission.Attributes) (err error) { } // NewExists creates a new namespace exists admission control handler -func NewExists(c clientset.Interface) admission.Interface { +func NewExists() admission.Interface { return &exists{ - client: c, Handler: admission.NewHandler(admission.Create, admission.Update, admission.Delete), } } +func (e *exists) SetInternalClientSet(client internalclientset.Interface) { + e.client = client +} + func (e *exists) SetInformerFactory(f informers.SharedInformerFactory) { e.namespaceInformer = f.InternalNamespaces().Informer() e.SetReadyFunc(e.namespaceInformer.HasSynced) @@ -104,5 +107,8 @@ func (e *exists) Validate() error { if e.namespaceInformer == nil { return fmt.Errorf("missing namespaceInformer") } + if e.client == nil { + return fmt.Errorf("missing client") + } return nil } diff --git a/plugin/pkg/admission/namespace/exists/admission_test.go b/plugin/pkg/admission/namespace/exists/admission_test.go index b29739e15e..6a6b94f3f2 100644 --- a/plugin/pkg/admission/namespace/exists/admission_test.go +++ b/plugin/pkg/admission/namespace/exists/admission_test.go @@ -28,6 +28,7 @@ import ( "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/testing/core" "k8s.io/kubernetes/pkg/controller/informers" + kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/util/wait" ) @@ -35,11 +36,10 @@ import ( // newHandlerForTest returns the admission controller configured for testing. func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) { f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute) - handler := NewExists(c) - plugins := []admission.Interface{handler} - pluginInitializer := admission.NewPluginInitializer(f, nil) - pluginInitializer.Initialize(plugins) - err := admission.Validate(plugins) + handler := NewExists() + pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil) + pluginInitializer.Initialize(handler) + err := admission.Validate(handler) return handler, f, err } diff --git a/plugin/pkg/admission/namespace/lifecycle/BUILD b/plugin/pkg/admission/namespace/lifecycle/BUILD index 19f2241f3e..f7dbb0b3c3 100644 --- a/plugin/pkg/admission/namespace/lifecycle/BUILD +++ b/plugin/pkg/admission/namespace/lifecycle/BUILD @@ -20,6 +20,7 @@ go_library( "//pkg/client/cache:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/controller/informers:go_default_library", + "//pkg/kubeapiserver/admission:go_default_library", "//pkg/util/cache:go_default_library", "//pkg/util/clock:go_default_library", "//pkg/util/sets:go_default_library", @@ -40,6 +41,7 @@ go_test( "//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/testing/core:go_default_library", "//pkg/controller/informers:go_default_library", + "//pkg/kubeapiserver/admission:go_default_library", "//pkg/runtime:go_default_library", "//pkg/util/clock:go_default_library", "//pkg/util/sets:go_default_library", diff --git a/plugin/pkg/admission/namespace/lifecycle/admission.go b/plugin/pkg/admission/namespace/lifecycle/admission.go index ee448c966d..d8269b48b0 100644 --- a/plugin/pkg/admission/namespace/lifecycle/admission.go +++ b/plugin/pkg/admission/namespace/lifecycle/admission.go @@ -23,14 +23,14 @@ import ( "github.com/golang/glog" - "k8s.io/kubernetes/pkg/client/cache" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "k8s.io/kubernetes/pkg/controller/informers" - "k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/errors" metav1 "k8s.io/kubernetes/pkg/apis/meta/v1" + "k8s.io/kubernetes/pkg/client/cache" + "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + "k8s.io/kubernetes/pkg/controller/informers" + kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" utilcache "k8s.io/kubernetes/pkg/util/cache" "k8s.io/kubernetes/pkg/util/clock" "k8s.io/kubernetes/pkg/util/sets" @@ -50,8 +50,8 @@ const ( ) func init() { - admission.RegisterPlugin(PluginName, func(client clientset.Interface, config io.Reader) (admission.Interface, error) { - return NewLifecycle(client, sets.NewString(api.NamespaceDefault, api.NamespaceSystem)) + admission.RegisterPlugin(PluginName, func(config io.Reader) (admission.Interface, error) { + return NewLifecycle(sets.NewString(api.NamespaceDefault, api.NamespaceSystem)) }) } @@ -59,7 +59,7 @@ func init() { // It enforces life-cycle constraints around a Namespace depending on its Phase type lifecycle struct { *admission.Handler - client clientset.Interface + client internalclientset.Interface immortalNamespaces sets.String namespaceInformer cache.SharedIndexInformer // forceLiveLookupCache holds a list of entries for namespaces that we have a strong reason to believe are stale in our local cache. @@ -71,7 +71,8 @@ type forceLiveLookupEntry struct { expiry time.Time } -var _ = admission.WantsInformerFactory(&lifecycle{}) +var _ = kubeapiserveradmission.WantsInformerFactory(&lifecycle{}) +var _ = kubeapiserveradmission.WantsInternalClientSet(&lifecycle{}) func makeNamespaceKey(namespace string) *api.Namespace { return &api.Namespace{ @@ -167,15 +168,14 @@ func (l *lifecycle) Admit(a admission.Attributes) error { } // NewLifecycle creates a new namespace lifecycle admission control handler -func NewLifecycle(c clientset.Interface, immortalNamespaces sets.String) (admission.Interface, error) { - return newLifecycleWithClock(c, immortalNamespaces, clock.RealClock{}) +func NewLifecycle(immortalNamespaces sets.String) (admission.Interface, error) { + return newLifecycleWithClock(immortalNamespaces, clock.RealClock{}) } -func newLifecycleWithClock(c clientset.Interface, immortalNamespaces sets.String, clock utilcache.Clock) (admission.Interface, error) { +func newLifecycleWithClock(immortalNamespaces sets.String, clock utilcache.Clock) (admission.Interface, error) { forceLiveLookupCache := utilcache.NewLRUExpireCacheWithClock(100, clock) return &lifecycle{ Handler: admission.NewHandler(admission.Create, admission.Update, admission.Delete), - client: c, immortalNamespaces: immortalNamespaces, forceLiveLookupCache: forceLiveLookupCache, }, nil @@ -186,9 +186,16 @@ func (l *lifecycle) SetInformerFactory(f informers.SharedInformerFactory) { l.SetReadyFunc(l.namespaceInformer.HasSynced) } +func (l *lifecycle) SetInternalClientSet(client internalclientset.Interface) { + l.client = client +} + func (l *lifecycle) Validate() error { if l.namespaceInformer == nil { return fmt.Errorf("missing namespaceInformer") } + if l.client == nil { + return fmt.Errorf("missing client") + } return nil } diff --git a/plugin/pkg/admission/namespace/lifecycle/admission_test.go b/plugin/pkg/admission/namespace/lifecycle/admission_test.go index aa09a5869c..1a74bc00d7 100644 --- a/plugin/pkg/admission/namespace/lifecycle/admission_test.go +++ b/plugin/pkg/admission/namespace/lifecycle/admission_test.go @@ -28,6 +28,7 @@ import ( "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/testing/core" "k8s.io/kubernetes/pkg/controller/informers" + kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/util/clock" "k8s.io/kubernetes/pkg/util/sets" @@ -42,14 +43,13 @@ func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.Sh // newHandlerForTestWithClock returns a configured handler for testing. func newHandlerForTestWithClock(c clientset.Interface, cacheClock clock.Clock) (admission.Interface, informers.SharedInformerFactory, error) { f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute) - handler, err := newLifecycleWithClock(c, sets.NewString(api.NamespaceDefault, api.NamespaceSystem), cacheClock) + handler, err := newLifecycleWithClock(sets.NewString(api.NamespaceDefault, api.NamespaceSystem), cacheClock) if err != nil { return nil, f, err } - plugins := []admission.Interface{handler} - pluginInitializer := admission.NewPluginInitializer(f, nil) - pluginInitializer.Initialize(plugins) - err = admission.Validate(plugins) + pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil) + pluginInitializer.Initialize(handler) + err = admission.Validate(handler) return handler, f, err } diff --git a/plugin/pkg/admission/persistentvolume/label/BUILD b/plugin/pkg/admission/persistentvolume/label/BUILD index 4399e2c52f..ff9db9f098 100644 --- a/plugin/pkg/admission/persistentvolume/label/BUILD +++ b/plugin/pkg/admission/persistentvolume/label/BUILD @@ -19,7 +19,6 @@ go_library( "//pkg/admission:go_default_library", "//pkg/api:go_default_library", "//pkg/apis/meta/v1:go_default_library", - "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/cloudprovider:go_default_library", "//pkg/cloudprovider/providers/aws:go_default_library", "//pkg/cloudprovider/providers/gce:go_default_library", diff --git a/plugin/pkg/admission/persistentvolume/label/admission.go b/plugin/pkg/admission/persistentvolume/label/admission.go index f2458e1217..453a91f918 100644 --- a/plugin/pkg/admission/persistentvolume/label/admission.go +++ b/plugin/pkg/admission/persistentvolume/label/admission.go @@ -21,8 +21,6 @@ import ( "io" "sync" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/api" metav1 "k8s.io/kubernetes/pkg/apis/meta/v1" @@ -33,7 +31,7 @@ import ( ) func init() { - admission.RegisterPlugin("PersistentVolumeLabel", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { + admission.RegisterPlugin("PersistentVolumeLabel", func(config io.Reader) (admission.Interface, error) { persistentVolumeLabelAdmission := NewPersistentVolumeLabel() return persistentVolumeLabelAdmission, nil }) diff --git a/plugin/pkg/admission/podnodeselector/BUILD b/plugin/pkg/admission/podnodeselector/BUILD index b5472cd509..9d54d7de3a 100644 --- a/plugin/pkg/admission/podnodeselector/BUILD +++ b/plugin/pkg/admission/podnodeselector/BUILD @@ -20,6 +20,7 @@ go_library( "//pkg/client/cache:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/controller/informers:go_default_library", + "//pkg/kubeapiserver/admission:go_default_library", "//pkg/labels:go_default_library", "//pkg/util/yaml:go_default_library", "//vendor:github.com/golang/glog", @@ -37,6 +38,7 @@ go_test( "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/controller/informers:go_default_library", + "//pkg/kubeapiserver/admission:go_default_library", "//pkg/labels:go_default_library", "//pkg/util/wait:go_default_library", ], diff --git a/plugin/pkg/admission/podnodeselector/admission.go b/plugin/pkg/admission/podnodeselector/admission.go index 680e0b903b..c33b51534b 100644 --- a/plugin/pkg/admission/podnodeselector/admission.go +++ b/plugin/pkg/admission/podnodeselector/admission.go @@ -28,8 +28,9 @@ import ( "k8s.io/kubernetes/pkg/api/errors" metav1 "k8s.io/kubernetes/pkg/apis/meta/v1" "k8s.io/kubernetes/pkg/client/cache" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/controller/informers" + kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/util/yaml" ) @@ -39,9 +40,9 @@ import ( var NamespaceNodeSelectors = []string{"scheduler.alpha.kubernetes.io/node-selector"} func init() { - admission.RegisterPlugin("PodNodeSelector", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { + admission.RegisterPlugin("PodNodeSelector", func(config io.Reader) (admission.Interface, error) { pluginConfig := readConfig(config) - plugin := NewPodNodeSelector(client, pluginConfig.PodNodeSelectorPluginConfig) + plugin := NewPodNodeSelector(pluginConfig.PodNodeSelectorPluginConfig) return plugin, nil }) } @@ -49,12 +50,14 @@ func init() { // podNodeSelector is an implementation of admission.Interface. type podNodeSelector struct { *admission.Handler - client clientset.Interface + client internalclientset.Interface namespaceInformer cache.SharedIndexInformer // global default node selector and namespace whitelists in a cluster. clusterNodeSelectors map[string]string } +var _ = kubeapiserveradmission.WantsInternalClientSet(&podNodeSelector{}) + type pluginConfig struct { PodNodeSelectorPluginConfig map[string]string } @@ -157,14 +160,17 @@ func (p *podNodeSelector) Admit(a admission.Attributes) error { return nil } -func NewPodNodeSelector(client clientset.Interface, clusterNodeSelectors map[string]string) *podNodeSelector { +func NewPodNodeSelector(clusterNodeSelectors map[string]string) *podNodeSelector { return &podNodeSelector{ Handler: admission.NewHandler(admission.Create), - client: client, clusterNodeSelectors: clusterNodeSelectors, } } +func (a *podNodeSelector) SetInternalClientSet(client internalclientset.Interface) { + a.client = client +} + func (p *podNodeSelector) SetInformerFactory(f informers.SharedInformerFactory) { p.namespaceInformer = f.InternalNamespaces().Informer() p.SetReadyFunc(p.namespaceInformer.HasSynced) @@ -174,6 +180,9 @@ func (p *podNodeSelector) Validate() error { if p.namespaceInformer == nil { return fmt.Errorf("missing namespaceInformer") } + if p.client == nil { + return fmt.Errorf("missing client") + } return nil } diff --git a/plugin/pkg/admission/podnodeselector/admission_test.go b/plugin/pkg/admission/podnodeselector/admission_test.go index fa54633b1b..88cc694a56 100644 --- a/plugin/pkg/admission/podnodeselector/admission_test.go +++ b/plugin/pkg/admission/podnodeselector/admission_test.go @@ -25,6 +25,7 @@ import ( clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/controller/informers" + kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/util/wait" ) @@ -169,7 +170,7 @@ func TestHandles(t *testing.T) { admission.Connect: false, admission.Delete: false, } { - nodeEnvionment := NewPodNodeSelector(nil, nil) + nodeEnvionment := NewPodNodeSelector(nil) if e, a := shouldHandle, nodeEnvionment.Handles(op); e != a { t.Errorf("%v: shouldHandle=%t, handles=%t", op, e, a) } @@ -179,10 +180,9 @@ func TestHandles(t *testing.T) { // newHandlerForTest returns the admission controller configured for testing. func newHandlerForTest(c clientset.Interface) (*podNodeSelector, informers.SharedInformerFactory, error) { f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute) - handler := NewPodNodeSelector(c, nil) - plugins := []admission.Interface{handler} - pluginInitializer := admission.NewPluginInitializer(f, nil) - pluginInitializer.Initialize(plugins) - err := admission.Validate(plugins) + handler := NewPodNodeSelector(nil) + pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil) + pluginInitializer.Initialize(handler) + err := admission.Validate(handler) return handler, f, err } diff --git a/plugin/pkg/admission/resourcequota/BUILD b/plugin/pkg/admission/resourcequota/BUILD index 4cfe9ec1aa..65e9fbf0a1 100644 --- a/plugin/pkg/admission/resourcequota/BUILD +++ b/plugin/pkg/admission/resourcequota/BUILD @@ -24,6 +24,7 @@ go_library( "//pkg/api/v1:go_default_library", "//pkg/client/cache:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", + "//pkg/kubeapiserver/admission:go_default_library", "//pkg/quota:go_default_library", "//pkg/quota/install:go_default_library", "//pkg/runtime:go_default_library", diff --git a/plugin/pkg/admission/resourcequota/admission.go b/plugin/pkg/admission/resourcequota/admission.go index d6ebfa44b2..42a51cbec0 100644 --- a/plugin/pkg/admission/resourcequota/admission.go +++ b/plugin/pkg/admission/resourcequota/admission.go @@ -17,24 +17,25 @@ limitations under the License. package resourcequota import ( + "fmt" "io" "time" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" "k8s.io/kubernetes/pkg/quota" "k8s.io/kubernetes/pkg/quota/install" ) func init() { admission.RegisterPlugin("ResourceQuota", - func(client clientset.Interface, config io.Reader) (admission.Interface, error) { + func(config io.Reader) (admission.Interface, error) { // NOTE: we do not provide informers to the registry because admission level decisions // does not require us to open watches for all items tracked by quota. registry := install.NewRegistry(nil, nil) - return NewResourceQuota(client, registry, 5, make(chan struct{})) + return NewResourceQuota(registry, 5, make(chan struct{})) }) } @@ -42,9 +43,14 @@ func init() { type quotaAdmission struct { *admission.Handler - evaluator Evaluator + stopCh <-chan struct{} + registry quota.Registry + numEvaluators int + evaluator Evaluator } +var _ = kubeapiserveradmission.WantsInternalClientSet("aAdmission{}) + type liveLookupEntry struct { expiry time.Time items []*api.ResourceQuota @@ -53,19 +59,33 @@ type liveLookupEntry struct { // NewResourceQuota configures an admission controller that can enforce quota constraints // using the provided registry. The registry must have the capability to handle group/kinds that // are persisted by the server this admission controller is intercepting -func NewResourceQuota(client clientset.Interface, registry quota.Registry, numEvaluators int, stopCh <-chan struct{}) (admission.Interface, error) { +func NewResourceQuota(registry quota.Registry, numEvaluators int, stopCh <-chan struct{}) (admission.Interface, error) { + return "aAdmission{ + Handler: admission.NewHandler(admission.Create, admission.Update), + stopCh: stopCh, + registry: registry, + numEvaluators: numEvaluators, + }, nil +} + +func (a *quotaAdmission) SetInternalClientSet(client internalclientset.Interface) { + var err error quotaAccessor, err := newQuotaAccessor(client) if err != nil { - return nil, err + // TODO handle errors more cleanly + panic(err) } - go quotaAccessor.Run(stopCh) + go quotaAccessor.Run(a.stopCh) - evaluator := NewQuotaEvaluator(quotaAccessor, registry, nil, numEvaluators, stopCh) + a.evaluator = NewQuotaEvaluator(quotaAccessor, a.registry, nil, a.numEvaluators, a.stopCh) +} - return "aAdmission{ - Handler: admission.NewHandler(admission.Create, admission.Update), - evaluator: evaluator, - }, nil +// Validate ensures an authorizer is set. +func (a *quotaAdmission) Validate() error { + if a.evaluator == nil { + return fmt.Errorf("missing evaluator") + } + return nil } // Admit makes admission decisions while enforcing quota diff --git a/plugin/pkg/admission/resourcequota/admission_test.go b/plugin/pkg/admission/resourcequota/admission_test.go index f0252891df..2f47474cf6 100644 --- a/plugin/pkg/admission/resourcequota/admission_test.go +++ b/plugin/pkg/admission/resourcequota/admission_test.go @@ -122,14 +122,21 @@ func TestPrettyPrint(t *testing.T) { // TestAdmissionIgnoresDelete verifies that the admission controller ignores delete operations func TestAdmissionIgnoresDelete(t *testing.T) { kubeClient := fake.NewSimpleClientset() + indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}) stopCh := make(chan struct{}) defer close(stopCh) - handler, err := NewResourceQuota(kubeClient, install.NewRegistry(nil, nil), 5, stopCh) - if err != nil { - t.Errorf("Unexpected error %v", err) + + quotaAccessor, _ := newQuotaAccessor(kubeClient) + quotaAccessor.indexer = indexer + go quotaAccessor.Run(stopCh) + evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, 5, stopCh) + + handler := "aAdmission{ + Handler: admission.NewHandler(admission.Create, admission.Update), + evaluator: evaluator, } namespace := "default" - err = handler.Admit(admission.NewAttributesRecord(nil, nil, api.Kind("Pod").WithVersion("version"), namespace, "name", api.Resource("pods").WithVersion("version"), "", admission.Delete, nil)) + err := handler.Admit(admission.NewAttributesRecord(nil, nil, api.Kind("Pod").WithVersion("version"), namespace, "name", api.Resource("pods").WithVersion("version"), "", admission.Delete, nil)) if err != nil { t.Errorf("ResourceQuota should admit all deletes: %v", err) } diff --git a/plugin/pkg/admission/security/podsecuritypolicy/BUILD b/plugin/pkg/admission/security/podsecuritypolicy/BUILD index b0f42f3b7b..9096f850c8 100644 --- a/plugin/pkg/admission/security/podsecuritypolicy/BUILD +++ b/plugin/pkg/admission/security/podsecuritypolicy/BUILD @@ -22,6 +22,7 @@ go_library( "//pkg/auth/user:go_default_library", "//pkg/client/cache:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", + "//pkg/kubeapiserver/admission:go_default_library", "//pkg/runtime:go_default_library", "//pkg/security/podsecuritypolicy:go_default_library", "//pkg/security/podsecuritypolicy/util:go_default_library", @@ -46,8 +47,6 @@ go_test( "//pkg/auth/authorizer:go_default_library", "//pkg/auth/user:go_default_library", "//pkg/client/cache:go_default_library", - "//pkg/client/clientset_generated/internalclientset:go_default_library", - "//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/security/apparmor:go_default_library", "//pkg/security/podsecuritypolicy:go_default_library", "//pkg/security/podsecuritypolicy/seccomp:go_default_library", diff --git a/plugin/pkg/admission/security/podsecuritypolicy/admission.go b/plugin/pkg/admission/security/podsecuritypolicy/admission.go index 895e0549d7..f05d262758 100644 --- a/plugin/pkg/admission/security/podsecuritypolicy/admission.go +++ b/plugin/pkg/admission/security/podsecuritypolicy/admission.go @@ -31,7 +31,8 @@ import ( "k8s.io/kubernetes/pkg/auth/authorizer" "k8s.io/kubernetes/pkg/auth/user" "k8s.io/kubernetes/pkg/client/cache" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" "k8s.io/kubernetes/pkg/runtime" psp "k8s.io/kubernetes/pkg/security/podsecuritypolicy" psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util" @@ -47,9 +48,8 @@ const ( ) func init() { - admission.RegisterPlugin(PluginName, func(client clientset.Interface, config io.Reader) (admission.Interface, error) { - plugin := NewPlugin(client, psp.NewSimpleStrategyFactory(), getMatchingPolicies, true) - plugin.Run() + admission.RegisterPlugin(PluginName, func(config io.Reader) (admission.Interface, error) { + plugin := NewPlugin(psp.NewSimpleStrategyFactory(), getMatchingPolicies, true) return plugin, nil }) } @@ -60,7 +60,6 @@ type PSPMatchFn func(store cache.Store, user user.Info, sa user.Info, authz auth // podSecurityPolicyPlugin holds state for and implements the admission plugin. type podSecurityPolicyPlugin struct { *admission.Handler - client clientset.Interface strategyFactory psp.StrategyFactory pspMatcher PSPMatchFn failOnNoPolicies bool @@ -81,43 +80,50 @@ func (plugin *podSecurityPolicyPlugin) Validate() error { if plugin.authz == nil { return fmt.Errorf("%s requires an authorizer", PluginName) } + if plugin.store == nil { + return fmt.Errorf("%s requires an client", PluginName) + } + if plugin.store == nil { + return fmt.Errorf("%s requires an client", PluginName) + } return nil } var _ admission.Interface = &podSecurityPolicyPlugin{} -var _ admission.WantsAuthorizer = &podSecurityPolicyPlugin{} +var _ kubeapiserveradmission.WantsAuthorizer = &podSecurityPolicyPlugin{} +var _ kubeapiserveradmission.WantsInternalClientSet = &podSecurityPolicyPlugin{} // NewPlugin creates a new PSP admission plugin. -func NewPlugin(kclient clientset.Interface, strategyFactory psp.StrategyFactory, pspMatcher PSPMatchFn, failOnNoPolicies bool) *podSecurityPolicyPlugin { - store := cache.NewStore(cache.MetaNamespaceKeyFunc) - reflector := cache.NewReflector( +func NewPlugin(strategyFactory psp.StrategyFactory, pspMatcher PSPMatchFn, failOnNoPolicies bool) *podSecurityPolicyPlugin { + + return &podSecurityPolicyPlugin{ + Handler: admission.NewHandler(admission.Create, admission.Update), + strategyFactory: strategyFactory, + pspMatcher: pspMatcher, + failOnNoPolicies: failOnNoPolicies, + } +} + +func (a *podSecurityPolicyPlugin) SetInternalClientSet(client internalclientset.Interface) { + a.store = cache.NewStore(cache.MetaNamespaceKeyFunc) + a.reflector = cache.NewReflector( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) - return kclient.Extensions().PodSecurityPolicies().List(internalOptions) + return client.Extensions().PodSecurityPolicies().List(internalOptions) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) - return kclient.Extensions().PodSecurityPolicies().Watch(internalOptions) + return client.Extensions().PodSecurityPolicies().Watch(internalOptions) }, }, &extensions.PodSecurityPolicy{}, - store, + a.store, 0, ) - - return &podSecurityPolicyPlugin{ - Handler: admission.NewHandler(admission.Create, admission.Update), - client: kclient, - strategyFactory: strategyFactory, - pspMatcher: pspMatcher, - failOnNoPolicies: failOnNoPolicies, - - store: store, - reflector: reflector, - } + a.Run() } func (a *podSecurityPolicyPlugin) Run() { diff --git a/plugin/pkg/admission/security/podsecuritypolicy/admission_test.go b/plugin/pkg/admission/security/podsecuritypolicy/admission_test.go index bf3944f39f..dc311506ea 100644 --- a/plugin/pkg/admission/security/podsecuritypolicy/admission_test.go +++ b/plugin/pkg/admission/security/podsecuritypolicy/admission_test.go @@ -30,8 +30,6 @@ import ( "k8s.io/kubernetes/pkg/auth/authorizer" "k8s.io/kubernetes/pkg/auth/user" "k8s.io/kubernetes/pkg/client/cache" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - clientsetfake "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/security/apparmor" kpsp "k8s.io/kubernetes/pkg/security/podsecuritypolicy" "k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp" @@ -44,10 +42,9 @@ const defaultContainerName = "test-c" // NewTestAdmission provides an admission plugin with test implementations of internal structs. It uses // an authorizer that always returns true. -func NewTestAdmission(store cache.Store, kclient clientset.Interface) kadmission.Interface { +func NewTestAdmission(store cache.Store) kadmission.Interface { return &podSecurityPolicyPlugin{ Handler: kadmission.NewHandler(kadmission.Create), - client: kclient, store: store, strategyFactory: kpsp.NewSimpleStrategyFactory(), pspMatcher: getMatchingPolicies, @@ -1339,16 +1336,13 @@ func TestAdmitSysctls(t *testing.T) { } func testPSPAdmit(testCaseName string, psps []*extensions.PodSecurityPolicy, pod *kapi.Pod, shouldPass bool, expectedPSP string, t *testing.T) { - namespace := createNamespaceForTest() - serviceAccount := createSAForTest() - tc := clientsetfake.NewSimpleClientset(namespace, serviceAccount) store := cache.NewStore(cache.MetaNamespaceKeyFunc) for _, psp := range psps { store.Add(psp) } - plugin := NewTestAdmission(store, tc) + plugin := NewTestAdmission(store) attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), "namespace", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{}) err := plugin.Admit(attrs) @@ -1512,10 +1506,8 @@ func TestCreateProvidersFromConstraints(t *testing.T) { for k, v := range testCases { store := cache.NewStore(cache.MetaNamespaceKeyFunc) - tc := clientsetfake.NewSimpleClientset() admit := &podSecurityPolicyPlugin{ Handler: kadmission.NewHandler(kadmission.Create, kadmission.Update), - client: tc, store: store, strategyFactory: kpsp.NewSimpleStrategyFactory(), } diff --git a/plugin/pkg/admission/securitycontext/scdeny/BUILD b/plugin/pkg/admission/securitycontext/scdeny/BUILD index e04b51ca5c..343aff7a42 100644 --- a/plugin/pkg/admission/securitycontext/scdeny/BUILD +++ b/plugin/pkg/admission/securitycontext/scdeny/BUILD @@ -16,7 +16,6 @@ go_library( "//pkg/admission:go_default_library", "//pkg/api:go_default_library", "//pkg/api/errors:go_default_library", - "//pkg/client/clientset_generated/internalclientset:go_default_library", ], ) diff --git a/plugin/pkg/admission/securitycontext/scdeny/admission.go b/plugin/pkg/admission/securitycontext/scdeny/admission.go index ae2be16e0b..16c0d41562 100644 --- a/plugin/pkg/admission/securitycontext/scdeny/admission.go +++ b/plugin/pkg/admission/securitycontext/scdeny/admission.go @@ -20,30 +20,25 @@ import ( "fmt" "io" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/api" apierrors "k8s.io/kubernetes/pkg/api/errors" ) func init() { - admission.RegisterPlugin("SecurityContextDeny", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { - return NewSecurityContextDeny(client), nil + admission.RegisterPlugin("SecurityContextDeny", func(config io.Reader) (admission.Interface, error) { + return NewSecurityContextDeny(), nil }) } -// plugin contains the client used by the SecurityContextDeny admission controller type plugin struct { *admission.Handler - client clientset.Interface } // NewSecurityContextDeny creates a new instance of the SecurityContextDeny admission controller -func NewSecurityContextDeny(client clientset.Interface) admission.Interface { +func NewSecurityContextDeny() admission.Interface { return &plugin{ Handler: admission.NewHandler(admission.Create, admission.Update), - client: client, } } diff --git a/plugin/pkg/admission/securitycontext/scdeny/admission_test.go b/plugin/pkg/admission/securitycontext/scdeny/admission_test.go index a8ef6ee644..d96e224041 100644 --- a/plugin/pkg/admission/securitycontext/scdeny/admission_test.go +++ b/plugin/pkg/admission/securitycontext/scdeny/admission_test.go @@ -25,7 +25,7 @@ import ( // ensures the SecurityContext is denied if it defines anything more than Caps or Privileged func TestAdmission(t *testing.T) { - handler := NewSecurityContextDeny(nil) + handler := NewSecurityContextDeny() var runAsUser int64 = 1 priv := true @@ -106,7 +106,7 @@ func TestAdmission(t *testing.T) { } func TestPodSecurityContextAdmission(t *testing.T) { - handler := NewSecurityContextDeny(nil) + handler := NewSecurityContextDeny() pod := api.Pod{ Spec: api.PodSpec{ Containers: []api.Container{ @@ -153,7 +153,7 @@ func TestPodSecurityContextAdmission(t *testing.T) { } func TestHandles(t *testing.T) { - handler := NewSecurityContextDeny(nil) + handler := NewSecurityContextDeny() tests := map[admission.Operation]bool{ admission.Update: true, admission.Create: true, diff --git a/plugin/pkg/admission/serviceaccount/BUILD b/plugin/pkg/admission/serviceaccount/BUILD index f9d6f7d034..062640dab5 100644 --- a/plugin/pkg/admission/serviceaccount/BUILD +++ b/plugin/pkg/admission/serviceaccount/BUILD @@ -24,6 +24,7 @@ go_library( "//pkg/client/cache:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/fields:go_default_library", + "//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubelet/types:go_default_library", "//pkg/runtime:go_default_library", "//pkg/runtime/schema:go_default_library", diff --git a/plugin/pkg/admission/serviceaccount/admission.go b/plugin/pkg/admission/serviceaccount/admission.go index 09652eb404..ee769d97a0 100644 --- a/plugin/pkg/admission/serviceaccount/admission.go +++ b/plugin/pkg/admission/serviceaccount/admission.go @@ -23,18 +23,18 @@ import ( "strconv" "time" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "k8s.io/kubernetes/pkg/runtime/schema" - "k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/v1" metav1 "k8s.io/kubernetes/pkg/apis/meta/v1" "k8s.io/kubernetes/pkg/client/cache" + "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/fields" + kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubelet "k8s.io/kubernetes/pkg/kubelet/types" "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/runtime/schema" "k8s.io/kubernetes/pkg/serviceaccount" "k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/watch" @@ -55,9 +55,8 @@ const DefaultAPITokenMountPath = "/var/run/secrets/kubernetes.io/serviceaccount" const PluginName = "ServiceAccount" func init() { - admission.RegisterPlugin(PluginName, func(client clientset.Interface, config io.Reader) (admission.Interface, error) { - serviceAccountAdmission := NewServiceAccount(client) - serviceAccountAdmission.Run() + admission.RegisterPlugin(PluginName, func(config io.Reader) (admission.Interface, error) { + serviceAccountAdmission := NewServiceAccount() return serviceAccountAdmission, nil }) } @@ -74,7 +73,7 @@ type serviceAccount struct { // MountServiceAccountToken creates Volume and VolumeMounts for the first referenced ServiceAccountToken for the pod's service account MountServiceAccountToken bool - client clientset.Interface + client internalclientset.Interface serviceAccounts cache.Indexer secrets cache.Indexer @@ -84,14 +83,29 @@ type serviceAccount struct { secretsReflector *cache.Reflector } +var _ = kubeapiserveradmission.WantsInternalClientSet(&serviceAccount{}) + // NewServiceAccount returns an admission.Interface implementation which limits admission of Pod CREATE requests based on the pod's ServiceAccount: // 1. If the pod does not specify a ServiceAccount, it sets the pod's ServiceAccount to "default" // 2. It ensures the ServiceAccount referenced by the pod exists // 3. If LimitSecretReferences is true, it rejects the pod if the pod references Secret objects which the pod's ServiceAccount does not reference // 4. If the pod does not contain any ImagePullSecrets, the ImagePullSecrets of the service account are added. // 5. If MountServiceAccountToken is true, it adds a VolumeMount with the pod's ServiceAccount's api token secret to containers -func NewServiceAccount(cl clientset.Interface) *serviceAccount { - serviceAccountsIndexer, serviceAccountsReflector := cache.NewNamespaceKeyedIndexerAndReflector( +func NewServiceAccount() *serviceAccount { + return &serviceAccount{ + Handler: admission.NewHandler(admission.Create), + // TODO: enable this once we've swept secret usage to account for adding secret references to service accounts + LimitSecretReferences: false, + // Auto mount service account API token secrets + MountServiceAccountToken: true, + // Reject pod creation until a service account token is available + RequireAPIToken: true, + } +} + +func (a *serviceAccount) SetInternalClientSet(cl internalclientset.Interface) { + a.client = cl + a.serviceAccounts, a.serviceAccountsReflector = cache.NewNamespaceKeyedIndexerAndReflector( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { internalOptions := api.ListOptions{} @@ -109,7 +123,7 @@ func NewServiceAccount(cl clientset.Interface) *serviceAccount { ) tokenSelector := fields.SelectorFromSet(map[string]string{api.SecretTypeField: string(api.SecretTypeServiceAccountToken)}) - secretsIndexer, secretsReflector := cache.NewNamespaceKeyedIndexerAndReflector( + a.secrets, a.secretsReflector = cache.NewNamespaceKeyedIndexerAndReflector( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { internalOptions := api.ListOptions{} @@ -128,23 +142,31 @@ func NewServiceAccount(cl clientset.Interface) *serviceAccount { 0, ) - return &serviceAccount{ - Handler: admission.NewHandler(admission.Create), - // TODO: enable this once we've swept secret usage to account for adding secret references to service accounts - LimitSecretReferences: false, - // Auto mount service account API token secrets - MountServiceAccountToken: true, - // Reject pod creation until a service account token is available - RequireAPIToken: true, - - client: cl, - serviceAccounts: serviceAccountsIndexer, - serviceAccountsReflector: serviceAccountsReflector, - secrets: secretsIndexer, - secretsReflector: secretsReflector, + if cl != nil { + a.Run() } } +// Validate ensures an authorizer is set. +func (a *serviceAccount) Validate() error { + if a.client == nil { + return fmt.Errorf("missing client") + } + if a.secrets == nil { + return fmt.Errorf("missing secretsIndexer") + } + if a.secretsReflector == nil { + return fmt.Errorf("missing secretsReflector") + } + if a.serviceAccounts == nil { + return fmt.Errorf("missing serviceAccountsIndexer") + } + if a.serviceAccountsReflector == nil { + return fmt.Errorf("missing serviceAccountsReflector") + } + return nil +} + func (s *serviceAccount) Run() { if s.stopChan == nil { s.stopChan = make(chan struct{}) diff --git a/plugin/pkg/admission/serviceaccount/admission_test.go b/plugin/pkg/admission/serviceaccount/admission_test.go index 10fd88e53b..667f42dd4a 100644 --- a/plugin/pkg/admission/serviceaccount/admission_test.go +++ b/plugin/pkg/admission/serviceaccount/admission_test.go @@ -33,7 +33,7 @@ func TestIgnoresNonCreate(t *testing.T) { pod := &api.Pod{} for _, op := range []admission.Operation{admission.Update, admission.Delete, admission.Connect} { attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", op, nil) - handler := admission.NewChainHandler(NewServiceAccount(nil)) + handler := admission.NewChainHandler(NewServiceAccount()) err := handler.Admit(attrs) if err != nil { t.Errorf("Expected %s operation allowed, got err: %v", op, err) @@ -44,7 +44,7 @@ func TestIgnoresNonCreate(t *testing.T) { func TestIgnoresNonPodResource(t *testing.T) { pod := &api.Pod{} attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("CustomResource").WithVersion("version"), "", admission.Create, nil) - err := NewServiceAccount(nil).Admit(attrs) + err := NewServiceAccount().Admit(attrs) if err != nil { t.Errorf("Expected non-pod resource allowed, got err: %v", err) } @@ -52,7 +52,7 @@ func TestIgnoresNonPodResource(t *testing.T) { func TestIgnoresNilObject(t *testing.T) { attrs := admission.NewAttributesRecord(nil, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) - err := NewServiceAccount(nil).Admit(attrs) + err := NewServiceAccount().Admit(attrs) if err != nil { t.Errorf("Expected nil object allowed allowed, got err: %v", err) } @@ -61,7 +61,7 @@ func TestIgnoresNilObject(t *testing.T) { func TestIgnoresNonPodObject(t *testing.T) { obj := &api.Namespace{} attrs := admission.NewAttributesRecord(obj, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) - err := NewServiceAccount(nil).Admit(attrs) + err := NewServiceAccount().Admit(attrs) if err != nil { t.Errorf("Expected non pod object allowed, got err: %v", err) } @@ -81,7 +81,7 @@ func TestIgnoresMirrorPod(t *testing.T) { }, } attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) - err := NewServiceAccount(nil).Admit(attrs) + err := NewServiceAccount().Admit(attrs) if err != nil { t.Errorf("Expected mirror pod without service account or secrets allowed, got err: %v", err) } @@ -99,7 +99,7 @@ func TestRejectsMirrorPodWithServiceAccount(t *testing.T) { }, } attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) - err := NewServiceAccount(nil).Admit(attrs) + err := NewServiceAccount().Admit(attrs) if err == nil { t.Errorf("Expected a mirror pod to be prevented from referencing a service account") } @@ -119,7 +119,7 @@ func TestRejectsMirrorPodWithSecretVolumes(t *testing.T) { }, } attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) - err := NewServiceAccount(nil).Admit(attrs) + err := NewServiceAccount().Admit(attrs) if err == nil { t.Errorf("Expected a mirror pod to be prevented from referencing a secret volume") } @@ -128,7 +128,8 @@ func TestRejectsMirrorPodWithSecretVolumes(t *testing.T) { func TestAssignsDefaultServiceAccountAndToleratesMissingAPIToken(t *testing.T) { ns := "myns" - admit := NewServiceAccount(nil) + admit := NewServiceAccount() + admit.SetInternalClientSet(nil) admit.MountServiceAccountToken = true admit.RequireAPIToken = false @@ -154,7 +155,8 @@ func TestAssignsDefaultServiceAccountAndToleratesMissingAPIToken(t *testing.T) { func TestAssignsDefaultServiceAccountAndRejectsMissingAPIToken(t *testing.T) { ns := "myns" - admit := NewServiceAccount(nil) + admit := NewServiceAccount() + admit.SetInternalClientSet(nil) admit.MountServiceAccountToken = true admit.RequireAPIToken = true @@ -185,7 +187,9 @@ func TestFetchesUncachedServiceAccount(t *testing.T) { }, }) - admit := NewServiceAccount(client) + admit := NewServiceAccount() + admit.SetInternalClientSet(nil) + admit.client = client admit.RequireAPIToken = false pod := &api.Pod{} @@ -205,7 +209,8 @@ func TestDeniesInvalidServiceAccount(t *testing.T) { // Build a test client that the admission plugin can use to look up the service account missing from its cache client := fake.NewSimpleClientset() - admit := NewServiceAccount(client) + admit := NewServiceAccount() + admit.SetInternalClientSet(client) pod := &api.Pod{} attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) @@ -233,7 +238,8 @@ func TestAutomountsAPIToken(t *testing.T) { MountPath: DefaultAPITokenMountPath, } - admit := NewServiceAccount(nil) + admit := NewServiceAccount() + admit.SetInternalClientSet(nil) admit.MountServiceAccountToken = true admit.RequireAPIToken = true @@ -332,7 +338,8 @@ func TestRespectsExistingMount(t *testing.T) { MountPath: DefaultAPITokenMountPath, } - admit := NewServiceAccount(nil) + admit := NewServiceAccount() + admit.SetInternalClientSet(nil) admit.MountServiceAccountToken = true admit.RequireAPIToken = true @@ -428,7 +435,8 @@ func TestRespectsExistingMount(t *testing.T) { func TestAllowsReferencedSecret(t *testing.T) { ns := "myns" - admit := NewServiceAccount(nil) + admit := NewServiceAccount() + admit.SetInternalClientSet(nil) admit.LimitSecretReferences = true admit.RequireAPIToken = false @@ -507,7 +515,8 @@ func TestAllowsReferencedSecret(t *testing.T) { func TestRejectsUnreferencedSecretVolumes(t *testing.T) { ns := "myns" - admit := NewServiceAccount(nil) + admit := NewServiceAccount() + admit.SetInternalClientSet(nil) admit.LimitSecretReferences = true admit.RequireAPIToken = false @@ -583,7 +592,8 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) { func TestAllowUnreferencedSecretVolumesForPermissiveSAs(t *testing.T) { ns := "myns" - admit := NewServiceAccount(nil) + admit := NewServiceAccount() + admit.SetInternalClientSet(nil) admit.LimitSecretReferences = false admit.RequireAPIToken = false @@ -613,7 +623,8 @@ func TestAllowUnreferencedSecretVolumesForPermissiveSAs(t *testing.T) { func TestAllowsReferencedImagePullSecrets(t *testing.T) { ns := "myns" - admit := NewServiceAccount(nil) + admit := NewServiceAccount() + admit.SetInternalClientSet(nil) admit.LimitSecretReferences = true admit.RequireAPIToken = false @@ -643,7 +654,8 @@ func TestAllowsReferencedImagePullSecrets(t *testing.T) { func TestRejectsUnreferencedImagePullSecrets(t *testing.T) { ns := "myns" - admit := NewServiceAccount(nil) + admit := NewServiceAccount() + admit.SetInternalClientSet(nil) admit.LimitSecretReferences = true admit.RequireAPIToken = false @@ -670,7 +682,8 @@ func TestRejectsUnreferencedImagePullSecrets(t *testing.T) { func TestDoNotAddImagePullSecrets(t *testing.T) { ns := "myns" - admit := NewServiceAccount(nil) + admit := NewServiceAccount() + admit.SetInternalClientSet(nil) admit.LimitSecretReferences = true admit.RequireAPIToken = false @@ -705,7 +718,8 @@ func TestDoNotAddImagePullSecrets(t *testing.T) { func TestAddImagePullSecrets(t *testing.T) { ns := "myns" - admit := NewServiceAccount(nil) + admit := NewServiceAccount() + admit.SetInternalClientSet(nil) admit.LimitSecretReferences = true admit.RequireAPIToken = false diff --git a/plugin/pkg/admission/storageclass/default/BUILD b/plugin/pkg/admission/storageclass/default/BUILD index 009ab40a1f..c2fdc00422 100644 --- a/plugin/pkg/admission/storageclass/default/BUILD +++ b/plugin/pkg/admission/storageclass/default/BUILD @@ -21,6 +21,7 @@ go_library( "//pkg/apis/storage/util:go_default_library", "//pkg/client/cache:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", + "//pkg/kubeapiserver/admission:go_default_library", "//pkg/runtime:go_default_library", "//pkg/watch:go_default_library", "//vendor:github.com/golang/glog", diff --git a/plugin/pkg/admission/storageclass/default/admission.go b/plugin/pkg/admission/storageclass/default/admission.go index 92d555a03b..08afa65514 100644 --- a/plugin/pkg/admission/storageclass/default/admission.go +++ b/plugin/pkg/admission/storageclass/default/admission.go @@ -29,7 +29,8 @@ import ( "k8s.io/kubernetes/pkg/apis/storage" storageutil "k8s.io/kubernetes/pkg/apis/storage/util" "k8s.io/kubernetes/pkg/client/cache" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/watch" ) @@ -39,9 +40,8 @@ const ( ) func init() { - admission.RegisterPlugin(PluginName, func(client clientset.Interface, config io.Reader) (admission.Interface, error) { - plugin := newPlugin(client) - plugin.Run() + admission.RegisterPlugin(PluginName, func(config io.Reader) (admission.Interface, error) { + plugin := newPlugin() return plugin, nil }) } @@ -49,7 +49,7 @@ func init() { // claimDefaulterPlugin holds state for and implements the admission plugin. type claimDefaulterPlugin struct { *admission.Handler - client clientset.Interface + client internalclientset.Interface reflector *cache.Reflector stopChan chan struct{} @@ -57,36 +57,55 @@ type claimDefaulterPlugin struct { } var _ admission.Interface = &claimDefaulterPlugin{} +var _ = kubeapiserveradmission.WantsInternalClientSet(&claimDefaulterPlugin{}) // newPlugin creates a new admission plugin. -func newPlugin(kclient clientset.Interface) *claimDefaulterPlugin { - store := cache.NewStore(cache.MetaNamespaceKeyFunc) - reflector := cache.NewReflector( +func newPlugin() *claimDefaulterPlugin { + return &claimDefaulterPlugin{ + Handler: admission.NewHandler(admission.Create), + } +} + +func (a *claimDefaulterPlugin) SetInternalClientSet(client internalclientset.Interface) { + a.client = client + a.store = cache.NewStore(cache.MetaNamespaceKeyFunc) + a.reflector = cache.NewReflector( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) - return kclient.Storage().StorageClasses().List(internalOptions) + return client.Storage().StorageClasses().List(internalOptions) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) - return kclient.Storage().StorageClasses().Watch(internalOptions) + return client.Storage().StorageClasses().Watch(internalOptions) }, }, &storage.StorageClass{}, - store, + a.store, 0, ) - return &claimDefaulterPlugin{ - Handler: admission.NewHandler(admission.Create), - client: kclient, - store: store, - reflector: reflector, + if client != nil { + a.Run() } } +// Validate ensures an authorizer is set. +func (a *claimDefaulterPlugin) Validate() error { + if a.client == nil { + return fmt.Errorf("missing client") + } + if a.reflector == nil { + return fmt.Errorf("missing reflector") + } + if a.store == nil { + return fmt.Errorf("missing store") + } + return nil +} + func (a *claimDefaulterPlugin) Run() { if a.stopChan == nil { a.stopChan = make(chan struct{}) diff --git a/plugin/pkg/admission/storageclass/default/admission_test.go b/plugin/pkg/admission/storageclass/default/admission_test.go index 2661e5a384..c1ca61d11f 100644 --- a/plugin/pkg/admission/storageclass/default/admission_test.go +++ b/plugin/pkg/admission/storageclass/default/admission_test.go @@ -192,7 +192,8 @@ func TestAdmission(t *testing.T) { } claim := clone.(*api.PersistentVolumeClaim) - ctrl := newPlugin(nil) + ctrl := newPlugin() + ctrl.SetInternalClientSet(nil) for _, c := range test.classes { ctrl.store.Add(c) } diff --git a/test/integration/quota/quota_test.go b/test/integration/quota/quota_test.go index afbbcd34db..cf049fb354 100644 --- a/test/integration/quota/quota_test.go +++ b/test/integration/quota/quota_test.go @@ -36,6 +36,7 @@ import ( replicationcontroller "k8s.io/kubernetes/pkg/controller/replication" resourcequotacontroller "k8s.io/kubernetes/pkg/controller/resourcequota" "k8s.io/kubernetes/pkg/fields" + kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" "k8s.io/kubernetes/pkg/labels" quotainstall "k8s.io/kubernetes/pkg/quota/install" "k8s.io/kubernetes/pkg/runtime/schema" @@ -62,10 +63,11 @@ func TestQuota(t *testing.T) { admissionCh := make(chan struct{}) clientset := clientset.NewForConfigOrDie(&restclient.Config{QPS: -1, Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(v1.GroupName).GroupVersion}}) internalClientset := internalclientset.NewForConfigOrDie(&restclient.Config{QPS: -1, Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(v1.GroupName).GroupVersion}}) - admission, err := resourcequota.NewResourceQuota(internalClientset, quotainstall.NewRegistry(nil, nil), 5, admissionCh) + admission, err := resourcequota.NewResourceQuota(quotainstall.NewRegistry(nil, nil), 5, admissionCh) if err != nil { t.Fatalf("unexpected error: %v", err) } + admission.(kubeadmission.WantsInternalClientSet).SetInternalClientSet(internalClientset) defer close(admissionCh) masterConfig := framework.NewIntegrationTestMasterConfig() diff --git a/test/integration/serviceaccount/service_account_test.go b/test/integration/serviceaccount/service_account_test.go index 555846ed8f..28ddcc2854 100644 --- a/test/integration/serviceaccount/service_account_test.go +++ b/test/integration/serviceaccount/service_account_test.go @@ -404,7 +404,8 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie }) // Set up admission plugin to auto-assign serviceaccounts to pods - serviceAccountAdmission := serviceaccountadmission.NewServiceAccount(internalRootClientset) + serviceAccountAdmission := serviceaccountadmission.NewServiceAccount() + serviceAccountAdmission.SetInternalClientSet(internalRootClientset) masterConfig := framework.NewMasterConfig() masterConfig.GenericConfig.EnableIndex = true