Commit 75c448db authored by David Eads's avatar David Eads

make easy validation admission plugins into validators

parent 40212c17
...@@ -33,6 +33,9 @@ func Register(plugins *admission.Plugins) { ...@@ -33,6 +33,9 @@ func Register(plugins *admission.Plugins) {
// 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{}
var _ admission.MutationInterface = AlwaysAdmit{}
var _ admission.ValidationInterface = AlwaysAdmit{}
// Admit makes an admission decision based on the request attributes // Admit makes an admission decision based on the request attributes
func (AlwaysAdmit) Admit(a admission.Attributes) (err error) { func (AlwaysAdmit) Admit(a admission.Attributes) (err error) {
return nil return nil
......
...@@ -13,6 +13,7 @@ go_library( ...@@ -13,6 +13,7 @@ go_library(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
"//vendor/k8s.io/apiserver/pkg/admission:go_default_library", "//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
], ],
) )
......
...@@ -28,6 +28,7 @@ import ( ...@@ -28,6 +28,7 @@ import (
"io" "io"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
) )
...@@ -45,10 +46,13 @@ type AlwaysPullImages struct { ...@@ -45,10 +46,13 @@ type AlwaysPullImages struct {
*admission.Handler *admission.Handler
} }
var _ admission.MutationInterface = &AlwaysPullImages{}
var _ admission.ValidationInterface = &AlwaysPullImages{}
// Admit makes an admission decision based on the request attributes // Admit makes an admission decision based on the request attributes
func (a *AlwaysPullImages) Admit(attributes admission.Attributes) (err error) { 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 shouldIgnore(attributes) {
return nil return nil
} }
pod, ok := attributes.GetObject().(*api.Pod) pod, ok := attributes.GetObject().(*api.Pod)
...@@ -67,6 +71,48 @@ func (a *AlwaysPullImages) Admit(attributes admission.Attributes) (err error) { ...@@ -67,6 +71,48 @@ func (a *AlwaysPullImages) Admit(attributes admission.Attributes) (err error) {
return nil return nil
} }
// Validate makes sure that all containers are set to always pull images
func (*AlwaysPullImages) Validate(attributes admission.Attributes) (err error) {
if shouldIgnore(attributes) {
return nil
}
pod, ok := attributes.GetObject().(*api.Pod)
if !ok {
return apierrors.NewBadRequest("Resource was marked with kind Pod but was unable to be converted")
}
for i := range pod.Spec.InitContainers {
if pod.Spec.InitContainers[i].ImagePullPolicy != api.PullAlways {
return admission.NewForbidden(attributes,
field.NotSupported(field.NewPath("spec", "initContainers").Index(i).Child("imagePullPolicy"),
pod.Spec.InitContainers[i].ImagePullPolicy, []string{string(api.PullAlways)},
),
)
}
}
for i := range pod.Spec.Containers {
if pod.Spec.Containers[i].ImagePullPolicy != api.PullAlways {
return admission.NewForbidden(attributes,
field.NotSupported(field.NewPath("spec", "containers").Index(i).Child("imagePullPolicy"),
pod.Spec.Containers[i].ImagePullPolicy, []string{string(api.PullAlways)},
),
)
}
}
return nil
}
func shouldIgnore(attributes admission.Attributes) bool {
// Ignore all calls to subresources or resources other than pods.
if len(attributes.GetSubresource()) != 0 || attributes.GetResource().GroupResource() != api.Resource("pods") {
return true
}
return false
}
// NewAlwaysPullImages creates a new always pull images admission control handler // NewAlwaysPullImages creates a new always pull images admission control handler
func NewAlwaysPullImages() *AlwaysPullImages { func NewAlwaysPullImages() *AlwaysPullImages {
return &AlwaysPullImages{ return &AlwaysPullImages{
......
...@@ -63,6 +63,36 @@ func TestAdmission(t *testing.T) { ...@@ -63,6 +63,36 @@ func TestAdmission(t *testing.T) {
} }
} }
func TestValidate(t *testing.T) {
namespace := "test"
handler := &AlwaysPullImages{}
pod := api.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: namespace},
Spec: api.PodSpec{
InitContainers: []api.Container{
{Name: "init1", Image: "image"},
{Name: "init2", Image: "image", ImagePullPolicy: api.PullNever},
{Name: "init3", Image: "image", ImagePullPolicy: api.PullIfNotPresent},
{Name: "init4", Image: "image", ImagePullPolicy: api.PullAlways},
},
Containers: []api.Container{
{Name: "ctr1", Image: "image"},
{Name: "ctr2", Image: "image", ImagePullPolicy: api.PullNever},
{Name: "ctr3", Image: "image", ImagePullPolicy: api.PullIfNotPresent},
{Name: "ctr4", Image: "image", ImagePullPolicy: api.PullAlways},
},
},
}
expectedError := `pods "123" is forbidden: spec.initContainers[0].imagePullPolicy: Unsupported value: "": supported values: "Always"`
err := handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
if err == nil {
t.Fatal("missing expected error")
}
if err.Error() != expectedError {
t.Fatal(err)
}
}
// TestOtherResources ensures that this admission controller is a no-op for other resources, // TestOtherResources ensures that this admission controller is a no-op for other resources,
// subresources, and non-pods. // subresources, and non-pods.
func TestOtherResources(t *testing.T) { func TestOtherResources(t *testing.T) {
......
...@@ -38,6 +38,8 @@ type Plugin struct { ...@@ -38,6 +38,8 @@ type Plugin struct {
*admission.Handler *admission.Handler
} }
var _ admission.ValidationInterface = &Plugin{}
// NewInterPodAntiAffinity creates a new instance of the LimitPodHardAntiAffinityTopology admission controller // NewInterPodAntiAffinity creates a new instance of the LimitPodHardAntiAffinityTopology admission controller
func NewInterPodAntiAffinity() *Plugin { func NewInterPodAntiAffinity() *Plugin {
return &Plugin{ return &Plugin{
...@@ -45,9 +47,9 @@ func NewInterPodAntiAffinity() *Plugin { ...@@ -45,9 +47,9 @@ func NewInterPodAntiAffinity() *Plugin {
} }
} }
// Admit will deny any pod that defines AntiAffinity topology key other than kubeletapis.LabelHostname i.e. "kubernetes.io/hostname" // Validate 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) Validate(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
......
...@@ -199,7 +199,7 @@ func TestInterPodAffinityAdmission(t *testing.T) { ...@@ -199,7 +199,7 @@ func TestInterPodAffinityAdmission(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
pod.Spec.Affinity = test.affinity pod.Spec.Affinity = test.affinity
err := handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil)) err := handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil))
if test.errorExpected && err == nil { if test.errorExpected && err == nil {
t.Errorf("Expected error for Anti Affinity %+v but did not get an error", test.affinity) t.Errorf("Expected error for Anti Affinity %+v but did not get an error", test.affinity)
...@@ -267,7 +267,7 @@ func TestOtherResources(t *testing.T) { ...@@ -267,7 +267,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.Validate(admission.NewAttributesRecord(tc.object, nil, api.Kind(tc.kind).WithVersion("version"), namespace, name, api.Resource(tc.resource).WithVersion("version"), tc.subresource, admission.Create, nil))
if tc.expectError { if tc.expectError {
if err == nil { if err == nil {
......
...@@ -34,11 +34,19 @@ func Register(plugins *admission.Plugins) { ...@@ -34,11 +34,19 @@ func Register(plugins *admission.Plugins) {
// 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{}
var _ admission.MutationInterface = AlwaysDeny{}
var _ admission.ValidationInterface = AlwaysDeny{}
// Admit makes an admission decision based on the request attributes. // Admit makes an admission decision based on the request attributes.
func (AlwaysDeny) Admit(a admission.Attributes) (err error) { 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"))
} }
// Validate makes an admission decision based on the request attributes. It is NOT allowed to mutate.
func (AlwaysDeny) Validate(a admission.Attributes) (err error) {
return admission.NewForbidden(a, errors.New("Admission control is denying all modifications"))
}
// Handles returns true if this admission controller can handle the given operation // Handles returns true if this admission controller can handle the given operation
// where operation can be one of CREATE, UPDATE, DELETE, or CONNECT // where operation can be one of CREATE, UPDATE, DELETE, or CONNECT
func (AlwaysDeny) Handles(operation admission.Operation) bool { func (AlwaysDeny) Handles(operation admission.Operation) bool {
......
...@@ -54,6 +54,8 @@ type Plugin struct { ...@@ -54,6 +54,8 @@ type Plugin struct {
limitEnforcers []*limitEnforcer limitEnforcers []*limitEnforcer
} }
var _ admission.ValidationInterface = &Plugin{}
// 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) (*Plugin, 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))
...@@ -73,8 +75,8 @@ func newEventRateLimit(config *eventratelimitapi.Configuration, clock flowcontro ...@@ -73,8 +75,8 @@ func newEventRateLimit(config *eventratelimitapi.Configuration, clock flowcontro
return eventRateLimitAdmission, nil return eventRateLimitAdmission, nil
} }
// Admit makes admission decisions while enforcing event rate limits // Validate makes admission decisions while enforcing event rate limits
func (a *Plugin) Admit(attr admission.Attributes) (err error) { func (a *Plugin) Validate(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
......
...@@ -482,7 +482,7 @@ func TestEventRateLimiting(t *testing.T) { ...@@ -482,7 +482,7 @@ func TestEventRateLimiting(t *testing.T) {
clock.Step(rq.delay) clock.Step(rq.delay)
} }
attributes := attributesForRequest(rq) attributes := attributesForRequest(rq)
err = eventratelimit.Admit(attributes) err = eventratelimit.Validate(attributes)
if rq.accepted != (err == nil) { if rq.accepted != (err == nil) {
expectedAction := "admitted" expectedAction := "admitted"
if !rq.accepted { if !rq.accepted {
......
...@@ -54,6 +54,8 @@ type DenyExec struct { ...@@ -54,6 +54,8 @@ type DenyExec struct {
privileged bool privileged bool
} }
var _ admission.ValidationInterface = &DenyExec{}
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
...@@ -79,8 +81,8 @@ func NewDenyExecOnPrivileged() *DenyExec { ...@@ -79,8 +81,8 @@ func NewDenyExecOnPrivileged() *DenyExec {
} }
} }
// Admit makes an admission decision based on the request attributes // Validate makes an admission decision based on the request attributes
func (d *DenyExec) Admit(a admission.Attributes) (err error) { func (d *DenyExec) Validate(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.")
......
...@@ -123,7 +123,7 @@ func testAdmission(t *testing.T, pod *api.Pod, handler *DenyExec, shouldAccept b ...@@ -123,7 +123,7 @@ func testAdmission(t *testing.T, pod *api.Pod, handler *DenyExec, shouldAccept b
// pods/exec // pods/exec
{ {
req := &rest.ConnectRequest{Name: pod.Name, ResourcePath: "pods/exec"} req := &rest.ConnectRequest{Name: pod.Name, ResourcePath: "pods/exec"}
err := handler.Admit(admission.NewAttributesRecord(req, nil, api.Kind("Pod").WithVersion("version"), "test", "name", api.Resource("pods").WithVersion("version"), "exec", admission.Connect, nil)) err := handler.Validate(admission.NewAttributesRecord(req, nil, api.Kind("Pod").WithVersion("version"), "test", "name", api.Resource("pods").WithVersion("version"), "exec", admission.Connect, nil))
if shouldAccept && err != nil { if shouldAccept && err != nil {
t.Errorf("Unexpected error returned from admission handler: %v", err) t.Errorf("Unexpected error returned from admission handler: %v", err)
} }
...@@ -135,7 +135,7 @@ func testAdmission(t *testing.T, pod *api.Pod, handler *DenyExec, shouldAccept b ...@@ -135,7 +135,7 @@ func testAdmission(t *testing.T, pod *api.Pod, handler *DenyExec, shouldAccept b
// pods/attach // pods/attach
{ {
req := &rest.ConnectRequest{Name: pod.Name, ResourcePath: "pods/attach"} req := &rest.ConnectRequest{Name: pod.Name, ResourcePath: "pods/attach"}
err := handler.Admit(admission.NewAttributesRecord(req, nil, api.Kind("Pod").WithVersion("version"), "test", "name", api.Resource("pods").WithVersion("version"), "attach", admission.Connect, nil)) err := handler.Validate(admission.NewAttributesRecord(req, nil, api.Kind("Pod").WithVersion("version"), "test", "name", api.Resource("pods").WithVersion("version"), "attach", admission.Connect, nil))
if shouldAccept && err != nil { if shouldAccept && err != nil {
t.Errorf("Unexpected error returned from admission handler: %v", err) t.Errorf("Unexpected error returned from admission handler: %v", err)
} }
......
...@@ -63,6 +63,8 @@ type gcPermissionsEnforcement struct { ...@@ -63,6 +63,8 @@ type gcPermissionsEnforcement struct {
whiteList []whiteListItem whiteList []whiteListItem
} }
var _ admission.ValidationInterface = &gcPermissionsEnforcement{}
// whiteListItem describes an entry in a whitelist ignored by gc permission enforcement. // whiteListItem describes an entry in a whitelist ignored by gc permission enforcement.
type whiteListItem struct { type whiteListItem struct {
groupResource schema.GroupResource groupResource schema.GroupResource
...@@ -79,7 +81,7 @@ func (a *gcPermissionsEnforcement) isWhiteListed(groupResource schema.GroupResou ...@@ -79,7 +81,7 @@ func (a *gcPermissionsEnforcement) isWhiteListed(groupResource schema.GroupResou
return false return false
} }
func (a *gcPermissionsEnforcement) Admit(attributes admission.Attributes) (err error) { func (a *gcPermissionsEnforcement) Validate(attributes admission.Attributes) (err error) {
// // if the request is in the whitelist, we skip mutation checks for this resource. // // if the request is in the whitelist, we skip mutation checks for this resource.
if a.isWhiteListed(attributes.GetResource().GroupResource(), attributes.GetSubresource()) { if a.isWhiteListed(attributes.GetResource().GroupResource(), attributes.GetSubresource()) {
return nil return nil
......
...@@ -269,7 +269,7 @@ func TestGCAdmission(t *testing.T) { ...@@ -269,7 +269,7 @@ func TestGCAdmission(t *testing.T) {
user := &user.DefaultInfo{Name: tc.username} user := &user.DefaultInfo{Name: tc.username}
attributes := admission.NewAttributesRecord(tc.newObj, tc.oldObj, schema.GroupVersionKind{}, metav1.NamespaceDefault, "foo", tc.resource, tc.subresource, operation, user) attributes := admission.NewAttributesRecord(tc.newObj, tc.oldObj, schema.GroupVersionKind{}, metav1.NamespaceDefault, "foo", tc.resource, tc.subresource, operation, user)
err := gcAdmit.Admit(attributes) err := gcAdmit.Validate(attributes)
if !tc.checkError(err) { if !tc.checkError(err) {
t.Errorf("%v: unexpected err: %v", tc.name, err) t.Errorf("%v: unexpected err: %v", tc.name, err)
} }
...@@ -517,7 +517,7 @@ func TestBlockOwnerDeletionAdmission(t *testing.T) { ...@@ -517,7 +517,7 @@ func TestBlockOwnerDeletionAdmission(t *testing.T) {
user := &user.DefaultInfo{Name: tc.username} user := &user.DefaultInfo{Name: tc.username}
attributes := admission.NewAttributesRecord(tc.newObj, tc.oldObj, schema.GroupVersionKind{}, metav1.NamespaceDefault, "foo", tc.resource, tc.subresource, operation, user) attributes := admission.NewAttributesRecord(tc.newObj, tc.oldObj, schema.GroupVersionKind{}, metav1.NamespaceDefault, "foo", tc.resource, tc.subresource, operation, user)
err := gcAdmit.Admit(attributes) err := gcAdmit.Validate(attributes)
if !tc.checkError(err) { if !tc.checkError(err) {
t.Errorf("%v: unexpected err: %v", tc.name, err) t.Errorf("%v: unexpected err: %v", tc.name, err)
} }
......
...@@ -69,6 +69,8 @@ type Plugin struct { ...@@ -69,6 +69,8 @@ type Plugin struct {
defaultAllow bool defaultAllow bool
} }
var _ admission.ValidationInterface = &Plugin{}
func (a *Plugin) 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
...@@ -107,8 +109,8 @@ func (a *Plugin) webhookError(pod *api.Pod, attributes admission.Attributes, err ...@@ -107,8 +109,8 @@ func (a *Plugin) webhookError(pod *api.Pod, attributes admission.Attributes, err
return nil return nil
} }
// Admit makes an admission decision based on the request attributes // Validate makes an admission decision based on the request attributes
func (a *Plugin) Admit(attributes admission.Attributes) (err error) { func (a *Plugin) Validate(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
......
...@@ -477,7 +477,7 @@ func TestTLSConfig(t *testing.T) { ...@@ -477,7 +477,7 @@ func TestTLSConfig(t *testing.T) {
// Allow all and see if we get an error. // Allow all and see if we get an error.
service.Allow() service.Allow()
err = wh.Admit(attr) err = wh.Validate(attr)
if tt.wantAllowed { if tt.wantAllowed {
if err != nil { if err != nil {
t.Errorf("expected successful admission") t.Errorf("expected successful admission")
...@@ -499,7 +499,7 @@ func TestTLSConfig(t *testing.T) { ...@@ -499,7 +499,7 @@ func TestTLSConfig(t *testing.T) {
} }
service.Deny() service.Deny()
if err := wh.Admit(attr); err == nil { if err := wh.Validate(attr); err == nil {
t.Errorf("%s: incorrectly admitted with DenyAll policy", tt.test) t.Errorf("%s: incorrectly admitted with DenyAll policy", tt.test)
} }
}() }()
...@@ -516,7 +516,7 @@ type webhookCacheTestCase struct { ...@@ -516,7 +516,7 @@ type webhookCacheTestCase struct {
func testWebhookCacheCases(t *testing.T, serv *mockService, wh *Plugin, 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.Validate(attr)
authorized := err == nil authorized := err == nil
if test.expectedErr && err == nil { if test.expectedErr && err == nil {
...@@ -749,7 +749,7 @@ func TestContainerCombinations(t *testing.T) { ...@@ -749,7 +749,7 @@ func TestContainerCombinations(t *testing.T) {
attr := admission.NewAttributesRecord(tt.pod, nil, api.Kind("Pod").WithVersion("version"), "namespace", "", api.Resource("pods").WithVersion("version"), "", admission.Create, &user.DefaultInfo{}) attr := admission.NewAttributesRecord(tt.pod, nil, api.Kind("Pod").WithVersion("version"), "namespace", "", api.Resource("pods").WithVersion("version"), "", admission.Create, &user.DefaultInfo{})
err = wh.Admit(attr) err = wh.Validate(attr)
if tt.wantAllowed { if tt.wantAllowed {
if err != nil { if err != nil {
t.Errorf("expected successful admission: %s", tt.test) t.Errorf("expected successful admission: %s", tt.test)
...@@ -827,7 +827,7 @@ func TestDefaultAllow(t *testing.T) { ...@@ -827,7 +827,7 @@ func TestDefaultAllow(t *testing.T) {
attr := admission.NewAttributesRecord(tt.pod, nil, api.Kind("Pod").WithVersion("version"), "namespace", "", api.Resource("pods").WithVersion("version"), "", admission.Create, &user.DefaultInfo{}) attr := admission.NewAttributesRecord(tt.pod, nil, api.Kind("Pod").WithVersion("version"), "namespace", "", api.Resource("pods").WithVersion("version"), "", admission.Create, &user.DefaultInfo{})
err = wh.Admit(attr) err = wh.Validate(attr)
if tt.wantAllowed { if tt.wantAllowed {
if err != nil { if err != nil {
t.Errorf("expected successful admission") t.Errorf("expected successful admission")
...@@ -919,7 +919,7 @@ func TestAnnotationFiltering(t *testing.T) { ...@@ -919,7 +919,7 @@ func TestAnnotationFiltering(t *testing.T) {
attr := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "namespace", "", api.Resource("pods").WithVersion("version"), "", admission.Create, &user.DefaultInfo{}) attr := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "namespace", "", api.Resource("pods").WithVersion("version"), "", admission.Create, &user.DefaultInfo{})
err = wh.Admit(attr) err = wh.Validate(attr)
if err != nil { if err != nil {
t.Errorf("expected successful admission") t.Errorf("expected successful admission")
} }
......
...@@ -46,11 +46,12 @@ type Exists struct { ...@@ -46,11 +46,12 @@ type Exists struct {
namespaceLister corelisters.NamespaceLister namespaceLister corelisters.NamespaceLister
} }
var _ admission.ValidationInterface = &Exists{}
var _ = kubeapiserveradmission.WantsInternalKubeInformerFactory(&Exists{}) var _ = kubeapiserveradmission.WantsInternalKubeInformerFactory(&Exists{})
var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&Exists{}) var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&Exists{})
// Admit makes an admission decision based on the request attributes // Validate makes an admission decision based on the request attributes
func (e *Exists) Admit(a admission.Attributes) error { func (e *Exists) Validate(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.
......
...@@ -34,7 +34,7 @@ import ( ...@@ -34,7 +34,7 @@ import (
) )
// newHandlerForTest returns the admission controller configured for testing. // newHandlerForTest returns the admission controller configured for testing.
func newHandlerForTest(c clientset.Interface) (admission.MutationInterface, informers.SharedInformerFactory, error) { func newHandlerForTest(c clientset.Interface) (admission.ValidationInterface, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(c, 5*time.Minute) f := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler := NewExists() handler := NewExists()
pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil, nil, nil, nil, nil) pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil, nil, nil, nil, nil)
...@@ -87,7 +87,7 @@ func TestAdmissionNamespaceExists(t *testing.T) { ...@@ -87,7 +87,7 @@ func TestAdmissionNamespaceExists(t *testing.T) {
informerFactory.Start(wait.NeverStop) informerFactory.Start(wait.NeverStop)
pod := newPod(namespace) pod := newPod(namespace)
err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) err = handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
if err != nil { if err != nil {
t.Errorf("unexpected error returned from admission handler") t.Errorf("unexpected error returned from admission handler")
} }
...@@ -107,7 +107,7 @@ func TestAdmissionNamespaceDoesNotExist(t *testing.T) { ...@@ -107,7 +107,7 @@ func TestAdmissionNamespaceDoesNotExist(t *testing.T) {
informerFactory.Start(wait.NeverStop) informerFactory.Start(wait.NeverStop)
pod := newPod(namespace) pod := newPod(namespace)
err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) err = handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
if err == nil { if err == nil {
actions := "" actions := ""
for _, action := range mockClient.Actions() { for _, action := range mockClient.Actions() {
......
...@@ -43,6 +43,7 @@ func Register(plugins *admission.Plugins) { ...@@ -43,6 +43,7 @@ func Register(plugins *admission.Plugins) {
} }
var _ admission.Interface = &persistentVolumeClaimResize{} var _ admission.Interface = &persistentVolumeClaimResize{}
var _ admission.ValidationInterface = &persistentVolumeClaimResize{}
var _ = kubeapiserveradmission.WantsInternalKubeInformerFactory(&persistentVolumeClaimResize{}) var _ = kubeapiserveradmission.WantsInternalKubeInformerFactory(&persistentVolumeClaimResize{})
type persistentVolumeClaimResize struct { type persistentVolumeClaimResize struct {
...@@ -79,7 +80,7 @@ func (pvcr *persistentVolumeClaimResize) ValidateInitialization() error { ...@@ -79,7 +80,7 @@ func (pvcr *persistentVolumeClaimResize) ValidateInitialization() error {
return nil return nil
} }
func (pvcr *persistentVolumeClaimResize) Admit(a admission.Attributes) error { func (pvcr *persistentVolumeClaimResize) Validate(a admission.Attributes) error {
if a.GetResource().GroupResource() != api.Resource("persistentvolumeclaims") { if a.GetResource().GroupResource() != api.Resource("persistentvolumeclaims") {
return nil return nil
} }
......
...@@ -323,7 +323,7 @@ func TestPVCResizeAdmission(t *testing.T) { ...@@ -323,7 +323,7 @@ func TestPVCResizeAdmission(t *testing.T) {
operation := admission.Update operation := admission.Update
attributes := admission.NewAttributesRecord(tc.newObj, tc.oldObj, schema.GroupVersionKind{}, metav1.NamespaceDefault, "foo", tc.resource, tc.subresource, operation, nil) attributes := admission.NewAttributesRecord(tc.newObj, tc.oldObj, schema.GroupVersionKind{}, metav1.NamespaceDefault, "foo", tc.resource, tc.subresource, operation, nil)
err := ctrl.Admit(attributes) err := ctrl.Validate(attributes)
fmt.Println(tc.name) fmt.Println(tc.name)
fmt.Println(err) fmt.Println(err)
if !tc.checkError(err) { if !tc.checkError(err) {
......
...@@ -61,6 +61,7 @@ type QuotaAdmission struct { ...@@ -61,6 +61,7 @@ type QuotaAdmission struct {
evaluator Evaluator evaluator Evaluator
} }
var _ admission.ValidationInterface = &QuotaAdmission{}
var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&QuotaAdmission{}) var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&QuotaAdmission{})
var _ = kubeapiserveradmission.WantsQuotaConfiguration(&QuotaAdmission{}) var _ = kubeapiserveradmission.WantsQuotaConfiguration(&QuotaAdmission{})
...@@ -120,8 +121,8 @@ func (a *QuotaAdmission) ValidateInitialization() error { ...@@ -120,8 +121,8 @@ func (a *QuotaAdmission) ValidateInitialization() error {
return nil return nil
} }
// Admit makes admission decisions while enforcing quota // Validate makes admission decisions while enforcing quota
func (a *QuotaAdmission) Admit(attr admission.Attributes) (err error) { func (a *QuotaAdmission) Validate(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
......
...@@ -37,6 +37,8 @@ type Plugin struct { ...@@ -37,6 +37,8 @@ type Plugin struct {
*admission.Handler *admission.Handler
} }
var _ admission.ValidationInterface = &Plugin{}
// NewSecurityContextDeny creates a new instance of the SecurityContextDeny admission controller // NewSecurityContextDeny creates a new instance of the SecurityContextDeny admission controller
func NewSecurityContextDeny() *Plugin { func NewSecurityContextDeny() *Plugin {
return &Plugin{ return &Plugin{
...@@ -44,8 +46,8 @@ func NewSecurityContextDeny() *Plugin { ...@@ -44,8 +46,8 @@ func NewSecurityContextDeny() *Plugin {
} }
} }
// Admit will deny any pod that defines SELinuxOptions or RunAsUser. // Validate will deny any pod that defines SELinuxOptions or RunAsUser.
func (p *Plugin) Admit(a admission.Attributes) (err error) { func (p *Plugin) Validate(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
} }
......
...@@ -82,7 +82,7 @@ func TestAdmission(t *testing.T) { ...@@ -82,7 +82,7 @@ func TestAdmission(t *testing.T) {
p.Spec.SecurityContext = tc.podSc p.Spec.SecurityContext = tc.podSc
p.Spec.Containers[0].SecurityContext = tc.sc p.Spec.Containers[0].SecurityContext = tc.sc
err := handler.Admit(admission.NewAttributesRecord(p, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil)) err := handler.Validate(admission.NewAttributesRecord(p, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil))
if err != nil && !tc.expectError { if err != nil && !tc.expectError {
t.Errorf("%v: unexpected error: %v", tc.name, err) t.Errorf("%v: unexpected error: %v", tc.name, err)
} else if err == nil && tc.expectError { } else if err == nil && tc.expectError {
...@@ -96,7 +96,7 @@ func TestAdmission(t *testing.T) { ...@@ -96,7 +96,7 @@ func TestAdmission(t *testing.T) {
p.Spec.InitContainers = p.Spec.Containers p.Spec.InitContainers = p.Spec.Containers
p.Spec.Containers = nil p.Spec.Containers = nil
err = handler.Admit(admission.NewAttributesRecord(p, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil)) err = handler.Validate(admission.NewAttributesRecord(p, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil))
if err != nil && !tc.expectError { if err != nil && !tc.expectError {
t.Errorf("%v: unexpected error: %v", tc.name, err) t.Errorf("%v: unexpected error: %v", tc.name, err)
} else if err == nil && tc.expectError { } else if err == nil && tc.expectError {
...@@ -140,7 +140,7 @@ func TestPodSecurityContextAdmission(t *testing.T) { ...@@ -140,7 +140,7 @@ func TestPodSecurityContextAdmission(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
pod.Spec.SecurityContext = &test.securityContext pod.Spec.SecurityContext = &test.securityContext
err := handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil)) err := handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil))
if test.errorExpected && err == nil { if test.errorExpected && err == nil {
t.Errorf("Expected error for security context %+v but did not get an error", test.securityContext) t.Errorf("Expected error for security context %+v but did not get an error", test.securityContext)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment