diff --git a/pkg/admission/audit.go b/pkg/admission/audit.go index d81622b92..6762f53db 100644 --- a/pkg/admission/audit.go +++ b/pkg/admission/audit.go @@ -17,6 +17,7 @@ limitations under the License. package admission import ( + "context" "fmt" auditinternal "k8s.io/apiserver/pkg/apis/audit" @@ -44,7 +45,7 @@ func WithAudit(i Interface, ae *auditinternal.Event) Interface { return &auditHandler{i, ae} } -func (handler auditHandler) Admit(a Attributes, o ObjectInterfaces) error { +func (handler auditHandler) Admit(ctx context.Context, a Attributes, o ObjectInterfaces) error { if !handler.Interface.Handles(a.GetOperation()) { return nil } @@ -53,13 +54,13 @@ func (handler auditHandler) Admit(a Attributes, o ObjectInterfaces) error { } var err error if mutator, ok := handler.Interface.(MutationInterface); ok { - err = mutator.Admit(a, o) + err = mutator.Admit(ctx, a, o) handler.logAnnotations(a) } return err } -func (handler auditHandler) Validate(a Attributes, o ObjectInterfaces) error { +func (handler auditHandler) Validate(ctx context.Context, a Attributes, o ObjectInterfaces) error { if !handler.Interface.Handles(a.GetOperation()) { return nil } @@ -68,7 +69,7 @@ func (handler auditHandler) Validate(a Attributes, o ObjectInterfaces) error { } var err error if validator, ok := handler.Interface.(ValidationInterface); ok { - err = validator.Validate(a, o) + err = validator.Validate(ctx, a, o) handler.logAnnotations(a) } return err diff --git a/pkg/admission/audit_test.go b/pkg/admission/audit_test.go index 4ead632f6..3e1d3d201 100644 --- a/pkg/admission/audit_test.go +++ b/pkg/admission/audit_test.go @@ -17,6 +17,7 @@ limitations under the License. package admission import ( + "context" "fmt" "testing" @@ -45,14 +46,14 @@ var _ Interface = &fakeHandler{} var _ MutationInterface = &fakeHandler{} var _ ValidationInterface = &fakeHandler{} -func (h fakeHandler) Admit(a Attributes, o ObjectInterfaces) error { +func (h fakeHandler) Admit(ctx context.Context, a Attributes, o ObjectInterfaces) error { for k, v := range h.admitAnnotations { a.AddAnnotation(k, v) } return h.admit } -func (h fakeHandler) Validate(a Attributes, o ObjectInterfaces) error { +func (h fakeHandler) Validate(ctx context.Context, a Attributes, o ObjectInterfaces) error { for k, v := range h.validateAnnotations { a.AddAnnotation(k, v) } @@ -149,13 +150,13 @@ func TestWithAudit(t *testing.T) { require.True(t, ok) auditMutator, ok := auditHandler.(MutationInterface) require.True(t, ok) - assert.Equal(t, mutator.Admit(a, nil), auditMutator.Admit(a, nil), tcName+": WithAudit decorator should not effect the return value") + assert.Equal(t, mutator.Admit(context.TODO(), a, nil), auditMutator.Admit(context.TODO(), a, nil), tcName+": WithAudit decorator should not effect the return value") validator, ok := handler.(ValidationInterface) require.True(t, ok) auditValidator, ok := auditHandler.(ValidationInterface) require.True(t, ok) - assert.Equal(t, validator.Validate(a, nil), auditValidator.Validate(a, nil), tcName+": WithAudit decorator should not effect the return value") + assert.Equal(t, validator.Validate(context.TODO(), a, nil), auditValidator.Validate(context.TODO(), a, nil), tcName+": WithAudit decorator should not effect the return value") annotations := make(map[string]string, len(tc.admitAnnotations)+len(tc.validateAnnotations)) for k, v := range tc.admitAnnotations { diff --git a/pkg/admission/chain.go b/pkg/admission/chain.go index 37405aeaf..f2af01ef3 100644 --- a/pkg/admission/chain.go +++ b/pkg/admission/chain.go @@ -16,6 +16,8 @@ limitations under the License. package admission +import "context" + // chainAdmissionHandler is an instance of admission.NamedHandler that performs admission control using // a chain of admission handlers type chainAdmissionHandler []Interface @@ -26,13 +28,13 @@ func NewChainHandler(handlers ...Interface) chainAdmissionHandler { } // Admit performs an admission control check using a chain of handlers, and returns immediately on first error -func (admissionHandler chainAdmissionHandler) Admit(a Attributes, o ObjectInterfaces) error { +func (admissionHandler chainAdmissionHandler) Admit(ctx context.Context, a Attributes, o ObjectInterfaces) error { for _, handler := range admissionHandler { if !handler.Handles(a.GetOperation()) { continue } if mutator, ok := handler.(MutationInterface); ok { - err := mutator.Admit(a, o) + err := mutator.Admit(ctx, a, o) if err != nil { return err } @@ -42,13 +44,13 @@ func (admissionHandler chainAdmissionHandler) Admit(a Attributes, o ObjectInterf } // Validate performs an admission control check using a chain of handlers, and returns immediately on first error -func (admissionHandler chainAdmissionHandler) Validate(a Attributes, o ObjectInterfaces) error { +func (admissionHandler chainAdmissionHandler) Validate(ctx context.Context, a Attributes, o ObjectInterfaces) error { for _, handler := range admissionHandler { if !handler.Handles(a.GetOperation()) { continue } if validator, ok := handler.(ValidationInterface); ok { - err := validator.Validate(a, o) + err := validator.Validate(ctx, a, o) if err != nil { return err } diff --git a/pkg/admission/chain_test.go b/pkg/admission/chain_test.go index 490a0af17..ec72a28ad 100644 --- a/pkg/admission/chain_test.go +++ b/pkg/admission/chain_test.go @@ -17,6 +17,7 @@ limitations under the License. package admission import ( + "context" "fmt" "testing" @@ -32,7 +33,7 @@ type FakeHandler struct { validate, validateCalled bool } -func (h *FakeHandler) Admit(a Attributes, o ObjectInterfaces) (err error) { +func (h *FakeHandler) Admit(ctx context.Context, a Attributes, o ObjectInterfaces) (err error) { h.admitCalled = true if h.admit { return nil @@ -40,7 +41,7 @@ func (h *FakeHandler) Admit(a Attributes, o ObjectInterfaces) (err error) { return fmt.Errorf("Don't admit") } -func (h *FakeHandler) Validate(a Attributes, o ObjectInterfaces) (err error) { +func (h *FakeHandler) Validate(ctx context.Context, a Attributes, o ObjectInterfaces) (err error) { h.validateCalled = true if h.validate { return nil @@ -125,7 +126,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, test.options, false, nil), nil) + err := test.chain.Admit(context.TODO(), NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, test.options, false, nil), nil) accepted := (err == nil) if accepted != test.accept { t.Errorf("unexpected result of admit call: %v", accepted) @@ -146,7 +147,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, test.options, false, nil), nil) + err = test.chain.Validate(context.TODO(), NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, test.options, false, nil), nil) accepted = (err == nil) if accepted != test.accept { t.Errorf("unexpected result of validate call: %v\n", accepted) diff --git a/pkg/admission/initializer/initializer_test.go b/pkg/admission/initializer/initializer_test.go index fd2d50061..2726671d5 100644 --- a/pkg/admission/initializer/initializer_test.go +++ b/pkg/admission/initializer/initializer_test.go @@ -17,6 +17,7 @@ limitations under the License. package initializer_test import ( + "context" "testing" "time" @@ -72,7 +73,7 @@ type WantExternalKubeInformerFactory struct { func (self *WantExternalKubeInformerFactory) SetExternalKubeInformerFactory(sf informers.SharedInformerFactory) { self.sf = sf } -func (self *WantExternalKubeInformerFactory) Admit(a admission.Attributes, o admission.ObjectInterfaces) error { +func (self *WantExternalKubeInformerFactory) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { return nil } func (self *WantExternalKubeInformerFactory) Handles(o admission.Operation) bool { return false } @@ -87,7 +88,7 @@ type WantExternalKubeClientSet struct { } func (self *WantExternalKubeClientSet) SetExternalKubeClientSet(cs kubernetes.Interface) { self.cs = cs } -func (self *WantExternalKubeClientSet) Admit(a admission.Attributes, o admission.ObjectInterfaces) error { +func (self *WantExternalKubeClientSet) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { return nil } func (self *WantExternalKubeClientSet) Handles(o admission.Operation) bool { return false } @@ -102,7 +103,7 @@ type WantAuthorizerAdmission struct { } func (self *WantAuthorizerAdmission) SetAuthorizer(a authorizer.Authorizer) { self.auth = a } -func (self *WantAuthorizerAdmission) Admit(a admission.Attributes, o admission.ObjectInterfaces) error { +func (self *WantAuthorizerAdmission) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { return nil } func (self *WantAuthorizerAdmission) Handles(o admission.Operation) bool { return false } @@ -124,7 +125,7 @@ type clientCertWanter struct { } func (s *clientCertWanter) SetClientCert(cert, key []byte) { s.gotCert, s.gotKey = cert, key } -func (s *clientCertWanter) Admit(a admission.Attributes, o admission.ObjectInterfaces) error { +func (s *clientCertWanter) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { return nil } func (s *clientCertWanter) Handles(o admission.Operation) bool { return false } diff --git a/pkg/admission/interfaces.go b/pkg/admission/interfaces.go index 5f6d703b2..a3e3cbdbe 100644 --- a/pkg/admission/interfaces.go +++ b/pkg/admission/interfaces.go @@ -17,6 +17,7 @@ limitations under the License. package admission import ( + "context" "io" "k8s.io/apimachinery/pkg/runtime" @@ -120,8 +121,9 @@ type Interface interface { type MutationInterface interface { Interface - // Admit makes an admission decision based on the request attributes - Admit(a Attributes, o ObjectInterfaces) (err error) + // Admit makes an admission decision based on the request attributes. + // Context is used only for timeout/deadline/cancellation and tracing information. + Admit(ctx context.Context, a Attributes, o ObjectInterfaces) (err error) } // ValidationInterface is an abstract, pluggable interface for Admission Control decisions. @@ -129,7 +131,8 @@ type ValidationInterface interface { Interface // Validate makes an admission decision based on the request attributes. It is NOT allowed to mutate - Validate(a Attributes, o ObjectInterfaces) (err error) + // Context is used only for timeout/deadline/cancellation and tracing information. + Validate(ctx context.Context, a Attributes, o ObjectInterfaces) (err error) } // Operation is the type of resource operation being checked for admission control diff --git a/pkg/admission/metrics/metrics.go b/pkg/admission/metrics/metrics.go index 56cc07edd..dbdc5db78 100644 --- a/pkg/admission/metrics/metrics.go +++ b/pkg/admission/metrics/metrics.go @@ -17,6 +17,7 @@ limitations under the License. package metrics import ( + "context" "fmt" "strconv" "time" @@ -75,27 +76,27 @@ type pluginHandlerWithMetrics struct { } // Admit performs a mutating admission control check and emit metrics. -func (p pluginHandlerWithMetrics) Admit(a admission.Attributes, o admission.ObjectInterfaces) error { +func (p pluginHandlerWithMetrics) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { mutatingHandler, ok := p.Interface.(admission.MutationInterface) if !ok { return nil } start := time.Now() - err := mutatingHandler.Admit(a, o) + err := mutatingHandler.Admit(ctx, a, o) p.observer(time.Since(start), err != nil, a, stepAdmit, p.extraLabels...) return err } // Validate performs a non-mutating admission control check and emits metrics. -func (p pluginHandlerWithMetrics) Validate(a admission.Attributes, o admission.ObjectInterfaces) error { +func (p pluginHandlerWithMetrics) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { validatingHandler, ok := p.Interface.(admission.ValidationInterface) if !ok { return nil } start := time.Now() - err := validatingHandler.Validate(a, o) + err := validatingHandler.Validate(ctx, a, o) p.observer(time.Since(start), err != nil, a, stepValidate, p.extraLabels...) return err } diff --git a/pkg/admission/metrics/metrics_test.go b/pkg/admission/metrics/metrics_test.go index 2934b624b..1b96d25a2 100644 --- a/pkg/admission/metrics/metrics_test.go +++ b/pkg/admission/metrics/metrics_test.go @@ -17,6 +17,7 @@ limitations under the License. package metrics import ( + "context" "fmt" "testing" "time" @@ -36,8 +37,8 @@ var ( func TestObserveAdmissionStep(t *testing.T) { Metrics.reset() handler := WithStepMetrics(&mutatingAndValidatingFakeHandler{admission.NewHandler(admission.Create), true, true}) - handler.(admission.MutationInterface).Admit(attr, nil) - handler.(admission.ValidationInterface).Validate(attr, nil) + handler.(admission.MutationInterface).Admit(context.TODO(), attr, nil) + handler.(admission.ValidationInterface).Validate(context.TODO(), attr, nil) wantLabels := map[string]string{ "operation": string(admission.Create), "type": "admit", @@ -54,8 +55,8 @@ func TestObserveAdmissionStep(t *testing.T) { func TestObserveAdmissionController(t *testing.T) { Metrics.reset() handler := WithControllerMetrics(&mutatingAndValidatingFakeHandler{admission.NewHandler(admission.Create), true, true}, "a") - handler.(admission.MutationInterface).Admit(attr, nil) - handler.(admission.ValidationInterface).Validate(attr, nil) + handler.(admission.MutationInterface).Admit(context.TODO(), attr, nil) + handler.(admission.ValidationInterface).Validate(context.TODO(), attr, nil) wantLabels := map[string]string{ "name": "a", "operation": string(admission.Create), @@ -154,7 +155,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, test.options, false, nil), nil) + err := h.(admission.MutationInterface).Admit(context.TODO(), admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, test.options, false, nil), nil) if test.admit && err != nil { t.Errorf("expected admit to succeed, but failed: %v", err) continue @@ -179,7 +180,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, test.options, false, nil), nil) + err = h.(admission.ValidationInterface).Validate(context.TODO(), admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, test.options, false, nil), nil) if test.validate && err != nil { t.Errorf("expected admit to succeed, but failed: %v", err) continue @@ -206,14 +207,14 @@ type mutatingAndValidatingFakeHandler struct { validate bool } -func (h *mutatingAndValidatingFakeHandler) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) { +func (h *mutatingAndValidatingFakeHandler) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) { if h.admit { return nil } return fmt.Errorf("don't admit") } -func (h *mutatingAndValidatingFakeHandler) Validate(a admission.Attributes, o admission.ObjectInterfaces) (err error) { +func (h *mutatingAndValidatingFakeHandler) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) { if h.validate { return nil } @@ -225,7 +226,7 @@ type validatingFakeHandler struct { validate bool } -func (h *validatingFakeHandler) Validate(a admission.Attributes, o admission.ObjectInterfaces) (err error) { +func (h *validatingFakeHandler) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) { if h.validate { return nil } @@ -237,7 +238,7 @@ type mutatingFakeHandler struct { admit bool } -func (h *mutatingFakeHandler) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) { +func (h *mutatingFakeHandler) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) { if h.admit { return nil } diff --git a/pkg/admission/plugin/namespace/lifecycle/admission.go b/pkg/admission/plugin/namespace/lifecycle/admission.go index c6517bee3..1fbac4517 100644 --- a/pkg/admission/plugin/namespace/lifecycle/admission.go +++ b/pkg/admission/plugin/namespace/lifecycle/admission.go @@ -17,13 +17,14 @@ limitations under the License. package lifecycle import ( + "context" "fmt" "io" "time" "k8s.io/klog" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" @@ -73,7 +74,7 @@ var _ = initializer.WantsExternalKubeInformerFactory(&Lifecycle{}) var _ = initializer.WantsExternalKubeClientSet(&Lifecycle{}) // Admit makes an admission decision based on the request attributes -func (l *Lifecycle) Admit(a admission.Attributes, o admission.ObjectInterfaces) error { +func (l *Lifecycle) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { // prevent deletion of immortal namespaces if a.GetOperation() == admission.Delete && a.GetKind().GroupKind() == v1.SchemeGroupVersion.WithKind("Namespace").GroupKind() && l.immortalNamespaces.Has(a.GetName()) { return errors.NewForbidden(a.GetResource().GroupResource(), a.GetName(), fmt.Errorf("this namespace may not be deleted")) diff --git a/pkg/admission/plugin/namespace/lifecycle/admission_test.go b/pkg/admission/plugin/namespace/lifecycle/admission_test.go index ccc17392e..0ab9bf3e7 100644 --- a/pkg/admission/plugin/namespace/lifecycle/admission_test.go +++ b/pkg/admission/plugin/namespace/lifecycle/admission_test.go @@ -17,6 +17,7 @@ limitations under the License. package lifecycle import ( + "context" "fmt" "testing" "time" @@ -104,7 +105,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, &metav1.CreateOptions{}, false, nil), nil) + err = handler.Admit(context.TODO(), 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, &metav1.CreateOptions{}, false, nil), nil) if err != nil { t.Error(err) } @@ -124,7 +125,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, &metav1.CreateOptions{}, false, nil), nil) + err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil) if err == nil { actions := "" for _, action := range mockClient.Actions() { @@ -134,19 +135,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, &metav1.CreateOptions{}, false, nil), nil) + err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), 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, &metav1.UpdateOptions{}, false, nil), nil) + err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Update, &metav1.UpdateOptions{}, false, nil), 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, &metav1.DeleteOptions{}, false, nil), nil) + err = handler.Admit(context.TODO(), admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Delete, &metav1.DeleteOptions{}, false, nil), nil) if err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } @@ -166,7 +167,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, &metav1.CreateOptions{}, false, nil), nil) + err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil) if err != nil { t.Errorf("unexpected error returned from admission handler") } @@ -187,31 +188,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, &metav1.CreateOptions{}, false, nil), nil) + err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), 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, &metav1.UpdateOptions{}, false, nil), nil) + err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Update, &metav1.UpdateOptions{}, false, nil), 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, &metav1.DeleteOptions{}, false, nil), nil) + err = handler.Admit(context.TODO(), admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Delete, &metav1.DeleteOptions{}, false, nil), 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, &metav1.DeleteOptions{}, false, nil), nil) + err = handler.Admit(context.TODO(), admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), "", metav1.NamespaceDefault, v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, &metav1.DeleteOptions{}, false, nil), 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, &metav1.DeleteOptions{}, false, nil), nil) + err = handler.Admit(context.TODO(), admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), "", "other", v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, &metav1.DeleteOptions{}, false, nil), nil) if err != nil { t.Errorf("Did not expect an error %v", err) } @@ -238,7 +239,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, &metav1.CreateOptions{}, false, nil), nil) + err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil) if err != nil { t.Errorf("Unexpected error rejecting creates in an active namespace") } @@ -248,7 +249,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, &metav1.DeleteOptions{}, false, nil), nil) + err = handler.Admit(context.TODO(), admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), namespace, namespace, v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, &metav1.DeleteOptions{}, false, nil), nil) if err != nil { t.Errorf("Expected namespace deletion to be allowed") } @@ -261,7 +262,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, &metav1.CreateOptions{}, false, nil), nil) + err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil) if err == nil { t.Errorf("Expected error rejecting creates in a namespace right after deleting it") } @@ -274,7 +275,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, &metav1.CreateOptions{}, false, nil), nil) + err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil) if err == nil { t.Errorf("Expected error rejecting creates in a namespace right after deleting it") } @@ -287,7 +288,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, &metav1.CreateOptions{}, false, nil), nil) + handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil) if getCalls != 0 { t.Errorf("Expected no live lookup of the namespace at t=forceLiveLookupTTL+1ms, got %d", getCalls) } diff --git a/pkg/admission/plugin/webhook/generic/webhook.go b/pkg/admission/plugin/webhook/generic/webhook.go index 51453a358..a4a6aff51 100644 --- a/pkg/admission/plugin/webhook/generic/webhook.go +++ b/pkg/admission/plugin/webhook/generic/webhook.go @@ -211,7 +211,7 @@ type attrWithResourceOverride struct { func (a *attrWithResourceOverride) GetResource() schema.GroupVersionResource { return a.resource } // Dispatch is called by the downstream Validate or Admit methods. -func (a *Webhook) Dispatch(attr admission.Attributes, o admission.ObjectInterfaces) error { +func (a *Webhook) Dispatch(ctx context.Context, attr admission.Attributes, o admission.ObjectInterfaces) error { if rules.IsWebhookConfigurationResource(attr) { return nil } @@ -219,8 +219,5 @@ func (a *Webhook) Dispatch(attr admission.Attributes, o admission.ObjectInterfac return admission.NewForbidden(attr, fmt.Errorf("not yet ready to handle request")) } hooks := a.hookSource.Webhooks() - // TODO: Figure out if adding one second timeout make sense here. - ctx := context.TODO() - return a.dispatcher.Dispatch(ctx, attr, o, hooks) } diff --git a/pkg/admission/plugin/webhook/mutating/plugin.go b/pkg/admission/plugin/webhook/mutating/plugin.go index 6202fbc63..fb07a61c1 100644 --- a/pkg/admission/plugin/webhook/mutating/plugin.go +++ b/pkg/admission/plugin/webhook/mutating/plugin.go @@ -17,6 +17,7 @@ limitations under the License. package mutating import ( + "context" "io" "k8s.io/apiserver/pkg/admission" @@ -70,6 +71,6 @@ func (a *Plugin) ValidateInitialization() error { } // Admit makes an admission decision based on the request attributes. -func (a *Plugin) Admit(attr admission.Attributes, o admission.ObjectInterfaces) error { - return a.Webhook.Dispatch(attr, o) +func (a *Plugin) Admit(ctx context.Context, attr admission.Attributes, o admission.ObjectInterfaces) error { + return a.Webhook.Dispatch(ctx, attr, o) } diff --git a/pkg/admission/plugin/webhook/mutating/plugin_test.go b/pkg/admission/plugin/webhook/mutating/plugin_test.go index db178eeca..a24087360 100644 --- a/pkg/admission/plugin/webhook/mutating/plugin_test.go +++ b/pkg/admission/plugin/webhook/mutating/plugin_test.go @@ -17,6 +17,7 @@ limitations under the License. package mutating import ( + "context" "fmt" "net/url" "reflect" @@ -80,7 +81,7 @@ func TestAdmit(t *testing.T) { attr = webhooktesting.NewAttribute(ns, tt.AdditionalLabels, tt.IsDryRun) } - err = wh.Admit(attr, objectInterfaces) + err = wh.Admit(context.TODO(), attr, objectInterfaces) if tt.ExpectAllow != (err == nil) { t.Errorf("expected allowed=%v, but got err=%v", tt.ExpectAllow, err) } @@ -163,7 +164,7 @@ func TestAdmitCachedClient(t *testing.T) { continue } - err = wh.Admit(webhooktesting.NewAttribute(ns, nil, false), objectInterfaces) + err = wh.Admit(context.TODO(), webhooktesting.NewAttribute(ns, nil, false), objectInterfaces) if tt.ExpectAllow != (err == nil) { t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err) } diff --git a/pkg/admission/plugin/webhook/validating/plugin.go b/pkg/admission/plugin/webhook/validating/plugin.go index 30e5c9d33..6972877b1 100644 --- a/pkg/admission/plugin/webhook/validating/plugin.go +++ b/pkg/admission/plugin/webhook/validating/plugin.go @@ -17,6 +17,7 @@ limitations under the License. package validating import ( + "context" "io" "k8s.io/apiserver/pkg/admission" @@ -61,6 +62,6 @@ func NewValidatingAdmissionWebhook(configFile io.Reader) (*Plugin, error) { } // Validate makes an admission decision based on the request attributes. -func (a *Plugin) Validate(attr admission.Attributes, o admission.ObjectInterfaces) error { - return a.Webhook.Dispatch(attr, o) +func (a *Plugin) Validate(ctx context.Context, attr admission.Attributes, o admission.ObjectInterfaces) error { + return a.Webhook.Dispatch(ctx, attr, o) } diff --git a/pkg/admission/plugin/webhook/validating/plugin_test.go b/pkg/admission/plugin/webhook/validating/plugin_test.go index a2aec191e..0734600f7 100644 --- a/pkg/admission/plugin/webhook/validating/plugin_test.go +++ b/pkg/admission/plugin/webhook/validating/plugin_test.go @@ -17,6 +17,7 @@ limitations under the License. package validating import ( + "context" "net/url" "strings" "testing" @@ -67,7 +68,7 @@ func TestValidate(t *testing.T) { } attr := webhooktesting.NewAttribute(ns, nil, tt.IsDryRun) - err = wh.Validate(attr, objectInterfaces) + err = wh.Validate(context.TODO(), attr, objectInterfaces) if tt.ExpectAllow != (err == nil) { t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err) } @@ -132,7 +133,7 @@ func TestValidateCachedClient(t *testing.T) { continue } - err = wh.Validate(webhooktesting.NewAttribute(ns, nil, false), objectInterfaces) + err = wh.Validate(context.TODO(), webhooktesting.NewAttribute(ns, nil, false), objectInterfaces) if tt.ExpectAllow != (err == nil) { t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err) } diff --git a/pkg/admission/reinvocation.go b/pkg/admission/reinvocation.go index b99e604e0..f93c703a1 100644 --- a/pkg/admission/reinvocation.go +++ b/pkg/admission/reinvocation.go @@ -16,6 +16,8 @@ limitations under the License. package admission +import "context" + // newReinvocationHandler creates a handler that wraps the provided admission chain and reinvokes it // if needed according to re-invocation policy of the webhooks. func newReinvocationHandler(admissionChain Interface) Interface { @@ -30,9 +32,9 @@ type reinvoker struct { // admission chain if needed according to the reinvocation policy. Plugins are expected to check // the admission attributes' reinvocation context against their reinvocation policy to decide if // they should re-run, and to update the reinvocation context if they perform any mutations. -func (r *reinvoker) Admit(a Attributes, o ObjectInterfaces) error { +func (r *reinvoker) Admit(ctx context.Context, a Attributes, o ObjectInterfaces) error { if mutator, ok := r.admissionChain.(MutationInterface); ok { - err := mutator.Admit(a, o) + err := mutator.Admit(ctx, a, o) if err != nil { return err } @@ -42,16 +44,16 @@ func (r *reinvoker) Admit(a Attributes, o ObjectInterfaces) error { // Calling admit a second time will reinvoke all in-tree plugins // as well as any webhook plugins that need to be reinvoked based on the // reinvocation policy. - return mutator.Admit(a, o) + return mutator.Admit(ctx, a, o) } } return nil } // Validate performs an admission control check using the wrapped admission chain, and returns immediately on first error. -func (r *reinvoker) Validate(a Attributes, o ObjectInterfaces) error { +func (r *reinvoker) Validate(ctx context.Context, a Attributes, o ObjectInterfaces) error { if validator, ok := r.admissionChain.(ValidationInterface); ok { - return validator.Validate(a, o) + return validator.Validate(ctx, a, o) } return nil } diff --git a/pkg/admission/testing/helpers.go b/pkg/admission/testing/helpers.go index 8ab448f77..45e126dab 100644 --- a/pkg/admission/testing/helpers.go +++ b/pkg/admission/testing/helpers.go @@ -17,6 +17,7 @@ limitations under the License. package testing import ( + "context" "reflect" "testing" @@ -40,11 +41,11 @@ type reinvoker struct { // Admit reinvokes the admission handler and reports a test error if the admission handler performs // non-idempotent mutatations to the admission object. -func (r *reinvoker) Admit(a admission.Attributes, o admission.ObjectInterfaces) error { +func (r *reinvoker) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { r.t.Helper() outputs := []runtime.Object{} for i := 0; i < 2; i++ { - err := r.admission.Admit(a, o) + err := r.admission.Admit(ctx, a, o) if err != nil { return err } diff --git a/pkg/endpoints/apiserver_test.go b/pkg/endpoints/apiserver_test.go index 1da6f6c47..dd6a8224e 100644 --- a/pkg/endpoints/apiserver_test.go +++ b/pkg/endpoints/apiserver_test.go @@ -77,7 +77,7 @@ import ( type alwaysMutatingDeny struct{} -func (alwaysMutatingDeny) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) { +func (alwaysMutatingDeny) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) { return admission.NewForbidden(a, errors.New("Mutating admission control is denying all modifications")) } @@ -87,7 +87,7 @@ func (alwaysMutatingDeny) Handles(operation admission.Operation) bool { type alwaysValidatingDeny struct{} -func (alwaysValidatingDeny) Validate(a admission.Attributes, o admission.ObjectInterfaces) (err error) { +func (alwaysValidatingDeny) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) { return admission.NewForbidden(a, errors.New("Validating admission control is denying all modifications")) } @@ -448,7 +448,7 @@ func (storage *SimpleRESTStorage) Delete(ctx context.Context, id string, deleteV if err := storage.errors["delete"]; err != nil { return nil, false, err } - if err := deleteValidation(&storage.item); err != nil { + if err := deleteValidation(ctx, &storage.item); err != nil { return nil, false, err } var obj runtime.Object = &metav1.Status{Status: metav1.StatusSuccess} @@ -477,7 +477,7 @@ func (storage *SimpleRESTStorage) Create(ctx context.Context, obj runtime.Object if storage.injectedFunction != nil { obj, err = storage.injectedFunction(obj) } - if err := createValidation(obj); err != nil { + if err := createValidation(ctx, obj); err != nil { return nil, err } return obj, err @@ -496,7 +496,7 @@ func (storage *SimpleRESTStorage) Update(ctx context.Context, name string, objIn if storage.injectedFunction != nil { obj, err = storage.injectedFunction(obj) } - if err := updateValidation(&storage.item, obj); err != nil { + if err := updateValidation(ctx, &storage.item, obj); err != nil { return nil, false, err } return obj, false, err @@ -654,7 +654,7 @@ func (storage *NamedCreaterRESTStorage) Create(ctx context.Context, name string, if storage.injectedFunction != nil { obj, err = storage.injectedFunction(obj) } - if err := createValidation(obj); err != nil { + if err := createValidation(ctx, obj); err != nil { return nil, err } return obj, err diff --git a/pkg/endpoints/handlers/create.go b/pkg/endpoints/handlers/create.go index 5f52acfc8..8f1201c28 100644 --- a/pkg/endpoints/handlers/create.go +++ b/pkg/endpoints/handlers/create.go @@ -132,7 +132,7 @@ func createHandler(r rest.NamedCreater, scope *RequestScope, admit admission.Int userInfo, _ := request.UserFrom(ctx) admissionAttributes := admission.NewAttributesRecord(obj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, options, dryrun.IsDryRun(options.DryRun), userInfo) if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && mutatingAdmission.Handles(admission.Create) { - err = mutatingAdmission.Admit(admissionAttributes, scope) + err = mutatingAdmission.Admit(ctx, admissionAttributes, scope) if err != nil { scope.err(err, w, req) return diff --git a/pkg/endpoints/handlers/patch.go b/pkg/endpoints/handlers/patch.go index fdaba2629..80570f80a 100644 --- a/pkg/endpoints/handlers/patch.go +++ b/pkg/endpoints/handlers/patch.go @@ -239,7 +239,7 @@ func PatchResource(r rest.Patcher, scope *RequestScope, admit admission.Interfac } } -type mutateObjectUpdateFunc func(obj, old runtime.Object) error +type mutateObjectUpdateFunc func(ctx context.Context, obj, old runtime.Object) error // patcher breaks the process of patch application and retries into smaller // pieces of functionality. @@ -515,7 +515,7 @@ func (p *patcher) applyAdmission(ctx context.Context, patchedObject runtime.Obje } if p.admissionCheck != nil && p.admissionCheck.Handles(operation) { attributes := p.admissionAttributes(ctx, patchedObject, currentObject, operation, options) - return patchedObject, p.admissionCheck.Admit(attributes, p.objectInterfaces) + return patchedObject, p.admissionCheck.Admit(ctx, attributes, p.objectInterfaces) } return patchedObject, nil } diff --git a/pkg/endpoints/handlers/rest.go b/pkg/endpoints/handlers/rest.go index 8aecd4c14..75764597f 100644 --- a/pkg/endpoints/handlers/rest.go +++ b/pkg/endpoints/handlers/rest.go @@ -163,14 +163,14 @@ func ConnectResource(connecter rest.Connecter, scope *RequestScope, admit admiss 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(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, nil, false, userInfo), scope) + err = mutatingAdmission.Admit(ctx, admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, nil, false, userInfo), scope) if err != nil { scope.err(err, w, req) return } } if validatingAdmission, ok := admit.(admission.ValidationInterface); ok { - err = validatingAdmission.Validate(admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, nil, false, userInfo), scope) + err = validatingAdmission.Validate(ctx, admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, nil, false, userInfo), scope) if err != nil { scope.err(err, w, req) return diff --git a/pkg/endpoints/handlers/rest_test.go b/pkg/endpoints/handlers/rest_test.go index d3a188059..924990a8c 100644 --- a/pkg/endpoints/handlers/rest_test.go +++ b/pkg/endpoints/handlers/rest_test.go @@ -260,11 +260,11 @@ func (p *testPatcher) Update(ctx context.Context, name string, objInfo rest.Upda } if currentPod == nil { - if err := createValidation(currentPod); err != nil { + if err := createValidation(ctx, currentPod); err != nil { return nil, false, err } } else { - if err := updateValidation(currentPod, inPod); err != nil { + if err := updateValidation(ctx, currentPod, inPod); err != nil { return nil, false, err } } @@ -351,13 +351,13 @@ func (tc *patchTestCase) Run(t *testing.T) { admissionMutation := tc.admissionMutation if admissionMutation == nil { - admissionMutation = func(updatedObject runtime.Object, currentObject runtime.Object) error { + admissionMutation = func(ctx context.Context, updatedObject runtime.Object, currentObject runtime.Object) error { return nil } } admissionValidation := tc.admissionValidation if admissionValidation == nil { - admissionValidation = func(updatedObject runtime.Object, currentObject runtime.Object) error { + admissionValidation = func(ctx context.Context, updatedObject runtime.Object, currentObject runtime.Object) error { return nil } } @@ -718,7 +718,7 @@ func TestPatchWithAdmissionRejection(t *testing.T) { for _, test := range []Test{ { name: "TestPatchWithMutatingAdmissionRejection", - admissionMutation: func(updatedObject runtime.Object, currentObject runtime.Object) error { + admissionMutation: func(ctx context.Context, updatedObject runtime.Object, currentObject runtime.Object) error { return errors.New("mutating admission failure") }, admissionValidation: rest.ValidateAllObjectUpdateFunc, @@ -727,17 +727,17 @@ func TestPatchWithAdmissionRejection(t *testing.T) { { name: "TestPatchWithValidatingAdmissionRejection", admissionMutation: rest.ValidateAllObjectUpdateFunc, - admissionValidation: func(updatedObject runtime.Object, currentObject runtime.Object) error { + admissionValidation: func(ctx context.Context, updatedObject runtime.Object, currentObject runtime.Object) error { return errors.New("validating admission failure") }, expectedError: "validating admission failure", }, { name: "TestPatchWithBothAdmissionRejections", - admissionMutation: func(updatedObject runtime.Object, currentObject runtime.Object) error { + admissionMutation: func(ctx context.Context, updatedObject runtime.Object, currentObject runtime.Object) error { return errors.New("mutating admission failure") }, - admissionValidation: func(updatedObject runtime.Object, currentObject runtime.Object) error { + admissionValidation: func(ctx context.Context, updatedObject runtime.Object, currentObject runtime.Object) error { return errors.New("validating admission failure") }, expectedError: "mutating admission failure", @@ -777,7 +777,7 @@ func TestPatchWithVersionConflictThenAdmissionFailure(t *testing.T) { tc := &patchTestCase{ name: "TestPatchWithVersionConflictThenAdmissionFailure", - admissionMutation: func(updatedObject runtime.Object, currentObject runtime.Object) error { + admissionMutation: func(ctx context.Context, updatedObject runtime.Object, currentObject runtime.Object) error { if seen { return errors.New("admission failure") } @@ -951,8 +951,8 @@ func (f mutateObjectUpdateFunc) Handles(operation admission.Operation) bool { return true } -func (f mutateObjectUpdateFunc) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) { - return f(a.GetObject(), a.GetOldObject()) +func (f mutateObjectUpdateFunc) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) { + return f(ctx, a.GetObject(), a.GetOldObject()) } func TestTransformDecodeErrorEnsuresBadRequestError(t *testing.T) { diff --git a/pkg/endpoints/handlers/update.go b/pkg/endpoints/handlers/update.go index 61a004aea..b7c2dbcd4 100644 --- a/pkg/endpoints/handlers/update.go +++ b/pkg/endpoints/handlers/update.go @@ -140,11 +140,11 @@ func UpdateResource(r rest.Updater, scope *RequestScope, admit admission.Interfa 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, updateToCreateOptions(options), dryrun.IsDryRun(options.DryRun), userInfo), scope) + return newObj, mutatingAdmission.Admit(ctx, admission.NewAttributesRecord(newObj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, updateToCreateOptions(options), dryrun.IsDryRun(options.DryRun), userInfo), scope) } } else { if mutatingAdmission.Handles(admission.Update) { - return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, options, dryrun.IsDryRun(options.DryRun), userInfo), scope) + return newObj, mutatingAdmission.Admit(ctx, admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, options, dryrun.IsDryRun(options.DryRun), userInfo), scope) } } return newObj, nil @@ -205,7 +205,7 @@ func withAuthorization(validate rest.ValidateObjectFunc, a authorizer.Authorizer var authorizerDecision authorizer.Decision var authorizerReason string var authorizerErr error - return func(obj runtime.Object) error { + return func(ctx context.Context, obj runtime.Object) error { if a == nil { return errors.NewInternalError(fmt.Errorf("no authorizer provided, unable to authorize a create on update")) } @@ -215,7 +215,7 @@ func withAuthorization(validate rest.ValidateObjectFunc, a authorizer.Authorizer // an authorizer like RBAC could encounter evaluation errors and still allow the request, so authorizer decision is checked before error here. if authorizerDecision == authorizer.DecisionAllow { // Continue to validating admission - return validate(obj) + return validate(ctx, obj) } if authorizerErr != nil { return errors.NewInternalError(authorizerErr) diff --git a/pkg/registry/generic/registry/dryrun.go b/pkg/registry/generic/registry/dryrun.go index 24a1b1ec2..3ff840380 100644 --- a/pkg/registry/generic/registry/dryrun.go +++ b/pkg/registry/generic/registry/dryrun.go @@ -52,7 +52,7 @@ func (s *DryRunnableStorage) Delete(ctx context.Context, key string, out runtime if err := preconditions.Check(key, out); err != nil { return err } - return deleteValidation(out) + return deleteValidation(ctx, out) } return s.Storage.Delete(ctx, key, out, preconditions, deleteValidation) } diff --git a/pkg/registry/generic/registry/store.go b/pkg/registry/generic/registry/store.go index be03caa41..95d0ad3f4 100644 --- a/pkg/registry/generic/registry/store.go +++ b/pkg/registry/generic/registry/store.go @@ -342,7 +342,7 @@ func (e *Store) Create(ctx context.Context, obj runtime.Object, createValidation // at this point we have a fully formed object. It is time to call the validators that the apiserver // handling chain wants to enforce. if createValidation != nil { - if err := createValidation(obj.DeepCopyObject()); err != nil { + if err := createValidation(ctx, obj.DeepCopyObject()); err != nil { return nil, err } } @@ -504,7 +504,7 @@ func (e *Store) Update(ctx context.Context, name string, objInfo rest.UpdatedObj // at this point we have a fully formed object. It is time to call the validators that the apiserver // handling chain wants to enforce. if createValidation != nil { - if err := createValidation(obj.DeepCopyObject()); err != nil { + if err := createValidation(ctx, obj.DeepCopyObject()); err != nil { return nil, nil, err } } @@ -546,7 +546,7 @@ func (e *Store) Update(ctx context.Context, name string, objInfo rest.UpdatedObj // at this point we have a fully formed object. It is time to call the validators that the apiserver // handling chain wants to enforce. if updateValidation != nil { - if err := updateValidation(obj.DeepCopyObject(), existing.DeepCopyObject()); err != nil { + if err := updateValidation(ctx, obj.DeepCopyObject(), existing.DeepCopyObject()); err != nil { return nil, nil, err } } @@ -812,7 +812,7 @@ func (e *Store) updateForGracefulDeletionAndFinalizers(ctx context.Context, name false, /* ignoreNotFound */ &preconditions, storage.SimpleUpdate(func(existing runtime.Object) (runtime.Object, error) { - if err := deleteValidation(existing); err != nil { + if err := deleteValidation(ctx, existing); err != nil { return nil, err } graceful, pendingGraceful, err := rest.BeforeDelete(e.DeleteStrategy, ctx, existing, options) diff --git a/pkg/registry/generic/registry/store_test.go b/pkg/registry/generic/registry/store_test.go index 32f050415..e498afc4a 100644 --- a/pkg/registry/generic/registry/store_test.go +++ b/pkg/registry/generic/registry/store_test.go @@ -1713,11 +1713,11 @@ func TestQualifiedResource(t *testing.T) { } } -func denyCreateValidation(obj runtime.Object) error { +func denyCreateValidation(ctx context.Context, obj runtime.Object) error { return fmt.Errorf("admission denied") } -func denyUpdateValidation(obj, old runtime.Object) error { +func denyUpdateValidation(ctx context.Context, obj, old runtime.Object) error { return fmt.Errorf("admission denied") } @@ -1933,7 +1933,7 @@ func TestRetryDeleteValidation(t *testing.T) { updated := make(chan struct{}) var readyOnce, updatedOnce sync.Once var called int - deleteValidation := func(runtime.Object) error { + deleteValidation := func(ctx context.Context, obj runtime.Object) error { readyOnce.Do(func() { close(ready) }) diff --git a/pkg/registry/rest/create.go b/pkg/registry/rest/create.go index 2fc47d9db..e5ae7562d 100644 --- a/pkg/registry/rest/create.go +++ b/pkg/registry/rest/create.go @@ -160,9 +160,9 @@ type NamespaceScopedStrategy interface { func AdmissionToValidateObjectFunc(admit admission.Interface, staticAttributes admission.Attributes, o admission.ObjectInterfaces) ValidateObjectFunc { validatingAdmission, ok := admit.(admission.ValidationInterface) if !ok { - return func(obj runtime.Object) error { return nil } + return func(ctx context.Context, obj runtime.Object) error { return nil } } - return func(obj runtime.Object) error { + return func(ctx context.Context, obj runtime.Object) error { finalAttributes := admission.NewAttributesRecord( obj, staticAttributes.GetOldObject(), @@ -179,6 +179,6 @@ func AdmissionToValidateObjectFunc(admit admission.Interface, staticAttributes a if !validatingAdmission.Handles(finalAttributes.GetOperation()) { return nil } - return validatingAdmission.Validate(finalAttributes, o) + return validatingAdmission.Validate(ctx, finalAttributes, o) } } diff --git a/pkg/registry/rest/delete.go b/pkg/registry/rest/delete.go index 2b5038b21..3e7ca85b7 100644 --- a/pkg/registry/rest/delete.go +++ b/pkg/registry/rest/delete.go @@ -150,7 +150,7 @@ func AdmissionToValidateObjectDeleteFunc(admit admission.Interface, staticAttrib mutating := isMutatingAdmission && mutatingAdmission.Handles(staticAttributes.GetOperation()) validating := isValidatingAdmission && validatingAdmission.Handles(staticAttributes.GetOperation()) - return func(old runtime.Object) error { + return func(ctx context.Context, old runtime.Object) error { if !mutating && !validating { return nil } @@ -169,12 +169,12 @@ func AdmissionToValidateObjectDeleteFunc(admit admission.Interface, staticAttrib staticAttributes.GetUserInfo(), ) if mutating { - if err := mutatingAdmission.Admit(finalAttributes, objInterfaces); err != nil { + if err := mutatingAdmission.Admit(ctx, finalAttributes, objInterfaces); err != nil { return err } } if validating { - if err := validatingAdmission.Validate(finalAttributes, objInterfaces); err != nil { + if err := validatingAdmission.Validate(ctx, finalAttributes, objInterfaces); err != nil { return err } } diff --git a/pkg/registry/rest/rest.go b/pkg/registry/rest/rest.go index 08c7cafc6..28f4bf07c 100644 --- a/pkg/registry/rest/rest.go +++ b/pkg/registry/rest/rest.go @@ -210,20 +210,20 @@ type UpdatedObjectInfo interface { // ValidateObjectFunc is a function to act on a given object. An error may be returned // if the hook cannot be completed. An ObjectFunc may NOT transform the provided // object. -type ValidateObjectFunc func(obj runtime.Object) error +type ValidateObjectFunc func(ctx context.Context, obj runtime.Object) error // ValidateAllObjectFunc is a "admit everything" instance of ValidateObjectFunc. -func ValidateAllObjectFunc(obj runtime.Object) error { +func ValidateAllObjectFunc(ctx context.Context, obj runtime.Object) error { return nil } // ValidateObjectUpdateFunc is a function to act on a given object and its predecessor. // An error may be returned if the hook cannot be completed. An UpdateObjectFunc // may NOT transform the provided object. -type ValidateObjectUpdateFunc func(obj, old runtime.Object) error +type ValidateObjectUpdateFunc func(ctx context.Context, obj, old runtime.Object) error // ValidateAllObjectUpdateFunc is a "admit everything" instance of ValidateObjectUpdateFunc. -func ValidateAllObjectUpdateFunc(obj, old runtime.Object) error { +func ValidateAllObjectUpdateFunc(ctx context.Context, obj, old runtime.Object) error { return nil } diff --git a/pkg/registry/rest/update.go b/pkg/registry/rest/update.go index a15d975ad..0741b84ec 100644 --- a/pkg/registry/rest/update.go +++ b/pkg/registry/rest/update.go @@ -255,9 +255,9 @@ func (i *wrappedUpdatedObjectInfo) UpdatedObject(ctx context.Context, oldObj run func AdmissionToValidateObjectUpdateFunc(admit admission.Interface, staticAttributes admission.Attributes, o admission.ObjectInterfaces) ValidateObjectUpdateFunc { validatingAdmission, ok := admit.(admission.ValidationInterface) if !ok { - return func(obj, old runtime.Object) error { return nil } + return func(ctx context.Context, obj, old runtime.Object) error { return nil } } - return func(obj, old runtime.Object) error { + return func(ctx context.Context, obj, old runtime.Object) error { finalAttributes := admission.NewAttributesRecord( obj, old, @@ -274,6 +274,6 @@ func AdmissionToValidateObjectUpdateFunc(admit admission.Interface, staticAttrib if !validatingAdmission.Handles(finalAttributes.GetOperation()) { return nil } - return validatingAdmission.Validate(finalAttributes, o) + return validatingAdmission.Validate(ctx, finalAttributes, o) } } diff --git a/pkg/storage/etcd3/store.go b/pkg/storage/etcd3/store.go index ba1953f49..425590aa8 100644 --- a/pkg/storage/etcd3/store.go +++ b/pkg/storage/etcd3/store.go @@ -208,7 +208,7 @@ func (s *store) conditionalDelete(ctx context.Context, key string, out runtime.O return err } } - if err := validateDeletion(origState.obj); err != nil { + if err := validateDeletion(ctx, origState.obj); err != nil { return err } startTime := time.Now() diff --git a/pkg/storage/interfaces.go b/pkg/storage/interfaces.go index f5d3b3ea7..f3ca36118 100644 --- a/pkg/storage/interfaces.go +++ b/pkg/storage/interfaces.go @@ -95,10 +95,10 @@ type UpdateFunc func(input runtime.Object, res ResponseMeta) (output runtime.Obj // ValidateObjectFunc is a function to act on a given object. An error may be returned // if the hook cannot be completed. The function may NOT transform the provided // object. -type ValidateObjectFunc func(obj runtime.Object) error +type ValidateObjectFunc func(ctx context.Context, obj runtime.Object) error // ValidateAllObjectFunc is a "admit everything" instance of ValidateObjectFunc. -func ValidateAllObjectFunc(obj runtime.Object) error { +func ValidateAllObjectFunc(ctx context.Context, obj runtime.Object) error { return nil }