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