Merge pull request #54485 from sttts/sttts-unify-admission-constructors

Automatic merge from submit-queue (batch tested with PRs 54761, 54748, 53991, 54485, 46951). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

admission: unify plugin constructors

It's common in Go to return the actual object in constructors, not **one interface**
it implements. This allows us to implement multiple interfaces, but only have
one constructor. As having private types in constructors, we export all plugin structs, of course with private fields.

Note: super interfaces do not work if there are overlapping methods.
This commit is contained in:
Kubernetes Submit Queue 2017-10-30 15:38:33 -07:00 committed by GitHub
commit 7a944a69d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 203 additions and 169 deletions

View File

@ -29,19 +29,22 @@ func Register(plugins *admission.Plugins) {
}) })
} }
// alwaysAdmit is an implementation of admission.Interface which always says yes to an admit request. // AlwaysAdmit is an implementation of admission.Interface which always says yes to an admit request.
// It is useful in tests and when using kubernetes in an open manner. // It is useful in tests and when using kubernetes in an open manner.
type alwaysAdmit struct{} type AlwaysAdmit struct{}
func (alwaysAdmit) Admit(a admission.Attributes) (err error) { // Admit makes an admission decision based on the request attributes
func (AlwaysAdmit) Admit(a admission.Attributes) (err error) {
return nil return nil
} }
func (alwaysAdmit) Handles(operation admission.Operation) bool { // Handles returns true if this admission controller can handle the given operation
// where operation can be one of CREATE, UPDATE, DELETE, or CONNECT
func (AlwaysAdmit) Handles(operation admission.Operation) bool {
return true return true
} }
// NewAlwaysAdmit creates a new always admit admission handler // NewAlwaysAdmit creates a new always admit admission handler
func NewAlwaysAdmit() admission.Interface { func NewAlwaysAdmit() *AlwaysAdmit {
return new(alwaysAdmit) return new(AlwaysAdmit)
} }

View File

@ -39,13 +39,14 @@ func Register(plugins *admission.Plugins) {
}) })
} }
// alwaysPullImages is an implementation of admission.Interface. // AlwaysPullImages is an implementation of admission.Interface.
// It looks at all new pods and overrides each container's image pull policy to Always. // It looks at all new pods and overrides each container's image pull policy to Always.
type alwaysPullImages struct { type AlwaysPullImages struct {
*admission.Handler *admission.Handler
} }
func (a *alwaysPullImages) Admit(attributes admission.Attributes) (err error) { // Admit makes an admission decision based on the request attributes
func (a *AlwaysPullImages) Admit(attributes admission.Attributes) (err error) {
// Ignore all calls to subresources or resources other than pods. // Ignore all calls to subresources or resources other than pods.
if len(attributes.GetSubresource()) != 0 || attributes.GetResource().GroupResource() != api.Resource("pods") { if len(attributes.GetSubresource()) != 0 || attributes.GetResource().GroupResource() != api.Resource("pods") {
return nil return nil
@ -67,8 +68,8 @@ func (a *alwaysPullImages) Admit(attributes admission.Attributes) (err error) {
} }
// NewAlwaysPullImages creates a new always pull images admission control handler // NewAlwaysPullImages creates a new always pull images admission control handler
func NewAlwaysPullImages() admission.Interface { func NewAlwaysPullImages() *AlwaysPullImages {
return &alwaysPullImages{ return &AlwaysPullImages{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
} }
} }

View File

@ -29,7 +29,7 @@ import (
// set to Always // set to Always
func TestAdmission(t *testing.T) { func TestAdmission(t *testing.T) {
namespace := "test" namespace := "test"
handler := &alwaysPullImages{} handler := &AlwaysPullImages{}
pod := api.Pod{ pod := api.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: namespace}, ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: namespace},
Spec: api.PodSpec{ Spec: api.PodSpec{
@ -107,7 +107,7 @@ func TestOtherResources(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
handler := &alwaysPullImages{} handler := &AlwaysPullImages{}
err := handler.Admit(admission.NewAttributesRecord(tc.object, nil, api.Kind(tc.kind).WithVersion("version"), namespace, name, api.Resource(tc.resource).WithVersion("version"), tc.subresource, admission.Create, nil)) err := handler.Admit(admission.NewAttributesRecord(tc.object, nil, api.Kind(tc.kind).WithVersion("version"), namespace, name, api.Resource(tc.resource).WithVersion("version"), tc.subresource, admission.Create, nil))

View File

@ -33,21 +33,21 @@ func Register(plugins *admission.Plugins) {
}) })
} }
// 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
} }
// NewInterPodAntiAffinity creates a new instance of the LimitPodHardAntiAffinityTopology admission controller // NewInterPodAntiAffinity creates a new instance of the LimitPodHardAntiAffinityTopology admission controller
func NewInterPodAntiAffinity() admission.Interface { func NewInterPodAntiAffinity() *Plugin {
return &plugin{ return &Plugin{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
} }
} }
// Admit will deny any pod that defines AntiAffinity topology key other than kubeletapis.LabelHostname i.e. "kubernetes.io/hostname" // Admit will deny any pod that defines AntiAffinity topology key other than kubeletapis.LabelHostname i.e. "kubernetes.io/hostname"
// in requiredDuringSchedulingRequiredDuringExecution and requiredDuringSchedulingIgnoredDuringExecution. // in requiredDuringSchedulingRequiredDuringExecution and requiredDuringSchedulingIgnoredDuringExecution.
func (p *plugin) Admit(attributes admission.Attributes) (err error) { func (p *Plugin) Admit(attributes admission.Attributes) (err error) {
// Ignore all calls to subresources or resources other than pods. // Ignore all calls to subresources or resources other than pods.
if len(attributes.GetSubresource()) != 0 || attributes.GetResource().GroupResource() != api.Resource("pods") { if len(attributes.GetSubresource()) != 0 || attributes.GetResource().GroupResource() != api.Resource("pods") {
return nil return nil

View File

@ -265,7 +265,7 @@ func TestOtherResources(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
handler := &plugin{} handler := &Plugin{}
err := handler.Admit(admission.NewAttributesRecord(tc.object, nil, api.Kind(tc.kind).WithVersion("version"), namespace, name, api.Resource(tc.resource).WithVersion("version"), tc.subresource, admission.Create, nil)) err := handler.Admit(admission.NewAttributesRecord(tc.object, nil, api.Kind(tc.kind).WithVersion("version"), namespace, name, api.Resource(tc.resource).WithVersion("version"), tc.subresource, admission.Create, nil))

View File

@ -45,24 +45,25 @@ func Register(plugins *admission.Plugins) {
}) })
} }
// plugin contains the client used by the admission controller // Plugin contains the client used by the admission controller
// It will add default tolerations for every pod // It will add default tolerations for every pod
// that tolerate taints `notReady:NoExecute` and `unreachable:NoExecute`, // that tolerate taints `notReady:NoExecute` and `unreachable:NoExecute`,
// with tolerationSeconds of 300s. // with tolerationSeconds of 300s.
// If the pod already specifies a toleration for taint `notReady:NoExecute` // If the pod already specifies a toleration for taint `notReady:NoExecute`
// or `unreachable:NoExecute`, the plugin won't touch it. // or `unreachable:NoExecute`, the plugin won't touch it.
type plugin struct { type Plugin struct {
*admission.Handler *admission.Handler
} }
// NewDefaultTolerationSeconds creates a new instance of the DefaultTolerationSeconds admission controller // NewDefaultTolerationSeconds creates a new instance of the DefaultTolerationSeconds admission controller
func NewDefaultTolerationSeconds() admission.Interface { func NewDefaultTolerationSeconds() *Plugin {
return &plugin{ return &Plugin{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
} }
} }
func (p *plugin) Admit(attributes admission.Attributes) (err error) { // Admit makes an admission decision based on the request attributes
func (p *Plugin) Admit(attributes admission.Attributes) (err error) {
if attributes.GetResource().GroupResource() != api.Resource("pods") { if attributes.GetResource().GroupResource() != api.Resource("pods") {
return nil return nil
} }

View File

@ -30,19 +30,22 @@ func Register(plugins *admission.Plugins) {
}) })
} }
// alwaysDeny is an implementation of admission.Interface which always says no to an admission request. // AlwaysDeny is an implementation of admission.Interface which always says no to an admission request.
// It is useful in unit tests to force an operation to be forbidden. // It is useful in unit tests to force an operation to be forbidden.
type alwaysDeny struct{} type AlwaysDeny struct{}
func (alwaysDeny) Admit(a admission.Attributes) (err error) { // Admit makes an admission decision based on the request attributes.
func (AlwaysDeny) Admit(a admission.Attributes) (err error) {
return admission.NewForbidden(a, errors.New("Admission control is denying all modifications")) return admission.NewForbidden(a, errors.New("Admission control is denying all modifications"))
} }
func (alwaysDeny) Handles(operation admission.Operation) bool { // Handles returns true if this admission controller can handle the given operation
// where operation can be one of CREATE, UPDATE, DELETE, or CONNECT
func (AlwaysDeny) Handles(operation admission.Operation) bool {
return true return true
} }
// NewAlwaysDeny creates an always deny admission handler // NewAlwaysDeny creates an always deny admission handler
func NewAlwaysDeny() admission.Interface { func NewAlwaysDeny() *AlwaysDeny {
return new(alwaysDeny) return new(AlwaysDeny)
} }

