From adafb1365e2b9f6c422c437e916e22a4fe1c2e3a Mon Sep 17 00:00:00 2001 From: jennybuckley Date: Mon, 6 Aug 2018 10:37:44 -0700 Subject: [PATCH] Support dry run in admission plugins --- plugin/pkg/admission/admit/admission_test.go | 2 +- .../alwayspullimages/admission_test.go | 6 +- .../admission/antiaffinity/admission_test.go | 4 +- .../admission_test.go | 2 +- plugin/pkg/admission/deny/admission_test.go | 2 +- .../pkg/admission/eventratelimit/admission.go | 7 + .../eventratelimit/admission_test.go | 22 ++ plugin/pkg/admission/exec/admission_test.go | 4 +- .../admission_test.go | 2 +- plugin/pkg/admission/gc/gc_admission_test.go | 4 +- .../admission/imagepolicy/admission_test.go | 12 +- .../admission/limitranger/admission_test.go | 14 +- .../namespace/autoprovision/admission.go | 5 + .../namespace/autoprovision/admission_test.go | 28 ++- .../namespace/exists/admission_test.go | 4 +- .../noderestriction/admission_test.go | 212 +++++++++--------- .../podnodeselector/admission_test.go | 10 +- .../pkg/admission/podpreset/admission_test.go | 1 + .../admission_test.go | 6 +- .../pkg/admission/priority/admission_test.go | 10 +- .../admission/resourcequota/admission_test.go | 101 +++++++-- .../pkg/admission/resourcequota/controller.go | 6 + .../podsecuritypolicy/admission_test.go | 8 +- .../securitycontext/scdeny/admission_test.go | 6 +- .../serviceaccount/admission_test.go | 58 ++--- .../persistentvolume/label/admission_test.go | 18 +- .../persistentvolume/resize/admission_test.go | 2 +- .../storageclass/setdefault/admission_test.go | 3 +- .../admission_test.go | 3 +- .../apiserver/pkg/admission/attributes.go | 8 +- .../apiserver/pkg/admission/audit_test.go | 2 +- .../apiserver/pkg/admission/chain_test.go | 4 +- .../apiserver/pkg/admission/errors_test.go | 1 + .../apiserver/pkg/admission/interfaces.go | 5 + .../pkg/admission/metrics/metrics_test.go | 6 +- .../initialization/initialization_test.go | 2 +- .../namespace/lifecycle/admission_test.go | 32 +-- .../webhook/mutating/dispatcher_test.go | 2 +- .../plugin/webhook/namespace/matcher_test.go | 12 +- .../plugin/webhook/rules/rules_test.go | 1 + .../plugin/webhook/testing/testcase.go | 2 +- .../apiserver/pkg/endpoints/handlers/BUILD | 1 + .../pkg/endpoints/handlers/create.go | 3 +- .../pkg/endpoints/handlers/delete.go | 45 ++-- .../apiserver/pkg/endpoints/handlers/patch.go | 3 + .../apiserver/pkg/endpoints/handlers/rest.go | 4 +- .../pkg/endpoints/handlers/update.go | 9 +- .../apiserver/pkg/registry/rest/create.go | 1 + .../apiserver/pkg/registry/rest/update.go | 1 + .../plugin/banflunder/admission_test.go | 1 + 50 files changed, 424 insertions(+), 283 deletions(-) diff --git a/plugin/pkg/admission/admit/admission_test.go b/plugin/pkg/admission/admit/admission_test.go index e1d6a377e8..cabd9cfc71 100644 --- a/plugin/pkg/admission/admit/admission_test.go +++ b/plugin/pkg/admission/admit/admission_test.go @@ -25,7 +25,7 @@ import ( func TestAdmissionNonNilAttribute(t *testing.T) { handler := NewAlwaysAdmit() - err := handler.(*alwaysAdmit).Admit(admission.NewAttributesRecord(nil, nil, api.Kind("kind").WithVersion("version"), "namespace", "name", api.Resource("resource").WithVersion("version"), "subresource", admission.Create, nil)) + err := handler.(*alwaysAdmit).Admit(admission.NewAttributesRecord(nil, nil, api.Kind("kind").WithVersion("version"), "namespace", "name", api.Resource("resource").WithVersion("version"), "subresource", admission.Create, false, nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler") } diff --git a/plugin/pkg/admission/alwayspullimages/admission_test.go b/plugin/pkg/admission/alwayspullimages/admission_test.go index de6fd5df9b..9d5ebbd6f4 100644 --- a/plugin/pkg/admission/alwayspullimages/admission_test.go +++ b/plugin/pkg/admission/alwayspullimages/admission_test.go @@ -47,7 +47,7 @@ func TestAdmission(t *testing.T) { }, }, } - 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.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler") } @@ -84,7 +84,7 @@ func TestValidate(t *testing.T) { }, } 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)) + err := handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err == nil { t.Fatal("missing expected error") } @@ -139,7 +139,7 @@ func TestOtherResources(t *testing.T) { for _, tc := range tests { 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, false, nil)) if tc.expectError { if err == nil { diff --git a/plugin/pkg/admission/antiaffinity/admission_test.go b/plugin/pkg/admission/antiaffinity/admission_test.go index dc79c91128..6d59059a95 100644 --- a/plugin/pkg/admission/antiaffinity/admission_test.go +++ b/plugin/pkg/admission/antiaffinity/admission_test.go @@ -199,7 +199,7 @@ func TestInterPodAffinityAdmission(t *testing.T) { } for _, test := range tests { pod.Spec.Affinity = test.affinity - err := handler.Validate(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", false, nil)) if test.errorExpected && err == nil { 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) { for _, tc := range tests { handler := &Plugin{} - 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)) + 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, false, nil)) if tc.expectError { if err == nil { diff --git a/plugin/pkg/admission/defaulttolerationseconds/admission_test.go b/plugin/pkg/admission/defaulttolerationseconds/admission_test.go index b94e41fe5b..a90bc50bcc 100644 --- a/plugin/pkg/admission/defaulttolerationseconds/admission_test.go +++ b/plugin/pkg/admission/defaulttolerationseconds/admission_test.go @@ -395,7 +395,7 @@ func TestForgivenessAdmission(t *testing.T) { } for _, test := range tests { - err := handler.Admit(admission.NewAttributesRecord(&test.requestedPod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil)) + err := handler.Admit(admission.NewAttributesRecord(&test.requestedPod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", false, nil)) if err != nil { t.Errorf("[%s]: unexpected error %v for pod %+v", test.description, err, test.requestedPod) } diff --git a/plugin/pkg/admission/deny/admission_test.go b/plugin/pkg/admission/deny/admission_test.go index 4eb25289cf..1573a7f793 100644 --- a/plugin/pkg/admission/deny/admission_test.go +++ b/plugin/pkg/admission/deny/admission_test.go @@ -25,7 +25,7 @@ import ( func TestAdmission(t *testing.T) { handler := NewAlwaysDeny() - err := handler.(*alwaysDeny).Admit(admission.NewAttributesRecord(nil, nil, api.Kind("kind").WithVersion("version"), "namespace", "name", api.Resource("resource").WithVersion("version"), "subresource", admission.Create, nil)) + err := handler.(*alwaysDeny).Admit(admission.NewAttributesRecord(nil, nil, api.Kind("kind").WithVersion("version"), "namespace", "name", api.Resource("resource").WithVersion("version"), "subresource", admission.Create, false, nil)) if err == nil { t.Error("Expected error returned from admission handler") } diff --git a/plugin/pkg/admission/eventratelimit/admission.go b/plugin/pkg/admission/eventratelimit/admission.go index d4880abddc..84e92db09d 100644 --- a/plugin/pkg/admission/eventratelimit/admission.go +++ b/plugin/pkg/admission/eventratelimit/admission.go @@ -87,6 +87,13 @@ func (a *Plugin) Validate(attr admission.Attributes) (err error) { return nil } + // ignore all requests that specify dry-run + // because they don't correspond to any calls to etcd, + // they should not be affected by the ratelimit + if attr.IsDryRun() { + return nil + } + var errors []error // give each limit enforcer a chance to reject the event for _, enforcer := range a.limitEnforcers { diff --git a/plugin/pkg/admission/eventratelimit/admission_test.go b/plugin/pkg/admission/eventratelimit/admission_test.go index e0e96176c6..f684852046 100644 --- a/plugin/pkg/admission/eventratelimit/admission_test.go +++ b/plugin/pkg/admission/eventratelimit/admission_test.go @@ -46,6 +46,7 @@ func attributesForRequest(rq request) admission.Attributes { api.Resource("resource").WithVersion("version"), "", admission.Create, + rq.dryRun, &user.DefaultInfo{Name: rq.username}) } @@ -56,6 +57,7 @@ type request struct { event *api.Event delay time.Duration accepted bool + dryRun bool } func newRequest(kind string) request { @@ -91,6 +93,11 @@ func (r request) withEventComponent(component string) request { }) } +func (r request) withDryRun(dryRun bool) request { + r.dryRun = dryRun + return r +} + func (r request) withUser(name string) request { r.username = name return r @@ -153,6 +160,21 @@ func TestEventRateLimiting(t *testing.T) { newEventRequest().blocked(), }, }, + { + name: "event not blocked by dry-run requests", + serverBurst: 3, + requests: []request{ + newEventRequest(), + newEventRequest(), + newEventRequest().withDryRun(true), + newEventRequest().withDryRun(true), + newEventRequest().withDryRun(true), + newEventRequest().withDryRun(true), + newEventRequest(), + newEventRequest().blocked(), + newEventRequest().withDryRun(true), + }, + }, { name: "non-event not blocked after tokens exhausted", serverBurst: 3, diff --git a/plugin/pkg/admission/exec/admission_test.go b/plugin/pkg/admission/exec/admission_test.go index 649089ced9..8541a4266a 100644 --- a/plugin/pkg/admission/exec/admission_test.go +++ b/plugin/pkg/admission/exec/admission_test.go @@ -123,7 +123,7 @@ func testAdmission(t *testing.T, pod *api.Pod, handler *DenyExec, shouldAccept b // pods/exec { req := &rest.ConnectRequest{Name: pod.Name, ResourcePath: "pods/exec"} - err := handler.Validate(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, false, nil)) if shouldAccept && err != nil { 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 // pods/attach { req := &rest.ConnectRequest{Name: pod.Name, ResourcePath: "pods/attach"} - err := handler.Validate(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, false, nil)) if shouldAccept && err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } diff --git a/plugin/pkg/admission/extendedresourcetoleration/admission_test.go b/plugin/pkg/admission/extendedresourcetoleration/admission_test.go index 646ae007e1..7c8f645034 100644 --- a/plugin/pkg/admission/extendedresourcetoleration/admission_test.go +++ b/plugin/pkg/admission/extendedresourcetoleration/admission_test.go @@ -354,7 +354,7 @@ func TestAdmit(t *testing.T) { }, } for i, test := range tests { - err := plugin.Admit(admission.NewAttributesRecord(&test.requestedPod, nil, core.Kind("Pod").WithVersion("version"), "foo", "name", core.Resource("pods").WithVersion("version"), "", "ignored", nil)) + err := plugin.Admit(admission.NewAttributesRecord(&test.requestedPod, nil, core.Kind("Pod").WithVersion("version"), "foo", "name", core.Resource("pods").WithVersion("version"), "", "ignored", false, nil)) if err != nil { t.Errorf("[%d: %s] unexpected error %v for pod %+v", i, test.description, err, test.requestedPod) } diff --git a/plugin/pkg/admission/gc/gc_admission_test.go b/plugin/pkg/admission/gc/gc_admission_test.go index d5eae44654..753d4dc3c8 100644 --- a/plugin/pkg/admission/gc/gc_admission_test.go +++ b/plugin/pkg/admission/gc/gc_admission_test.go @@ -270,7 +270,7 @@ func TestGCAdmission(t *testing.T) { operation = admission.Update } 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, false, user) err = gcAdmit.Validate(attributes) if !tc.checkError(err) { @@ -518,7 +518,7 @@ func TestBlockOwnerDeletionAdmission(t *testing.T) { operation = admission.Update } 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, false, user) err := gcAdmit.Validate(attributes) if !tc.checkError(err) { diff --git a/plugin/pkg/admission/imagepolicy/admission_test.go b/plugin/pkg/admission/imagepolicy/admission_test.go index 04cd782254..bf31cef852 100644 --- a/plugin/pkg/admission/imagepolicy/admission_test.go +++ b/plugin/pkg/admission/imagepolicy/admission_test.go @@ -472,7 +472,7 @@ func TestTLSConfig(t *testing.T) { return } pod := goodPod(strconv.Itoa(rand.Intn(1000))) - 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, false, &user.DefaultInfo{}) // Allow all and see if we get an error. service.Allow() @@ -561,7 +561,7 @@ func TestWebhookCache(t *testing.T) { {statusCode: 500, expectedErr: false, expectedAuthorized: true, expectedCached: true}, } - attr := admission.NewAttributesRecord(goodPod("test"), nil, api.Kind("Pod").WithVersion("version"), "namespace", "", api.Resource("pods").WithVersion("version"), "", admission.Create, &user.DefaultInfo{}) + attr := admission.NewAttributesRecord(goodPod("test"), nil, api.Kind("Pod").WithVersion("version"), "namespace", "", api.Resource("pods").WithVersion("version"), "", admission.Create, false, &user.DefaultInfo{}) serv.allow = true @@ -573,7 +573,7 @@ func TestWebhookCache(t *testing.T) { {statusCode: 200, expectedErr: false, expectedAuthorized: true, expectedCached: false}, {statusCode: 500, expectedErr: false, expectedAuthorized: true, expectedCached: true}, } - attr = admission.NewAttributesRecord(goodPod("test2"), nil, api.Kind("Pod").WithVersion("version"), "namespace", "", api.Resource("pods").WithVersion("version"), "", admission.Create, &user.DefaultInfo{}) + attr = admission.NewAttributesRecord(goodPod("test2"), nil, api.Kind("Pod").WithVersion("version"), "namespace", "", api.Resource("pods").WithVersion("version"), "", admission.Create, false, &user.DefaultInfo{}) testWebhookCacheCases(t, serv, wh, attr, tests) } @@ -747,7 +747,7 @@ func TestContainerCombinations(t *testing.T) { return } - 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, false, &user.DefaultInfo{}) err = wh.Validate(attr) if tt.wantAllowed { @@ -825,7 +825,7 @@ func TestDefaultAllow(t *testing.T) { return } - 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, false, &user.DefaultInfo{}) err = wh.Validate(attr) if tt.wantAllowed { @@ -917,7 +917,7 @@ func TestAnnotationFiltering(t *testing.T) { pod := goodPod("test") pod.Annotations = tt.annotations - 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, false, &user.DefaultInfo{}) err = wh.Validate(attr) if err != nil { diff --git a/plugin/pkg/admission/limitranger/admission_test.go b/plugin/pkg/admission/limitranger/admission_test.go index 33213a582b..0504614310 100644 --- a/plugin/pkg/admission/limitranger/admission_test.go +++ b/plugin/pkg/admission/limitranger/admission_test.go @@ -694,16 +694,16 @@ func TestLimitRangerIgnoresSubresource(t *testing.T) { informerFactory.Start(wait.NeverStop) testPod := validPod("testPod", 1, api.ResourceRequirements{}) - err = handler.Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, nil)) + err = handler.Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil)) if err != nil { t.Fatal(err) } - err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, nil)) + err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil)) if err == nil { t.Errorf("Expected an error since the pod did not specify resource limits in its update call") } - err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, nil)) + err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, false, nil)) if err != nil { t.Errorf("Should have ignored calls to any subresource of pod %v", err) } @@ -720,16 +720,16 @@ func TestLimitRangerAdmitPod(t *testing.T) { informerFactory.Start(wait.NeverStop) testPod := validPod("testPod", 1, api.ResourceRequirements{}) - err = handler.Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, nil)) + err = handler.Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil)) if err != nil { t.Fatal(err) } - err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, nil)) + err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil)) if err == nil { t.Errorf("Expected an error since the pod did not specify resource limits in its update call") } - err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, nil)) + err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, false, nil)) if err != nil { t.Errorf("Should have ignored calls to any subresource of pod %v", err) } @@ -738,7 +738,7 @@ func TestLimitRangerAdmitPod(t *testing.T) { terminatingPod := validPod("terminatingPod", 1, api.ResourceRequirements{}) now := metav1.Now() terminatingPod.DeletionTimestamp = &now - err = handler.Validate(admission.NewAttributesRecord(&terminatingPod, &terminatingPod, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "terminatingPod", api.Resource("pods").WithVersion("version"), "", admission.Update, nil)) + err = handler.Validate(admission.NewAttributesRecord(&terminatingPod, &terminatingPod, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "terminatingPod", api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil)) if err != nil { t.Errorf("LimitRange should ignore a pod marked for termination") } diff --git a/plugin/pkg/admission/namespace/autoprovision/admission.go b/plugin/pkg/admission/namespace/autoprovision/admission.go index c87a1aac2b..9e84a6cf2d 100644 --- a/plugin/pkg/admission/namespace/autoprovision/admission.go +++ b/plugin/pkg/admission/namespace/autoprovision/admission.go @@ -55,6 +55,11 @@ var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&Provision{}) // Admit makes an admission decision based on the request attributes func (p *Provision) Admit(a admission.Attributes) error { + // Don't create a namespace if the request is for a dry-run. + if a.IsDryRun() { + return nil + } + // 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 // its a namespaced resource. diff --git a/plugin/pkg/admission/namespace/autoprovision/admission_test.go b/plugin/pkg/admission/namespace/autoprovision/admission_test.go index df316c4378..748ef9f382 100644 --- a/plugin/pkg/admission/namespace/autoprovision/admission_test.go +++ b/plugin/pkg/admission/namespace/autoprovision/admission_test.go @@ -98,7 +98,7 @@ func TestAdmission(t *testing.T) { informerFactory.Start(wait.NeverStop) 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.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("unexpected error returned from admission handler") } @@ -118,7 +118,27 @@ func TestAdmissionNamespaceExists(t *testing.T) { informerFactory.Start(wait.NeverStop) 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.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) + if err != nil { + t.Errorf("unexpected error returned from admission handler") + } + if hasCreateNamespaceAction(mockClient) { + t.Errorf("unexpected create namespace action") + } +} + +// TestAdmissionDryRun verifies that no client call is made on a dry run request +func TestAdmissionDryRun(t *testing.T) { + namespace := "test" + mockClient := newMockClientForTest([]string{}) + handler, informerFactory, err := newHandlerForTest(mockClient) + if err != nil { + t.Errorf("unexpected error initializing handler: %v", err) + } + informerFactory.Start(wait.NeverStop) + + 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, true, nil)) if err != nil { t.Errorf("unexpected error returned from admission handler") } @@ -139,7 +159,7 @@ func TestIgnoreAdmission(t *testing.T) { chainHandler := admission.NewChainHandler(handler) pod := newPod(namespace) - err = chainHandler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, nil)) + err = chainHandler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil)) if err != nil { t.Errorf("unexpected error returned from admission handler") } @@ -161,7 +181,7 @@ func TestAdmissionWithLatentCache(t *testing.T) { informerFactory.Start(wait.NeverStop) 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.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("unexpected error returned from admission handler") } diff --git a/plugin/pkg/admission/namespace/exists/admission_test.go b/plugin/pkg/admission/namespace/exists/admission_test.go index 6cfc2d96e8..99b0734e82 100644 --- a/plugin/pkg/admission/namespace/exists/admission_test.go +++ b/plugin/pkg/admission/namespace/exists/admission_test.go @@ -87,7 +87,7 @@ func TestAdmissionNamespaceExists(t *testing.T) { informerFactory.Start(wait.NeverStop) pod := newPod(namespace) - err = handler.Validate(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, false, nil)) if err != nil { t.Errorf("unexpected error returned from admission handler") } @@ -107,7 +107,7 @@ func TestAdmissionNamespaceDoesNotExist(t *testing.T) { informerFactory.Start(wait.NeverStop) pod := newPod(namespace) - err = handler.Validate(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, false, nil)) if err == nil { actions := "" for _, action := range mockClient.Actions() { diff --git a/plugin/pkg/admission/noderestriction/admission_test.go b/plugin/pkg/admission/noderestriction/admission_test.go index 0c22775dfd..c608b46c91 100644 --- a/plugin/pkg/admission/noderestriction/admission_test.go +++ b/plugin/pkg/admission/noderestriction/admission_test.go @@ -175,61 +175,61 @@ func Test_nodePlugin_Admit(t *testing.T) { { name: "allow creating a mirror pod bound to self", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(mymirrorpod, nil, podKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "", admission.Create, mynode), + attributes: admission.NewAttributesRecord(mymirrorpod, nil, podKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "", admission.Create, false, mynode), err: "", }, { name: "forbid update of mirror pod bound to self", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mymirrorpod, mymirrorpod, podKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mymirrorpod, mymirrorpod, podKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "", admission.Update, false, mynode), err: "forbidden: unexpected operation", }, { name: "allow delete of mirror pod bound to self", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(nil, nil, podKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(nil, nil, podKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "", admission.Delete, false, mynode), err: "", }, { name: "forbid create of mirror pod status bound to self", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(mymirrorpod, nil, podKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "status", admission.Create, mynode), + attributes: admission.NewAttributesRecord(mymirrorpod, nil, podKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "status", admission.Create, false, mynode), err: "forbidden: unexpected operation", }, { name: "allow update of mirror pod status bound to self", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mymirrorpod, mymirrorpod, podKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "status", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mymirrorpod, mymirrorpod, podKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "status", admission.Update, false, mynode), err: "", }, { name: "forbid delete of mirror pod status bound to self", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(nil, nil, podKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "status", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(nil, nil, podKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "status", admission.Delete, false, mynode), err: "forbidden: unexpected operation", }, { name: "allow create of eviction for mirror pod bound to self", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mymirrorpodEviction, nil, evictionKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "eviction", admission.Create, mynode), + attributes: admission.NewAttributesRecord(mymirrorpodEviction, nil, evictionKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "eviction", admission.Create, false, mynode), err: "", }, { name: "forbid update of eviction for mirror pod bound to self", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mymirrorpodEviction, nil, evictionKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "eviction", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mymirrorpodEviction, nil, evictionKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "eviction", admission.Update, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid delete of eviction for mirror pod bound to self", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mymirrorpodEviction, nil, evictionKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "eviction", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(mymirrorpodEviction, nil, evictionKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "eviction", admission.Delete, false, mynode), err: "forbidden: unexpected operation", }, { name: "allow create of unnamed eviction for mirror pod bound to self", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "eviction", admission.Create, mynode), + attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "eviction", admission.Create, false, mynode), err: "", }, @@ -237,61 +237,61 @@ func Test_nodePlugin_Admit(t *testing.T) { { name: "forbid creating a mirror pod bound to another", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(othermirrorpod, nil, podKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "", admission.Create, mynode), + attributes: admission.NewAttributesRecord(othermirrorpod, nil, podKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "", admission.Create, false, mynode), err: "spec.nodeName set to itself", }, { name: "forbid update of mirror pod bound to another", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(othermirrorpod, othermirrorpod, podKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "", admission.Update, mynode), + attributes: admission.NewAttributesRecord(othermirrorpod, othermirrorpod, podKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "", admission.Update, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid delete of mirror pod bound to another", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(nil, nil, podKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(nil, nil, podKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "", admission.Delete, false, mynode), err: "spec.nodeName set to itself", }, { name: "forbid create of mirror pod status bound to another", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(othermirrorpod, nil, podKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "status", admission.Create, mynode), + attributes: admission.NewAttributesRecord(othermirrorpod, nil, podKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "status", admission.Create, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid update of mirror pod status bound to another", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(othermirrorpod, othermirrorpod, podKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "status", admission.Update, mynode), + attributes: admission.NewAttributesRecord(othermirrorpod, othermirrorpod, podKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "status", admission.Update, false, mynode), err: "spec.nodeName set to itself", }, { name: "forbid delete of mirror pod status bound to another", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(nil, nil, podKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "status", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(nil, nil, podKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "status", admission.Delete, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid create of eviction for mirror pod bound to another", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(othermirrorpodEviction, nil, evictionKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "eviction", admission.Create, mynode), + attributes: admission.NewAttributesRecord(othermirrorpodEviction, nil, evictionKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "eviction", admission.Create, false, mynode), err: "spec.nodeName set to itself", }, { name: "forbid update of eviction for mirror pod bound to another", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(othermirrorpodEviction, nil, evictionKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "eviction", admission.Update, mynode), + attributes: admission.NewAttributesRecord(othermirrorpodEviction, nil, evictionKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "eviction", admission.Update, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid delete of eviction for mirror pod bound to another", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(othermirrorpodEviction, nil, evictionKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "eviction", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(othermirrorpodEviction, nil, evictionKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "eviction", admission.Delete, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid create of unnamed eviction for mirror pod to another", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "eviction", admission.Create, mynode), + attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "eviction", admission.Create, false, mynode), err: "spec.nodeName set to itself", }, @@ -299,61 +299,61 @@ func Test_nodePlugin_Admit(t *testing.T) { { name: "forbid creating a mirror pod unbound", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(unboundmirrorpod, nil, podKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "", admission.Create, mynode), + attributes: admission.NewAttributesRecord(unboundmirrorpod, nil, podKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "", admission.Create, false, mynode), err: "spec.nodeName set to itself", }, { name: "forbid update of mirror pod unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unboundmirrorpod, unboundmirrorpod, podKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "", admission.Update, mynode), + attributes: admission.NewAttributesRecord(unboundmirrorpod, unboundmirrorpod, podKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "", admission.Update, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid delete of mirror pod unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(nil, nil, podKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(nil, nil, podKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "", admission.Delete, false, mynode), err: "spec.nodeName set to itself", }, { name: "forbid create of mirror pod status unbound", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(unboundmirrorpod, nil, podKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "status", admission.Create, mynode), + attributes: admission.NewAttributesRecord(unboundmirrorpod, nil, podKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "status", admission.Create, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid update of mirror pod status unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unboundmirrorpod, unboundmirrorpod, podKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "status", admission.Update, mynode), + attributes: admission.NewAttributesRecord(unboundmirrorpod, unboundmirrorpod, podKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "status", admission.Update, false, mynode), err: "spec.nodeName set to itself", }, { name: "forbid delete of mirror pod status unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(nil, nil, podKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "status", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(nil, nil, podKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "status", admission.Delete, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid create of eviction for mirror pod unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unboundmirrorpodEviction, nil, evictionKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "eviction", admission.Create, mynode), + attributes: admission.NewAttributesRecord(unboundmirrorpodEviction, nil, evictionKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "eviction", admission.Create, false, mynode), err: "spec.nodeName set to itself", }, { name: "forbid update of eviction for mirror pod unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unboundmirrorpodEviction, nil, evictionKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "eviction", admission.Update, mynode), + attributes: admission.NewAttributesRecord(unboundmirrorpodEviction, nil, evictionKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "eviction", admission.Update, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid delete of eviction for mirror pod unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unboundmirrorpodEviction, nil, evictionKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "eviction", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(unboundmirrorpodEviction, nil, evictionKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "eviction", admission.Delete, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid create of unnamed eviction for mirror pod unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "eviction", admission.Create, mynode), + attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "eviction", admission.Create, false, mynode), err: "spec.nodeName set to itself", }, @@ -361,55 +361,55 @@ func Test_nodePlugin_Admit(t *testing.T) { { name: "forbid creating a normal pod bound to self", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(mypod, nil, podKind, mypod.Namespace, mypod.Name, podResource, "", admission.Create, mynode), + attributes: admission.NewAttributesRecord(mypod, nil, podKind, mypod.Namespace, mypod.Name, podResource, "", admission.Create, false, mynode), err: "can only create mirror pods", }, { name: "forbid update of normal pod bound to self", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mypod, mypod, podKind, mypod.Namespace, mypod.Name, podResource, "", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mypod, mypod, podKind, mypod.Namespace, mypod.Name, podResource, "", admission.Update, false, mynode), err: "forbidden: unexpected operation", }, { name: "allow delete of normal pod bound to self", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(nil, nil, podKind, mypod.Namespace, mypod.Name, podResource, "", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(nil, nil, podKind, mypod.Namespace, mypod.Name, podResource, "", admission.Delete, false, mynode), err: "", }, { name: "forbid create of normal pod status bound to self", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(mypod, nil, podKind, mypod.Namespace, mypod.Name, podResource, "status", admission.Create, mynode), + attributes: admission.NewAttributesRecord(mypod, nil, podKind, mypod.Namespace, mypod.Name, podResource, "status", admission.Create, false, mynode), err: "forbidden: unexpected operation", }, { name: "allow update of normal pod status bound to self", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mypod, mypod, podKind, mypod.Namespace, mypod.Name, podResource, "status", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mypod, mypod, podKind, mypod.Namespace, mypod.Name, podResource, "status", admission.Update, false, mynode), err: "", }, { name: "forbid delete of normal pod status bound to self", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(nil, nil, podKind, mypod.Namespace, mypod.Name, podResource, "status", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(nil, nil, podKind, mypod.Namespace, mypod.Name, podResource, "status", admission.Delete, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid update of eviction for normal pod bound to self", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Update, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid delete of eviction for normal pod bound to self", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Delete, false, mynode), err: "forbidden: unexpected operation", }, { name: "allow create of unnamed eviction for normal pod bound to self", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Create, mynode), + attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Create, false, mynode), err: "", }, @@ -417,61 +417,61 @@ func Test_nodePlugin_Admit(t *testing.T) { { name: "forbid creating a normal pod bound to another", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(otherpod, nil, podKind, otherpod.Namespace, otherpod.Name, podResource, "", admission.Create, mynode), + attributes: admission.NewAttributesRecord(otherpod, nil, podKind, otherpod.Namespace, otherpod.Name, podResource, "", admission.Create, false, mynode), err: "can only create mirror pods", }, { name: "forbid update of normal pod bound to another", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(otherpod, otherpod, podKind, otherpod.Namespace, otherpod.Name, podResource, "", admission.Update, mynode), + attributes: admission.NewAttributesRecord(otherpod, otherpod, podKind, otherpod.Namespace, otherpod.Name, podResource, "", admission.Update, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid delete of normal pod bound to another", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(nil, nil, podKind, otherpod.Namespace, otherpod.Name, podResource, "", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(nil, nil, podKind, otherpod.Namespace, otherpod.Name, podResource, "", admission.Delete, false, mynode), err: "spec.nodeName set to itself", }, { name: "forbid create of normal pod status bound to another", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(otherpod, nil, podKind, otherpod.Namespace, otherpod.Name, podResource, "status", admission.Create, mynode), + attributes: admission.NewAttributesRecord(otherpod, nil, podKind, otherpod.Namespace, otherpod.Name, podResource, "status", admission.Create, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid update of normal pod status bound to another", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(otherpod, otherpod, podKind, otherpod.Namespace, otherpod.Name, podResource, "status", admission.Update, mynode), + attributes: admission.NewAttributesRecord(otherpod, otherpod, podKind, otherpod.Namespace, otherpod.Name, podResource, "status", admission.Update, false, mynode), err: "spec.nodeName set to itself", }, { name: "forbid delete of normal pod status bound to another", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(nil, nil, podKind, otherpod.Namespace, otherpod.Name, podResource, "status", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(nil, nil, podKind, otherpod.Namespace, otherpod.Name, podResource, "status", admission.Delete, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid create of eviction for normal pod bound to another", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(otherpodEviction, nil, evictionKind, otherpodEviction.Namespace, otherpodEviction.Name, podResource, "eviction", admission.Create, mynode), + attributes: admission.NewAttributesRecord(otherpodEviction, nil, evictionKind, otherpodEviction.Namespace, otherpodEviction.Name, podResource, "eviction", admission.Create, false, mynode), err: "spec.nodeName set to itself", }, { name: "forbid update of eviction for normal pod bound to another", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(otherpodEviction, nil, evictionKind, otherpodEviction.Namespace, otherpodEviction.Name, podResource, "eviction", admission.Update, mynode), + attributes: admission.NewAttributesRecord(otherpodEviction, nil, evictionKind, otherpodEviction.Namespace, otherpodEviction.Name, podResource, "eviction", admission.Update, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid delete of eviction for normal pod bound to another", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(otherpodEviction, nil, evictionKind, otherpodEviction.Namespace, otherpodEviction.Name, podResource, "eviction", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(otherpodEviction, nil, evictionKind, otherpodEviction.Namespace, otherpodEviction.Name, podResource, "eviction", admission.Delete, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid create of unnamed eviction for normal pod bound to another", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, otherpod.Namespace, otherpod.Name, podResource, "eviction", admission.Create, mynode), + attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, otherpod.Namespace, otherpod.Name, podResource, "eviction", admission.Create, false, mynode), err: "spec.nodeName set to itself", }, @@ -479,61 +479,61 @@ func Test_nodePlugin_Admit(t *testing.T) { { name: "forbid creating a normal pod unbound", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(unboundpod, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "", admission.Create, mynode), + attributes: admission.NewAttributesRecord(unboundpod, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "", admission.Create, false, mynode), err: "can only create mirror pods", }, { name: "forbid update of normal pod unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unboundpod, unboundpod, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "", admission.Update, mynode), + attributes: admission.NewAttributesRecord(unboundpod, unboundpod, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "", admission.Update, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid delete of normal pod unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(nil, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(nil, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "", admission.Delete, false, mynode), err: "spec.nodeName set to itself", }, { name: "forbid create of normal pod status unbound", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(unboundpod, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "status", admission.Create, mynode), + attributes: admission.NewAttributesRecord(unboundpod, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "status", admission.Create, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid update of normal pod status unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unboundpod, unboundpod, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "status", admission.Update, mynode), + attributes: admission.NewAttributesRecord(unboundpod, unboundpod, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "status", admission.Update, false, mynode), err: "spec.nodeName set to itself", }, { name: "forbid delete of normal pod status unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(nil, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "status", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(nil, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "status", admission.Delete, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid create of eviction for normal pod unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unboundpodEviction, nil, evictionKind, unboundpod.Namespace, unboundpod.Name, podResource, "eviction", admission.Create, mynode), + attributes: admission.NewAttributesRecord(unboundpodEviction, nil, evictionKind, unboundpod.Namespace, unboundpod.Name, podResource, "eviction", admission.Create, false, mynode), err: "spec.nodeName set to itself", }, { name: "forbid update of eviction for normal pod unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unboundpodEviction, nil, evictionKind, unboundpod.Namespace, unboundpod.Name, podResource, "eviction", admission.Update, mynode), + attributes: admission.NewAttributesRecord(unboundpodEviction, nil, evictionKind, unboundpod.Namespace, unboundpod.Name, podResource, "eviction", admission.Update, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid delete of eviction for normal pod unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unboundpodEviction, nil, evictionKind, unboundpod.Namespace, unboundpod.Name, podResource, "eviction", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(unboundpodEviction, nil, evictionKind, unboundpod.Namespace, unboundpod.Name, podResource, "eviction", admission.Delete, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid create of unnamed eviction for normal unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, unboundpod.Namespace, unboundpod.Name, podResource, "eviction", admission.Create, mynode), + attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, unboundpod.Namespace, unboundpod.Name, podResource, "eviction", admission.Create, false, mynode), err: "spec.nodeName set to itself", }, @@ -541,31 +541,31 @@ func Test_nodePlugin_Admit(t *testing.T) { { name: "forbid delete of unknown pod", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(nil, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(nil, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "", admission.Delete, false, mynode), err: "not found", }, { name: "forbid create of eviction for unknown pod", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Create, mynode), + attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Create, false, mynode), err: "not found", }, { name: "forbid update of eviction for unknown pod", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Update, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid delete of eviction for unknown pod", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Delete, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid create of unnamed eviction for unknown pod", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Create, mynode), + attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Create, false, mynode), err: "not found", }, @@ -573,26 +573,26 @@ func Test_nodePlugin_Admit(t *testing.T) { { name: "allow create of eviction for unnamed pod", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, unnamedpod.Namespace, unnamedpod.Name, podResource, "eviction", admission.Create, mynode), + attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, unnamedpod.Namespace, unnamedpod.Name, podResource, "eviction", admission.Create, false, mynode), // use the submitted eviction resource name as the pod name err: "", }, { name: "forbid update of eviction for unnamed pod", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, unnamedpod.Namespace, unnamedpod.Name, podResource, "eviction", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, unnamedpod.Namespace, unnamedpod.Name, podResource, "eviction", admission.Update, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid delete of eviction for unnamed pod", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, unnamedpod.Namespace, unnamedpod.Name, podResource, "eviction", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, unnamedpod.Namespace, unnamedpod.Name, podResource, "eviction", admission.Delete, false, mynode), err: "forbidden: unexpected operation", }, { name: "forbid create of unnamed eviction for unnamed pod", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, unnamedpod.Namespace, unnamedpod.Name, podResource, "eviction", admission.Create, mynode), + attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, unnamedpod.Namespace, unnamedpod.Name, podResource, "eviction", admission.Create, false, mynode), err: "could not determine pod from request data", }, @@ -600,25 +600,25 @@ func Test_nodePlugin_Admit(t *testing.T) { { name: "forbid create of pod referencing service account", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(sapod, nil, podKind, sapod.Namespace, sapod.Name, podResource, "", admission.Create, mynode), + attributes: admission.NewAttributesRecord(sapod, nil, podKind, sapod.Namespace, sapod.Name, podResource, "", admission.Create, false, mynode), err: "reference a service account", }, { name: "forbid create of pod referencing secret", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(secretpod, nil, podKind, secretpod.Namespace, secretpod.Name, podResource, "", admission.Create, mynode), + attributes: admission.NewAttributesRecord(secretpod, nil, podKind, secretpod.Namespace, secretpod.Name, podResource, "", admission.Create, false, mynode), err: "reference secrets", }, { name: "forbid create of pod referencing configmap", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(configmappod, nil, podKind, configmappod.Namespace, configmappod.Name, podResource, "", admission.Create, mynode), + attributes: admission.NewAttributesRecord(configmappod, nil, podKind, configmappod.Namespace, configmappod.Name, podResource, "", admission.Create, false, mynode), err: "reference configmaps", }, { name: "forbid create of pod referencing persistentvolumeclaim", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(pvcpod, nil, podKind, pvcpod.Namespace, pvcpod.Name, podResource, "", admission.Create, mynode), + attributes: admission.NewAttributesRecord(pvcpod, nil, podKind, pvcpod.Namespace, pvcpod.Name, podResource, "", admission.Create, false, mynode), err: "reference persistentvolumeclaims", }, @@ -626,91 +626,91 @@ func Test_nodePlugin_Admit(t *testing.T) { { name: "allow create of my node", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(mynodeObj, nil, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Create, mynode), + attributes: admission.NewAttributesRecord(mynodeObj, nil, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Create, false, mynode), err: "", }, { name: "allow create of my node pulling name from object", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(mynodeObj, nil, nodeKind, mynodeObj.Namespace, "", nodeResource, "", admission.Create, mynode), + attributes: admission.NewAttributesRecord(mynodeObj, nil, nodeKind, mynodeObj.Namespace, "", nodeResource, "", admission.Create, false, mynode), err: "", }, { name: "allow create of my node with taints", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(mynodeObjTaintA, nil, nodeKind, mynodeObj.Namespace, "", nodeResource, "", admission.Create, mynode), + attributes: admission.NewAttributesRecord(mynodeObjTaintA, nil, nodeKind, mynodeObj.Namespace, "", nodeResource, "", admission.Create, false, mynode), err: "", }, { name: "allow update of my node", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mynodeObj, mynodeObj, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mynodeObj, mynodeObj, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, false, mynode), err: "", }, { name: "allow delete of my node", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(nil, nil, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(nil, nil, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Delete, false, mynode), err: "", }, { name: "allow update of my node status", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mynodeObj, mynodeObj, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "status", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mynodeObj, mynodeObj, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "status", admission.Update, false, mynode), err: "", }, { name: "forbid create of my node with non-nil configSource", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(mynodeObjConfigA, nil, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Create, mynode), + attributes: admission.NewAttributesRecord(mynodeObjConfigA, nil, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Create, false, mynode), err: "create with non-nil configSource", }, { name: "forbid update of my node: nil configSource to new non-nil configSource", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mynodeObjConfigA, mynodeObj, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mynodeObjConfigA, mynodeObj, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, false, mynode), err: "update configSource to a new non-nil configSource", }, { name: "forbid update of my node: non-nil configSource to new non-nil configSource", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mynodeObjConfigB, mynodeObjConfigA, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mynodeObjConfigB, mynodeObjConfigA, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, false, mynode), err: "update configSource to a new non-nil configSource", }, { name: "allow update of my node: non-nil configSource unchanged", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mynodeObjConfigA, mynodeObjConfigA, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mynodeObjConfigA, mynodeObjConfigA, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, false, mynode), err: "", }, { name: "allow update of my node: non-nil configSource to nil configSource", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mynodeObj, mynodeObjConfigA, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mynodeObj, mynodeObjConfigA, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, false, mynode), err: "", }, { name: "allow update of my node: no change to taints", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mynodeObjTaintA, mynodeObjTaintA, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mynodeObjTaintA, mynodeObjTaintA, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, false, mynode), err: "", }, { name: "forbid update of my node: add taints", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mynodeObjTaintA, mynodeObj, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mynodeObjTaintA, mynodeObj, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, false, mynode), err: "cannot modify taints", }, { name: "forbid update of my node: remove taints", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mynodeObj, mynodeObjTaintA, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mynodeObj, mynodeObjTaintA, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, false, mynode), err: "cannot modify taints", }, { name: "forbid update of my node: change taints", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(mynodeObjTaintA, mynodeObjTaintB, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, mynode), + attributes: admission.NewAttributesRecord(mynodeObjTaintA, mynodeObjTaintB, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, false, mynode), err: "cannot modify taints", }, @@ -718,31 +718,31 @@ func Test_nodePlugin_Admit(t *testing.T) { { name: "forbid create of other node", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(othernodeObj, nil, nodeKind, othernodeObj.Namespace, othernodeObj.Name, nodeResource, "", admission.Create, mynode), + attributes: admission.NewAttributesRecord(othernodeObj, nil, nodeKind, othernodeObj.Namespace, othernodeObj.Name, nodeResource, "", admission.Create, false, mynode), err: "cannot modify node", }, { name: "forbid create of other node pulling name from object", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(othernodeObj, nil, nodeKind, othernodeObj.Namespace, "", nodeResource, "", admission.Create, mynode), + attributes: admission.NewAttributesRecord(othernodeObj, nil, nodeKind, othernodeObj.Namespace, "", nodeResource, "", admission.Create, false, mynode), err: "cannot modify node", }, { name: "forbid update of other node", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(othernodeObj, othernodeObj, nodeKind, othernodeObj.Namespace, othernodeObj.Name, nodeResource, "", admission.Update, mynode), + attributes: admission.NewAttributesRecord(othernodeObj, othernodeObj, nodeKind, othernodeObj.Namespace, othernodeObj.Name, nodeResource, "", admission.Update, false, mynode), err: "cannot modify node", }, { name: "forbid delete of other node", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(nil, nil, nodeKind, othernodeObj.Namespace, othernodeObj.Name, nodeResource, "", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(nil, nil, nodeKind, othernodeObj.Namespace, othernodeObj.Name, nodeResource, "", admission.Delete, false, mynode), err: "cannot modify node", }, { name: "forbid update of other node status", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(othernodeObj, othernodeObj, nodeKind, othernodeObj.Namespace, othernodeObj.Name, nodeResource, "status", admission.Update, mynode), + attributes: admission.NewAttributesRecord(othernodeObj, othernodeObj, nodeKind, othernodeObj.Namespace, othernodeObj.Name, nodeResource, "status", admission.Update, false, mynode), err: "cannot modify node", }, @@ -751,54 +751,54 @@ func Test_nodePlugin_Admit(t *testing.T) { name: "forbid create of unbound token", podsGetter: noExistingPods, features: trEnabledFeature, - attributes: admission.NewAttributesRecord(makeTokenRequest("", ""), nil, tokenrequestKind, "ns", "mysa", svcacctResource, "token", admission.Create, mynode), + attributes: admission.NewAttributesRecord(makeTokenRequest("", ""), nil, tokenrequestKind, "ns", "mysa", svcacctResource, "token", admission.Create, false, mynode), err: "not bound to a pod", }, { name: "forbid create of token bound to nonexistant pod", podsGetter: noExistingPods, features: trEnabledFeature, - attributes: admission.NewAttributesRecord(makeTokenRequest("nopod", "someuid"), nil, tokenrequestKind, "ns", "mysa", svcacctResource, "token", admission.Create, mynode), + attributes: admission.NewAttributesRecord(makeTokenRequest("nopod", "someuid"), nil, tokenrequestKind, "ns", "mysa", svcacctResource, "token", admission.Create, false, mynode), err: "not found", }, { name: "forbid create of token bound to pod without uid", podsGetter: existingPods, features: trEnabledFeature, - attributes: admission.NewAttributesRecord(makeTokenRequest(mypod.Name, ""), nil, tokenrequestKind, "ns", "mysa", svcacctResource, "token", admission.Create, mynode), + attributes: admission.NewAttributesRecord(makeTokenRequest(mypod.Name, ""), nil, tokenrequestKind, "ns", "mysa", svcacctResource, "token", admission.Create, false, mynode), err: "pod binding without a uid", }, { name: "forbid create of token bound to pod scheduled on another node", podsGetter: existingPods, features: trEnabledFeature, - attributes: admission.NewAttributesRecord(makeTokenRequest(otherpod.Name, otherpod.UID), nil, tokenrequestKind, otherpod.Namespace, "mysa", svcacctResource, "token", admission.Create, mynode), + attributes: admission.NewAttributesRecord(makeTokenRequest(otherpod.Name, otherpod.UID), nil, tokenrequestKind, otherpod.Namespace, "mysa", svcacctResource, "token", admission.Create, false, mynode), err: "pod scheduled on a different node", }, { name: "allow create of token bound to pod scheduled this node", podsGetter: existingPods, features: trEnabledFeature, - attributes: admission.NewAttributesRecord(makeTokenRequest(mypod.Name, mypod.UID), nil, tokenrequestKind, mypod.Namespace, "mysa", svcacctResource, "token", admission.Create, mynode), + attributes: admission.NewAttributesRecord(makeTokenRequest(mypod.Name, mypod.UID), nil, tokenrequestKind, mypod.Namespace, "mysa", svcacctResource, "token", admission.Create, false, mynode), }, // Unrelated objects { name: "allow create of unrelated object", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(&api.ConfigMap{}, nil, configmapKind, "myns", "mycm", configmapResource, "", admission.Create, mynode), + attributes: admission.NewAttributesRecord(&api.ConfigMap{}, nil, configmapKind, "myns", "mycm", configmapResource, "", admission.Create, false, mynode), err: "", }, { name: "allow update of unrelated object", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(&api.ConfigMap{}, &api.ConfigMap{}, configmapKind, "myns", "mycm", configmapResource, "", admission.Update, mynode), + attributes: admission.NewAttributesRecord(&api.ConfigMap{}, &api.ConfigMap{}, configmapKind, "myns", "mycm", configmapResource, "", admission.Update, false, mynode), err: "", }, { name: "allow delete of unrelated object", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(nil, nil, configmapKind, "myns", "mycm", configmapResource, "", admission.Delete, mynode), + attributes: admission.NewAttributesRecord(nil, nil, configmapKind, "myns", "mycm", configmapResource, "", admission.Delete, false, mynode), err: "", }, @@ -806,37 +806,37 @@ func Test_nodePlugin_Admit(t *testing.T) { { name: "allow unrelated user creating a normal pod unbound", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(unboundpod, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "", admission.Create, bob), + attributes: admission.NewAttributesRecord(unboundpod, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "", admission.Create, false, bob), err: "", }, { name: "allow unrelated user update of normal pod unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unboundpod, unboundpod, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "", admission.Update, bob), + attributes: admission.NewAttributesRecord(unboundpod, unboundpod, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "", admission.Update, false, bob), err: "", }, { name: "allow unrelated user delete of normal pod unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(nil, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "", admission.Delete, bob), + attributes: admission.NewAttributesRecord(nil, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "", admission.Delete, false, bob), err: "", }, { name: "allow unrelated user create of normal pod status unbound", podsGetter: noExistingPods, - attributes: admission.NewAttributesRecord(unboundpod, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "status", admission.Create, bob), + attributes: admission.NewAttributesRecord(unboundpod, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "status", admission.Create, false, bob), err: "", }, { name: "allow unrelated user update of normal pod status unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(unboundpod, unboundpod, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "status", admission.Update, bob), + attributes: admission.NewAttributesRecord(unboundpod, unboundpod, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "status", admission.Update, false, bob), err: "", }, { name: "allow unrelated user delete of normal pod status unbound", podsGetter: existingPods, - attributes: admission.NewAttributesRecord(nil, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "status", admission.Delete, bob), + attributes: admission.NewAttributesRecord(nil, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "status", admission.Delete, false, bob), err: "", }, } diff --git a/plugin/pkg/admission/podnodeselector/admission_test.go b/plugin/pkg/admission/podnodeselector/admission_test.go index 2f77359317..f9aad7bebb 100644 --- a/plugin/pkg/admission/podnodeselector/admission_test.go +++ b/plugin/pkg/admission/podnodeselector/admission_test.go @@ -166,7 +166,7 @@ func TestPodAdmission(t *testing.T) { handler.clusterNodeSelectors[namespace.Name] = test.whitelist pod.Spec = api.PodSpec{NodeSelector: test.podNodeSelector} - err := handler.Admit(admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err := handler.Admit(admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if test.admit && err != nil { t.Errorf("Test: %s, expected no error but got: %s", test.testName, err) } else if !test.admit && err == nil { @@ -175,7 +175,7 @@ func TestPodAdmission(t *testing.T) { if test.admit && !labels.Equals(test.mergedNodeSelector, labels.Set(pod.Spec.NodeSelector)) { t.Errorf("Test: %s, expected: %s but got: %s", test.testName, test.mergedNodeSelector, pod.Spec.NodeSelector) } - err = handler.Validate(admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err = handler.Validate(admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if test.admit && err != nil { t.Errorf("Test: %s, expected no error but got: %s", test.testName, err) } else if !test.admit && err == nil { @@ -183,7 +183,7 @@ func TestPodAdmission(t *testing.T) { } // handles update of uninitialized pod like it's newly created. - err = handler.Admit(admission.NewAttributesRecord(pod, &oldPod, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, nil)) + err = handler.Admit(admission.NewAttributesRecord(pod, &oldPod, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil)) if test.admit && err != nil { t.Errorf("Test: %s, expected no error but got: %s", test.testName, err) } else if !test.admit && err == nil { @@ -192,7 +192,7 @@ func TestPodAdmission(t *testing.T) { if test.admit && !labels.Equals(test.mergedNodeSelector, labels.Set(pod.Spec.NodeSelector)) { t.Errorf("Test: %s, expected: %s but got: %s", test.testName, test.mergedNodeSelector, pod.Spec.NodeSelector) } - err = handler.Validate(admission.NewAttributesRecord(pod, &oldPod, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, nil)) + err = handler.Validate(admission.NewAttributesRecord(pod, &oldPod, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil)) if test.admit && err != nil { t.Errorf("Test: %s, expected no error but got: %s", test.testName, err) } else if !test.admit && err == nil { @@ -243,7 +243,7 @@ func TestIgnoreUpdatingInitializedPod(t *testing.T) { } // if the update of initialized pod is not ignored, an error will be returned because the pod's nodeSelector conflicts with namespace's nodeSelector. - err = handler.Admit(admission.NewAttributesRecord(pod, pod, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, nil)) + err = handler.Admit(admission.NewAttributesRecord(pod, pod, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil)) if err != nil { t.Errorf("expected no error, got: %v", err) } diff --git a/plugin/pkg/admission/podpreset/admission_test.go b/plugin/pkg/admission/podpreset/admission_test.go index b2236df82e..3342530f24 100644 --- a/plugin/pkg/admission/podpreset/admission_test.go +++ b/plugin/pkg/admission/podpreset/admission_test.go @@ -818,6 +818,7 @@ func admitPod(pod *api.Pod, pip *settings.PodPreset) error { api.Resource("pods").WithVersion("version"), "", kadmission.Create, + false, &user.DefaultInfo{}, ) diff --git a/plugin/pkg/admission/podtolerationrestriction/admission_test.go b/plugin/pkg/admission/podtolerationrestriction/admission_test.go index 36abae7d55..7cb49d5f75 100644 --- a/plugin/pkg/admission/podtolerationrestriction/admission_test.go +++ b/plugin/pkg/admission/podtolerationrestriction/admission_test.go @@ -258,7 +258,7 @@ func TestPodAdmission(t *testing.T) { oldPod.Initializers = &metav1.Initializers{Pending: []metav1.Initializer{{Name: "init"}}} oldPod.Spec.Tolerations = []api.Toleration{{Key: "testKey", Operator: "Equal", Value: "testValue1", Effect: "NoSchedule", TolerationSeconds: nil}} - err = handler.Admit(admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if test.admit && err != nil { t.Errorf("Test: %s, expected no error but got: %s", test.testName, err) } else if !test.admit && err == nil { @@ -271,7 +271,7 @@ func TestPodAdmission(t *testing.T) { } // handles update of uninitialized pod like it's newly created. - err = handler.Admit(admission.NewAttributesRecord(pod, &oldPod, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, nil)) + err = handler.Admit(admission.NewAttributesRecord(pod, &oldPod, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil)) if test.admit && err != nil { t.Errorf("Test: %s, expected no error but got: %s", test.testName, err) } else if !test.admit && err == nil { @@ -348,7 +348,7 @@ func TestIgnoreUpdatingInitializedPod(t *testing.T) { } // if the update of initialized pod is not ignored, an error will be returned because the pod's Tolerations conflicts with namespace's Tolerations. - err = handler.Admit(admission.NewAttributesRecord(pod, pod, api.Kind("Pod").WithVersion("version"), "testNamespace", pod.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, nil)) + err = handler.Admit(admission.NewAttributesRecord(pod, pod, api.Kind("Pod").WithVersion("version"), "testNamespace", pod.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil)) if err != nil { t.Errorf("expected no error, got: %v", err) } diff --git a/plugin/pkg/admission/priority/admission_test.go b/plugin/pkg/admission/priority/admission_test.go index 05f571f3e3..378d9d515a 100644 --- a/plugin/pkg/admission/priority/admission_test.go +++ b/plugin/pkg/admission/priority/admission_test.go @@ -146,6 +146,7 @@ func TestPriorityClassAdmission(t *testing.T) { scheduling.Resource("priorityclasses").WithVersion("version"), "", admission.Create, + false, test.userInfo, ) err := ctrl.Validate(attrs) @@ -186,7 +187,7 @@ func TestDefaultPriority(t *testing.T) { name: "add a default class", classesBefore: []*scheduling.PriorityClass{nondefaultClass1}, classesAfter: []*scheduling.PriorityClass{nondefaultClass1, defaultClass1}, - attributes: admission.NewAttributesRecord(defaultClass1, nil, pcKind, "", defaultClass1.Name, pcResource, "", admission.Create, nil), + attributes: admission.NewAttributesRecord(defaultClass1, nil, pcKind, "", defaultClass1.Name, pcResource, "", admission.Create, false, nil), expectedDefaultBefore: scheduling.DefaultPriorityWhenNoDefaultClassExists, expectedDefaultAfter: defaultClass1.Value, }, @@ -194,7 +195,7 @@ func TestDefaultPriority(t *testing.T) { name: "multiple default classes resolves to the minimum value among them", classesBefore: []*scheduling.PriorityClass{defaultClass1, defaultClass2}, classesAfter: []*scheduling.PriorityClass{defaultClass2}, - attributes: admission.NewAttributesRecord(nil, nil, pcKind, "", defaultClass1.Name, pcResource, "", admission.Delete, nil), + attributes: admission.NewAttributesRecord(nil, nil, pcKind, "", defaultClass1.Name, pcResource, "", admission.Delete, false, nil), expectedDefaultBefore: defaultClass1.Value, expectedDefaultAfter: defaultClass2.Value, }, @@ -202,7 +203,7 @@ func TestDefaultPriority(t *testing.T) { name: "delete default priority class", classesBefore: []*scheduling.PriorityClass{defaultClass1}, classesAfter: []*scheduling.PriorityClass{}, - attributes: admission.NewAttributesRecord(nil, nil, pcKind, "", defaultClass1.Name, pcResource, "", admission.Delete, nil), + attributes: admission.NewAttributesRecord(nil, nil, pcKind, "", defaultClass1.Name, pcResource, "", admission.Delete, false, nil), expectedDefaultBefore: defaultClass1.Value, expectedDefaultAfter: scheduling.DefaultPriorityWhenNoDefaultClassExists, }, @@ -210,7 +211,7 @@ func TestDefaultPriority(t *testing.T) { name: "update default class and remove its global default", classesBefore: []*scheduling.PriorityClass{defaultClass1}, classesAfter: []*scheduling.PriorityClass{&updatedDefaultClass1}, - attributes: admission.NewAttributesRecord(&updatedDefaultClass1, defaultClass1, pcKind, "", defaultClass1.Name, pcResource, "", admission.Update, nil), + attributes: admission.NewAttributesRecord(&updatedDefaultClass1, defaultClass1, pcKind, "", defaultClass1.Name, pcResource, "", admission.Update, false, nil), expectedDefaultBefore: defaultClass1.Value, expectedDefaultAfter: scheduling.DefaultPriorityWhenNoDefaultClassExists, }, @@ -568,6 +569,7 @@ func TestPodAdmission(t *testing.T) { api.Resource("pods").WithVersion("version"), "", admission.Create, + false, nil, ) err := ctrl.Admit(attrs) diff --git a/plugin/pkg/admission/resourcequota/admission_test.go b/plugin/pkg/admission/resourcequota/admission_test.go index d51ac50126..610b2dec51 100644 --- a/plugin/pkg/admission/resourcequota/admission_test.go +++ b/plugin/pkg/admission/resourcequota/admission_test.go @@ -150,7 +150,7 @@ func TestAdmissionIgnoresDelete(t *testing.T) { evaluator: evaluator, } namespace := "default" - err := handler.Validate(admission.NewAttributesRecord(nil, nil, api.Kind("Pod").WithVersion("version"), namespace, "name", api.Resource("pods").WithVersion("version"), "", admission.Delete, nil)) + err := handler.Validate(admission.NewAttributesRecord(nil, nil, api.Kind("Pod").WithVersion("version"), namespace, "name", api.Resource("pods").WithVersion("version"), "", admission.Delete, false, nil)) if err != nil { t.Errorf("ResourceQuota should admit all deletes: %v", err) } @@ -187,11 +187,11 @@ func TestAdmissionIgnoresSubresources(t *testing.T) { } informerFactory.Core().InternalVersion().ResourceQuotas().Informer().GetIndexer().Add(resourceQuota) newPod := validPod("123", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("", ""))) - err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err == nil { t.Errorf("Expected an error because the pod exceeded allowed quota") } - err = handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "subresource", admission.Create, nil)) + err = handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "subresource", admission.Create, false, nil)) if err != nil { t.Errorf("Did not expect an error because the action went to a subresource: %v", err) } @@ -232,7 +232,7 @@ func TestAdmitBelowQuotaLimit(t *testing.T) { } informerFactory.Core().InternalVersion().ResourceQuotas().Informer().GetIndexer().Add(resourceQuota) newPod := validPod("allowed-pod", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("", ""))) - err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -278,6 +278,59 @@ func TestAdmitBelowQuotaLimit(t *testing.T) { } } +// TestAdmitDryRun verifies that a pod when created with dry-run doesn not have its usage reflected on the quota +// and that dry-run requests can still be rejected if they would exceed the quota +func TestAdmitDryRun(t *testing.T) { + resourceQuota := &api.ResourceQuota{ + ObjectMeta: metav1.ObjectMeta{Name: "quota", Namespace: "test", ResourceVersion: "124"}, + Status: api.ResourceQuotaStatus{ + Hard: api.ResourceList{ + api.ResourceCPU: resource.MustParse("3"), + api.ResourceMemory: resource.MustParse("100Gi"), + api.ResourcePods: resource.MustParse("5"), + }, + Used: api.ResourceList{ + api.ResourceCPU: resource.MustParse("1"), + api.ResourceMemory: resource.MustParse("50Gi"), + api.ResourcePods: resource.MustParse("3"), + }, + }, + } + stopCh := make(chan struct{}) + defer close(stopCh) + + kubeClient := fake.NewSimpleClientset(resourceQuota) + informerFactory := informers.NewSharedInformerFactory(kubeClient, controller.NoResyncPeriodFunc()) + quotaAccessor, _ := newQuotaAccessor() + quotaAccessor.client = kubeClient + quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister() + config := &resourcequotaapi.Configuration{} + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration.IgnoredResources(), generic.NewRegistry(quotaConfiguration.Evaluators()), nil, config, 5, stopCh) + + handler := &QuotaAdmission{ + Handler: admission.NewHandler(admission.Create, admission.Update), + evaluator: evaluator, + } + informerFactory.Core().InternalVersion().ResourceQuotas().Informer().GetIndexer().Add(resourceQuota) + + newPod := validPod("allowed-pod", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("", ""))) + err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, true, nil)) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + newPod = validPod("too-large-pod", 1, getResourceRequirements(getResourceList("100m", "60Gi"), getResourceList("", ""))) + err = handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, true, nil)) + if err == nil { + t.Errorf("Expected error but got none") + } + + if len(kubeClient.Actions()) != 0 { + t.Errorf("Expected no client action on dry-run") + } +} + // TestAdmitHandlesOldObjects verifies that admit handles updates correctly with old objects func TestAdmitHandlesOldObjects(t *testing.T) { // in this scenario, the old quota was based on a service type=loadbalancer @@ -328,7 +381,7 @@ func TestAdmitHandlesOldObjects(t *testing.T) { Ports: []api.ServicePort{{Port: 1234}}, }, } - err := handler.Validate(admission.NewAttributesRecord(newService, existingService, api.Kind("Service").WithVersion("version"), newService.Namespace, newService.Name, api.Resource("services").WithVersion("version"), "", admission.Update, nil)) + err := handler.Validate(admission.NewAttributesRecord(newService, existingService, api.Kind("Service").WithVersion("version"), newService.Namespace, newService.Name, api.Resource("services").WithVersion("version"), "", admission.Update, false, nil)) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -437,7 +490,7 @@ func TestAdmitHandlesNegativePVCUpdates(t *testing.T) { }, } - err = handler.Validate(admission.NewAttributesRecord(newPVC, oldPVC, api.Kind("PersistentVolumeClaim").WithVersion("version"), newPVC.Namespace, newPVC.Name, api.Resource("persistentvolumeclaims").WithVersion("version"), "", admission.Update, nil)) + err = handler.Validate(admission.NewAttributesRecord(newPVC, oldPVC, api.Kind("PersistentVolumeClaim").WithVersion("version"), newPVC.Namespace, newPVC.Name, api.Resource("persistentvolumeclaims").WithVersion("version"), "", admission.Update, false, nil)) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -504,7 +557,7 @@ func TestAdmitHandlesPVCUpdates(t *testing.T) { }, } - err = handler.Validate(admission.NewAttributesRecord(newPVC, oldPVC, api.Kind("PersistentVolumeClaim").WithVersion("version"), newPVC.Namespace, newPVC.Name, api.Resource("persistentvolumeclaims").WithVersion("version"), "", admission.Update, nil)) + err = handler.Validate(admission.NewAttributesRecord(newPVC, oldPVC, api.Kind("PersistentVolumeClaim").WithVersion("version"), newPVC.Namespace, newPVC.Name, api.Resource("persistentvolumeclaims").WithVersion("version"), "", admission.Update, false, nil)) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -601,7 +654,7 @@ func TestAdmitHandlesCreatingUpdates(t *testing.T) { Ports: []api.ServicePort{{Port: 1234}}, }, } - err := handler.Validate(admission.NewAttributesRecord(newService, oldService, api.Kind("Service").WithVersion("version"), newService.Namespace, newService.Name, api.Resource("services").WithVersion("version"), "", admission.Update, nil)) + err := handler.Validate(admission.NewAttributesRecord(newService, oldService, api.Kind("Service").WithVersion("version"), newService.Namespace, newService.Name, api.Resource("services").WithVersion("version"), "", admission.Update, false, nil)) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -684,7 +737,7 @@ func TestAdmitExceedQuotaLimit(t *testing.T) { } informerFactory.Core().InternalVersion().ResourceQuotas().Informer().GetIndexer().Add(resourceQuota) newPod := validPod("not-allowed-pod", 1, getResourceRequirements(getResourceList("3", "2Gi"), getResourceList("", ""))) - err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err == nil { t.Errorf("Expected an error exceeding quota") } @@ -730,7 +783,7 @@ func TestAdmitEnforceQuotaConstraints(t *testing.T) { informerFactory.Core().InternalVersion().ResourceQuotas().Informer().GetIndexer().Add(resourceQuota) // verify all values are specified as required on the quota newPod := validPod("not-allowed-pod", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("200m", ""))) - err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err == nil { t.Errorf("Expected an error because the pod does not specify a memory limit") } @@ -781,7 +834,7 @@ func TestAdmitPodInNamespaceWithoutQuota(t *testing.T) { newPod := validPod("not-allowed-pod", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("200m", ""))) // Add to the lru cache so we do not do a live client lookup liveLookupCache.Add(newPod.Namespace, liveLookupEntry{expiry: time.Now().Add(time.Duration(30 * time.Second)), items: []*api.ResourceQuota{}}) - err = handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err = handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("Did not expect an error because the pod is in a different namespace than the quota") } @@ -850,7 +903,7 @@ func TestAdmitBelowTerminatingQuotaLimit(t *testing.T) { newPod := validPod("allowed-pod", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("", ""))) activeDeadlineSeconds := int64(30) newPod.Spec.ActiveDeadlineSeconds = &activeDeadlineSeconds - err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -954,7 +1007,7 @@ func TestAdmitBelowBestEffortQuotaLimit(t *testing.T) { // create a pod that is best effort because it does not make a request for anything newPod := validPod("allowed-pod", 1, getResourceRequirements(getResourceList("", ""), getResourceList("", ""))) - err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -1044,7 +1097,7 @@ func TestAdmitBestEffortQuotaLimitIgnoresBurstable(t *testing.T) { } informerFactory.Core().InternalVersion().ResourceQuotas().Informer().GetIndexer().Add(resourceQuota) newPod := validPod("allowed-pod", 1, getResourceRequirements(getResourceList("100m", "1Gi"), getResourceList("", ""))) - err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -1134,7 +1187,7 @@ func TestAdmissionSetsMissingNamespace(t *testing.T) { // unset the namespace newPod.ObjectMeta.Namespace = "" - err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("Got unexpected error: %v", err) } @@ -1177,14 +1230,14 @@ func TestAdmitRejectsNegativeUsage(t *testing.T) { informerFactory.Core().InternalVersion().ResourceQuotas().Informer().GetIndexer().Add(resourceQuota) // verify quota rejects negative pvc storage requests newPvc := validPersistentVolumeClaim("not-allowed-pvc", getResourceRequirements(api.ResourceList{api.ResourceStorage: resource.MustParse("-1Gi")}, api.ResourceList{})) - err := handler.Validate(admission.NewAttributesRecord(newPvc, nil, api.Kind("PersistentVolumeClaim").WithVersion("version"), newPvc.Namespace, newPvc.Name, api.Resource("persistentvolumeclaims").WithVersion("version"), "", admission.Create, nil)) + err := handler.Validate(admission.NewAttributesRecord(newPvc, nil, api.Kind("PersistentVolumeClaim").WithVersion("version"), newPvc.Namespace, newPvc.Name, api.Resource("persistentvolumeclaims").WithVersion("version"), "", admission.Create, false, nil)) if err == nil { t.Errorf("Expected an error because the pvc has negative storage usage") } // verify quota accepts non-negative pvc storage requests newPvc = validPersistentVolumeClaim("not-allowed-pvc", getResourceRequirements(api.ResourceList{api.ResourceStorage: resource.MustParse("1Gi")}, api.ResourceList{})) - err = handler.Validate(admission.NewAttributesRecord(newPvc, nil, api.Kind("PersistentVolumeClaim").WithVersion("version"), newPvc.Namespace, newPvc.Name, api.Resource("persistentvolumeclaims").WithVersion("version"), "", admission.Create, nil)) + err = handler.Validate(admission.NewAttributesRecord(newPvc, nil, api.Kind("PersistentVolumeClaim").WithVersion("version"), newPvc.Namespace, newPvc.Name, api.Resource("persistentvolumeclaims").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -1225,7 +1278,7 @@ func TestAdmitWhenUnrelatedResourceExceedsQuota(t *testing.T) { // create a pod that should pass existing quota newPod := validPod("allowed-pod", 1, getResourceRequirements(getResourceList("", ""), getResourceList("", ""))) - err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -1259,7 +1312,7 @@ func TestAdmitLimitedResourceNoQuota(t *testing.T) { evaluator: evaluator, } newPod := validPod("not-allowed-pod", 1, getResourceRequirements(getResourceList("3", "2Gi"), getResourceList("", ""))) - err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err == nil { t.Errorf("Expected an error for consuming a limited resource without quota.") } @@ -1293,7 +1346,7 @@ func TestAdmitLimitedResourceNoQuotaIgnoresNonMatchingResources(t *testing.T) { evaluator: evaluator, } newPod := validPod("allowed-pod", 1, getResourceRequirements(getResourceList("3", "2Gi"), getResourceList("", ""))) - err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Fatalf("Unexpected error: %v", err) } @@ -1341,7 +1394,7 @@ func TestAdmitLimitedResourceWithQuota(t *testing.T) { } indexer.Add(resourceQuota) newPod := validPod("allowed-pod", 1, getResourceRequirements(getResourceList("3", "2Gi"), getResourceList("", ""))) - err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -1401,7 +1454,7 @@ func TestAdmitLimitedResourceWithMultipleQuota(t *testing.T) { indexer.Add(resourceQuota1) indexer.Add(resourceQuota2) newPod := validPod("allowed-pod", 1, getResourceRequirements(getResourceList("3", "2Gi"), getResourceList("", ""))) - err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -1449,7 +1502,7 @@ func TestAdmitLimitedResourceWithQuotaThatDoesNotCover(t *testing.T) { } indexer.Add(resourceQuota) newPod := validPod("not-allowed-pod", 1, getResourceRequirements(getResourceList("3", "2Gi"), getResourceList("", ""))) - err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err == nil { t.Fatalf("Expected an error since the quota did not cover cpu") } @@ -2110,7 +2163,7 @@ func TestAdmitLimitedScopeWithCoverQuota(t *testing.T) { if testCase.anotherQuota != nil { indexer.Add(testCase.anotherQuota) } - err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err := handler.Validate(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if testCase.expErr == "" { if err != nil { t.Fatalf("Testcase, %v, failed with unexpected error: %v. ExpErr: %v", testCase.description, err, testCase.expErr) diff --git a/plugin/pkg/admission/resourcequota/controller.go b/plugin/pkg/admission/resourcequota/controller.go index 745bb2d5ba..0907218d51 100644 --- a/plugin/pkg/admission/resourcequota/controller.go +++ b/plugin/pkg/admission/resourcequota/controller.go @@ -231,6 +231,12 @@ func (e *quotaEvaluator) checkQuotas(quotas []api.ResourceQuota, admissionAttrib continue } + // Don't update quota for admissionAttributes that correspond to dry-run requests + if admissionAttribute.attributes.IsDryRun() { + admissionAttribute.result = nil + continue + } + // if the new quotas are the same as the old quotas, then this particular one doesn't issue any updates // that means that no quota docs applied, so it can get a pass atLeastOneChangeForThisWaiter := false diff --git a/plugin/pkg/admission/security/podsecuritypolicy/admission_test.go b/plugin/pkg/admission/security/podsecuritypolicy/admission_test.go index 7ee136a72b..29f686994e 100644 --- a/plugin/pkg/admission/security/podsecuritypolicy/admission_test.go +++ b/plugin/pkg/admission/security/podsecuritypolicy/admission_test.go @@ -472,7 +472,7 @@ func TestAdmitPreferNonmutating(t *testing.T) { func TestFailClosedOnInvalidPod(t *testing.T) { plugin := NewTestAdmission(nil, nil) pod := &v1.Pod{} - attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{}) + attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, false, &user.DefaultInfo{}) err := plugin.Admit(attrs) if err == nil { @@ -1769,7 +1769,7 @@ func testPSPAdmitAdvanced(testCaseName string, op kadmission.Operation, psps []* originalPod := pod.DeepCopy() plugin := NewTestAdmission(psps, authz) - attrs := kadmission.NewAttributesRecord(pod, oldPod, kapi.Kind("Pod").WithVersion("version"), pod.Namespace, "", kapi.Resource("pods").WithVersion("version"), "", op, userInfo) + attrs := kadmission.NewAttributesRecord(pod, oldPod, kapi.Kind("Pod").WithVersion("version"), pod.Namespace, "", kapi.Resource("pods").WithVersion("version"), "", op, false, userInfo) annotations := make(map[string]string) attrs = &fakeAttributes{attrs, annotations} err := plugin.Admit(attrs) @@ -2227,7 +2227,7 @@ func TestPolicyAuthorizationErrors(t *testing.T) { pod.Spec.SecurityContext.HostPID = true plugin := NewTestAdmission(tc.inPolicies, authz) - attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), ns, "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{Name: userName}) + attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), ns, "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, false, &user.DefaultInfo{Name: userName}) allowedPod, _, validationErrs, err := plugin.computeSecurityContext(attrs, pod, true, "") assert.Nil(t, allowedPod) @@ -2320,7 +2320,7 @@ func TestPreferValidatedPSP(t *testing.T) { pod.Spec.Containers[0].SecurityContext.AllowPrivilegeEscalation = &allowPrivilegeEscalation plugin := NewTestAdmission(tc.inPolicies, authz) - attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), "ns", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Update, &user.DefaultInfo{Name: "test"}) + attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), "ns", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Update, false, &user.DefaultInfo{Name: "test"}) _, pspName, validationErrs, err := plugin.computeSecurityContext(attrs, pod, false, tc.validatedPSPHint) assert.NoError(t, err) diff --git a/plugin/pkg/admission/securitycontext/scdeny/admission_test.go b/plugin/pkg/admission/securitycontext/scdeny/admission_test.go index 9fb041c51a..aca4352bec 100644 --- a/plugin/pkg/admission/securitycontext/scdeny/admission_test.go +++ b/plugin/pkg/admission/securitycontext/scdeny/admission_test.go @@ -82,7 +82,7 @@ func TestAdmission(t *testing.T) { p.Spec.SecurityContext = tc.podSc p.Spec.Containers[0].SecurityContext = tc.sc - err := handler.Validate(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", false, nil)) if err != nil && !tc.expectError { t.Errorf("%v: unexpected error: %v", tc.name, err) } else if err == nil && tc.expectError { @@ -96,7 +96,7 @@ func TestAdmission(t *testing.T) { p.Spec.InitContainers = p.Spec.Containers p.Spec.Containers = nil - err = handler.Validate(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", false, nil)) if err != nil && !tc.expectError { t.Errorf("%v: unexpected error: %v", tc.name, err) } else if err == nil && tc.expectError { @@ -140,7 +140,7 @@ func TestPodSecurityContextAdmission(t *testing.T) { } for _, test := range tests { pod.Spec.SecurityContext = &test.securityContext - err := handler.Validate(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", false, nil)) if test.errorExpected && err == nil { t.Errorf("Expected error for security context %+v but did not get an error", test.securityContext) diff --git a/plugin/pkg/admission/serviceaccount/admission_test.go b/plugin/pkg/admission/serviceaccount/admission_test.go index 18ed0ee9ee..899a873912 100644 --- a/plugin/pkg/admission/serviceaccount/admission_test.go +++ b/plugin/pkg/admission/serviceaccount/admission_test.go @@ -46,7 +46,7 @@ func TestIgnoresNonCreate(t *testing.T) { func TestIgnoresUpdateOfInitializedPod(t *testing.T) { pod := &api.Pod{} oldPod := &api.Pod{} - attrs := admission.NewAttributesRecord(pod, oldPod, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Update, nil) + attrs := admission.NewAttributesRecord(pod, oldPod, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil) handler := NewServiceAccount() err := handler.Admit(attrs) if err != nil { @@ -56,7 +56,7 @@ func TestIgnoresUpdateOfInitializedPod(t *testing.T) { func TestIgnoresNonPodResource(t *testing.T) { pod := &api.Pod{} - attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("CustomResource").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("CustomResource").WithVersion("version"), "", admission.Create, false, nil) err := NewServiceAccount().Admit(attrs) if err != nil { t.Errorf("Expected non-pod resource allowed, got err: %v", err) @@ -64,7 +64,7 @@ func TestIgnoresNonPodResource(t *testing.T) { } func TestIgnoresNilObject(t *testing.T) { - attrs := admission.NewAttributesRecord(nil, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(nil, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) err := NewServiceAccount().Admit(attrs) if err != nil { t.Errorf("Expected nil object allowed allowed, got err: %v", err) @@ -73,7 +73,7 @@ func TestIgnoresNilObject(t *testing.T) { func TestIgnoresNonPodObject(t *testing.T) { obj := &api.Namespace{} - attrs := admission.NewAttributesRecord(obj, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(obj, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) err := NewServiceAccount().Admit(attrs) if err != nil { t.Errorf("Expected non pod object allowed, got err: %v", err) @@ -93,7 +93,7 @@ func TestIgnoresMirrorPod(t *testing.T) { }, }, } - attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) err := NewServiceAccount().Admit(attrs) if err != nil { t.Errorf("Expected mirror pod without service account or secrets allowed, got err: %v", err) @@ -111,7 +111,7 @@ func TestRejectsMirrorPodWithServiceAccount(t *testing.T) { ServiceAccountName: "default", }, } - attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) err := NewServiceAccount().Admit(attrs) if err == nil { t.Errorf("Expected a mirror pod to be prevented from referencing a service account") @@ -131,7 +131,7 @@ func TestRejectsMirrorPodWithSecretVolumes(t *testing.T) { }, }, } - attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) err := NewServiceAccount().Admit(attrs) if err == nil { t.Errorf("Expected a mirror pod to be prevented from referencing a secret volume") @@ -156,7 +156,7 @@ func TestRejectsMirrorPodWithServiceAccountTokenVolumeProjections(t *testing.T) }, }, } - attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) err := NewServiceAccount().Admit(attrs) if err == nil { t.Errorf("Expected a mirror pod to be prevented from referencing a ServiceAccountToken volume projection") @@ -181,7 +181,7 @@ func TestAssignsDefaultServiceAccountAndToleratesMissingAPIToken(t *testing.T) { }) pod := &api.Pod{} - attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) err := admit.Admit(attrs) if err != nil { t.Errorf("Unexpected error: %v", err) @@ -209,7 +209,7 @@ func TestAssignsDefaultServiceAccountAndRejectsMissingAPIToken(t *testing.T) { }) pod := &api.Pod{} - attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) err := admit.Admit(attrs) if err == nil || !errors.IsServerTimeout(err) { t.Errorf("Expected server timeout error for missing API token: %v", err) @@ -234,7 +234,7 @@ func TestFetchesUncachedServiceAccount(t *testing.T) { admit.RequireAPIToken = false pod := &api.Pod{} - attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) err := admit.Admit(attrs) if err != nil { t.Errorf("Unexpected error: %v", err) @@ -256,7 +256,7 @@ func TestDeniesInvalidServiceAccount(t *testing.T) { admit.SetInternalKubeInformerFactory(informerFactory) pod := &api.Pod{} - attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) err := admit.Admit(attrs) if err == nil { t.Errorf("Expected error for missing service account, got none") @@ -321,7 +321,7 @@ func TestAutomountsAPIToken(t *testing.T) { }, }, } - attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) err := admit.Admit(attrs) if err != nil { t.Errorf("Unexpected error: %v", err) @@ -369,7 +369,7 @@ func TestAutomountsAPIToken(t *testing.T) { }, }, } - attrs = admission.NewAttributesRecord(pod, oldPod, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Update, nil) + attrs = admission.NewAttributesRecord(pod, oldPod, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil) err = admit.Admit(attrs) if err != nil { t.Errorf("Unexpected error: %v", err) @@ -398,7 +398,7 @@ func TestAutomountsAPIToken(t *testing.T) { }, }, } - attrs = admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs = admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) if err := admit.Admit(attrs); err != nil { t.Errorf("Unexpected error: %v", err) } @@ -478,7 +478,7 @@ func TestRespectsExistingMount(t *testing.T) { }, }, } - attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) err := admit.Admit(attrs) if err != nil { t.Errorf("Unexpected error: %v", err) @@ -508,7 +508,7 @@ func TestRespectsExistingMount(t *testing.T) { }, }, } - attrs = admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs = admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) if err := admit.Admit(attrs); err != nil { t.Errorf("Unexpected error: %v", err) } @@ -553,7 +553,7 @@ func TestAllowsReferencedSecret(t *testing.T) { }, }, } - attrs := admission.NewAttributesRecord(pod1, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod1, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) if err := admit.Admit(attrs); err != nil { t.Errorf("Unexpected error: %v", err) } @@ -577,7 +577,7 @@ func TestAllowsReferencedSecret(t *testing.T) { }, }, } - attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) if err := admit.Admit(attrs); err != nil { t.Errorf("Unexpected error: %v", err) } @@ -601,7 +601,7 @@ func TestAllowsReferencedSecret(t *testing.T) { }, }, } - attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) if err := admit.Admit(attrs); err != nil { t.Errorf("Unexpected error: %v", err) } @@ -631,7 +631,7 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) { }, }, } - attrs := admission.NewAttributesRecord(pod1, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod1, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) if err := admit.Admit(attrs); err == nil { t.Errorf("Expected rejection for using a secret the service account does not reference") } @@ -655,7 +655,7 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) { }, }, } - attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) if err := admit.Admit(attrs); err == nil || !strings.Contains(err.Error(), "with envVar") { t.Errorf("Unexpected error: %v", err) } @@ -679,7 +679,7 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) { }, }, } - attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) if err := admit.Admit(attrs); err == nil || !strings.Contains(err.Error(), "with envVar") { t.Errorf("Unexpected error: %v", err) } @@ -710,7 +710,7 @@ func TestAllowUnreferencedSecretVolumesForPermissiveSAs(t *testing.T) { }, }, } - attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) err := admit.Admit(attrs) if err == nil { t.Errorf("Expected rejection for using a secret the service account does not reference") @@ -742,7 +742,7 @@ func TestAllowsReferencedImagePullSecrets(t *testing.T) { ImagePullSecrets: []api.LocalObjectReference{{Name: "foo"}}, }, } - attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) err := admit.Admit(attrs) if err != nil { t.Errorf("Unexpected error: %v", err) @@ -771,7 +771,7 @@ func TestRejectsUnreferencedImagePullSecrets(t *testing.T) { ImagePullSecrets: []api.LocalObjectReference{{Name: "foo"}}, }, } - attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) err := admit.Admit(attrs) if err == nil { t.Errorf("Expected rejection for using a secret the service account does not reference") @@ -804,7 +804,7 @@ func TestDoNotAddImagePullSecrets(t *testing.T) { ImagePullSecrets: []api.LocalObjectReference{{Name: "foo"}}, }, } - attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) err := admit.Admit(attrs) if err != nil { t.Errorf("Unexpected error: %v", err) @@ -838,7 +838,7 @@ func TestAddImagePullSecrets(t *testing.T) { informerFactory.Core().InternalVersion().ServiceAccounts().Informer().GetStore().Add(sa) pod := &api.Pod{} - attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) err := admit.Admit(attrs) if err != nil { t.Errorf("Unexpected error: %v", err) @@ -921,7 +921,7 @@ func TestMultipleReferencedSecrets(t *testing.T) { }, } - attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil) + attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil) if err := admit.Admit(attrs); err != nil { t.Fatal(err) } diff --git a/plugin/pkg/admission/storage/persistentvolume/label/admission_test.go b/plugin/pkg/admission/storage/persistentvolume/label/admission_test.go index 965e9a3a3e..bc462e7410 100644 --- a/plugin/pkg/admission/storage/persistentvolume/label/admission_test.go +++ b/plugin/pkg/admission/storage/persistentvolume/label/admission_test.go @@ -126,20 +126,20 @@ func TestAdmission(t *testing.T) { defer utilfeature.DefaultFeatureGate.Set("VolumeScheduling=false") // Non-cloud PVs are ignored - err := handler.Admit(admission.NewAttributesRecord(&ignoredPV, nil, api.Kind("PersistentVolume").WithVersion("version"), ignoredPV.Namespace, ignoredPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil)) + err := handler.Admit(admission.NewAttributesRecord(&ignoredPV, nil, api.Kind("PersistentVolume").WithVersion("version"), ignoredPV.Namespace, ignoredPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler (on ignored pv): %v", err) } // We only add labels on creation - err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Delete, nil)) + err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Delete, false, nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler (when deleting aws pv): %v", err) } // Errors from the cloudprovider block creation of the volume pvHandler.ebsVolumes = mockVolumeFailure(fmt.Errorf("invalid volume")) - err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, false, nil)) if err == nil { t.Errorf("Expected error when aws pv info fails") } @@ -147,7 +147,7 @@ func TestAdmission(t *testing.T) { // Don't add labels if the cloudprovider doesn't return any labels := make(map[string]string) pvHandler.ebsVolumes = mockVolumeLabels(labels) - err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("Expected no error when creating aws pv") } @@ -160,7 +160,7 @@ func TestAdmission(t *testing.T) { // Don't panic if the cloudprovider returns nil, nil pvHandler.ebsVolumes = mockVolumeFailure(nil) - err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("Expected no error when cloud provider returns empty labels") } @@ -172,7 +172,7 @@ func TestAdmission(t *testing.T) { zones, _ := volumeutil.ZonesToSet("1,2,3") labels[kubeletapis.LabelZoneFailureDomain] = volumeutil.ZonesSetToLabelValue(zones) pvHandler.ebsVolumes = mockVolumeLabels(labels) - err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("Expected no error when creating aws pv") } @@ -210,7 +210,7 @@ func TestAdmission(t *testing.T) { awsPV.ObjectMeta.Labels = make(map[string]string) awsPV.ObjectMeta.Labels["a"] = "not1" awsPV.ObjectMeta.Labels["c"] = "3" - err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("Expected no error when creating aws pv") } @@ -227,7 +227,7 @@ func TestAdmission(t *testing.T) { labels["b"] = "2" labels["c"] = "3" pvHandler.ebsVolumes = mockVolumeLabels(labels) - err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("Expected no error when creating aws pv") } @@ -248,7 +248,7 @@ func TestAdmission(t *testing.T) { labels["f"] = "2" labels["g"] = "3" pvHandler.ebsVolumes = mockVolumeLabels(labels) - err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("Expected no error when creating aws pv") } diff --git a/plugin/pkg/admission/storage/persistentvolume/resize/admission_test.go b/plugin/pkg/admission/storage/persistentvolume/resize/admission_test.go index ab5e7817ba..e9b32c5bb9 100644 --- a/plugin/pkg/admission/storage/persistentvolume/resize/admission_test.go +++ b/plugin/pkg/admission/storage/persistentvolume/resize/admission_test.go @@ -321,7 +321,7 @@ func TestPVCResizeAdmission(t *testing.T) { for _, tc := range tests { 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, false, nil) err := ctrl.Validate(attributes) fmt.Println(tc.name) diff --git a/plugin/pkg/admission/storage/storageclass/setdefault/admission_test.go b/plugin/pkg/admission/storage/storageclass/setdefault/admission_test.go index 6be3765430..00baec0931 100644 --- a/plugin/pkg/admission/storage/storageclass/setdefault/admission_test.go +++ b/plugin/pkg/admission/storage/storageclass/setdefault/admission_test.go @@ -208,7 +208,8 @@ func TestAdmission(t *testing.T) { api.Resource("persistentvolumeclaims").WithVersion("version"), "", // subresource admission.Create, - nil, // userInfo + false, // dryRun + nil, // userInfo ) err := ctrl.Admit(attrs) glog.Infof("Got %v", err) diff --git a/plugin/pkg/admission/storage/storageobjectinuseprotection/admission_test.go b/plugin/pkg/admission/storage/storageobjectinuseprotection/admission_test.go index 6d27856ed1..4a7c9ce7fc 100644 --- a/plugin/pkg/admission/storage/storageobjectinuseprotection/admission_test.go +++ b/plugin/pkg/admission/storage/storageobjectinuseprotection/admission_test.go @@ -133,7 +133,8 @@ func TestAdmit(t *testing.T) { test.resource, "", // subresource admission.Create, - nil, // userInfo + false, // dryRun + nil, // userInfo ) err := ctrl.Admit(attrs) diff --git a/staging/src/k8s.io/apiserver/pkg/admission/attributes.go b/staging/src/k8s.io/apiserver/pkg/admission/attributes.go index 7272e888bc..c8973cc629 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/attributes.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/attributes.go @@ -34,6 +34,7 @@ type attributesRecord struct { resource schema.GroupVersionResource subresource string operation Operation + dryRun bool object runtime.Object oldObject runtime.Object userInfo user.Info @@ -44,7 +45,7 @@ type attributesRecord struct { annotationsLock sync.RWMutex } -func NewAttributesRecord(object runtime.Object, oldObject runtime.Object, kind schema.GroupVersionKind, namespace, name string, resource schema.GroupVersionResource, subresource string, operation Operation, userInfo user.Info) Attributes { +func NewAttributesRecord(object runtime.Object, oldObject runtime.Object, kind schema.GroupVersionKind, namespace, name string, resource schema.GroupVersionResource, subresource string, operation Operation, dryRun bool, userInfo user.Info) Attributes { return &attributesRecord{ kind: kind, namespace: namespace, @@ -52,6 +53,7 @@ func NewAttributesRecord(object runtime.Object, oldObject runtime.Object, kind s resource: resource, subresource: subresource, operation: operation, + dryRun: dryRun, object: object, oldObject: oldObject, userInfo: userInfo, @@ -82,6 +84,10 @@ func (record *attributesRecord) GetOperation() Operation { return record.operation } +func (record *attributesRecord) IsDryRun() bool { + return record.dryRun +} + func (record *attributesRecord) GetObject() runtime.Object { return record.object } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/audit_test.go b/staging/src/k8s.io/apiserver/pkg/admission/audit_test.go index 31f3b5881c..2dd88e9c9f 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/audit_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/audit_test.go @@ -64,7 +64,7 @@ func (h fakeHandler) Handles(o Operation) bool { } func attributes() Attributes { - return NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, "", "", schema.GroupVersionResource{}, "", "", nil) + return NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, "", "", schema.GroupVersionResource{}, "", "", false, nil) } func TestWithAudit(t *testing.T) { diff --git a/staging/src/k8s.io/apiserver/pkg/admission/chain_test.go b/staging/src/k8s.io/apiserver/pkg/admission/chain_test.go index e3821e731d..7c3d940e1e 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/chain_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/chain_test.go @@ -119,7 +119,7 @@ func TestAdmitAndValidate(t *testing.T) { for _, test := range tests { t.Logf("testcase = %s", test.name) // call admit and check that validate was not called at all - err := test.chain.Admit(NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, nil)) + err := test.chain.Admit(NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil)) accepted := (err == nil) if accepted != test.accept { t.Errorf("unexpected result of admit call: %v", accepted) @@ -140,7 +140,7 @@ func TestAdmitAndValidate(t *testing.T) { } // call validate and check that admit was not called at all - err = test.chain.Validate(NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, nil)) + err = test.chain.Validate(NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil)) accepted = (err == nil) if accepted != test.accept { t.Errorf("unexpected result of validate call: %v\n", accepted) diff --git a/staging/src/k8s.io/apiserver/pkg/admission/errors_test.go b/staging/src/k8s.io/apiserver/pkg/admission/errors_test.go index 305a39dc12..871d7a5715 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/errors_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/errors_test.go @@ -36,6 +36,7 @@ func TestNewForbidden(t *testing.T) { schema.GroupVersionResource{Group: "foo", Version: "bar", Resource: "baz"}, "", Create, + false, nil) err := errors.New("some error") expectedErr := `baz.foo "Unknown/errorGettingName" is forbidden: some error` diff --git a/staging/src/k8s.io/apiserver/pkg/admission/interfaces.go b/staging/src/k8s.io/apiserver/pkg/admission/interfaces.go index 68ef558da4..a17c28990a 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/interfaces.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/interfaces.go @@ -41,6 +41,11 @@ type Attributes interface { GetSubresource() string // GetOperation is the operation being performed GetOperation() Operation + // IsDryRun indicates that modifications will definitely not be persisted for this request. This is to prevent + // admission controllers with side effects and a method of reconciliation from being overwhelmed. + // However, a value of false for this does not mean that the modification will be persisted, because it + // could still be rejected by a subsequent validation step. + IsDryRun() bool // GetObject is the object from the incoming request prior to default values being applied GetObject() runtime.Object // GetOldObject is the existing object. Only populated for UPDATE requests. diff --git a/staging/src/k8s.io/apiserver/pkg/admission/metrics/metrics_test.go b/staging/src/k8s.io/apiserver/pkg/admission/metrics/metrics_test.go index 859e3d30eb..d2b4bf75af 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/metrics/metrics_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/metrics/metrics_test.go @@ -28,7 +28,7 @@ import ( var ( kind = schema.GroupVersionKind{Group: "kgroup", Version: "kversion", Kind: "kind"} resource = schema.GroupVersionResource{Group: "rgroup", Version: "rversion", Resource: "resource"} - attr = admission.NewAttributesRecord(nil, nil, kind, "ns", "name", resource, "subresource", admission.Create, nil) + attr = admission.NewAttributesRecord(nil, nil, kind, "ns", "name", resource, "subresource", admission.Create, false, nil) ) func TestObserveAdmissionStep(t *testing.T) { @@ -156,7 +156,7 @@ func TestWithMetrics(t *testing.T) { h := WithMetrics(test.handler, Metrics.ObserveAdmissionController, test.name) // test mutation - err := h.(admission.MutationInterface).Admit(admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, nil)) + err := h.(admission.MutationInterface).Admit(admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil)) if test.admit && err != nil { t.Errorf("expected admit to succeed, but failed: %v", err) continue @@ -181,7 +181,7 @@ func TestWithMetrics(t *testing.T) { } // test validation - err = h.(admission.ValidationInterface).Validate(admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, nil)) + err = h.(admission.ValidationInterface).Validate(admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil)) if test.validate && err != nil { t.Errorf("expected admit to succeed, but failed: %v", err) continue diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/initialization/initialization_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/initialization/initialization_test.go index a3bb0991b3..fd9e1fa774 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/initialization/initialization_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/initialization/initialization_test.go @@ -179,7 +179,7 @@ func TestAdmitUpdate(t *testing.T) { oldObj.Initializers = tc.oldInitializers newObj := &v1.Pod{} newObj.Initializers = tc.newInitializers - a := admission.NewAttributesRecord(newObj, oldObj, schema.GroupVersionKind{}, "", "foo", schema.GroupVersionResource{}, "", admission.Update, nil) + a := admission.NewAttributesRecord(newObj, oldObj, schema.GroupVersionKind{}, "", "foo", schema.GroupVersionResource{}, "", admission.Update, false, nil) err := plugin.Admit(a) switch { case tc.err == "" && err != nil: diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go index 3eca3b67f2..8a56cc3e86 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go @@ -104,7 +104,7 @@ func TestAccessReviewCheckOnMissingNamespace(t *testing.T) { } informerFactory.Start(wait.NeverStop) - err = handler.Admit(admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "authorization.k8s.io", Version: "v1", Kind: "LocalSubjectAccesReview"}, namespace, "", schema.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1", Resource: "localsubjectaccessreviews"}, "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "authorization.k8s.io", Version: "v1", Kind: "LocalSubjectAccesReview"}, namespace, "", schema.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1", Resource: "localsubjectaccessreviews"}, "", admission.Create, false, nil)) if err != nil { t.Error(err) } @@ -124,7 +124,7 @@ func TestAdmissionNamespaceDoesNotExist(t *testing.T) { informerFactory.Start(wait.NeverStop) pod := newPod(namespace) - err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err == nil { actions := "" for _, action := range mockClient.Actions() { @@ -134,19 +134,19 @@ func TestAdmissionNamespaceDoesNotExist(t *testing.T) { } // verify create operations in the namespace cause an error - err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err == nil { t.Errorf("Expected error rejecting creates in a namespace when it is missing") } // verify update operations in the namespace cause an error - err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Update, nil)) + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Update, false, nil)) if err == nil { t.Errorf("Expected error rejecting updates in a namespace when it is missing") } // verify delete operations in the namespace can proceed - err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Delete, nil)) + err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Delete, false, nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } @@ -166,7 +166,7 @@ func TestAdmissionNamespaceActive(t *testing.T) { informerFactory.Start(wait.NeverStop) pod := newPod(namespace) - err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("unexpected error returned from admission handler") } @@ -187,31 +187,31 @@ func TestAdmissionNamespaceTerminating(t *testing.T) { pod := newPod(namespace) // verify create operations in the namespace cause an error - err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err == nil { t.Errorf("Expected error rejecting creates in a namespace when it is terminating") } // verify update operations in the namespace can proceed - err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Update, nil)) + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Update, false, nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } // verify delete operations in the namespace can proceed - err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Delete, nil)) + err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Delete, false, nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } // verify delete of namespace default can never proceed - err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), "", metav1.NamespaceDefault, v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, nil)) + err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), "", metav1.NamespaceDefault, v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, false, nil)) if err == nil { t.Errorf("Expected an error that this namespace can never be deleted") } // verify delete of namespace other than default can proceed - err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), "", "other", v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, nil)) + err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), "", "other", v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, false, nil)) if err != nil { t.Errorf("Did not expect an error %v", err) } @@ -238,7 +238,7 @@ func TestAdmissionNamespaceForceLiveLookup(t *testing.T) { pod := newPod(namespace) // verify create operations in the namespace is allowed - err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { t.Errorf("Unexpected error rejecting creates in an active namespace") } @@ -248,7 +248,7 @@ func TestAdmissionNamespaceForceLiveLookup(t *testing.T) { getCalls = 0 // verify delete of namespace can proceed - err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), namespace, namespace, v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, nil)) + err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), namespace, namespace, v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, false, nil)) if err != nil { t.Errorf("Expected namespace deletion to be allowed") } @@ -261,7 +261,7 @@ func TestAdmissionNamespaceForceLiveLookup(t *testing.T) { phases[namespace] = v1.NamespaceTerminating // verify create operations in the namespace cause an error - err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err == nil { t.Errorf("Expected error rejecting creates in a namespace right after deleting it") } @@ -274,7 +274,7 @@ func TestAdmissionNamespaceForceLiveLookup(t *testing.T) { fakeClock.Step(forceLiveLookupTTL) // verify create operations in the namespace cause an error - err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if err == nil { t.Errorf("Expected error rejecting creates in a namespace right after deleting it") } @@ -287,7 +287,7 @@ func TestAdmissionNamespaceForceLiveLookup(t *testing.T) { fakeClock.Step(time.Millisecond) // verify create operations in the namespace don't force a live lookup after the timeout - handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if getCalls != 0 { t.Errorf("Expected no live lookup of the namespace at t=forceLiveLookupTTL+1ms, got %d", getCalls) } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/dispatcher_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/dispatcher_test.go index efa534c082..ccea268624 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/dispatcher_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/dispatcher_test.go @@ -123,7 +123,7 @@ func TestDispatch(t *testing.T) { }, } attr := generic.VersionedAttributes{ - Attributes: admission.NewAttributesRecord(test.out, nil, schema.GroupVersionKind{}, "", "", schema.GroupVersionResource{}, "", admission.Operation(""), nil), + Attributes: admission.NewAttributesRecord(test.out, nil, schema.GroupVersionKind{}, "", "", schema.GroupVersionResource{}, "", admission.Operation(""), false, nil), VersionedOldObject: nil, VersionedObject: test.in, } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace/matcher_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace/matcher_test.go index d0aee1499e..bf7dee828c 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace/matcher_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace/matcher_test.go @@ -75,27 +75,27 @@ func TestGetNamespaceLabels(t *testing.T) { }{ { name: "request is for creating namespace, the labels should be from the object itself", - attr: admission.NewAttributesRecord(&namespace2, nil, schema.GroupVersionKind{}, "", namespace2.Name, schema.GroupVersionResource{Resource: "namespaces"}, "", admission.Create, nil), + attr: admission.NewAttributesRecord(&namespace2, nil, schema.GroupVersionKind{}, "", namespace2.Name, schema.GroupVersionResource{Resource: "namespaces"}, "", admission.Create, false, nil), expectedLabels: namespace2Labels, }, { name: "request is for updating namespace, the labels should be from the new object", - attr: admission.NewAttributesRecord(&namespace2, nil, schema.GroupVersionKind{}, namespace2.Name, namespace2.Name, schema.GroupVersionResource{Resource: "namespaces"}, "", admission.Update, nil), + attr: admission.NewAttributesRecord(&namespace2, nil, schema.GroupVersionKind{}, namespace2.Name, namespace2.Name, schema.GroupVersionResource{Resource: "namespaces"}, "", admission.Update, false, nil), expectedLabels: namespace2Labels, }, { name: "request is for deleting namespace, the labels should be from the cache", - attr: admission.NewAttributesRecord(&namespace2, nil, schema.GroupVersionKind{}, namespace1.Name, namespace1.Name, schema.GroupVersionResource{Resource: "namespaces"}, "", admission.Delete, nil), + attr: admission.NewAttributesRecord(&namespace2, nil, schema.GroupVersionKind{}, namespace1.Name, namespace1.Name, schema.GroupVersionResource{Resource: "namespaces"}, "", admission.Delete, false, nil), expectedLabels: namespace1Labels, }, { name: "request is for namespace/finalizer", - attr: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, namespace1.Name, "mock-name", schema.GroupVersionResource{Resource: "namespaces"}, "finalizers", admission.Create, nil), + attr: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, namespace1.Name, "mock-name", schema.GroupVersionResource{Resource: "namespaces"}, "finalizers", admission.Create, false, nil), expectedLabels: namespace1Labels, }, { name: "request is for pod", - attr: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, namespace1.Name, "mock-name", schema.GroupVersionResource{Resource: "pods"}, "", admission.Create, nil), + attr: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, namespace1.Name, "mock-name", schema.GroupVersionResource{Resource: "pods"}, "", admission.Create, false, nil), expectedLabels: namespace1Labels, }, } @@ -117,7 +117,7 @@ func TestNotExemptClusterScopedResource(t *testing.T) { hook := ®istrationv1beta1.Webhook{ NamespaceSelector: &metav1.LabelSelector{}, } - attr := admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, "", "mock-name", schema.GroupVersionResource{Version: "v1", Resource: "nodes"}, "", admission.Create, nil) + attr := admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, "", "mock-name", schema.GroupVersionResource{Version: "v1", Resource: "nodes"}, "", admission.Create, false, nil) matcher := Matcher{} matches, err := matcher.MatchNamespaceSelector(hook, attr) if err != nil { diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/rules/rules_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/rules/rules_test.go index 3418a17086..2827558af2 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/rules/rules_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/rules/rules_test.go @@ -38,6 +38,7 @@ func a(group, version, resource, subresource, name string, operation admission.O "ns", name, schema.GroupVersionResource{Group: group, Version: version, Resource: resource}, subresource, operation, + false, nil, ) } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/testcase.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/testcase.go index e2bb01bd65..453ba11ee4 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/testcase.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/testcase.go @@ -95,7 +95,7 @@ func newAttributesRecord(object metav1.Object, oldObject metav1.Object, kind sch UID: "webhook-test", } - return admission.NewAttributesRecord(object.(runtime.Object), oldObject.(runtime.Object), kind, namespace, name, gvr, subResource, admission.Update, &userInfo) + return admission.NewAttributesRecord(object.(runtime.Object), oldObject.(runtime.Object), kind, namespace, name, gvr, subResource, admission.Update, false, &userInfo) } // NewAttribute returns static admission Attributes for testing. diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/BUILD b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/BUILD index a7f19e953b..117236967d 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/BUILD @@ -79,6 +79,7 @@ go_library( "//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library", "//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library", "//staging/src/k8s.io/apiserver/pkg/server/httplog:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/util/dryrun:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/trace:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/wsstream:go_default_library", "//vendor/github.com/evanphx/json-patch:go_default_library", diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/create.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/create.go index c838546a79..69006c5bbd 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/create.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/create.go @@ -34,6 +34,7 @@ import ( "k8s.io/apiserver/pkg/endpoints/handlers/negotiation" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/apiserver/pkg/util/dryrun" utiltrace "k8s.io/apiserver/pkg/util/trace" ) @@ -116,7 +117,7 @@ func createHandler(r rest.NamedCreater, scope RequestScope, admit admission.Inte audit.LogRequestObject(ae, obj, scope.Resource, scope.Subresource, scope.Serializer) userInfo, _ := request.UserFrom(ctx) - admissionAttributes := admission.NewAttributesRecord(obj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, userInfo) + admissionAttributes := admission.NewAttributesRecord(obj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo) if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && mutatingAdmission.Handles(admission.Create) { err = mutatingAdmission.Admit(admissionAttributes) if err != nil { diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/delete.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/delete.go index fc37e71b2d..b753b83b5d 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/delete.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/delete.go @@ -32,6 +32,7 @@ import ( "k8s.io/apiserver/pkg/endpoints/handlers/negotiation" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/apiserver/pkg/util/dryrun" utiltrace "k8s.io/apiserver/pkg/util/trace" ) @@ -108,7 +109,7 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestSco trace.Step("About to check admission control") if admit != nil && admit.Handles(admission.Delete) { userInfo, _ := request.UserFrom(ctx) - attrs := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, userInfo) + attrs := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, dryrun.IsDryRun(options.DryRun), userInfo) if mutatingAdmission, ok := admit.(admission.MutationInterface); ok { if err := mutatingAdmission.Admit(attrs); err != nil { scope.err(err, w, req) @@ -196,27 +197,6 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestSco ctx := req.Context() ctx = request.WithNamespace(ctx, namespace) ae := request.AuditEventFrom(ctx) - admit = admission.WithAudit(admit, ae) - - if admit != nil && admit.Handles(admission.Delete) { - userInfo, _ := request.UserFrom(ctx) - attrs := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, "", scope.Resource, scope.Subresource, admission.Delete, userInfo) - if mutatingAdmission, ok := admit.(admission.MutationInterface); ok { - err = mutatingAdmission.Admit(attrs) - if err != nil { - scope.err(err, w, req) - return - } - } - - if validatingAdmission, ok := admit.(admission.ValidationInterface); ok { - err = validatingAdmission.Validate(attrs) - if err != nil { - scope.err(err, w, req) - return - } - } - } listOptions := metainternalversion.ListOptions{} if err := metainternalversion.ParameterCodec.DecodeParameters(req.URL.Query(), scope.MetaGroupVersion, &listOptions); err != nil { @@ -279,6 +259,27 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestSco return } + admit = admission.WithAudit(admit, ae) + if admit != nil && admit.Handles(admission.Delete) { + userInfo, _ := request.UserFrom(ctx) + attrs := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, "", scope.Resource, scope.Subresource, admission.Delete, dryrun.IsDryRun(options.DryRun), userInfo) + if mutatingAdmission, ok := admit.(admission.MutationInterface); ok { + err = mutatingAdmission.Admit(attrs) + if err != nil { + scope.err(err, w, req) + return + } + } + + if validatingAdmission, ok := admit.(admission.ValidationInterface); ok { + err = validatingAdmission.Validate(attrs) + if err != nil { + scope.err(err, w, req) + return + } + } + } + result, err := finishRequest(timeout, func() (runtime.Object, error) { return r.DeleteCollection(ctx, options, &listOptions) }) diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/patch.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/patch.go index 65588638b6..95e7ab5f6c 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/patch.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/patch.go @@ -41,6 +41,7 @@ import ( "k8s.io/apiserver/pkg/endpoints/handlers/negotiation" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/apiserver/pkg/util/dryrun" utiltrace "k8s.io/apiserver/pkg/util/trace" ) @@ -130,6 +131,7 @@ func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface scope.Resource, scope.Subresource, admission.Update, + dryrun.IsDryRun(options.DryRun), userInfo, ) admissionCheck := func(updatedObject runtime.Object, currentObject runtime.Object) error { @@ -144,6 +146,7 @@ func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface scope.Resource, scope.Subresource, admission.Update, + dryrun.IsDryRun(options.DryRun), userInfo, )) } diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/rest.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/rest.go index 3f1b42327f..aa37600723 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/rest.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/rest.go @@ -123,14 +123,14 @@ func ConnectResource(connecter rest.Connecter, scope RequestScope, admit admissi userInfo, _ := request.UserFrom(ctx) // TODO: remove the mutating admission here as soon as we have ported all plugin that handle CONNECT if mutatingAdmission, ok := admit.(admission.MutationInterface); ok { - err = mutatingAdmission.Admit(admission.NewAttributesRecord(connectRequest, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, userInfo)) + err = mutatingAdmission.Admit(admission.NewAttributesRecord(connectRequest, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, false, userInfo)) if err != nil { scope.err(err, w, req) return } } if validatingAdmission, ok := admit.(admission.ValidationInterface); ok { - err = validatingAdmission.Validate(admission.NewAttributesRecord(connectRequest, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, userInfo)) + err = validatingAdmission.Validate(admission.NewAttributesRecord(connectRequest, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, false, userInfo)) if err != nil { scope.err(err, w, req) return diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/update.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/update.go index a164ca203f..dafe8c7678 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/update.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/update.go @@ -35,6 +35,7 @@ import ( "k8s.io/apiserver/pkg/endpoints/handlers/negotiation" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/apiserver/pkg/util/dryrun" utiltrace "k8s.io/apiserver/pkg/util/trace" ) @@ -119,11 +120,11 @@ func UpdateResource(r rest.Updater, scope RequestScope, admit admission.Interfac return nil, fmt.Errorf("unexpected error when extracting UID from oldObj: %v", err.Error()) } else if !isNotZeroObject { if mutatingAdmission.Handles(admission.Create) { - return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, userInfo)) + return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo)) } } else { if mutatingAdmission.Handles(admission.Update) { - return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo)) + return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, dryrun.IsDryRun(options.DryRun), userInfo)) } } return newObj, nil @@ -153,11 +154,11 @@ func UpdateResource(r rest.Updater, scope RequestScope, admit admission.Interfac rest.DefaultUpdatedObjectInfo(obj, transformers...), withAuthorization(rest.AdmissionToValidateObjectFunc( admit, - admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, userInfo)), + admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo)), scope.Authorizer, createAuthorizerAttributes), rest.AdmissionToValidateObjectUpdateFunc( admit, - admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo)), + admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, dryrun.IsDryRun(options.DryRun), userInfo)), false, options, ) diff --git a/staging/src/k8s.io/apiserver/pkg/registry/rest/create.go b/staging/src/k8s.io/apiserver/pkg/registry/rest/create.go index f399ebdc21..619acc3e0b 100644 --- a/staging/src/k8s.io/apiserver/pkg/registry/rest/create.go +++ b/staging/src/k8s.io/apiserver/pkg/registry/rest/create.go @@ -170,6 +170,7 @@ func AdmissionToValidateObjectFunc(admit admission.Interface, staticAttributes a staticAttributes.GetResource(), staticAttributes.GetSubresource(), staticAttributes.GetOperation(), + staticAttributes.IsDryRun(), staticAttributes.GetUserInfo(), ) if !validatingAdmission.Handles(finalAttributes.GetOperation()) { diff --git a/staging/src/k8s.io/apiserver/pkg/registry/rest/update.go b/staging/src/k8s.io/apiserver/pkg/registry/rest/update.go index b08dd14791..24e918604c 100644 --- a/staging/src/k8s.io/apiserver/pkg/registry/rest/update.go +++ b/staging/src/k8s.io/apiserver/pkg/registry/rest/update.go @@ -263,6 +263,7 @@ func AdmissionToValidateObjectUpdateFunc(admit admission.Interface, staticAttrib staticAttributes.GetResource(), staticAttributes.GetSubresource(), staticAttributes.GetOperation(), + staticAttributes.IsDryRun(), staticAttributes.GetUserInfo(), ) if !validatingAdmission.Handles(finalAttributes.GetOperation()) { diff --git a/staging/src/k8s.io/sample-apiserver/pkg/admission/plugin/banflunder/admission_test.go b/staging/src/k8s.io/sample-apiserver/pkg/admission/plugin/banflunder/admission_test.go index 4e21833e04..9023d82c28 100644 --- a/staging/src/k8s.io/sample-apiserver/pkg/admission/plugin/banflunder/admission_test.go +++ b/staging/src/k8s.io/sample-apiserver/pkg/admission/plugin/banflunder/admission_test.go @@ -136,6 +136,7 @@ func TestBanflunderAdmissionPlugin(t *testing.T) { scenario.admissionInputResource, "", admission.Create, + false, nil), )