refactored admission to avoid internal client references

This commit is contained in:
deads2k
2016-12-21 16:16:16 -05:00
parent 834f193b25
commit 2861509b6d
65 changed files with 559 additions and 424 deletions

View File

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

View File

@@ -19,13 +19,11 @@ package admit
import (
"io"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/admission"
)
func init() {
admission.RegisterPlugin("AlwaysAdmit", func(client clientset.Interface, config io.Reader) (admission.Interface, error) {
admission.RegisterPlugin("AlwaysAdmit", func(config io.Reader) (admission.Interface, error) {
return NewAlwaysAdmit(), nil
})
}

View File

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

View File

@@ -27,15 +27,13 @@ package alwayspullimages
import (
"io"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api"
apierrors "k8s.io/kubernetes/pkg/api/errors"
)
func init() {
admission.RegisterPlugin("AlwaysPullImages", func(client clientset.Interface, config io.Reader) (admission.Interface, error) {
admission.RegisterPlugin("AlwaysPullImages", func(config io.Reader) (admission.Interface, error) {
return NewAlwaysPullImages(), nil
})
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -20,13 +20,11 @@ import (
"errors"
"io"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/admission"
)
func init() {
admission.RegisterPlugin("AlwaysDeny", func(client clientset.Interface, config io.Reader) (admission.Interface, error) {
admission.RegisterPlugin("AlwaysDeny", func(config io.Reader) (admission.Interface, error) {
return NewAlwaysDeny(), nil
})
}

View File

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

View File

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

View File

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

View File

@@ -24,12 +24,11 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/auth/authorizer"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/runtime"
)
func init() {
admission.RegisterPlugin("OwnerReferencesPermissionEnforcement", func(client clientset.Interface, config io.Reader) (admission.Interface, error) {
admission.RegisterPlugin("OwnerReferencesPermissionEnforcement", func(config io.Reader) (admission.Interface, error) {
return &gcPermissionsEnforcement{
Handler: admission.NewHandler(admission.Create, admission.Update),
}, nil

View File

@@ -21,7 +21,6 @@ go_library(
"//pkg/api:go_default_library",
"//pkg/api/errors:go_default_library",
"//pkg/apis/imagepolicy/v1alpha1:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/restclient:go_default_library",
"//pkg/runtime/schema:go_default_library",
"//pkg/util/cache:go_default_library",
@@ -46,7 +45,6 @@ go_test(
"//pkg/apis/imagepolicy/install:go_default_library",
"//pkg/apis/imagepolicy/v1alpha1:go_default_library",
"//pkg/auth/user:go_default_library",
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/client/unversioned/clientcmd/api/v1:go_default_library",
],
)

View File

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

View File

@@ -32,7 +32,6 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/imagepolicy/v1alpha1"
"k8s.io/kubernetes/pkg/auth/user"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1"
"fmt"
@@ -244,7 +243,7 @@ current-context: default
}
defer configFile.Close()
_, err = NewImagePolicyWebhook(fake.NewSimpleClientset(), configFile)
_, err = NewImagePolicyWebhook(configFile)
return err
}()
if err != nil && !tt.wantErr {
@@ -404,7 +403,7 @@ func newImagePolicyWebhook(callbackURL string, clientCert, clientKey, ca []byte,
return nil, fmt.Errorf("failed to read test config: %v", err)
}
defer configFile.Close()
wh, err := NewImagePolicyWebhook(fake.NewSimpleClientset(), configFile)
wh, err := NewImagePolicyWebhook(configFile)
return wh.(*imagePolicyWebhook), err
}

View File

@@ -23,7 +23,6 @@ go_library(
"//pkg/api:go_default_library",
"//pkg/api/errors:go_default_library",
"//pkg/api/resource:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/restclient:go_default_library",
"//pkg/client/unversioned/clientcmd:go_default_library",
"//vendor:cloud.google.com/go/compute/metadata",

View File

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

View File

@@ -23,6 +23,7 @@ go_library(
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/listers/core/internalversion:go_default_library",
"//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/labels:go_default_library",
"//pkg/runtime:go_default_library",
"//pkg/util/errors:go_default_library",
@@ -44,6 +45,7 @@ go_test(
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/client/testing/core:go_default_library",
"//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/runtime:go_default_library",
"//pkg/util/wait:go_default_library",
],

View File

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

View File

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

View File

@@ -19,6 +19,7 @@ go_library(
"//pkg/client/cache:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
],
)
@@ -36,6 +37,7 @@ go_test(
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/client/testing/core:go_default_library",
"//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/runtime:go_default_library",
"//pkg/util/wait:go_default_library",
],

View File

@@ -17,22 +17,21 @@ limitations under the License.
package autoprovision
import (
"io"
"k8s.io/kubernetes/pkg/client/cache"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"fmt"
"io"
"k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/client/cache"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/controller/informers"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
)
func init() {
admission.RegisterPlugin("NamespaceAutoProvision", func(client clientset.Interface, config io.Reader) (admission.Interface, error) {
return NewProvision(client), nil
admission.RegisterPlugin("NamespaceAutoProvision", func(config io.Reader) (admission.Interface, error) {
return NewProvision(), nil
})
}
@@ -41,11 +40,12 @@ func init() {
// It is useful in deployments that do not want to restrict creation of a namespace prior to its usage.
type provision struct {
*admission.Handler
client clientset.Interface
client internalclientset.Interface
namespaceInformer cache.SharedIndexInformer
}
var _ = admission.WantsInformerFactory(&provision{})
var _ = kubeapiserveradmission.WantsInformerFactory(&provision{})
var _ = kubeapiserveradmission.WantsInformerFactory(&provision{})
func (p *provision) Admit(a admission.Attributes) (err error) {
// if we're here, then we've already passed authentication, so we're allowed to do what we're trying to do
@@ -80,13 +80,16 @@ func (p *provision) Admit(a admission.Attributes) (err error) {
}
// NewProvision creates a new namespace provision admission control handler
func NewProvision(c clientset.Interface) admission.Interface {
func NewProvision() admission.Interface {
return &provision{
Handler: admission.NewHandler(admission.Create),
client: c,
}
}
func (p *provision) SetInternalClientSet(client internalclientset.Interface) {
p.client = client
}
func (p *provision) SetInformerFactory(f informers.SharedInformerFactory) {
p.namespaceInformer = f.InternalNamespaces().Informer()
p.SetReadyFunc(p.namespaceInformer.HasSynced)
@@ -96,5 +99,8 @@ func (p *provision) Validate() error {
if p.namespaceInformer == nil {
return fmt.Errorf("missing namespaceInformer")
}
if p.client == nil {
return fmt.Errorf("missing client")
}
return nil
}

View File

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

View File

@@ -20,6 +20,7 @@ go_library(
"//pkg/client/cache:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
],
)
@@ -36,6 +37,7 @@ go_test(
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/client/testing/core:go_default_library",
"//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/runtime:go_default_library",
"//pkg/util/wait:go_default_library",
],

View File

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

View File

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

View File

@@ -20,6 +20,7 @@ go_library(
"//pkg/client/cache:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/util/cache:go_default_library",
"//pkg/util/clock:go_default_library",
"//pkg/util/sets:go_default_library",
@@ -40,6 +41,7 @@ go_test(
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/client/testing/core:go_default_library",
"//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/runtime:go_default_library",
"//pkg/util/clock:go_default_library",
"//pkg/util/sets:go_default_library",

View File

@@ -23,14 +23,14 @@ import (
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/client/cache"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/controller/informers"
"k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/client/cache"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/controller/informers"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
utilcache "k8s.io/kubernetes/pkg/util/cache"
"k8s.io/kubernetes/pkg/util/clock"
"k8s.io/kubernetes/pkg/util/sets"
@@ -50,8 +50,8 @@ const (
)
func init() {
admission.RegisterPlugin(PluginName, func(client clientset.Interface, config io.Reader) (admission.Interface, error) {
return NewLifecycle(client, sets.NewString(api.NamespaceDefault, api.NamespaceSystem))
admission.RegisterPlugin(PluginName, func(config io.Reader) (admission.Interface, error) {
return NewLifecycle(sets.NewString(api.NamespaceDefault, api.NamespaceSystem))
})
}
@@ -59,7 +59,7 @@ func init() {
// It enforces life-cycle constraints around a Namespace depending on its Phase
type lifecycle struct {
*admission.Handler
client clientset.Interface
client internalclientset.Interface
immortalNamespaces sets.String
namespaceInformer cache.SharedIndexInformer
// forceLiveLookupCache holds a list of entries for namespaces that we have a strong reason to believe are stale in our local cache.
@@ -71,7 +71,8 @@ type forceLiveLookupEntry struct {
expiry time.Time
}
var _ = admission.WantsInformerFactory(&lifecycle{})
var _ = kubeapiserveradmission.WantsInformerFactory(&lifecycle{})
var _ = kubeapiserveradmission.WantsInternalClientSet(&lifecycle{})
func makeNamespaceKey(namespace string) *api.Namespace {
return &api.Namespace{
@@ -167,15 +168,14 @@ func (l *lifecycle) Admit(a admission.Attributes) error {
}
// NewLifecycle creates a new namespace lifecycle admission control handler
func NewLifecycle(c clientset.Interface, immortalNamespaces sets.String) (admission.Interface, error) {
return newLifecycleWithClock(c, immortalNamespaces, clock.RealClock{})
func NewLifecycle(immortalNamespaces sets.String) (admission.Interface, error) {
return newLifecycleWithClock(immortalNamespaces, clock.RealClock{})
}
func newLifecycleWithClock(c clientset.Interface, immortalNamespaces sets.String, clock utilcache.Clock) (admission.Interface, error) {
func newLifecycleWithClock(immortalNamespaces sets.String, clock utilcache.Clock) (admission.Interface, error) {
forceLiveLookupCache := utilcache.NewLRUExpireCacheWithClock(100, clock)
return &lifecycle{
Handler: admission.NewHandler(admission.Create, admission.Update, admission.Delete),
client: c,
immortalNamespaces: immortalNamespaces,
forceLiveLookupCache: forceLiveLookupCache,
}, nil
@@ -186,9 +186,16 @@ func (l *lifecycle) SetInformerFactory(f informers.SharedInformerFactory) {
l.SetReadyFunc(l.namespaceInformer.HasSynced)
}
func (l *lifecycle) SetInternalClientSet(client internalclientset.Interface) {
l.client = client
}
func (l *lifecycle) Validate() error {
if l.namespaceInformer == nil {
return fmt.Errorf("missing namespaceInformer")
}
if l.client == nil {
return fmt.Errorf("missing client")
}
return nil
}

View File

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

View File

@@ -19,7 +19,6 @@ go_library(
"//pkg/admission:go_default_library",
"//pkg/api:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/cloudprovider:go_default_library",
"//pkg/cloudprovider/providers/aws:go_default_library",
"//pkg/cloudprovider/providers/gce:go_default_library",

View File

@@ -21,8 +21,6 @@ import (
"io"
"sync"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api"
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
@@ -33,7 +31,7 @@ import (
)
func init() {
admission.RegisterPlugin("PersistentVolumeLabel", func(client clientset.Interface, config io.Reader) (admission.Interface, error) {
admission.RegisterPlugin("PersistentVolumeLabel", func(config io.Reader) (admission.Interface, error) {
persistentVolumeLabelAdmission := NewPersistentVolumeLabel()
return persistentVolumeLabelAdmission, nil
})

View File

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

View File

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

View File

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

View File

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

View File

@@ -17,24 +17,25 @@ limitations under the License.
package resourcequota
import (
"fmt"
"io"
"time"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
"k8s.io/kubernetes/pkg/quota"
"k8s.io/kubernetes/pkg/quota/install"
)
func init() {
admission.RegisterPlugin("ResourceQuota",
func(client clientset.Interface, config io.Reader) (admission.Interface, error) {
func(config io.Reader) (admission.Interface, error) {
// NOTE: we do not provide informers to the registry because admission level decisions
// does not require us to open watches for all items tracked by quota.
registry := install.NewRegistry(nil, nil)
return NewResourceQuota(client, registry, 5, make(chan struct{}))
return NewResourceQuota(registry, 5, make(chan struct{}))
})
}
@@ -42,9 +43,14 @@ func init() {
type quotaAdmission struct {
*admission.Handler
evaluator Evaluator
stopCh <-chan struct{}
registry quota.Registry
numEvaluators int
evaluator Evaluator
}
var _ = kubeapiserveradmission.WantsInternalClientSet(&quotaAdmission{})
type liveLookupEntry struct {
expiry time.Time
items []*api.ResourceQuota
@@ -53,19 +59,33 @@ type liveLookupEntry struct {
// NewResourceQuota configures an admission controller that can enforce quota constraints
// using the provided registry. The registry must have the capability to handle group/kinds that
// are persisted by the server this admission controller is intercepting
func NewResourceQuota(client clientset.Interface, registry quota.Registry, numEvaluators int, stopCh <-chan struct{}) (admission.Interface, error) {
func NewResourceQuota(registry quota.Registry, numEvaluators int, stopCh <-chan struct{}) (admission.Interface, error) {
return &quotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update),
stopCh: stopCh,
registry: registry,
numEvaluators: numEvaluators,
}, nil
}
func (a *quotaAdmission) SetInternalClientSet(client internalclientset.Interface) {
var err error
quotaAccessor, err := newQuotaAccessor(client)
if err != nil {
return nil, err
// TODO handle errors more cleanly
panic(err)
}
go quotaAccessor.Run(stopCh)
go quotaAccessor.Run(a.stopCh)
evaluator := NewQuotaEvaluator(quotaAccessor, registry, nil, numEvaluators, stopCh)
a.evaluator = NewQuotaEvaluator(quotaAccessor, a.registry, nil, a.numEvaluators, a.stopCh)
}
return &quotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator,
}, nil
// Validate ensures an authorizer is set.
func (a *quotaAdmission) Validate() error {
if a.evaluator == nil {
return fmt.Errorf("missing evaluator")
}
return nil
}
// Admit makes admission decisions while enforcing quota

View File

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

View File

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

View File

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

View File

@@ -30,8 +30,6 @@ import (
"k8s.io/kubernetes/pkg/auth/authorizer"
"k8s.io/kubernetes/pkg/auth/user"
"k8s.io/kubernetes/pkg/client/cache"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
clientsetfake "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/security/apparmor"
kpsp "k8s.io/kubernetes/pkg/security/podsecuritypolicy"
"k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp"
@@ -44,10 +42,9 @@ const defaultContainerName = "test-c"
// NewTestAdmission provides an admission plugin with test implementations of internal structs. It uses
// an authorizer that always returns true.
func NewTestAdmission(store cache.Store, kclient clientset.Interface) kadmission.Interface {
func NewTestAdmission(store cache.Store) kadmission.Interface {
return &podSecurityPolicyPlugin{
Handler: kadmission.NewHandler(kadmission.Create),
client: kclient,
store: store,
strategyFactory: kpsp.NewSimpleStrategyFactory(),
pspMatcher: getMatchingPolicies,
@@ -1339,16 +1336,13 @@ func TestAdmitSysctls(t *testing.T) {
}
func testPSPAdmit(testCaseName string, psps []*extensions.PodSecurityPolicy, pod *kapi.Pod, shouldPass bool, expectedPSP string, t *testing.T) {
namespace := createNamespaceForTest()
serviceAccount := createSAForTest()
tc := clientsetfake.NewSimpleClientset(namespace, serviceAccount)
store := cache.NewStore(cache.MetaNamespaceKeyFunc)
for _, psp := range psps {
store.Add(psp)
}
plugin := NewTestAdmission(store, tc)
plugin := NewTestAdmission(store)
attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), "namespace", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{})
err := plugin.Admit(attrs)
@@ -1512,10 +1506,8 @@ func TestCreateProvidersFromConstraints(t *testing.T) {
for k, v := range testCases {
store := cache.NewStore(cache.MetaNamespaceKeyFunc)
tc := clientsetfake.NewSimpleClientset()
admit := &podSecurityPolicyPlugin{
Handler: kadmission.NewHandler(kadmission.Create, kadmission.Update),
client: tc,
store: store,
strategyFactory: kpsp.NewSimpleStrategyFactory(),
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -23,18 +23,18 @@ import (
"strconv"
"time"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/v1"
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/client/cache"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/fields"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
kubelet "k8s.io/kubernetes/pkg/kubelet/types"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/serviceaccount"
"k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/watch"
@@ -55,9 +55,8 @@ const DefaultAPITokenMountPath = "/var/run/secrets/kubernetes.io/serviceaccount"
const PluginName = "ServiceAccount"
func init() {
admission.RegisterPlugin(PluginName, func(client clientset.Interface, config io.Reader) (admission.Interface, error) {
serviceAccountAdmission := NewServiceAccount(client)
serviceAccountAdmission.Run()
admission.RegisterPlugin(PluginName, func(config io.Reader) (admission.Interface, error) {
serviceAccountAdmission := NewServiceAccount()
return serviceAccountAdmission, nil
})
}
@@ -74,7 +73,7 @@ type serviceAccount struct {
// MountServiceAccountToken creates Volume and VolumeMounts for the first referenced ServiceAccountToken for the pod's service account
MountServiceAccountToken bool
client clientset.Interface
client internalclientset.Interface
serviceAccounts cache.Indexer
secrets cache.Indexer
@@ -84,14 +83,29 @@ type serviceAccount struct {
secretsReflector *cache.Reflector
}
var _ = kubeapiserveradmission.WantsInternalClientSet(&serviceAccount{})
// NewServiceAccount returns an admission.Interface implementation which limits admission of Pod CREATE requests based on the pod's ServiceAccount:
// 1. If the pod does not specify a ServiceAccount, it sets the pod's ServiceAccount to "default"
// 2. It ensures the ServiceAccount referenced by the pod exists
// 3. If LimitSecretReferences is true, it rejects the pod if the pod references Secret objects which the pod's ServiceAccount does not reference
// 4. If the pod does not contain any ImagePullSecrets, the ImagePullSecrets of the service account are added.
// 5. If MountServiceAccountToken is true, it adds a VolumeMount with the pod's ServiceAccount's api token secret to containers
func NewServiceAccount(cl clientset.Interface) *serviceAccount {
serviceAccountsIndexer, serviceAccountsReflector := cache.NewNamespaceKeyedIndexerAndReflector(
func NewServiceAccount() *serviceAccount {
return &serviceAccount{
Handler: admission.NewHandler(admission.Create),
// TODO: enable this once we've swept secret usage to account for adding secret references to service accounts
LimitSecretReferences: false,
// Auto mount service account API token secrets
MountServiceAccountToken: true,
// Reject pod creation until a service account token is available
RequireAPIToken: true,
}
}
func (a *serviceAccount) SetInternalClientSet(cl internalclientset.Interface) {
a.client = cl
a.serviceAccounts, a.serviceAccountsReflector = cache.NewNamespaceKeyedIndexerAndReflector(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
internalOptions := api.ListOptions{}
@@ -109,7 +123,7 @@ func NewServiceAccount(cl clientset.Interface) *serviceAccount {
)
tokenSelector := fields.SelectorFromSet(map[string]string{api.SecretTypeField: string(api.SecretTypeServiceAccountToken)})
secretsIndexer, secretsReflector := cache.NewNamespaceKeyedIndexerAndReflector(
a.secrets, a.secretsReflector = cache.NewNamespaceKeyedIndexerAndReflector(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
internalOptions := api.ListOptions{}
@@ -128,23 +142,31 @@ func NewServiceAccount(cl clientset.Interface) *serviceAccount {
0,
)
return &serviceAccount{
Handler: admission.NewHandler(admission.Create),
// TODO: enable this once we've swept secret usage to account for adding secret references to service accounts
LimitSecretReferences: false,
// Auto mount service account API token secrets
MountServiceAccountToken: true,
// Reject pod creation until a service account token is available
RequireAPIToken: true,
client: cl,
serviceAccounts: serviceAccountsIndexer,
serviceAccountsReflector: serviceAccountsReflector,
secrets: secretsIndexer,
secretsReflector: secretsReflector,
if cl != nil {
a.Run()
}
}
// Validate ensures an authorizer is set.
func (a *serviceAccount) Validate() error {
if a.client == nil {
return fmt.Errorf("missing client")
}
if a.secrets == nil {
return fmt.Errorf("missing secretsIndexer")
}
if a.secretsReflector == nil {
return fmt.Errorf("missing secretsReflector")
}
if a.serviceAccounts == nil {
return fmt.Errorf("missing serviceAccountsIndexer")
}
if a.serviceAccountsReflector == nil {
return fmt.Errorf("missing serviceAccountsReflector")
}
return nil
}
func (s *serviceAccount) Run() {
if s.stopChan == nil {
s.stopChan = make(chan struct{})

View File

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

View File

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

View File

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

View File

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