refactored admission to avoid internal client references

pull/6/head
deads2k 2016-12-21 16:16:16 -05:00
parent 834f193b25
commit 2861509b6d
65 changed files with 559 additions and 424 deletions

View File

@ -30,6 +30,7 @@ go_library(
"//pkg/generated/openapi:go_default_library", "//pkg/generated/openapi:go_default_library",
"//pkg/genericapiserver:go_default_library", "//pkg/genericapiserver:go_default_library",
"//pkg/genericapiserver/filters:go_default_library", "//pkg/genericapiserver/filters:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/kubeapiserver/authenticator:go_default_library", "//pkg/kubeapiserver/authenticator:go_default_library",
"//pkg/master:go_default_library", "//pkg/master:go_default_library",
"//pkg/registry/cachesize:go_default_library", "//pkg/registry/cachesize:go_default_library",

View File

@ -49,6 +49,7 @@ import (
generatedopenapi "k8s.io/kubernetes/pkg/generated/openapi" generatedopenapi "k8s.io/kubernetes/pkg/generated/openapi"
"k8s.io/kubernetes/pkg/genericapiserver" "k8s.io/kubernetes/pkg/genericapiserver"
"k8s.io/kubernetes/pkg/genericapiserver/filters" "k8s.io/kubernetes/pkg/genericapiserver/filters"
kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
kubeauthenticator "k8s.io/kubernetes/pkg/kubeapiserver/authenticator" kubeauthenticator "k8s.io/kubernetes/pkg/kubeapiserver/authenticator"
"k8s.io/kubernetes/pkg/master" "k8s.io/kubernetes/pkg/master"
"k8s.io/kubernetes/pkg/registry/cachesize" "k8s.io/kubernetes/pkg/registry/cachesize"
@ -266,8 +267,8 @@ func Run(s *options.ServerRunOptions) error {
} }
admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",") admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",")
pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer) pluginInitializer := kubeadmission.NewPluginInitializer(client, sharedInformers, apiAuthorizer)
admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer) admissionController, err := admission.NewFromPlugins(admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer)
if err != nil { if err != nil {
return fmt.Errorf("failed to initialize plugins: %v", err) return fmt.Errorf("failed to initialize plugins: %v", err)
} }

View File

@ -41,6 +41,7 @@ go_library(
"//pkg/generated/openapi:go_default_library", "//pkg/generated/openapi:go_default_library",
"//pkg/genericapiserver:go_default_library", "//pkg/genericapiserver:go_default_library",
"//pkg/genericapiserver/filters: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/batch/job/etcd:go_default_library",
"//pkg/registry/cachesize:go_default_library", "//pkg/registry/cachesize:go_default_library",
"//pkg/registry/core/configmap/etcd:go_default_library", "//pkg/registry/core/configmap/etcd:go_default_library",

View File

@ -37,6 +37,7 @@ import (
"k8s.io/kubernetes/pkg/generated/openapi" "k8s.io/kubernetes/pkg/generated/openapi"
"k8s.io/kubernetes/pkg/genericapiserver" "k8s.io/kubernetes/pkg/genericapiserver"
"k8s.io/kubernetes/pkg/genericapiserver/filters" "k8s.io/kubernetes/pkg/genericapiserver/filters"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
"k8s.io/kubernetes/pkg/registry/cachesize" "k8s.io/kubernetes/pkg/registry/cachesize"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
genericregistry "k8s.io/kubernetes/pkg/registry/generic/registry" genericregistry "k8s.io/kubernetes/pkg/registry/generic/registry"
@ -156,8 +157,8 @@ func Run(s *options.ServerRunOptions) error {
} }
admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",") admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",")
pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer) pluginInitializer := kubeapiserveradmission.NewPluginInitializer(client, sharedInformers, apiAuthorizer)
admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer) admissionController, err := admission.NewFromPlugins(admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer)
if err != nil { if err != nil {
return fmt.Errorf("failed to initialize plugins: %v", err) return fmt.Errorf("failed to initialize plugins: %v", err)
} }

View File

@ -15,19 +15,14 @@ go_library(
"chain.go", "chain.go",
"errors.go", "errors.go",
"handler.go", "handler.go",
"init.go",
"interfaces.go", "interfaces.go",
"plugins.go", "plugins.go",
"types.go",
], ],
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//pkg/api/errors:go_default_library", "//pkg/api/errors:go_default_library",
"//pkg/api/meta:go_default_library", "//pkg/api/meta:go_default_library",
"//pkg/auth/authorizer:go_default_library",
"//pkg/auth/user: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:go_default_library",
"//pkg/runtime/schema:go_default_library", "//pkg/runtime/schema:go_default_library",
"//pkg/util/errors:go_default_library", "//pkg/util/errors:go_default_library",
@ -38,14 +33,8 @@ go_library(
go_test( go_test(
name = "go_default_test", name = "go_default_test",
srcs = [ srcs = ["chain_test.go"],
"chain_test.go",
"init_test.go",
],
library = ":go_default_library", library = ":go_default_library",
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = ["//pkg/runtime/schema:go_default_library"],
"//pkg/auth/authorizer:go_default_library",
"//pkg/runtime/schema:go_default_library",
],
) )

View File

@ -16,29 +16,9 @@ limitations under the License.
package admission 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 // chainAdmissionHandler is an instance of admission.Interface that performs admission control using a chain of admission handlers
type chainAdmissionHandler []Interface 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. // NewChainHandler creates a new chain handler from an array of handlers. Used for testing.
func NewChainHandler(handlers ...Interface) Interface { func NewChainHandler(handlers ...Interface) Interface {
return chainAdmissionHandler(handlers) return chainAdmissionHandler(handlers)

View File

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

View File

@ -69,3 +69,15 @@ const (
Delete Operation = "DELETE" Delete Operation = "DELETE"
Connect Operation = "CONNECT" 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
}

View File

@ -18,6 +18,7 @@ package admission
import ( import (
"bytes" "bytes"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
@ -26,15 +27,13 @@ import (
"sync" "sync"
"github.com/golang/glog" "github.com/golang/glog"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
) )
// Factory is a function that returns an Interface for admission decisions. // Factory is a function that returns an Interface for admission decisions.
// The config parameter provides an io.Reader handler to the factory in // The config parameter provides an io.Reader handler to the factory in
// order to load specific configurations. If no configuration is provided // order to load specific configurations. If no configuration is provided
// the parameter is nil. // 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. // All registered admission options.
var ( 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 // 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 // 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. // 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() pluginsMutex.Lock()
defer pluginsMutex.Unlock() defer pluginsMutex.Unlock()
f, found := plugins[name] f, found := plugins[name]
@ -95,7 +94,7 @@ func getPlugin(name string, client clientset.Interface, config io.Reader) (Inter
return nil, true, nil return nil, true, nil
} }
ret, err := f(client, config2) ret, err := f(config2)
return ret, true, err 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 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. // 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 ( var (
config *os.File config *os.File
err error err error
@ -122,7 +137,7 @@ func InitPlugin(name string, client clientset.Interface, configFilePath string)
if name == "" { if name == "" {
glog.Info("No admission plugin specified.") glog.Info("No admission plugin specified.")
return nil return nil, nil
} }
if configFilePath != "" { if configFilePath != "" {
@ -135,13 +150,39 @@ func InitPlugin(name string, client clientset.Interface, configFilePath string)
defer config.Close() defer config.Close()
} }
plugin, found, err := getPlugin(name, client, config) plugin, found, err := getPlugin(name, config)
if err != nil { 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 { 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)
}
} }

View File

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

View File

@ -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",
],
)

View File

@ -19,6 +19,7 @@ package admission
import ( import (
"testing" "testing"
"k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/auth/authorizer" "k8s.io/kubernetes/pkg/auth/authorizer"
) )
@ -40,19 +41,19 @@ type WantAuthorizerAdmission struct {
func (self *WantAuthorizerAdmission) SetAuthorizer(a authorizer.Authorizer) { func (self *WantAuthorizerAdmission) SetAuthorizer(a authorizer.Authorizer) {
self.auth = a self.auth = a
} }
func (self *WantAuthorizerAdmission) Admit(a Attributes) error { return nil } func (self *WantAuthorizerAdmission) Admit(a admission.Attributes) error { return nil }
func (self *WantAuthorizerAdmission) Handles(o Operation) bool { return false } func (self *WantAuthorizerAdmission) Handles(o admission.Operation) bool { return false }
func (self *WantAuthorizerAdmission) Validate() error { return nil } func (self *WantAuthorizerAdmission) Validate() error { return nil }
var _ Interface = &WantAuthorizerAdmission{} var _ admission.Interface = &WantAuthorizerAdmission{}
var _ WantsAuthorizer = &WantAuthorizerAdmission{} var _ WantsAuthorizer = &WantAuthorizerAdmission{}
// TestWantsAuthorizer ensures that the authorizer is injected when the WantsAuthorizer // TestWantsAuthorizer ensures that the authorizer is injected when the WantsAuthorizer
// interface is implemented. // interface is implemented.
func TestWantsAuthorizer(t *testing.T) { func TestWantsAuthorizer(t *testing.T) {
initializer := NewPluginInitializer(nil, &TestAuthorizer{}) initializer := NewPluginInitializer(nil, nil, &TestAuthorizer{})
wantAuthorizerAdmission := &WantAuthorizerAdmission{} wantAuthorizerAdmission := &WantAuthorizerAdmission{}
initializer.Initialize([]Interface{wantAuthorizerAdmission}) initializer.Initialize(wantAuthorizerAdmission)
if wantAuthorizerAdmission.auth == nil { if wantAuthorizerAdmission.auth == nil {
t.Errorf("expected authorizer to be initialized but found nil") t.Errorf("expected authorizer to be initialized but found nil")
} }

View File

@ -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)
}
}

