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