View File

@ -45,8 +45,8 @@ func Register(plugins *admission.Plugins) {
}) })
} }
// eventRateLimitAdmission implements an admission controller that can enforce event rate limits // Plugin implements an admission controller that can enforce event rate limits
type eventRateLimitAdmission struct { type Plugin struct {
*admission.Handler *admission.Handler
// limitEnforcers is the collection of limit enforcers. There is one limit enforcer for each // limitEnforcers is the collection of limit enforcers. There is one limit enforcer for each
// active limit type. As there are 4 limit types, the length of the array will be at most 4. // active limit type. As there are 4 limit types, the length of the array will be at most 4.
@ -55,7 +55,7 @@ type eventRateLimitAdmission struct {
} }
// newEventRateLimit configures an admission controller that can enforce event rate limits // newEventRateLimit configures an admission controller that can enforce event rate limits
func newEventRateLimit(config *eventratelimitapi.Configuration, clock flowcontrol.Clock) (admission.Interface, error) { func newEventRateLimit(config *eventratelimitapi.Configuration, clock flowcontrol.Clock) (*Plugin, error) {
limitEnforcers := make([]*limitEnforcer, 0, len(config.Limits)) limitEnforcers := make([]*limitEnforcer, 0, len(config.Limits))
for _, limitConfig := range config.Limits { for _, limitConfig := range config.Limits {
enforcer, err := newLimitEnforcer(limitConfig, clock) enforcer, err := newLimitEnforcer(limitConfig, clock)
@ -65,7 +65,7 @@ func newEventRateLimit(config *eventratelimitapi.Configuration, clock flowcontro
limitEnforcers = append(limitEnforcers, enforcer) limitEnforcers = append(limitEnforcers, enforcer)
} }
eventRateLimitAdmission := &eventRateLimitAdmission{ eventRateLimitAdmission := &Plugin{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
limitEnforcers: limitEnforcers, limitEnforcers: limitEnforcers,
} }
@ -74,7 +74,7 @@ func newEventRateLimit(config *eventratelimitapi.Configuration, clock flowcontro
} }
// Admit makes admission decisions while enforcing event rate limits // Admit makes admission decisions while enforcing event rate limits
func (a *eventRateLimitAdmission) Admit(attr admission.Attributes) (err error) { func (a *Plugin) Admit(attr admission.Attributes) (err error) {
// ignore all operations that do not correspond to an Event kind // ignore all operations that do not correspond to an Event kind
if attr.GetKind().GroupKind() != api.Kind("Event") { if attr.GetKind().GroupKind() != api.Kind("Event") {
return nil return nil

View File

@ -42,9 +42,9 @@ func Register(plugins *admission.Plugins) {
}) })
} }
// denyExec is an implementation of admission.Interface which says no to a pod/exec on // DenyExec is an implementation of admission.Interface which says no to a pod/exec on
// a pod using host based configurations. // a pod using host based configurations.
type denyExec struct { type DenyExec struct {
*admission.Handler *admission.Handler
client internalclientset.Interface client internalclientset.Interface
@ -54,12 +54,12 @@ type denyExec struct {
privileged bool privileged bool
} }
var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&denyExec{}) var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&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() admission.Interface { func NewDenyEscalatingExec() *DenyExec {
return &denyExec{ return &DenyExec{
Handler: admission.NewHandler(admission.Connect), Handler: admission.NewHandler(admission.Connect),
hostIPC: true, hostIPC: true,
hostPID: true, hostPID: true,
@ -70,8 +70,8 @@ func NewDenyEscalatingExec() 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() admission.Interface { func NewDenyExecOnPrivileged() *DenyExec {
return &denyExec{ return &DenyExec{
Handler: admission.NewHandler(admission.Connect), Handler: admission.NewHandler(admission.Connect),
hostIPC: false, hostIPC: false,
hostPID: false, hostPID: false,
@ -79,7 +79,8 @@ func NewDenyExecOnPrivileged() admission.Interface {
} }
} }
func (d *denyExec) Admit(a admission.Attributes) (err error) { // Admit makes an admission decision based on the request attributes
func (d *DenyExec) Admit(a admission.Attributes) (err error) {
connectRequest, ok := a.GetObject().(*rest.ConnectRequest) connectRequest, ok := a.GetObject().(*rest.ConnectRequest)
if !ok { if !ok {
return errors.NewBadRequest("a connect request was received, but could not convert the request object.") return errors.NewBadRequest("a connect request was received, but could not convert the request object.")
@ -129,11 +130,13 @@ func isPrivileged(pod *api.Pod) bool {
return false return false
} }
func (d *denyExec) SetInternalKubeClientSet(client internalclientset.Interface) { // SetInternalKubeClientSet implements the WantsInternalKubeClientSet interface.
func (d *DenyExec) SetInternalKubeClientSet(client internalclientset.Interface) {
d.client = client d.client = client
} }
func (d *denyExec) Validate() error { // Validate implements the Validator interface.
func (d *DenyExec) Validate() error {
if d.client == nil { if d.client == nil {
return fmt.Errorf("missing client") return fmt.Errorf("missing client")
} }

View File

@ -30,8 +30,8 @@ import (
// newAllowEscalatingExec returns `admission.Interface` that allows execution on // newAllowEscalatingExec returns `admission.Interface` that allows execution on
// "hostIPC", "hostPID" and "privileged". // "hostIPC", "hostPID" and "privileged".
func newAllowEscalatingExec() admission.Interface { func newAllowEscalatingExec() *DenyExec {
return &denyExec{ return &DenyExec{
Handler: admission.NewHandler(admission.Connect), Handler: admission.NewHandler(admission.Connect),
hostIPC: false, hostIPC: false,
hostPID: false, hostPID: false,
@ -77,21 +77,21 @@ func TestAdmission(t *testing.T) {
} }
// Get the direct object though to allow testAdmission to inject the client // Get the direct object though to allow testAdmission to inject the client
handler := NewDenyEscalatingExec().(*denyExec) handler := NewDenyEscalatingExec()
for _, tc := range testCases { for _, tc := range testCases {
testAdmission(t, tc.pod, handler, tc.shouldAccept) testAdmission(t, tc.pod, handler, tc.shouldAccept)
} }
// run with a permissive config and all cases should pass // run with a permissive config and all cases should pass
handler = newAllowEscalatingExec().(*denyExec) handler = newAllowEscalatingExec()
for _, tc := range testCases { for _, tc := range testCases {
testAdmission(t, tc.pod, handler, true) testAdmission(t, tc.pod, handler, true)
} }
// run against an init container // run against an init container
handler = NewDenyEscalatingExec().(*denyExec) handler = NewDenyEscalatingExec()
for _, tc := range testCases { for _, tc := range testCases {
tc.pod.Spec.InitContainers = tc.pod.Spec.Containers tc.pod.Spec.InitContainers = tc.pod.Spec.Containers
@ -100,14 +100,14 @@ func TestAdmission(t *testing.T) {
} }
// run with a permissive config and all cases should pass // run with a permissive config and all cases should pass
handler = newAllowEscalatingExec().(*denyExec) handler = newAllowEscalatingExec()
for _, tc := range testCases { for _, tc := range testCases {
testAdmission(t, tc.pod, handler, true) testAdmission(t, tc.pod, handler, true)
} }
} }
func testAdmission(t *testing.T, pod *api.Pod, handler *denyExec, shouldAccept bool) { func testAdmission(t *testing.T, pod *api.Pod, handler *DenyExec, shouldAccept bool) {
mockClient := &fake.Clientset{} mockClient := &fake.Clientset{}
mockClient.AddReactor("get", "pods", func(action core.Action) (bool, runtime.Object, error) { mockClient.AddReactor("get", "pods", func(action core.Action) (bool, runtime.Object, error) {
if action.(core.GetAction).GetName() == pod.Name { if action.(core.GetAction).GetName() == pod.Name {
@ -184,7 +184,7 @@ func TestDenyExecOnPrivileged(t *testing.T) {
} }
// Get the direct object though to allow testAdmission to inject the client // Get the direct object though to allow testAdmission to inject the client
handler := NewDenyExecOnPrivileged().(*denyExec) handler := NewDenyExecOnPrivileged()
for _, tc := range testCases { for _, tc := range testCases {
testAdmission(t, tc.pod, handler, tc.shouldAccept) testAdmission(t, tc.pod, handler, tc.shouldAccept)

View File

@ -58,8 +58,8 @@ func Register(plugins *admission.Plugins) {
}) })
} }
// imagePolicyWebhook is an implementation of admission.Interface. // Plugin is an implementation of admission.Interface.
type imagePolicyWebhook struct { type Plugin struct {
*admission.Handler *admission.Handler
webhook *webhook.GenericWebhook webhook *webhook.GenericWebhook
responseCache *cache.LRUExpireCache responseCache *cache.LRUExpireCache
@ -69,7 +69,7 @@ type imagePolicyWebhook struct {
defaultAllow bool defaultAllow bool
} }
func (a *imagePolicyWebhook) statusTTL(status v1alpha1.ImageReviewStatus) time.Duration { func (a *Plugin) statusTTL(status v1alpha1.ImageReviewStatus) time.Duration {
if status.Allowed { if status.Allowed {
return a.allowTTL return a.allowTTL
} }
@ -77,7 +77,7 @@ func (a *imagePolicyWebhook) statusTTL(status v1alpha1.ImageReviewStatus) time.D
} }
// Filter out annotations that don't match *.image-policy.k8s.io/* // Filter out annotations that don't match *.image-policy.k8s.io/*
func (a *imagePolicyWebhook) filterAnnotations(allAnnotations map[string]string) map[string]string { func (a *Plugin) filterAnnotations(allAnnotations map[string]string) map[string]string {
annotations := make(map[string]string) annotations := make(map[string]string)
for k, v := range allAnnotations { for k, v := range allAnnotations {
if strings.Contains(k, ".image-policy.k8s.io/") { if strings.Contains(k, ".image-policy.k8s.io/") {
@ -88,7 +88,7 @@ func (a *imagePolicyWebhook) filterAnnotations(allAnnotations map[string]string)
} }
// Function to call on webhook failure; behavior determined by defaultAllow flag // Function to call on webhook failure; behavior determined by defaultAllow flag
func (a *imagePolicyWebhook) webhookError(pod *api.Pod, attributes admission.Attributes, err error) error { func (a *Plugin) webhookError(pod *api.Pod, attributes admission.Attributes, err error) error {
if err != nil { if err != nil {
glog.V(2).Infof("error contacting webhook backend: %s", err) glog.V(2).Infof("error contacting webhook backend: %s", err)
if a.defaultAllow { if a.defaultAllow {
@ -107,7 +107,8 @@ func (a *imagePolicyWebhook) webhookError(pod *api.Pod, attributes admission.Att
return nil return nil
} }
func (a *imagePolicyWebhook) Admit(attributes admission.Attributes) (err error) { // Admit makes an admission decision based on the request attributes
func (a *Plugin) Admit(attributes admission.Attributes) (err error) {
// Ignore all calls to subresources or resources other than pods. // Ignore all calls to subresources or resources other than pods.
if attributes.GetSubresource() != "" || attributes.GetResource().GroupResource() != api.Resource("pods") { if attributes.GetSubresource() != "" || attributes.GetResource().GroupResource() != api.Resource("pods") {
return nil return nil
@ -141,7 +142,7 @@ func (a *imagePolicyWebhook) Admit(attributes admission.Attributes) (err error)
return nil return nil
} }
func (a *imagePolicyWebhook) admitPod(pod *api.Pod, attributes admission.Attributes, review *v1alpha1.ImageReview) error { func (a *Plugin) admitPod(pod *api.Pod, attributes admission.Attributes, review *v1alpha1.ImageReview) error {
cacheKey, err := json.Marshal(review.Spec) cacheKey, err := json.Marshal(review.Spec)
if err != nil { if err != nil {
return err return err
@ -178,7 +179,7 @@ func (a *imagePolicyWebhook) admitPod(pod *api.Pod, attributes admission.Attribu
return nil return nil
} }
// NewImagePolicyWebhook a new imagePolicyWebhook from the provided config file. // NewImagePolicyWebhook a new ImagePolicyWebhook plugin from the provided config file.
// The config file is specified by --admission-control-config-file and has the // The config file is specified by --admission-control-config-file and has the
// following format for a webhook: // following format for a webhook:
// //
@ -215,7 +216,7 @@ func (a *imagePolicyWebhook) admitPod(pod *api.Pod, attributes admission.Attribu
// //
// 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(configFile io.Reader) (admission.Interface, error) { func NewImagePolicyWebhook(configFile io.Reader) (*Plugin, error) {
// TODO: move this to a versioned configuration file format // TODO: move this to a versioned configuration file format
var config AdmissionConfig var config AdmissionConfig
d := yaml.NewYAMLOrJSONDecoder(configFile, 4096) d := yaml.NewYAMLOrJSONDecoder(configFile, 4096)
@ -233,7 +234,7 @@ func NewImagePolicyWebhook(configFile io.Reader) (admission.Interface, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &imagePolicyWebhook{ return &Plugin{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
webhook: gw, webhook: gw,
responseCache: cache.NewLRUExpireCache(1024), responseCache: cache.NewLRUExpireCache(1024),

View File

@ -346,7 +346,7 @@ func (m *mockService) HTTPStatusCode() int { return m.statusCode }
// newImagePolicyWebhook creates a temporary kubeconfig file from the provided arguments and attempts to load // newImagePolicyWebhook creates a temporary kubeconfig file from the provided arguments and attempts to load
// a new newImagePolicyWebhook from it. // a new newImagePolicyWebhook from it.
func newImagePolicyWebhook(callbackURL string, clientCert, clientKey, ca []byte, cacheTime time.Duration, defaultAllow bool) (*imagePolicyWebhook, error) { func newImagePolicyWebhook(callbackURL string, clientCert, clientKey, ca []byte, cacheTime time.Duration, defaultAllow bool) (*Plugin, error) {
tempfile, err := ioutil.TempFile("", "") tempfile, err := ioutil.TempFile("", "")
if err != nil { if err != nil {
return nil, err return nil, err
@ -407,7 +407,7 @@ func newImagePolicyWebhook(callbackURL string, clientCert, clientKey, ca []byte,
if err != nil { if err != nil {
return nil, err return nil, err
} }
return wh.(*imagePolicyWebhook), err return wh, err
} }
func TestTLSConfig(t *testing.T) { func TestTLSConfig(t *testing.T) {
@ -513,7 +513,7 @@ type webhookCacheTestCase struct {
expectedCached bool expectedCached bool
} }
func testWebhookCacheCases(t *testing.T, serv *mockService, wh *imagePolicyWebhook, attr admission.Attributes, tests []webhookCacheTestCase) { func testWebhookCacheCases(t *testing.T, serv *mockService, wh *Plugin, attr admission.Attributes, tests []webhookCacheTestCase) {
for _, test := range tests { for _, test := range tests {
serv.statusCode = test.statusCode serv.statusCode = test.statusCode
err := wh.Admit(attr) err := wh.Admit(attr)

View File

@ -57,15 +57,15 @@ func Register(plugins *admission.Plugins) {
}) })
} }
type initialResources struct { type InitialResources struct {
*admission.Handler *admission.Handler
source dataSource source dataSource
percentile int64 percentile int64
nsOnly bool nsOnly bool
} }
func newInitialResources(source dataSource, percentile int64, nsOnly bool) admission.Interface { func newInitialResources(source dataSource, percentile int64, nsOnly bool) *InitialResources {
return &initialResources{ return &InitialResources{
Handler: admission.NewHandler(admission.Create), Handler: admission.NewHandler(admission.Create),
source: source, source: source,
percentile: percentile, percentile: percentile,
@ -73,7 +73,8 @@ func newInitialResources(source dataSource, percentile int64, nsOnly bool) admis
} }
} }
func (ir initialResources) Admit(a admission.Attributes) (err error) { // Admit makes an admission decision based on the request attributes
func (ir InitialResources) Admit(a admission.Attributes) (err error) {
// Ignore all calls to subresources or resources other than pods. // Ignore all calls to subresources or resources other than pods.
if a.GetSubresource() != "" || a.GetResource().GroupResource() != api.Resource("pods") { if a.GetSubresource() != "" || a.GetResource().GroupResource() != api.Resource("pods") {
return nil return nil
@ -89,7 +90,7 @@ func (ir initialResources) Admit(a admission.Attributes) (err error) {
// The method veryfies whether resources should be set for the given pod and // The method veryfies whether resources should be set for the given pod and
// if there is estimation available the method fills Request field. // if there is estimation available the method fills Request field.
func (ir initialResources) estimateAndFillResourcesIfNotSet(pod *api.Pod) { func (ir InitialResources) estimateAndFillResourcesIfNotSet(pod *api.Pod) {
var annotations []string var annotations []string
for i := range pod.Spec.InitContainers { for i := range pod.Spec.InitContainers {
annotations = append(annotations, ir.estimateContainer(pod, &pod.Spec.InitContainers[i], "init container")...) annotations = append(annotations, ir.estimateContainer(pod, &pod.Spec.InitContainers[i], "init container")...)
@ -106,7 +107,7 @@ func (ir initialResources) estimateAndFillResourcesIfNotSet(pod *api.Pod) {
} }
} }
func (ir initialResources) estimateContainer(pod *api.Pod, c *api.Container, message string) []string { func (ir InitialResources) estimateContainer(pod *api.Pod, c *api.Container, message string) []string {
var annotations []string var annotations []string
req := c.Resources.Requests req := c.Resources.Requests
cpu := ir.getEstimationIfNeeded(api.ResourceCPU, c, pod.ObjectMeta.Namespace) cpu := ir.getEstimationIfNeeded(api.ResourceCPU, c, pod.ObjectMeta.Namespace)
@ -137,7 +138,7 @@ func (ir initialResources) estimateContainer(pod *api.Pod, c *api.Container, mes
// getEstimationIfNeeded estimates compute resource for container if its corresponding // getEstimationIfNeeded estimates compute resource for container if its corresponding
// Request(min amount) and Limit(max amount) both are not specified. // Request(min amount) and Limit(max amount) both are not specified.
func (ir initialResources) getEstimationIfNeeded(kind api.ResourceName, c *api.Container, ns string) *resource.Quantity { func (ir InitialResources) getEstimationIfNeeded(kind api.ResourceName, c *api.Container, ns string) *resource.Quantity {
requests := c.Resources.Requests requests := c.Resources.Requests
limits := c.Resources.Limits limits := c.Resources.Limits
var quantity *resource.Quantity var quantity *resource.Quantity
@ -152,7 +153,7 @@ func (ir initialResources) getEstimationIfNeeded(kind api.ResourceName, c *api.C
} }
return quantity return quantity
} }
func (ir initialResources) getEstimation(kind api.ResourceName, c *api.Container, ns string) (*resource.Quantity, error) { func (ir InitialResources) getEstimation(kind api.ResourceName, c *api.Container, ns string) (*resource.Quantity, error) {
end := time.Now() end := time.Now()
start := end.Add(-week) start := end.Add(-week)
var usage, samples int64 var usage, samples int64

View File

@ -50,8 +50,8 @@ func Register(plugins *admission.Plugins) {
}) })
} }
// 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 internalclientset.Interface client internalclientset.Interface
actions LimitRangerActions actions LimitRangerActions
@ -69,13 +69,13 @@ type liveLookupEntry struct {
items []*api.LimitRange items []*api.LimitRange
} }
func (l *limitRanger) SetInternalKubeInformerFactory(f informers.SharedInformerFactory) { func (l *LimitRanger) SetInternalKubeInformerFactory(f informers.SharedInformerFactory) {
limitRangeInformer := f.Core().InternalVersion().LimitRanges() limitRangeInformer := f.Core().InternalVersion().LimitRanges()
l.SetReadyFunc(limitRangeInformer.Informer().HasSynced) l.SetReadyFunc(limitRangeInformer.Informer().HasSynced)
l.lister = limitRangeInformer.Lister() l.lister = limitRangeInformer.Lister()
} }
func (l *limitRanger) Validate() error { 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")
} }
@ -86,7 +86,7 @@ func (l *limitRanger) Validate() error {
} }
// Admit admits resources into cluster that do not violate any defined LimitRange in the namespace // Admit admits resources into cluster that do not violate any defined LimitRange in the namespace
func (l *limitRanger) Admit(a admission.Attributes) (err error) { func (l *LimitRanger) Admit(a admission.Attributes) (err error) {
if !l.actions.SupportsAttributes(a) { if !l.actions.SupportsAttributes(a) {
return nil return nil
} }
@ -150,7 +150,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(actions LimitRangerActions) (admission.Interface, error) { func NewLimitRanger(actions LimitRangerActions) (*LimitRanger, error) {
liveLookupCache, err := lru.New(10000) liveLookupCache, err := lru.New(10000)
if err != nil { if err != nil {
return nil, err return nil, err
@ -160,7 +160,7 @@ func NewLimitRanger(actions LimitRangerActions) (admission.Interface, error) {
actions = &DefaultLimitRangerActions{} actions = &DefaultLimitRangerActions{}
} }
return &limitRanger{ return &LimitRanger{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
actions: actions, actions: actions,
liveLookupCache: liveLookupCache, liveLookupCache: liveLookupCache,
@ -168,10 +168,10 @@ func NewLimitRanger(actions LimitRangerActions) (admission.Interface, error) {
}, nil }, nil
} }
var _ = kubeapiserveradmission.WantsInternalKubeInformerFactory(&limitRanger{}) var _ = kubeapiserveradmission.WantsInternalKubeInformerFactory(&LimitRanger{})
var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&limitRanger{}) var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&LimitRanger{})
func (a *limitRanger) SetInternalKubeClientSet(client internalclientset.Interface) { func (a *LimitRanger) SetInternalKubeClientSet(client internalclientset.Interface) {
a.client = client a.client = client
} }

View File

@ -738,7 +738,7 @@ 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) (*LimitRanger, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(c, 5*time.Minute) f := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler, err := NewLimitRanger(&DefaultLimitRangerActions{}) handler, err := NewLimitRanger(&DefaultLimitRangerActions{})
if err != nil { if err != nil {

View File

@ -37,19 +37,20 @@ func Register(plugins *admission.Plugins) {
}) })
} }
// provision is an implementation of admission.Interface. // Provision is an implementation of admission.Interface.
// It looks at all incoming requests in a namespace context, and if the namespace does not exist, it creates one. // It looks at all incoming requests in a namespace context, and if the namespace does not exist, it creates one.
// 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 internalclientset.Interface client internalclientset.Interface
namespaceLister corelisters.NamespaceLister namespaceLister corelisters.NamespaceLister
} }
var _ = kubeapiserveradmission.WantsInternalKubeInformerFactory(&provision{}) var _ = kubeapiserveradmission.WantsInternalKubeInformerFactory(&Provision{})
var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&provision{}) var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&Provision{})
func (p *provision) Admit(a admission.Attributes) error { // Admit makes an admission decision based on the request attributes
func (p *Provision) Admit(a admission.Attributes) 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
// if we're here, then the API server has found a route, which means that if we have a non-empty namespace // if we're here, then the API server has found a route, which means that if we have a non-empty namespace
// its a namespaced resource. // its a namespaced resource.
@ -87,23 +88,26 @@ func (p *provision) Admit(a admission.Attributes) error {
} }
// NewProvision creates a new namespace provision admission control handler // NewProvision creates a new namespace provision admission control handler
func NewProvision() admission.Interface { func NewProvision() *Provision {
return &provision{ return &Provision{
Handler: admission.NewHandler(admission.Create), Handler: admission.NewHandler(admission.Create),
} }
} }
func (p *provision) SetInternalKubeClientSet(client internalclientset.Interface) { // SetInternalKubeClientSet implements the WantsInternalKubeClientSet interface.
func (p *Provision) SetInternalKubeClientSet(client internalclientset.Interface) {
p.client = client p.client = client
} }
func (p *provision) SetInternalKubeInformerFactory(f informers.SharedInformerFactory) { // SetInternalKubeInformerFactory implements the WantsInternalKubeInformerFactory interface.
func (p *Provision) SetInternalKubeInformerFactory(f informers.SharedInformerFactory) {
namespaceInformer := f.Core().InternalVersion().Namespaces() namespaceInformer := f.Core().InternalVersion().Namespaces()
p.namespaceLister = namespaceInformer.Lister() p.namespaceLister = namespaceInformer.Lister()
p.SetReadyFunc(namespaceInformer.Informer().HasSynced) p.SetReadyFunc(namespaceInformer.Informer().HasSynced)
} }
func (p *provision) Validate() error { // Validate implements the Validator interface.
func (p *Provision) Validate() error {
if p.namespaceLister == nil { if p.namespaceLister == nil {
return fmt.Errorf("missing namespaceLister") return fmt.Errorf("missing namespaceLister")
} }

View File

@ -37,19 +37,20 @@ func Register(plugins *admission.Plugins) {
}) })
} }
// exists is an implementation of admission.Interface. // Exists is an implementation of admission.Interface.
// It rejects all incoming requests in a namespace context if the namespace does not exist. // It rejects all incoming requests in a namespace context if the namespace does not exist.
// 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 internalclientset.Interface client internalclientset.Interface
namespaceLister corelisters.NamespaceLister namespaceLister corelisters.NamespaceLister
} }
var _ = kubeapiserveradmission.WantsInternalKubeInformerFactory(&exists{}) var _ = kubeapiserveradmission.WantsInternalKubeInformerFactory(&Exists{})
var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&exists{}) var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&Exists{})
func (e *exists) Admit(a admission.Attributes) error { // Admit makes an admission decision based on the request attributes
func (e *Exists) Admit(a admission.Attributes) 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
// if we're here, then the API server has found a route, which means that if we have a non-empty namespace // if we're here, then the API server has found a route, which means that if we have a non-empty namespace
// its a namespaced resource. // its a namespaced resource.
@ -82,23 +83,26 @@ func (e *exists) Admit(a admission.Attributes) error {
} }
// NewExists creates a new namespace exists admission control handler // NewExists creates a new namespace exists admission control handler
func NewExists() admission.Interface { func NewExists() *Exists {
return &exists{ return &Exists{
Handler: admission.NewHandler(admission.Create, admission.Update, admission.Delete), Handler: admission.NewHandler(admission.Create, admission.Update, admission.Delete),
} }
} }
func (e *exists) SetInternalKubeClientSet(client internalclientset.Interface) { // SetInternalKubeClientSet implements the WantsInternalKubeClientSet interface.
func (e *Exists) SetInternalKubeClientSet(client internalclientset.Interface) {
e.client = client e.client = client
} }
func (e *exists) SetInternalKubeInformerFactory(f informers.SharedInformerFactory) { // SetInternalKubeInformerFactory implements the WantsInternalKubeInformerFactory interface.
func (e *Exists) SetInternalKubeInformerFactory(f informers.SharedInformerFactory) {
namespaceInformer := f.Core().InternalVersion().Namespaces() namespaceInformer := f.Core().InternalVersion().Namespaces()
e.namespaceLister = namespaceInformer.Lister() e.namespaceLister = namespaceInformer.Lister()
e.SetReadyFunc(namespaceInformer.Informer().HasSynced) e.SetReadyFunc(namespaceInformer.Informer().HasSynced)
} }
func (e *exists) Validate() error { // Validate implements the Validator interface.
func (e *Exists) Validate() error {
if e.namespaceLister == nil { if e.namespaceLister == nil {
return fmt.Errorf("missing namespaceLister") return fmt.Errorf("missing namespaceLister")
} }

View File

@ -55,8 +55,8 @@ func Register(plugins *admission.Plugins) {
}) })
} }
// priorityPlugin is an implementation of admission.Interface. // PriorityPlugin is an implementation of admission.Interface.
type priorityPlugin struct { type PriorityPlugin struct {
*admission.Handler *admission.Handler
client internalclientset.Interface client internalclientset.Interface
lister schedulinglisters.PriorityClassLister lister schedulinglisters.PriorityClassLister
@ -64,17 +64,18 @@ type priorityPlugin struct {
globalDefaultPriority *int32 globalDefaultPriority *int32
} }
var _ = kubeapiserveradmission.WantsInternalKubeInformerFactory(&priorityPlugin{}) var _ = kubeapiserveradmission.WantsInternalKubeInformerFactory(&PriorityPlugin{})
var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&priorityPlugin{}) var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&PriorityPlugin{})
// NewPlugin creates a new priority admission plugin. // NewPlugin creates a new priority admission plugin.
func NewPlugin() admission.Interface { func NewPlugin() *PriorityPlugin {
return &priorityPlugin{ return &PriorityPlugin{
Handler: admission.NewHandler(admission.Create, admission.Update, admission.Delete), Handler: admission.NewHandler(admission.Create, admission.Update, admission.Delete),
} }
} }
func (p *priorityPlugin) Validate() error { // Validate implements the Validator interface.
func (p *PriorityPlugin) Validate() error {
if p.client == nil { if p.client == nil {
return fmt.Errorf("%s requires a client", pluginName) return fmt.Errorf("%s requires a client", pluginName)
} }
@ -84,11 +85,13 @@ func (p *priorityPlugin) Validate() error {
return nil return nil
} }
func (p *priorityPlugin) SetInternalKubeClientSet(client internalclientset.Interface) { // SetInternalKubeClientSet implements the WantsInternalKubeClientSet interface.
func (p *PriorityPlugin) SetInternalKubeClientSet(client internalclientset.Interface) {
p.client = client p.client = client
} }
func (p *priorityPlugin) SetInternalKubeInformerFactory(f informers.SharedInformerFactory) { // SetInternalKubeInformerFactory implements the WantsInternalKubeInformerFactory interface.
func (p *PriorityPlugin) SetInternalKubeInformerFactory(f informers.SharedInformerFactory) {
priorityInformer := f.Scheduling().InternalVersion().PriorityClasses() priorityInformer := f.Scheduling().InternalVersion().PriorityClasses()
p.lister = priorityInformer.Lister() p.lister = priorityInformer.Lister()
p.SetReadyFunc(priorityInformer.Informer().HasSynced) p.SetReadyFunc(priorityInformer.Informer().HasSynced)
@ -100,7 +103,7 @@ var (
) )
// Admit checks Pods and PriorityClasses and admits or rejects them. It also resolves the priority of pods based on their PriorityClass. // Admit checks Pods and PriorityClasses and admits or rejects them. It also resolves the priority of pods based on their PriorityClass.
func (p *priorityPlugin) Admit(a admission.Attributes) error { func (p *PriorityPlugin) Admit(a admission.Attributes) error {
operation := a.GetOperation() operation := a.GetOperation()
// Ignore all calls to subresources or resources other than pods. // Ignore all calls to subresources or resources other than pods.
// Ignore all operations other than Create and Update. // Ignore all operations other than Create and Update.
@ -132,7 +135,7 @@ func (p *priorityPlugin) Admit(a admission.Attributes) error {
// admitPod makes sure a new pod does not set spec.Priority field. It also makes sure that the PriorityClassName exists if it is provided and resolves the pod priority from the PriorityClassName. // admitPod makes sure a new pod does not set spec.Priority field. It also makes sure that the PriorityClassName exists if it is provided and resolves the pod priority from the PriorityClassName.
// Note that pod validation mechanism prevents update of a pod priority. // Note that pod validation mechanism prevents update of a pod priority.
func (p *priorityPlugin) admitPod(a admission.Attributes) error { func (p *PriorityPlugin) admitPod(a admission.Attributes) error {
operation := a.GetOperation() operation := a.GetOperation()
pod, ok := a.GetObject().(*api.Pod) pod, ok := a.GetObject().(*api.Pod)
if !ok { if !ok {
@ -174,7 +177,7 @@ func (p *priorityPlugin) admitPod(a admission.Attributes) error {
} }
// admitPriorityClass ensures that the value field is not larger than the highest user definable priority. If the GlobalDefault is set, it ensures that there is no other PriorityClass whose GlobalDefault is set. // admitPriorityClass ensures that the value field is not larger than the highest user definable priority. If the GlobalDefault is set, it ensures that there is no other PriorityClass whose GlobalDefault is set.
func (p *priorityPlugin) admitPriorityClass(a admission.Attributes) error { func (p *PriorityPlugin) admitPriorityClass(a admission.Attributes) error {
operation := a.GetOperation() operation := a.GetOperation()
pc, ok := a.GetObject().(*scheduling.PriorityClass) pc, ok := a.GetObject().(*scheduling.PriorityClass)
if !ok { if !ok {
@ -204,7 +207,7 @@ func (p *priorityPlugin) admitPriorityClass(a admission.Attributes) error {
return nil return nil
} }
func (p *priorityPlugin) getDefaultPriorityClass() (*scheduling.PriorityClass, error) { func (p *PriorityPlugin) getDefaultPriorityClass() (*scheduling.PriorityClass, error) {
list, err := p.lister.List(labels.Everything()) list, err := p.lister.List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@ -217,7 +220,7 @@ func (p *priorityPlugin) getDefaultPriorityClass() (*scheduling.PriorityClass, e
return nil, nil return nil, nil
} }
func (p *priorityPlugin) getDefaultPriority() (int32, error) { func (p *PriorityPlugin) getDefaultPriority() (int32, error) {
// If global default priority is cached, return it. // If global default priority is cached, return it.
if p.globalDefaultPriority != nil { if p.globalDefaultPriority != nil {
return *p.globalDefaultPriority, nil return *p.globalDefaultPriority, nil
@ -236,6 +239,6 @@ func (p *priorityPlugin) getDefaultPriority() (int32, error) {
} }
// invalidateCachedDefaultPriority sets global default priority to nil to indicate that it should be looked up again. // invalidateCachedDefaultPriority sets global default priority to nil to indicate that it should be looked up again.
func (p *priorityPlugin) invalidateCachedDefaultPriority() { func (p *PriorityPlugin) invalidateCachedDefaultPriority() {
p.globalDefaultPriority = nil p.globalDefaultPriority = nil
} }

View File

@ -32,7 +32,7 @@ import (
"k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/features"
) )
func addPriorityClasses(ctrl *priorityPlugin, priorityClasses []*scheduling.PriorityClass) { func addPriorityClasses(ctrl *PriorityPlugin, priorityClasses []*scheduling.PriorityClass) {
informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc()) informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
ctrl.SetInternalKubeInformerFactory(informerFactory) ctrl.SetInternalKubeInformerFactory(informerFactory)
// First add the existing classes to the cache. // First add the existing classes to the cache.
@ -132,7 +132,7 @@ func TestPriorityClassAdmission(t *testing.T) {
for _, test := range tests { for _, test := range tests {
glog.V(4).Infof("starting test %q", test.name) glog.V(4).Infof("starting test %q", test.name)
ctrl := NewPlugin().(*priorityPlugin) ctrl := NewPlugin()
// Add existing priority classes. // Add existing priority classes.
addPriorityClasses(ctrl, test.existingClasses) addPriorityClasses(ctrl, test.existingClasses)
// Now add the new class. // Now add the new class.
@ -209,7 +209,7 @@ func TestDefaultPriority(t *testing.T) {
for _, test := range tests { for _, test := range tests {
glog.V(4).Infof("starting test %q", test.name) glog.V(4).Infof("starting test %q", test.name)
ctrl := NewPlugin().(*priorityPlugin) ctrl := NewPlugin()
addPriorityClasses(ctrl, test.classesBefore) addPriorityClasses(ctrl, test.classesBefore)
defaultPriority, err := ctrl.getDefaultPriority() defaultPriority, err := ctrl.getDefaultPriority()
if err != nil { if err != nil {
@ -383,7 +383,7 @@ func TestPodAdmission(t *testing.T) {
for _, test := range tests { for _, test := range tests {
glog.V(4).Infof("starting test %q", test.name) glog.V(4).Infof("starting test %q", test.name)
ctrl := NewPlugin().(*priorityPlugin) ctrl := NewPlugin()
// Add existing priority classes. // Add existing priority classes.
addPriorityClasses(ctrl, test.existingClasses) addPriorityClasses(ctrl, test.existingClasses)

View File

@ -50,8 +50,8 @@ func Register(plugins *admission.Plugins) {
}) })
} }
// quotaAdmission implements an admission controller that can enforce quota constraints // QuotaAdmission implements an admission controller that can enforce quota constraints
type quotaAdmission struct { type QuotaAdmission struct {
*admission.Handler *admission.Handler
config *resourcequotaapi.Configuration config *resourcequotaapi.Configuration
stopCh <-chan struct{} stopCh <-chan struct{}
@ -61,8 +61,8 @@ type quotaAdmission struct {
evaluator Evaluator evaluator Evaluator
} }
var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&quotaAdmission{}) var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&QuotaAdmission{})
var _ = kubeapiserveradmission.WantsQuotaConfiguration(&quotaAdmission{}) var _ = kubeapiserveradmission.WantsQuotaConfiguration(&QuotaAdmission{})
type liveLookupEntry struct { type liveLookupEntry struct {
expiry time.Time expiry time.Time
@ -72,13 +72,13 @@ 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(config *resourcequotaapi.Configuration, numEvaluators int, stopCh <-chan struct{}) (admission.Interface, error) { func NewResourceQuota(config *resourcequotaapi.Configuration, numEvaluators int, stopCh <-chan struct{}) (*QuotaAdmission, error) {
quotaAccessor, err := newQuotaAccessor() quotaAccessor, err := newQuotaAccessor()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &quotaAdmission{ return &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
stopCh: stopCh, stopCh: stopCh,
numEvaluators: numEvaluators, numEvaluators: numEvaluators,
@ -87,21 +87,21 @@ func NewResourceQuota(config *resourcequotaapi.Configuration, numEvaluators int,
}, nil }, nil
} }
func (a *quotaAdmission) SetInternalKubeClientSet(client internalclientset.Interface) { func (a *QuotaAdmission) SetInternalKubeClientSet(client internalclientset.Interface) {
a.quotaAccessor.client = client a.quotaAccessor.client = client
} }
func (a *quotaAdmission) SetInternalKubeInformerFactory(f informers.SharedInformerFactory) { func (a *QuotaAdmission) SetInternalKubeInformerFactory(f informers.SharedInformerFactory) {
a.quotaAccessor.lister = f.Core().InternalVersion().ResourceQuotas().Lister() a.quotaAccessor.lister = f.Core().InternalVersion().ResourceQuotas().Lister()
} }
func (a *quotaAdmission) SetQuotaConfiguration(c quota.Configuration) { func (a *QuotaAdmission) SetQuotaConfiguration(c quota.Configuration) {
a.quotaConfiguration = c a.quotaConfiguration = c
a.evaluator = NewQuotaEvaluator(a.quotaAccessor, a.quotaConfiguration, nil, a.config, a.numEvaluators, a.stopCh) a.evaluator = NewQuotaEvaluator(a.quotaAccessor, a.quotaConfiguration, nil, a.config, a.numEvaluators, a.stopCh)
} }
// Validate ensures an authorizer is set. // Validate ensures an authorizer is set.
func (a *quotaAdmission) Validate() error { func (a *QuotaAdmission) Validate() error {
if a.quotaAccessor == nil { if a.quotaAccessor == nil {
return fmt.Errorf("missing quotaAccessor") return fmt.Errorf("missing quotaAccessor")
} }
@ -121,7 +121,7 @@ func (a *quotaAdmission) Validate() error {
} }
// Admit makes admission decisions while enforcing quota // Admit makes admission decisions while enforcing quota
func (a *quotaAdmission) Admit(attr admission.Attributes) (err error) { func (a *QuotaAdmission) Admit(attr admission.Attributes) (err error) {
// ignore all operations that correspond to sub-resource actions // ignore all operations that correspond to sub-resource actions
if attr.GetSubresource() != "" { if attr.GetSubresource() != "" {
return nil return nil

View File

@ -135,7 +135,7 @@ func TestAdmissionIgnoresDelete(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -171,7 +171,7 @@ func TestAdmissionIgnoresSubresources(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -216,7 +216,7 @@ func TestAdmitBelowQuotaLimit(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -300,7 +300,7 @@ func TestAdmitHandlesOldObjects(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -407,7 +407,7 @@ func TestAdmitHandlesNegativePVCUpdates(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -474,7 +474,7 @@ func TestAdmitHandlesPVCUpdates(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -573,7 +573,7 @@ func TestAdmitHandlesCreatingUpdates(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -668,7 +668,7 @@ func TestAdmitExceedQuotaLimit(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -713,7 +713,7 @@ func TestAdmitEnforceQuotaConstraints(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -768,7 +768,7 @@ func TestAdmitPodInNamespaceWithoutQuota(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -835,7 +835,7 @@ func TestAdmitBelowTerminatingQuotaLimit(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -941,7 +941,7 @@ func TestAdmitBelowBestEffortQuotaLimit(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -1034,7 +1034,7 @@ func TestAdmitBestEffortQuotaLimitIgnoresBurstable(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -1120,7 +1120,7 @@ func TestAdmissionSetsMissingNamespace(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -1166,7 +1166,7 @@ func TestAdmitRejectsNegativeUsage(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -1213,7 +1213,7 @@ func TestAdmitWhenUnrelatedResourceExceedsQuota(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -1250,7 +1250,7 @@ func TestAdmitLimitedResourceNoQuota(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -1284,7 +1284,7 @@ func TestAdmitLimitedResourceNoQuotaIgnoresNonMatchingResources(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -1331,7 +1331,7 @@ func TestAdmitLimitedResourceWithQuota(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -1390,7 +1390,7 @@ func TestAdmitLimitedResourceWithMultipleQuota(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }
@ -1439,7 +1439,7 @@ func TestAdmitLimitedResourceWithQuotaThatDoesNotCover(t *testing.T) {
quotaConfiguration := install.NewQuotaConfigurationForAdmission() quotaConfiguration := install.NewQuotaConfigurationForAdmission()
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
handler := &quotaAdmission{ handler := &QuotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
evaluator: evaluator, evaluator: evaluator,
} }

View File

@ -32,19 +32,20 @@ func Register(plugins *admission.Plugins) {
}) })
} }
type plugin struct { // Plugin implements admission.Interface.
type Plugin struct {
*admission.Handler *admission.Handler
} }
// NewSecurityContextDeny creates a new instance of the SecurityContextDeny admission controller // NewSecurityContextDeny creates a new instance of the SecurityContextDeny admission controller
func NewSecurityContextDeny() admission.Interface { func NewSecurityContextDeny() *Plugin {
return &plugin{ return &Plugin{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
} }
} }
// Admit will deny any pod that defines SELinuxOptions or RunAsUser. // Admit will deny any pod that defines SELinuxOptions or RunAsUser.
func (p *plugin) Admit(a admission.Attributes) (err error) { func (p *Plugin) Admit(a admission.Attributes) (err error) {
if a.GetSubresource() != "" || a.GetResource().GroupResource() != api.Resource("pods") { if a.GetSubresource() != "" || a.GetResource().GroupResource() != api.Resource("pods") {
return nil return nil
} }

View File

@ -20,7 +20,7 @@ package admission
type chainAdmissionHandler []Interface type chainAdmissionHandler []Interface
// 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) chainAdmissionHandler {
return chainAdmissionHandler(handlers) return chainAdmissionHandler(handlers)
} }

View File

@ -74,6 +74,7 @@ func NewInitializer() admission.Interface {
return &initializer{} return &initializer{}
} }
// Validate implements the Validator interface.
func (i *initializer) Validate() error { func (i *initializer) Validate() error {
if i.config == nil { if i.config == nil {
return fmt.Errorf("the Initializer admission plugin requires a Kubernetes client to be provided") return fmt.Errorf("the Initializer admission plugin requires a Kubernetes client to be provided")
@ -94,10 +95,12 @@ func (i *initializer) Validate() error {
return nil return nil
} }
// SetExternalKubeClientSet implements the WantsExternalKubeClientSet interface.
func (i *initializer) SetExternalKubeClientSet(client clientset.Interface) { func (i *initializer) SetExternalKubeClientSet(client clientset.Interface) {
i.config = configuration.NewInitializerConfigurationManager(client.Admissionregistration().InitializerConfigurations()) i.config = configuration.NewInitializerConfigurationManager(client.Admissionregistration().InitializerConfigurations())
} }
// SetAuthorizer implements the WantsAuthorizer interface.
func (i *initializer) SetAuthorizer(a authorizer.Authorizer) { func (i *initializer) SetAuthorizer(a authorizer.Authorizer) {
i.authorizer = a i.authorizer = a
} }
@ -276,6 +279,8 @@ func (i *initializer) canInitialize(a admission.Attributes, message string) erro
return nil return nil
} }
// Handles returns true if this admission controller can handle the given operation
// where operation can be one of CREATE, UPDATE, DELETE, or CONNECT
func (i *initializer) Handles(op admission.Operation) bool { func (i *initializer) Handles(op admission.Operation) bool {
return op == admission.Create || op == admission.Update return op == admission.Create || op == admission.Update
} }

View File

@ -202,16 +202,19 @@ func newLifecycleWithClock(immortalNamespaces sets.String, clock utilcache.Clock
}, nil }, nil
} }
// SetExternalKubeInformerFactory implements the WantsExternalKubeInformerFactory interface.
func (l *lifecycle) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) { func (l *lifecycle) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
namespaceInformer := f.Core().V1().Namespaces() namespaceInformer := f.Core().V1().Namespaces()
l.namespaceLister = namespaceInformer.Lister() l.namespaceLister = namespaceInformer.Lister()
l.SetReadyFunc(namespaceInformer.Informer().HasSynced) l.SetReadyFunc(namespaceInformer.Informer().HasSynced)
} }
// SetExternalKubeClientSet implements the WantsExternalKubeClientSet interface.
func (l *lifecycle) SetExternalKubeClientSet(client kubernetes.Interface) { func (l *lifecycle) SetExternalKubeClientSet(client kubernetes.Interface) {
l.client = client l.client = client
} }
// Validate implement the Validator interface.
func (l *lifecycle) Validate() error { func (l *lifecycle) Validate() error {
if l.namespaceLister == nil { if l.namespaceLister == nil {
return fmt.Errorf("missing namespaceLister") return fmt.Errorf("missing namespaceLister")

View File

@ -151,10 +151,13 @@ func (a *GenericAdmissionWebhook) SetScheme(scheme *runtime.Scheme) {
} }
} }
// WantsExternalKubeClientSet defines a function which sets external ClientSet for admission plugins that need it
func (a *GenericAdmissionWebhook) SetExternalKubeClientSet(client clientset.Interface) { func (a *GenericAdmissionWebhook) SetExternalKubeClientSet(client clientset.Interface) {
a.hookSource = configuration.NewExternalAdmissionHookConfigurationManager(client.Admissionregistration().ExternalAdmissionHookConfigurations()) a.hookSource = configuration.NewExternalAdmissionHookConfigurationManager(client.Admissionregistration().ExternalAdmissionHookConfigurations())
} }
// Validator holds Validate functions, which are responsible for validation of initialized shared resources
// and should be implemented on admission plugins
func (a *GenericAdmissionWebhook) Validate() error { func (a *GenericAdmissionWebhook) Validate() error {
if a.hookSource == nil { if a.hookSource == nil {
return fmt.Errorf("the GenericAdmissionWebhook admission plugin requires a Kubernetes client to be provided") return fmt.Errorf("the GenericAdmissionWebhook admission plugin requires a Kubernetes client to be provided")

View File

@ -21,7 +21,6 @@ go_test(
"//pkg/controller:go_default_library", "//pkg/controller:go_default_library",
"//pkg/controller/replication:go_default_library", "//pkg/controller/replication:go_default_library",
"//pkg/controller/resourcequota:go_default_library", "//pkg/controller/resourcequota:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//pkg/quota/generic:go_default_library", "//pkg/quota/generic:go_default_library",
"//pkg/quota/install:go_default_library", "//pkg/quota/install:go_default_library",
"//plugin/pkg/admission/resourcequota:go_default_library", "//plugin/pkg/admission/resourcequota:go_default_library",

View File

@ -40,7 +40,6 @@ import (
"k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller"
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"
kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
"k8s.io/kubernetes/pkg/quota/generic" "k8s.io/kubernetes/pkg/quota/generic"
quotainstall "k8s.io/kubernetes/pkg/quota/install" quotainstall "k8s.io/kubernetes/pkg/quota/install"
"k8s.io/kubernetes/plugin/pkg/admission/resourcequota" "k8s.io/kubernetes/plugin/pkg/admission/resourcequota"
@ -70,11 +69,11 @@ func TestQuota(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
admission.(kubeadmission.WantsInternalKubeClientSet).SetInternalKubeClientSet(internalClientset) admission.SetInternalKubeClientSet(internalClientset)
internalInformers := internalinformers.NewSharedInformerFactory(internalClientset, controller.NoResyncPeriodFunc()) internalInformers := internalinformers.NewSharedInformerFactory(internalClientset, controller.NoResyncPeriodFunc())
admission.(kubeadmission.WantsInternalKubeInformerFactory).SetInternalKubeInformerFactory(internalInformers) admission.SetInternalKubeInformerFactory(internalInformers)
qca := quotainstall.NewQuotaConfigurationForAdmission() qca := quotainstall.NewQuotaConfigurationForAdmission()
admission.(kubeadmission.WantsQuotaConfiguration).SetQuotaConfiguration(qca) admission.SetQuotaConfiguration(qca)
defer close(admissionCh) defer close(admissionCh)
masterConfig := framework.NewIntegrationTestMasterConfig() masterConfig := framework.NewIntegrationTestMasterConfig()
@ -268,10 +267,10 @@ func TestQuotaLimitedResourceDenial(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
admission.(kubeadmission.WantsInternalKubeClientSet).SetInternalKubeClientSet(internalClientset) admission.SetInternalKubeClientSet(internalClientset)
internalInformers := internalinformers.NewSharedInformerFactory(internalClientset, controller.NoResyncPeriodFunc()) internalInformers := internalinformers.NewSharedInformerFactory(internalClientset, controller.NoResyncPeriodFunc())
admission.(kubeadmission.WantsInternalKubeInformerFactory).SetInternalKubeInformerFactory(internalInformers) admission.SetInternalKubeInformerFactory(internalInformers)
admission.(kubeadmission.WantsQuotaConfiguration).SetQuotaConfiguration(qca) admission.SetQuotaConfiguration(qca)
defer close(admissionCh) defer close(admissionCh)
masterConfig := framework.NewIntegrationTestMasterConfig() masterConfig := framework.NewIntegrationTestMasterConfig()