View File

@ -12,10 +12,7 @@ go_library(
name = "go_default_library", name = "go_default_library",
srcs = ["admission.go"], srcs = ["admission.go"],
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = ["//pkg/admission:go_default_library"],
"//pkg/admission:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
],
) )
go_test( go_test(

View File

@ -19,13 +19,11 @@ package admit
import ( import (
"io" "io"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/admission"
) )
func init() { 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 return NewAlwaysAdmit(), nil
}) })
} }

View File

@ -16,7 +16,6 @@ go_library(
"//pkg/admission:go_default_library", "//pkg/admission:go_default_library",
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/api/errors:go_default_library", "//pkg/api/errors:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
], ],
) )

View File

@ -27,15 +27,13 @@ package alwayspullimages
import ( import (
"io" "io"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
apierrors "k8s.io/kubernetes/pkg/api/errors" apierrors "k8s.io/kubernetes/pkg/api/errors"
) )
func init() { 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 return NewAlwaysPullImages(), nil
}) })
} }

View File

@ -20,7 +20,6 @@ go_library(
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/api/errors:go_default_library", "//pkg/api/errors:go_default_library",
"//pkg/apis/meta/v1:go_default_library", "//pkg/apis/meta/v1:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//vendor:github.com/golang/glog", "//vendor:github.com/golang/glog",
], ],
) )

View File

@ -25,26 +25,23 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
apierrors "k8s.io/kubernetes/pkg/api/errors" apierrors "k8s.io/kubernetes/pkg/api/errors"
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1" metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
) )
func init() { func init() {
admission.RegisterPlugin("LimitPodHardAntiAffinityTopology", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { admission.RegisterPlugin("LimitPodHardAntiAffinityTopology", func(config io.Reader) (admission.Interface, error) {
return NewInterPodAntiAffinity(client), nil return NewInterPodAntiAffinity(), nil
}) })
} }
// plugin contains the client used by the admission controller // plugin contains the client used by the admission controller
type plugin struct { type plugin struct {
*admission.Handler *admission.Handler
client clientset.Interface
} }
// NewInterPodAntiAffinity creates a new instance of the LimitPodHardAntiAffinityTopology admission controller // NewInterPodAntiAffinity creates a new instance of the LimitPodHardAntiAffinityTopology admission controller
func NewInterPodAntiAffinity(client clientset.Interface) admission.Interface { func NewInterPodAntiAffinity() admission.Interface {
return &plugin{ return &plugin{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
client: client,
} }
} }

View File

@ -27,7 +27,7 @@ import (
// ensures the hard PodAntiAffinity is denied if it defines TopologyKey other than kubernetes.io/hostname. // ensures the hard PodAntiAffinity is denied if it defines TopologyKey other than kubernetes.io/hostname.
func TestInterPodAffinityAdmission(t *testing.T) { func TestInterPodAffinityAdmission(t *testing.T) {
handler := NewInterPodAntiAffinity(nil) handler := NewInterPodAntiAffinity()
pod := api.Pod{ pod := api.Pod{
Spec: api.PodSpec{}, Spec: api.PodSpec{},
} }
@ -226,7 +226,7 @@ func TestInterPodAffinityAdmission(t *testing.T) {
} }
} }
func TestHandles(t *testing.T) { func TestHandles(t *testing.T) {
handler := NewInterPodAntiAffinity(nil) handler := NewInterPodAntiAffinity()
tests := map[admission.Operation]bool{ tests := map[admission.Operation]bool{
admission.Update: true, admission.Update: true,
admission.Create: true, admission.Create: true,

View File

@ -12,10 +12,7 @@ go_library(
name = "go_default_library", name = "go_default_library",
srcs = ["admission.go"], srcs = ["admission.go"],
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = ["//pkg/admission:go_default_library"],
"//pkg/admission:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
],
) )
go_test( go_test(

View File

@ -20,13 +20,11 @@ import (
"errors" "errors"
"io" "io"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/admission"
) )
func init() { 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 return NewAlwaysDeny(), nil
}) })
} }

View File

@ -19,6 +19,7 @@ go_library(
"//pkg/api/rest:go_default_library", "//pkg/api/rest:go_default_library",
"//pkg/apis/meta/v1:go_default_library", "//pkg/apis/meta/v1:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
], ],
) )

View File

@ -20,24 +20,24 @@ import (
"fmt" "fmt"
"io" "io"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/rest" "k8s.io/kubernetes/pkg/api/rest"
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1" 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() { func init() {
admission.RegisterPlugin("DenyEscalatingExec", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { admission.RegisterPlugin("DenyEscalatingExec", func(config io.Reader) (admission.Interface, error) {
return NewDenyEscalatingExec(client), nil return NewDenyEscalatingExec(), nil
}) })
// This is for legacy support of the DenyExecOnPrivileged admission controller. Most // This is for legacy support of the DenyExecOnPrivileged admission controller. Most
// of the time DenyEscalatingExec should be preferred. // of the time DenyEscalatingExec should be preferred.
admission.RegisterPlugin("DenyExecOnPrivileged", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { admission.RegisterPlugin("DenyExecOnPrivileged", func(config io.Reader) (admission.Interface, error) {
return NewDenyExecOnPrivileged(client), nil return NewDenyExecOnPrivileged(), nil
}) })
} }
@ -45,7 +45,7 @@ func init() {
// a pod using host based configurations. // a pod using host based configurations.
type denyExec struct { type denyExec struct {
*admission.Handler *admission.Handler
client clientset.Interface client internalclientset.Interface
// these flags control which items will be checked to deny exec/attach // these flags control which items will be checked to deny exec/attach
hostIPC bool hostIPC bool
@ -53,12 +53,13 @@ type denyExec struct {
privileged bool privileged bool
} }
var _ = kubeapiserveradmission.WantsInternalClientSet(&denyExec{})
// NewDenyEscalatingExec creates a new admission controller that denies an exec operation on a pod // NewDenyEscalatingExec creates a new admission controller that denies an exec operation on a pod
// using host based configurations. // using host based configurations.
func NewDenyEscalatingExec(client clientset.Interface) admission.Interface { func NewDenyEscalatingExec() admission.Interface {
return &denyExec{ return &denyExec{
Handler: admission.NewHandler(admission.Connect), Handler: admission.NewHandler(admission.Connect),
client: client,
hostIPC: true, hostIPC: true,
hostPID: true, hostPID: true,
privileged: 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 // NewDenyExecOnPrivileged creates a new admission controller that is only checking the privileged
// option. This is for legacy support of the DenyExecOnPrivileged admission controller. Most // option. This is for legacy support of the DenyExecOnPrivileged admission controller. Most
// of the time NewDenyEscalatingExec should be preferred. // of the time NewDenyEscalatingExec should be preferred.
func NewDenyExecOnPrivileged(client clientset.Interface) admission.Interface { func NewDenyExecOnPrivileged() admission.Interface {
return &denyExec{ return &denyExec{
Handler: admission.NewHandler(admission.Connect), Handler: admission.NewHandler(admission.Connect),
client: client,
hostIPC: false, hostIPC: false,
hostPID: false, hostPID: false,
privileged: true, privileged: true,
@ -127,3 +127,14 @@ func isPrivileged(pod *api.Pod) bool {
} }
return false 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
}

View File

@ -17,7 +17,6 @@ go_library(
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/api/meta:go_default_library", "//pkg/api/meta:go_default_library",
"//pkg/auth/authorizer:go_default_library", "//pkg/auth/authorizer:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/runtime:go_default_library", "//pkg/runtime:go_default_library",
], ],
) )

View File

@ -24,12 +24,11 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/auth/authorizer" "k8s.io/kubernetes/pkg/auth/authorizer"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
) )
func init() { 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{ return &gcPermissionsEnforcement{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
}, nil }, nil

View File

@ -21,7 +21,6 @@ go_library(
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/api/errors:go_default_library", "//pkg/api/errors:go_default_library",
"//pkg/apis/imagepolicy/v1alpha1: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/client/restclient:go_default_library",
"//pkg/runtime/schema:go_default_library", "//pkg/runtime/schema:go_default_library",
"//pkg/util/cache: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/install:go_default_library",
"//pkg/apis/imagepolicy/v1alpha1:go_default_library", "//pkg/apis/imagepolicy/v1alpha1:go_default_library",
"//pkg/auth/user: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", "//pkg/client/unversioned/clientcmd/api/v1:go_default_library",
], ],
) )

View File

@ -31,7 +31,6 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
apierrors "k8s.io/kubernetes/pkg/api/errors" apierrors "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/apis/imagepolicy/v1alpha1" "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/runtime/schema"
"k8s.io/kubernetes/pkg/util/yaml" "k8s.io/kubernetes/pkg/util/yaml"
@ -47,8 +46,8 @@ var (
) )
func init() { func init() {
admission.RegisterPlugin("ImagePolicyWebhook", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { admission.RegisterPlugin("ImagePolicyWebhook", func(config io.Reader) (admission.Interface, error) {
newImagePolicyWebhook, err := NewImagePolicyWebhook(client, config) newImagePolicyWebhook, err := NewImagePolicyWebhook(config)
if err != nil { if err != nil {
return nil, err 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 // For additional HTTP configuration, refer to the kubeconfig documentation
// http://kubernetes.io/v1.1/docs/user-guide/kubeconfig-file.html. // 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 var config AdmissionConfig
d := yaml.NewYAMLOrJSONDecoder(configFile, 4096) d := yaml.NewYAMLOrJSONDecoder(configFile, 4096)
err := d.Decode(&config) err := d.Decode(&config)

View File

@ -32,7 +32,6 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/imagepolicy/v1alpha1" "k8s.io/kubernetes/pkg/apis/imagepolicy/v1alpha1"
"k8s.io/kubernetes/pkg/auth/user" "k8s.io/kubernetes/pkg/auth/user"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1" "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1"
"fmt" "fmt"
@ -244,7 +243,7 @@ current-context: default
} }
defer configFile.Close() defer configFile.Close()
_, err = NewImagePolicyWebhook(fake.NewSimpleClientset(), configFile) _, err = NewImagePolicyWebhook(configFile)
return err return err
}() }()
if err != nil && !tt.wantErr { 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) return nil, fmt.Errorf("failed to read test config: %v", err)
} }
defer configFile.Close() defer configFile.Close()
wh, err := NewImagePolicyWebhook(fake.NewSimpleClientset(), configFile) wh, err := NewImagePolicyWebhook(configFile)
return wh.(*imagePolicyWebhook), err return wh.(*imagePolicyWebhook), err
} }

View File

@ -23,7 +23,6 @@ go_library(
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/api/errors:go_default_library", "//pkg/api/errors:go_default_library",
"//pkg/api/resource: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/restclient:go_default_library",
"//pkg/client/unversioned/clientcmd:go_default_library", "//pkg/client/unversioned/clientcmd:go_default_library",
"//vendor:cloud.google.com/go/compute/metadata", "//vendor:cloud.google.com/go/compute/metadata",

View File

@ -24,8 +24,6 @@ import (
"strings" "strings"
"time" "time"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
@ -48,7 +46,7 @@ const (
// WARNING: this feature is experimental and will definitely change. // WARNING: this feature is experimental and will definitely change.
func init() { 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) s, err := newDataSource(*source)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -23,6 +23,7 @@ go_library(
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/listers/core/internalversion:go_default_library", "//pkg/client/listers/core/internalversion:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/labels:go_default_library", "//pkg/labels:go_default_library",
"//pkg/runtime:go_default_library", "//pkg/runtime:go_default_library",
"//pkg/util/errors: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/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/client/testing/core:go_default_library", "//pkg/client/testing/core:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/runtime:go_default_library", "//pkg/runtime:go_default_library",
"//pkg/util/wait:go_default_library", "//pkg/util/wait:go_default_library",
], ],

View File

@ -25,14 +25,14 @@ import (
lru "github.com/hashicorp/golang-lru" 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/admission"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/resource" "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/labels"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
utilerrors "k8s.io/kubernetes/pkg/util/errors" utilerrors "k8s.io/kubernetes/pkg/util/errors"
@ -43,15 +43,15 @@ const (
) )
func init() { func init() {
admission.RegisterPlugin("LimitRanger", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { admission.RegisterPlugin("LimitRanger", func(config io.Reader) (admission.Interface, error) {
return NewLimitRanger(client, &DefaultLimitRangerActions{}) return NewLimitRanger(&DefaultLimitRangerActions{})
}) })
} }
// limitRanger enforces usage limits on a per resource basis in the namespace // limitRanger enforces usage limits on a per resource basis in the namespace
type limitRanger struct { type limitRanger struct {
*admission.Handler *admission.Handler
client clientset.Interface client internalclientset.Interface
actions LimitRangerActions actions LimitRangerActions
lister coreinternallisters.LimitRangeLister lister coreinternallisters.LimitRangeLister
@ -77,6 +77,9 @@ func (l *limitRanger) Validate() error {
if l.lister == nil { if l.lister == nil {
return fmt.Errorf("missing limitRange lister") return fmt.Errorf("missing limitRange lister")
} }
if l.client == nil {
return fmt.Errorf("missing client")
}
return nil 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 // 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) liveLookupCache, err := lru.New(10000)
if err != nil { if err != nil {
return nil, err return nil, err
@ -157,13 +160,18 @@ func NewLimitRanger(client clientset.Interface, actions LimitRangerActions) (adm
return &limitRanger{ return &limitRanger{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
client: client,
actions: actions, actions: actions,
liveLookupCache: liveLookupCache, liveLookupCache: liveLookupCache,
liveTTL: time.Duration(30 * time.Second), liveTTL: time.Duration(30 * time.Second),
}, nil }, nil
} }
var _ = kubeapiserveradmission.WantsInternalClientSet(&limitRanger{})
func (a *limitRanger) SetInternalClientSet(client internalclientset.Interface) {
a.client = client
}
// defaultContainerResourceRequirements returns the default requirements for a container // defaultContainerResourceRequirements returns the default requirements for a container
// the requirement.Limits are taken from the LimitRange defaults (if specified) // the requirement.Limits are taken from the LimitRange defaults (if specified)
// the requirement.Requests are taken from the LimitRange default request (if specified) // the requirement.Requests are taken from the LimitRange default request (if specified)

View File

@ -30,6 +30,7 @@ import (
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/client/testing/core" "k8s.io/kubernetes/pkg/client/testing/core"
"k8s.io/kubernetes/pkg/controller/informers" "k8s.io/kubernetes/pkg/controller/informers"
kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/wait" "k8s.io/kubernetes/pkg/util/wait"
) )
@ -589,14 +590,13 @@ func newMockClientForTest(limitRanges []api.LimitRange) *fake.Clientset {
// newHandlerForTest returns a handler configured for testing. // newHandlerForTest returns a handler configured for testing.
func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) { func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute) f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute)
handler, err := NewLimitRanger(c, &DefaultLimitRangerActions{}) handler, err := NewLimitRanger(&DefaultLimitRangerActions{})
if err != nil { if err != nil {
return nil, f, err return nil, f, err
} }
plugins := []admission.Interface{handler} pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil)
pluginInitializer := admission.NewPluginInitializer(f, nil) pluginInitializer.Initialize(handler)
pluginInitializer.Initialize(plugins) err = admission.Validate(handler)
err = admission.Validate(plugins)
return handler, f, err return handler, f, err
} }

View File

@ -19,6 +19,7 @@ go_library(
"//pkg/client/cache:go_default_library", "//pkg/client/cache:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/controller/informers: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/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/client/testing/core:go_default_library", "//pkg/client/testing/core:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/runtime:go_default_library", "//pkg/runtime:go_default_library",
"//pkg/util/wait:go_default_library", "//pkg/util/wait:go_default_library",
], ],

View File

@ -17,22 +17,21 @@ limitations under the License.
package autoprovision package autoprovision
import ( import (
"io"
"k8s.io/kubernetes/pkg/client/cache"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"fmt" "fmt"
"io"
"k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors" "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" "k8s.io/kubernetes/pkg/controller/informers"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
) )
func init() { func init() {
admission.RegisterPlugin("NamespaceAutoProvision", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { admission.RegisterPlugin("NamespaceAutoProvision", func(config io.Reader) (admission.Interface, error) {
return NewProvision(client), nil 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. // It is useful in deployments that do not want to restrict creation of a namespace prior to its usage.
type provision struct { type provision struct {
*admission.Handler *admission.Handler
client clientset.Interface client internalclientset.Interface
namespaceInformer cache.SharedIndexInformer namespaceInformer cache.SharedIndexInformer
} }
var _ = admission.WantsInformerFactory(&provision{}) var _ = kubeapiserveradmission.WantsInformerFactory(&provision{})
var _ = kubeapiserveradmission.WantsInformerFactory(&provision{})
func (p *provision) Admit(a admission.Attributes) (err error) { 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 // 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 // NewProvision creates a new namespace provision admission control handler
func NewProvision(c clientset.Interface) admission.Interface { func NewProvision() admission.Interface {
return &provision{ return &provision{
Handler: admission.NewHandler(admission.Create), Handler: admission.NewHandler(admission.Create),
client: c,
} }
} }
func (p *provision) SetInternalClientSet(client internalclientset.Interface) {
p.client = client
}
func (p *provision) SetInformerFactory(f informers.SharedInformerFactory) { func (p *provision) SetInformerFactory(f informers.SharedInformerFactory) {
p.namespaceInformer = f.InternalNamespaces().Informer() p.namespaceInformer = f.InternalNamespaces().Informer()
p.SetReadyFunc(p.namespaceInformer.HasSynced) p.SetReadyFunc(p.namespaceInformer.HasSynced)
@ -96,5 +99,8 @@ func (p *provision) Validate() error {
if p.namespaceInformer == nil { if p.namespaceInformer == nil {
return fmt.Errorf("missing namespaceInformer") return fmt.Errorf("missing namespaceInformer")
} }
if p.client == nil {
return fmt.Errorf("missing client")
}
return nil return nil
} }

View File

@ -29,6 +29,7 @@ import (
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/client/testing/core" "k8s.io/kubernetes/pkg/client/testing/core"
"k8s.io/kubernetes/pkg/controller/informers" "k8s.io/kubernetes/pkg/controller/informers"
kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/wait" "k8s.io/kubernetes/pkg/util/wait"
) )
@ -36,11 +37,10 @@ import (
// newHandlerForTest returns the admission controller configured for testing. // newHandlerForTest returns the admission controller configured for testing.
func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) { func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute) f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute)
handler := NewProvision(c) handler := NewProvision()
plugins := []admission.Interface{handler} pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil)
pluginInitializer := admission.NewPluginInitializer(f, nil) pluginInitializer.Initialize(handler)
pluginInitializer.Initialize(plugins) err := admission.Validate(handler)
err := admission.Validate(plugins)
return handler, f, err return handler, f, err
} }

View File

@ -20,6 +20,7 @@ go_library(
"//pkg/client/cache:go_default_library", "//pkg/client/cache:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/controller/informers: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/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/client/testing/core:go_default_library", "//pkg/client/testing/core:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/runtime:go_default_library", "//pkg/runtime:go_default_library",
"//pkg/util/wait:go_default_library", "//pkg/util/wait:go_default_library",
], ],

View File

@ -17,23 +17,22 @@ limitations under the License.
package exists package exists
import ( import (
"io"
"k8s.io/kubernetes/pkg/client/cache"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"fmt" "fmt"
"io"
"k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
metav1 "k8s.io/kubernetes/pkg/apis/meta/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/controller/informers" "k8s.io/kubernetes/pkg/controller/informers"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
) )
func init() { func init() {
admission.RegisterPlugin("NamespaceExists", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { admission.RegisterPlugin("NamespaceExists", func(config io.Reader) (admission.Interface, error) {
return NewExists(client), nil return NewExists(), nil
}) })
} }
@ -42,11 +41,12 @@ func init() {
// It is useful in deployments that want to enforce pre-declaration of a Namespace resource. // It is useful in deployments that want to enforce pre-declaration of a Namespace resource.
type exists struct { type exists struct {
*admission.Handler *admission.Handler
client clientset.Interface client internalclientset.Interface
namespaceInformer cache.SharedIndexInformer namespaceInformer cache.SharedIndexInformer
} }
var _ = admission.WantsInformerFactory(&exists{}) var _ = kubeapiserveradmission.WantsInformerFactory(&exists{})
var _ = kubeapiserveradmission.WantsInternalClientSet(&exists{})
func (e *exists) Admit(a admission.Attributes) (err error) { 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 // 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 // NewExists creates a new namespace exists admission control handler
func NewExists(c clientset.Interface) admission.Interface { func NewExists() admission.Interface {
return &exists{ return &exists{
client: c,
Handler: admission.NewHandler(admission.Create, admission.Update, admission.Delete), 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) { func (e *exists) SetInformerFactory(f informers.SharedInformerFactory) {
e.namespaceInformer = f.InternalNamespaces().Informer() e.namespaceInformer = f.InternalNamespaces().Informer()
e.SetReadyFunc(e.namespaceInformer.HasSynced) e.SetReadyFunc(e.namespaceInformer.HasSynced)
@ -104,5 +107,8 @@ func (e *exists) Validate() error {
if e.namespaceInformer == nil { if e.namespaceInformer == nil {
return fmt.Errorf("missing namespaceInformer") return fmt.Errorf("missing namespaceInformer")
} }
if e.client == nil {
return fmt.Errorf("missing client")
}
return nil return nil
} }

View File

@ -28,6 +28,7 @@ import (
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/client/testing/core" "k8s.io/kubernetes/pkg/client/testing/core"
"k8s.io/kubernetes/pkg/controller/informers" "k8s.io/kubernetes/pkg/controller/informers"
kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/wait" "k8s.io/kubernetes/pkg/util/wait"
) )
@ -35,11 +36,10 @@ import (
// newHandlerForTest returns the admission controller configured for testing. // newHandlerForTest returns the admission controller configured for testing.
func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) { func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute) f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute)
handler := NewExists(c) handler := NewExists()
plugins := []admission.Interface{handler} pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil)
pluginInitializer := admission.NewPluginInitializer(f, nil) pluginInitializer.Initialize(handler)
pluginInitializer.Initialize(plugins) err := admission.Validate(handler)
err := admission.Validate(plugins)
return handler, f, err return handler, f, err
} }

View File

@ -20,6 +20,7 @@ go_library(
"//pkg/client/cache:go_default_library", "//pkg/client/cache:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/util/cache:go_default_library", "//pkg/util/cache:go_default_library",
"//pkg/util/clock:go_default_library", "//pkg/util/clock:go_default_library",
"//pkg/util/sets: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/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/client/testing/core:go_default_library", "//pkg/client/testing/core:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/runtime:go_default_library", "//pkg/runtime:go_default_library",
"//pkg/util/clock:go_default_library", "//pkg/util/clock:go_default_library",
"//pkg/util/sets:go_default_library", "//pkg/util/sets:go_default_library",

View File

@ -23,14 +23,14 @@ import (
"github.com/golang/glog" "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/admission"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
metav1 "k8s.io/kubernetes/pkg/apis/meta/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/controller/informers"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
utilcache "k8s.io/kubernetes/pkg/util/cache" utilcache "k8s.io/kubernetes/pkg/util/cache"
"k8s.io/kubernetes/pkg/util/clock" "k8s.io/kubernetes/pkg/util/clock"
"k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/sets"
@ -50,8 +50,8 @@ const (
) )
func init() { func init() {
admission.RegisterPlugin(PluginName, func(client clientset.Interface, config io.Reader) (admission.Interface, error) { admission.RegisterPlugin(PluginName, func(config io.Reader) (admission.Interface, error) {
return NewLifecycle(client, sets.NewString(api.NamespaceDefault, api.NamespaceSystem)) 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 // It enforces life-cycle constraints around a Namespace depending on its Phase
type lifecycle struct { type lifecycle struct {
*admission.Handler *admission.Handler
client clientset.Interface client internalclientset.Interface
immortalNamespaces sets.String immortalNamespaces sets.String
namespaceInformer cache.SharedIndexInformer 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. // 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 expiry time.Time
} }
var _ = admission.WantsInformerFactory(&lifecycle{}) var _ = kubeapiserveradmission.WantsInformerFactory(&lifecycle{})
var _ = kubeapiserveradmission.WantsInternalClientSet(&lifecycle{})
func makeNamespaceKey(namespace string) *api.Namespace { func makeNamespaceKey(namespace string) *api.Namespace {
return &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 // NewLifecycle creates a new namespace lifecycle admission control handler
func NewLifecycle(c clientset.Interface, immortalNamespaces sets.String) (admission.Interface, error) { func NewLifecycle(immortalNamespaces sets.String) (admission.Interface, error) {
return newLifecycleWithClock(c, immortalNamespaces, clock.RealClock{}) 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) forceLiveLookupCache := utilcache.NewLRUExpireCacheWithClock(100, clock)
return &lifecycle{ return &lifecycle{
Handler: admission.NewHandler(admission.Create, admission.Update, admission.Delete), Handler: admission.NewHandler(admission.Create, admission.Update, admission.Delete),
client: c,
immortalNamespaces: immortalNamespaces, immortalNamespaces: immortalNamespaces,
forceLiveLookupCache: forceLiveLookupCache, forceLiveLookupCache: forceLiveLookupCache,
}, nil }, nil
@ -186,9 +186,16 @@ func (l *lifecycle) SetInformerFactory(f informers.SharedInformerFactory) {
l.SetReadyFunc(l.namespaceInformer.HasSynced) l.SetReadyFunc(l.namespaceInformer.HasSynced)
} }
func (l *lifecycle) SetInternalClientSet(client internalclientset.Interface) {
l.client = client
}
func (l *lifecycle) Validate() error { func (l *lifecycle) Validate() error {
if l.namespaceInformer == nil { if l.namespaceInformer == nil {
return fmt.Errorf("missing namespaceInformer") return fmt.Errorf("missing namespaceInformer")
} }
if l.client == nil {
return fmt.Errorf("missing client")
}
return nil return nil
} }

View File

@ -28,6 +28,7 @@ import (
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/client/testing/core" "k8s.io/kubernetes/pkg/client/testing/core"
"k8s.io/kubernetes/pkg/controller/informers" "k8s.io/kubernetes/pkg/controller/informers"
kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/clock" "k8s.io/kubernetes/pkg/util/clock"
"k8s.io/kubernetes/pkg/util/sets" "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. // newHandlerForTestWithClock returns a configured handler for testing.
func newHandlerForTestWithClock(c clientset.Interface, cacheClock clock.Clock) (admission.Interface, informers.SharedInformerFactory, error) { func newHandlerForTestWithClock(c clientset.Interface, cacheClock clock.Clock) (admission.Interface, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute) 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 { if err != nil {
return nil, f, err return nil, f, err
} }
plugins := []admission.Interface{handler} pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil)
pluginInitializer := admission.NewPluginInitializer(f, nil) pluginInitializer.Initialize(handler)
pluginInitializer.Initialize(plugins) err = admission.Validate(handler)
err = admission.Validate(plugins)
return handler, f, err return handler, f, err
} }

View File

@ -19,7 +19,6 @@ go_library(
"//pkg/admission:go_default_library", "//pkg/admission:go_default_library",
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/apis/meta/v1: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:go_default_library",
"//pkg/cloudprovider/providers/aws:go_default_library", "//pkg/cloudprovider/providers/aws:go_default_library",
"//pkg/cloudprovider/providers/gce:go_default_library", "//pkg/cloudprovider/providers/gce:go_default_library",

View File

@ -21,8 +21,6 @@ import (
"io" "io"
"sync" "sync"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1" metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
@ -33,7 +31,7 @@ import (
) )
func init() { 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() persistentVolumeLabelAdmission := NewPersistentVolumeLabel()
return persistentVolumeLabelAdmission, nil return persistentVolumeLabelAdmission, nil
}) })

View File

@ -20,6 +20,7 @@ go_library(
"//pkg/client/cache:go_default_library", "//pkg/client/cache:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/labels:go_default_library", "//pkg/labels:go_default_library",
"//pkg/util/yaml:go_default_library", "//pkg/util/yaml:go_default_library",
"//vendor:github.com/golang/glog", "//vendor:github.com/golang/glog",
@ -37,6 +38,7 @@ go_test(
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/labels:go_default_library", "//pkg/labels:go_default_library",
"//pkg/util/wait:go_default_library", "//pkg/util/wait:go_default_library",
], ],

View File

@ -28,8 +28,9 @@ import (
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1" metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/client/cache" "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" "k8s.io/kubernetes/pkg/controller/informers"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/util/yaml" "k8s.io/kubernetes/pkg/util/yaml"
) )
@ -39,9 +40,9 @@ import (
var NamespaceNodeSelectors = []string{"scheduler.alpha.kubernetes.io/node-selector"} var NamespaceNodeSelectors = []string{"scheduler.alpha.kubernetes.io/node-selector"}
func init() { 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) pluginConfig := readConfig(config)
plugin := NewPodNodeSelector(client, pluginConfig.PodNodeSelectorPluginConfig) plugin := NewPodNodeSelector(pluginConfig.PodNodeSelectorPluginConfig)
return plugin, nil return plugin, nil
}) })
} }
@ -49,12 +50,14 @@ func init() {
// podNodeSelector is an implementation of admission.Interface. // podNodeSelector is an implementation of admission.Interface.
type podNodeSelector struct { type podNodeSelector struct {
*admission.Handler *admission.Handler
client clientset.Interface client internalclientset.Interface
namespaceInformer cache.SharedIndexInformer namespaceInformer cache.SharedIndexInformer
// global default node selector and namespace whitelists in a cluster. // global default node selector and namespace whitelists in a cluster.
clusterNodeSelectors map[string]string clusterNodeSelectors map[string]string
} }
var _ = kubeapiserveradmission.WantsInternalClientSet(&podNodeSelector{})
type pluginConfig struct { type pluginConfig struct {
PodNodeSelectorPluginConfig map[string]string PodNodeSelectorPluginConfig map[string]string
} }
@ -157,14 +160,17 @@ func (p *podNodeSelector) Admit(a admission.Attributes) error {
return nil return nil
} }
func NewPodNodeSelector(client clientset.Interface, clusterNodeSelectors map[string]string) *podNodeSelector { func NewPodNodeSelector(clusterNodeSelectors map[string]string) *podNodeSelector {
return &podNodeSelector{ return &podNodeSelector{
Handler: admission.NewHandler(admission.Create), Handler: admission.NewHandler(admission.Create),
client: client,
clusterNodeSelectors: clusterNodeSelectors, clusterNodeSelectors: clusterNodeSelectors,
} }
} }
func (a *podNodeSelector) SetInternalClientSet(client internalclientset.Interface) {
a.client = client
}
func (p *podNodeSelector) SetInformerFactory(f informers.SharedInformerFactory) { func (p *podNodeSelector) SetInformerFactory(f informers.SharedInformerFactory) {
p.namespaceInformer = f.InternalNamespaces().Informer() p.namespaceInformer = f.InternalNamespaces().Informer()
p.SetReadyFunc(p.namespaceInformer.HasSynced) p.SetReadyFunc(p.namespaceInformer.HasSynced)
@ -174,6 +180,9 @@ func (p *podNodeSelector) Validate() error {
if p.namespaceInformer == nil { if p.namespaceInformer == nil {
return fmt.Errorf("missing namespaceInformer") return fmt.Errorf("missing namespaceInformer")
} }
if p.client == nil {
return fmt.Errorf("missing client")
}
return nil return nil
} }

View File

@ -25,6 +25,7 @@ import (
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/controller/informers" "k8s.io/kubernetes/pkg/controller/informers"
kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/util/wait" "k8s.io/kubernetes/pkg/util/wait"
) )
@ -169,7 +170,7 @@ func TestHandles(t *testing.T) {
admission.Connect: false, admission.Connect: false,
admission.Delete: false, admission.Delete: false,
} { } {
nodeEnvionment := NewPodNodeSelector(nil, nil) nodeEnvionment := NewPodNodeSelector(nil)
if e, a := shouldHandle, nodeEnvionment.Handles(op); e != a { if e, a := shouldHandle, nodeEnvionment.Handles(op); e != a {
t.Errorf("%v: shouldHandle=%t, handles=%t", 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. // newHandlerForTest returns the admission controller configured for testing.
func newHandlerForTest(c clientset.Interface) (*podNodeSelector, informers.SharedInformerFactory, error) { func newHandlerForTest(c clientset.Interface) (*podNodeSelector, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute) f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute)
handler := NewPodNodeSelector(c, nil) handler := NewPodNodeSelector(nil)
plugins := []admission.Interface{handler} pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil)
pluginInitializer := admission.NewPluginInitializer(f, nil) pluginInitializer.Initialize(handler)
pluginInitializer.Initialize(plugins) err := admission.Validate(handler)
err := admission.Validate(plugins)
return handler, f, err return handler, f, err
} }

View File

@ -24,6 +24,7 @@ go_library(
"//pkg/api/v1:go_default_library", "//pkg/api/v1:go_default_library",
"//pkg/client/cache:go_default_library", "//pkg/client/cache:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/quota:go_default_library", "//pkg/quota:go_default_library",
"//pkg/quota/install:go_default_library", "//pkg/quota/install:go_default_library",
"//pkg/runtime:go_default_library", "//pkg/runtime:go_default_library",

View File

@ -17,24 +17,25 @@ limitations under the License.
package resourcequota package resourcequota
import ( import (
"fmt"
"io" "io"
"time" "time"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api" "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"
"k8s.io/kubernetes/pkg/quota/install" "k8s.io/kubernetes/pkg/quota/install"
) )
func init() { func init() {
admission.RegisterPlugin("ResourceQuota", 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 // 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. // does not require us to open watches for all items tracked by quota.
registry := install.NewRegistry(nil, nil) 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 { type quotaAdmission struct {
*admission.Handler *admission.Handler
evaluator Evaluator stopCh <-chan struct{}
registry quota.Registry
numEvaluators int
evaluator Evaluator
} }
var _ = kubeapiserveradmission.WantsInternalClientSet(&quotaAdmission{})
type liveLookupEntry struct { type liveLookupEntry struct {
expiry time.Time expiry time.Time
items []*api.ResourceQuota items []*api.ResourceQuota
@ -53,19 +59,33 @@ type liveLookupEntry struct {
// NewResourceQuota configures an admission controller that can enforce quota constraints // 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 // 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 // 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 &quotaAdmission{
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) quotaAccessor, err := newQuotaAccessor(client)
if err != nil { 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 &quotaAdmission{ // Validate ensures an authorizer is set.
Handler: admission.NewHandler(admission.Create, admission.Update), func (a *quotaAdmission) Validate() error {
evaluator: evaluator, if a.evaluator == nil {
}, nil return fmt.Errorf("missing evaluator")
}
return nil
} }
// Admit makes admission decisions while enforcing quota // Admit makes admission decisions while enforcing quota

View File

@ -122,14 +122,21 @@ func TestPrettyPrint(t *testing.T) {
// TestAdmissionIgnoresDelete verifies that the admission controller ignores delete operations // TestAdmissionIgnoresDelete verifies that the admission controller ignores delete operations
func TestAdmissionIgnoresDelete(t *testing.T) { func TestAdmissionIgnoresDelete(t *testing.T) {
kubeClient := fake.NewSimpleClientset() kubeClient := fake.NewSimpleClientset()
indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc})
stopCh := make(chan struct{}) stopCh := make(chan struct{})
defer close(stopCh) defer close(stopCh)
handler, err := NewResourceQuota(kubeClient, install.NewRegistry(nil, nil), 5, stopCh)
if err != nil { quotaAccessor, _ := newQuotaAccessor(kubeClient)
t.Errorf("Unexpected error %v", err) quotaAccessor.indexer = indexer
go quotaAccessor.Run(stopCh)
evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, 5, stopCh)
handler := &quotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator,
} }
namespace := "default" 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 { if err != nil {
t.Errorf("ResourceQuota should admit all deletes: %v", err) t.Errorf("ResourceQuota should admit all deletes: %v", err)
} }

View File

@ -22,6 +22,7 @@ go_library(
"//pkg/auth/user:go_default_library", "//pkg/auth/user:go_default_library",
"//pkg/client/cache:go_default_library", "//pkg/client/cache:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/runtime:go_default_library", "//pkg/runtime:go_default_library",
"//pkg/security/podsecuritypolicy:go_default_library", "//pkg/security/podsecuritypolicy:go_default_library",
"//pkg/security/podsecuritypolicy/util:go_default_library", "//pkg/security/podsecuritypolicy/util:go_default_library",
@ -46,8 +47,6 @@ go_test(
"//pkg/auth/authorizer:go_default_library", "//pkg/auth/authorizer:go_default_library",
"//pkg/auth/user:go_default_library", "//pkg/auth/user:go_default_library",
"//pkg/client/cache: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/apparmor:go_default_library",
"//pkg/security/podsecuritypolicy:go_default_library", "//pkg/security/podsecuritypolicy:go_default_library",
"//pkg/security/podsecuritypolicy/seccomp:go_default_library", "//pkg/security/podsecuritypolicy/seccomp:go_default_library",

View File

@ -31,7 +31,8 @@ import (
"k8s.io/kubernetes/pkg/auth/authorizer" "k8s.io/kubernetes/pkg/auth/authorizer"
"k8s.io/kubernetes/pkg/auth/user" "k8s.io/kubernetes/pkg/auth/user"
"k8s.io/kubernetes/pkg/client/cache" "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/runtime"
psp "k8s.io/kubernetes/pkg/security/podsecuritypolicy" psp "k8s.io/kubernetes/pkg/security/podsecuritypolicy"
psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util" psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util"
@ -47,9 +48,8 @@ const (
) )
func init() { func init() {
admission.RegisterPlugin(PluginName, func(client clientset.Interface, config io.Reader) (admission.Interface, error) { admission.RegisterPlugin(PluginName, func(config io.Reader) (admission.Interface, error) {
plugin := NewPlugin(client, psp.NewSimpleStrategyFactory(), getMatchingPolicies, true) plugin := NewPlugin(psp.NewSimpleStrategyFactory(), getMatchingPolicies, true)
plugin.Run()
return plugin, nil 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. // podSecurityPolicyPlugin holds state for and implements the admission plugin.
type podSecurityPolicyPlugin struct { type podSecurityPolicyPlugin struct {
*admission.Handler *admission.Handler
client clientset.Interface
strategyFactory psp.StrategyFactory strategyFactory psp.StrategyFactory
pspMatcher PSPMatchFn pspMatcher PSPMatchFn
failOnNoPolicies bool failOnNoPolicies bool
@ -81,43 +80,50 @@ func (plugin *podSecurityPolicyPlugin) Validate() error {
if plugin.authz == nil { if plugin.authz == nil {
return fmt.Errorf("%s requires an authorizer", PluginName) 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 return nil
} }
var _ admission.Interface = &podSecurityPolicyPlugin{} var _ admission.Interface = &podSecurityPolicyPlugin{}
var _ admission.WantsAuthorizer = &podSecurityPolicyPlugin{} var _ kubeapiserveradmission.WantsAuthorizer = &podSecurityPolicyPlugin{}
var _ kubeapiserveradmission.WantsInternalClientSet = &podSecurityPolicyPlugin{}
// NewPlugin creates a new PSP admission plugin. // NewPlugin creates a new PSP admission plugin.
func NewPlugin(kclient clientset.Interface, strategyFactory psp.StrategyFactory, pspMatcher PSPMatchFn, failOnNoPolicies bool) *podSecurityPolicyPlugin { func NewPlugin(strategyFactory psp.StrategyFactory, pspMatcher PSPMatchFn, failOnNoPolicies bool) *podSecurityPolicyPlugin {
store := cache.NewStore(cache.MetaNamespaceKeyFunc)
reflector := cache.NewReflector( 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{ &cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) { ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
internalOptions := api.ListOptions{} internalOptions := api.ListOptions{}
v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) 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) { WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
internalOptions := api.ListOptions{} internalOptions := api.ListOptions{}
v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil)
return kclient.Extensions().PodSecurityPolicies().Watch(internalOptions) return client.Extensions().PodSecurityPolicies().Watch(internalOptions)
}, },
}, },
&extensions.PodSecurityPolicy{}, &extensions.PodSecurityPolicy{},
store, a.store,
0, 0,
) )
a.Run()
return &podSecurityPolicyPlugin{
Handler: admission.NewHandler(admission.Create, admission.Update),
client: kclient,
strategyFactory: strategyFactory,
pspMatcher: pspMatcher,
failOnNoPolicies: failOnNoPolicies,
store: store,
reflector: reflector,
}
} }
func (a *podSecurityPolicyPlugin) Run() { func (a *podSecurityPolicyPlugin) Run() {

View File

@ -30,8 +30,6 @@ import (
"k8s.io/kubernetes/pkg/auth/authorizer" "k8s.io/kubernetes/pkg/auth/authorizer"
"k8s.io/kubernetes/pkg/auth/user" "k8s.io/kubernetes/pkg/auth/user"
"k8s.io/kubernetes/pkg/client/cache" "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" "k8s.io/kubernetes/pkg/security/apparmor"
kpsp "k8s.io/kubernetes/pkg/security/podsecuritypolicy" kpsp "k8s.io/kubernetes/pkg/security/podsecuritypolicy"
"k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp" "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 // NewTestAdmission provides an admission plugin with test implementations of internal structs. It uses
// an authorizer that always returns true. // 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{ return &podSecurityPolicyPlugin{
Handler: kadmission.NewHandler(kadmission.Create), Handler: kadmission.NewHandler(kadmission.Create),
client: kclient,
store: store, store: store,
strategyFactory: kpsp.NewSimpleStrategyFactory(), strategyFactory: kpsp.NewSimpleStrategyFactory(),
pspMatcher: getMatchingPolicies, 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) { 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) store := cache.NewStore(cache.MetaNamespaceKeyFunc)
for _, psp := range psps { for _, psp := range psps {
store.Add(psp) 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{}) attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), "namespace", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{})
err := plugin.Admit(attrs) err := plugin.Admit(attrs)
@ -1512,10 +1506,8 @@ func TestCreateProvidersFromConstraints(t *testing.T) {
for k, v := range testCases { for k, v := range testCases {
store := cache.NewStore(cache.MetaNamespaceKeyFunc) store := cache.NewStore(cache.MetaNamespaceKeyFunc)
tc := clientsetfake.NewSimpleClientset()
admit := &podSecurityPolicyPlugin{ admit := &podSecurityPolicyPlugin{
Handler: kadmission.NewHandler(kadmission.Create, kadmission.Update), Handler: kadmission.NewHandler(kadmission.Create, kadmission.Update),
client: tc,
store: store, store: store,
strategyFactory: kpsp.NewSimpleStrategyFactory(), strategyFactory: kpsp.NewSimpleStrategyFactory(),
} }

View File

@ -16,7 +16,6 @@ go_library(
"//pkg/admission:go_default_library", "//pkg/admission:go_default_library",
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/api/errors:go_default_library", "//pkg/api/errors:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
], ],
) )

View File

@ -20,30 +20,25 @@ import (
"fmt" "fmt"
"io" "io"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
apierrors "k8s.io/kubernetes/pkg/api/errors" apierrors "k8s.io/kubernetes/pkg/api/errors"
) )
func init() { func init() {
admission.RegisterPlugin("SecurityContextDeny", func(client clientset.Interface, config io.Reader) (admission.Interface, error) { admission.RegisterPlugin("SecurityContextDeny", func(config io.Reader) (admission.Interface, error) {
return NewSecurityContextDeny(client), nil return NewSecurityContextDeny(), nil
}) })
} }
// plugin contains the client used by the SecurityContextDeny admission controller
type plugin struct { type plugin struct {
*admission.Handler *admission.Handler
client clientset.Interface
} }
// NewSecurityContextDeny creates a new instance of the SecurityContextDeny admission controller // NewSecurityContextDeny creates a new instance of the SecurityContextDeny admission controller
func NewSecurityContextDeny(client clientset.Interface) admission.Interface { func NewSecurityContextDeny() admission.Interface {
return &plugin{ return &plugin{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
client: client,
} }
} }

View File

@ -25,7 +25,7 @@ import (
// ensures the SecurityContext is denied if it defines anything more than Caps or Privileged // ensures the SecurityContext is denied if it defines anything more than Caps or Privileged
func TestAdmission(t *testing.T) { func TestAdmission(t *testing.T) {
handler := NewSecurityContextDeny(nil) handler := NewSecurityContextDeny()
var runAsUser int64 = 1 var runAsUser int64 = 1
priv := true priv := true
@ -106,7 +106,7 @@ func TestAdmission(t *testing.T) {
} }
func TestPodSecurityContextAdmission(t *testing.T) { func TestPodSecurityContextAdmission(t *testing.T) {
handler := NewSecurityContextDeny(nil) handler := NewSecurityContextDeny()
pod := api.Pod{ pod := api.Pod{
Spec: api.PodSpec{ Spec: api.PodSpec{
Containers: []api.Container{ Containers: []api.Container{
@ -153,7 +153,7 @@ func TestPodSecurityContextAdmission(t *testing.T) {
} }
func TestHandles(t *testing.T) { func TestHandles(t *testing.T) {
handler := NewSecurityContextDeny(nil) handler := NewSecurityContextDeny()
tests := map[admission.Operation]bool{ tests := map[admission.Operation]bool{
admission.Update: true, admission.Update: true,
admission.Create: true, admission.Create: true,

View File

@ -24,6 +24,7 @@ go_library(
"//pkg/client/cache:go_default_library", "//pkg/client/cache:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/fields:go_default_library", "//pkg/fields:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/kubelet/types:go_default_library", "//pkg/kubelet/types:go_default_library",
"//pkg/runtime:go_default_library", "//pkg/runtime:go_default_library",
"//pkg/runtime/schema:go_default_library", "//pkg/runtime/schema:go_default_library",

View File

@ -23,18 +23,18 @@ import (
"strconv" "strconv"
"time" "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/admission"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/api/v1"
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1" metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/client/cache" "k8s.io/kubernetes/pkg/client/cache"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/fields"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
kubelet "k8s.io/kubernetes/pkg/kubelet/types" kubelet "k8s.io/kubernetes/pkg/kubelet/types"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/serviceaccount" "k8s.io/kubernetes/pkg/serviceaccount"
"k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/watch" "k8s.io/kubernetes/pkg/watch"
@ -55,9 +55,8 @@ const DefaultAPITokenMountPath = "/var/run/secrets/kubernetes.io/serviceaccount"
const PluginName = "ServiceAccount" const PluginName = "ServiceAccount"
func init() { func init() {
admission.RegisterPlugin(PluginName, func(client clientset.Interface, config io.Reader) (admission.Interface, error) { admission.RegisterPlugin(PluginName, func(config io.Reader) (admission.Interface, error) {
serviceAccountAdmission := NewServiceAccount(client) serviceAccountAdmission := NewServiceAccount()
serviceAccountAdmission.Run()
return serviceAccountAdmission, nil 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 creates Volume and VolumeMounts for the first referenced ServiceAccountToken for the pod's service account
MountServiceAccountToken bool MountServiceAccountToken bool
client clientset.Interface client internalclientset.Interface
serviceAccounts cache.Indexer serviceAccounts cache.Indexer
secrets cache.Indexer secrets cache.Indexer
@ -84,14 +83,29 @@ type serviceAccount struct {
secretsReflector *cache.Reflector 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: // 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" // 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 // 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 // 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. // 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 // 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 { func NewServiceAccount() *serviceAccount {
serviceAccountsIndexer, serviceAccountsReflector := cache.NewNamespaceKeyedIndexerAndReflector( 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{ &cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) { ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
internalOptions := api.ListOptions{} internalOptions := api.ListOptions{}
@ -109,7 +123,7 @@ func NewServiceAccount(cl clientset.Interface) *serviceAccount {
) )
tokenSelector := fields.SelectorFromSet(map[string]string{api.SecretTypeField: string(api.SecretTypeServiceAccountToken)}) tokenSelector := fields.SelectorFromSet(map[string]string{api.SecretTypeField: string(api.SecretTypeServiceAccountToken)})
secretsIndexer, secretsReflector := cache.NewNamespaceKeyedIndexerAndReflector( a.secrets, a.secretsReflector = cache.NewNamespaceKeyedIndexerAndReflector(
&cache.ListWatch{ &cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) { ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
internalOptions := api.ListOptions{} internalOptions := api.ListOptions{}
@ -128,23 +142,31 @@ func NewServiceAccount(cl clientset.Interface) *serviceAccount {
0, 0,
) )
return &serviceAccount{ if cl != nil {
Handler: admission.NewHandler(admission.Create), a.Run()
// 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,
} }
} }
// 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() { func (s *serviceAccount) Run() {
if s.stopChan == nil { if s.stopChan == nil {
s.stopChan = make(chan struct{}) s.stopChan = make(chan struct{})

View File

@ -33,7 +33,7 @@ func TestIgnoresNonCreate(t *testing.T) {
pod := &api.Pod{} pod := &api.Pod{}
for _, op := range []admission.Operation{admission.Update, admission.Delete, admission.Connect} { 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) 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) err := handler.Admit(attrs)
if err != nil { if err != nil {
t.Errorf("Expected %s operation allowed, got err: %v", op, err) 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) { func TestIgnoresNonPodResource(t *testing.T) {
pod := &api.Pod{} pod := &api.Pod{}
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("CustomResource").WithVersion("version"), "", admission.Create, nil) 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 { if err != nil {
t.Errorf("Expected non-pod resource allowed, got err: %v", err) 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) { 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) 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 { if err != nil {
t.Errorf("Expected nil object allowed allowed, got err: %v", err) 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) { func TestIgnoresNonPodObject(t *testing.T) {
obj := &api.Namespace{} obj := &api.Namespace{}
attrs := admission.NewAttributesRecord(obj, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) 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 { if err != nil {
t.Errorf("Expected non pod object allowed, got err: %v", err) 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) 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 { if err != nil {
t.Errorf("Expected mirror pod without service account or secrets allowed, got err: %v", err) 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) 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 { if err == nil {
t.Errorf("Expected a mirror pod to be prevented from referencing a service account") 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) 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 { if err == nil {
t.Errorf("Expected a mirror pod to be prevented from referencing a secret volume") 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) { func TestAssignsDefaultServiceAccountAndToleratesMissingAPIToken(t *testing.T) {
ns := "myns" ns := "myns"
admit := NewServiceAccount(nil) admit := NewServiceAccount()
admit.SetInternalClientSet(nil)
admit.MountServiceAccountToken = true admit.MountServiceAccountToken = true
admit.RequireAPIToken = false admit.RequireAPIToken = false
@ -154,7 +155,8 @@ func TestAssignsDefaultServiceAccountAndToleratesMissingAPIToken(t *testing.T) {
func TestAssignsDefaultServiceAccountAndRejectsMissingAPIToken(t *testing.T) { func TestAssignsDefaultServiceAccountAndRejectsMissingAPIToken(t *testing.T) {
ns := "myns" ns := "myns"
admit := NewServiceAccount(nil) admit := NewServiceAccount()
admit.SetInternalClientSet(nil)
admit.MountServiceAccountToken = true admit.MountServiceAccountToken = true
admit.RequireAPIToken = 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 admit.RequireAPIToken = false
pod := &api.Pod{} 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 // Build a test client that the admission plugin can use to look up the service account missing from its cache
client := fake.NewSimpleClientset() client := fake.NewSimpleClientset()
admit := NewServiceAccount(client) admit := NewServiceAccount()
admit.SetInternalClientSet(client)
pod := &api.Pod{} pod := &api.Pod{}
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) 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, MountPath: DefaultAPITokenMountPath,
} }
admit := NewServiceAccount(nil) admit := NewServiceAccount()
admit.SetInternalClientSet(nil)
admit.MountServiceAccountToken = true admit.MountServiceAccountToken = true
admit.RequireAPIToken = true admit.RequireAPIToken = true
@ -332,7 +338,8 @@ func TestRespectsExistingMount(t *testing.T) {
MountPath: DefaultAPITokenMountPath, MountPath: DefaultAPITokenMountPath,
} }
admit := NewServiceAccount(nil) admit := NewServiceAccount()
admit.SetInternalClientSet(nil)
admit.MountServiceAccountToken = true admit.MountServiceAccountToken = true
admit.RequireAPIToken = true admit.RequireAPIToken = true
@ -428,7 +435,8 @@ func TestRespectsExistingMount(t *testing.T) {
func TestAllowsReferencedSecret(t *testing.T) { func TestAllowsReferencedSecret(t *testing.T) {
ns := "myns" ns := "myns"
admit := NewServiceAccount(nil) admit := NewServiceAccount()
admit.SetInternalClientSet(nil)
admit.LimitSecretReferences = true admit.LimitSecretReferences = true
admit.RequireAPIToken = false admit.RequireAPIToken = false
@ -507,7 +515,8 @@ func TestAllowsReferencedSecret(t *testing.T) {
func TestRejectsUnreferencedSecretVolumes(t *testing.T) { func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
ns := "myns" ns := "myns"
admit := NewServiceAccount(nil) admit := NewServiceAccount()
admit.SetInternalClientSet(nil)
admit.LimitSecretReferences = true admit.LimitSecretReferences = true
admit.RequireAPIToken = false admit.RequireAPIToken = false
@ -583,7 +592,8 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
func TestAllowUnreferencedSecretVolumesForPermissiveSAs(t *testing.T) { func TestAllowUnreferencedSecretVolumesForPermissiveSAs(t *testing.T) {
ns := "myns" ns := "myns"
admit := NewServiceAccount(nil) admit := NewServiceAccount()
admit.SetInternalClientSet(nil)
admit.LimitSecretReferences = false admit.LimitSecretReferences = false
admit.RequireAPIToken = false admit.RequireAPIToken = false
@ -613,7 +623,8 @@ func TestAllowUnreferencedSecretVolumesForPermissiveSAs(t *testing.T) {
func TestAllowsReferencedImagePullSecrets(t *testing.T) { func TestAllowsReferencedImagePullSecrets(t *testing.T) {
ns := "myns" ns := "myns"
admit := NewServiceAccount(nil) admit := NewServiceAccount()
admit.SetInternalClientSet(nil)
admit.LimitSecretReferences = true admit.LimitSecretReferences = true
admit.RequireAPIToken = false admit.RequireAPIToken = false
@ -643,7 +654,8 @@ func TestAllowsReferencedImagePullSecrets(t *testing.T) {
func TestRejectsUnreferencedImagePullSecrets(t *testing.T) { func TestRejectsUnreferencedImagePullSecrets(t *testing.T) {
ns := "myns" ns := "myns"
admit := NewServiceAccount(nil) admit := NewServiceAccount()
admit.SetInternalClientSet(nil)
admit.LimitSecretReferences = true admit.LimitSecretReferences = true
admit.RequireAPIToken = false admit.RequireAPIToken = false
@ -670,7 +682,8 @@ func TestRejectsUnreferencedImagePullSecrets(t *testing.T) {
func TestDoNotAddImagePullSecrets(t *testing.T) { func TestDoNotAddImagePullSecrets(t *testing.T) {
ns := "myns" ns := "myns"
admit := NewServiceAccount(nil) admit := NewServiceAccount()
admit.SetInternalClientSet(nil)
admit.LimitSecretReferences = true admit.LimitSecretReferences = true
admit.RequireAPIToken = false admit.RequireAPIToken = false
@ -705,7 +718,8 @@ func TestDoNotAddImagePullSecrets(t *testing.T) {
func TestAddImagePullSecrets(t *testing.T) { func TestAddImagePullSecrets(t *testing.T) {
ns := "myns" ns := "myns"
admit := NewServiceAccount(nil) admit := NewServiceAccount()
admit.SetInternalClientSet(nil)
admit.LimitSecretReferences = true admit.LimitSecretReferences = true
admit.RequireAPIToken = false admit.RequireAPIToken = false

View File

@ -21,6 +21,7 @@ go_library(
"//pkg/apis/storage/util:go_default_library", "//pkg/apis/storage/util:go_default_library",
"//pkg/client/cache:go_default_library", "//pkg/client/cache:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/runtime:go_default_library", "//pkg/runtime:go_default_library",
"//pkg/watch:go_default_library", "//pkg/watch:go_default_library",
"//vendor:github.com/golang/glog", "//vendor:github.com/golang/glog",

View File

@ -29,7 +29,8 @@ import (
"k8s.io/kubernetes/pkg/apis/storage" "k8s.io/kubernetes/pkg/apis/storage"
storageutil "k8s.io/kubernetes/pkg/apis/storage/util" storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
"k8s.io/kubernetes/pkg/client/cache" "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/runtime"
"k8s.io/kubernetes/pkg/watch" "k8s.io/kubernetes/pkg/watch"
) )
@ -39,9 +40,8 @@ const (
) )
func init() { func init() {
admission.RegisterPlugin(PluginName, func(client clientset.Interface, config io.Reader) (admission.Interface, error) { admission.RegisterPlugin(PluginName, func(config io.Reader) (admission.Interface, error) {
plugin := newPlugin(client) plugin := newPlugin()
plugin.Run()
return plugin, nil return plugin, nil
}) })
} }
@ -49,7 +49,7 @@ func init() {
// claimDefaulterPlugin holds state for and implements the admission plugin. // claimDefaulterPlugin holds state for and implements the admission plugin.
type claimDefaulterPlugin struct { type claimDefaulterPlugin struct {
*admission.Handler *admission.Handler
client clientset.Interface client internalclientset.Interface
reflector *cache.Reflector reflector *cache.Reflector
stopChan chan struct{} stopChan chan struct{}
@ -57,36 +57,55 @@ type claimDefaulterPlugin struct {
} }
var _ admission.Interface = &claimDefaulterPlugin{} var _ admission.Interface = &claimDefaulterPlugin{}
var _ = kubeapiserveradmission.WantsInternalClientSet(&claimDefaulterPlugin{})
// newPlugin creates a new admission plugin. // newPlugin creates a new admission plugin.
func newPlugin(kclient clientset.Interface) *claimDefaulterPlugin { func newPlugin() *claimDefaulterPlugin {
store := cache.NewStore(cache.MetaNamespaceKeyFunc) return &claimDefaulterPlugin{
reflector := cache.NewReflector( 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{ &cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) { ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
internalOptions := api.ListOptions{} internalOptions := api.ListOptions{}
v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) 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) { WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
internalOptions := api.ListOptions{} internalOptions := api.ListOptions{}
v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil)
return kclient.Storage().StorageClasses().Watch(internalOptions) return client.Storage().StorageClasses().Watch(internalOptions)
}, },
}, },
&storage.StorageClass{}, &storage.StorageClass{},
store, a.store,
0, 0,
) )
return &claimDefaulterPlugin{ if client != nil {
Handler: admission.NewHandler(admission.Create), a.Run()
client: kclient,
store: store,
reflector: reflector,
} }
} }
// 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() { func (a *claimDefaulterPlugin) Run() {
if a.stopChan == nil { if a.stopChan == nil {
a.stopChan = make(chan struct{}) a.stopChan = make(chan struct{})

View File

@ -192,7 +192,8 @@ func TestAdmission(t *testing.T) {
} }
claim := clone.(*api.PersistentVolumeClaim) claim := clone.(*api.PersistentVolumeClaim)
ctrl := newPlugin(nil) ctrl := newPlugin()
ctrl.SetInternalClientSet(nil)
for _, c := range test.classes { for _, c := range test.classes {
ctrl.store.Add(c) ctrl.store.Add(c)
} }

View File

@ -36,6 +36,7 @@ import (
replicationcontroller "k8s.io/kubernetes/pkg/controller/replication" replicationcontroller "k8s.io/kubernetes/pkg/controller/replication"
resourcequotacontroller "k8s.io/kubernetes/pkg/controller/resourcequota" resourcequotacontroller "k8s.io/kubernetes/pkg/controller/resourcequota"
"k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/fields"
kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
quotainstall "k8s.io/kubernetes/pkg/quota/install" quotainstall "k8s.io/kubernetes/pkg/quota/install"
"k8s.io/kubernetes/pkg/runtime/schema" "k8s.io/kubernetes/pkg/runtime/schema"
@ -62,10 +63,11 @@ func TestQuota(t *testing.T) {
admissionCh := make(chan struct{}) admissionCh := make(chan struct{})
clientset := clientset.NewForConfigOrDie(&restclient.Config{QPS: -1, Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &registered.GroupOrDie(v1.GroupName).GroupVersion}}) clientset := clientset.NewForConfigOrDie(&restclient.Config{QPS: -1, Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &registered.GroupOrDie(v1.GroupName).GroupVersion}})
internalClientset := internalclientset.NewForConfigOrDie(&restclient.Config{QPS: -1, Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &registered.GroupOrDie(v1.GroupName).GroupVersion}}) internalClientset := internalclientset.NewForConfigOrDie(&restclient.Config{QPS: -1, Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &registered.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 { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
admission.(kubeadmission.WantsInternalClientSet).SetInternalClientSet(internalClientset)
defer close(admissionCh) defer close(admissionCh)
masterConfig := framework.NewIntegrationTestMasterConfig() masterConfig := framework.NewIntegrationTestMasterConfig()

View File

@ -404,7 +404,8 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie
}) })
// Set up admission plugin to auto-assign serviceaccounts to pods // Set up admission plugin to auto-assign serviceaccounts to pods
serviceAccountAdmission := serviceaccountadmission.NewServiceAccount(internalRootClientset) serviceAccountAdmission := serviceaccountadmission.NewServiceAccount()
serviceAccountAdmission.SetInternalClientSet(internalRootClientset)
masterConfig := framework.NewMasterConfig() masterConfig := framework.NewMasterConfig()
masterConfig.GenericConfig.EnableIndex = true masterConfig.GenericConfig.EnableIndex = true