Add ObjectInterfaces to Admission and Validation
Kubernetes-commit: 513a87c7b25aa58f84fafe0dc170cee4c76e481b
This commit is contained in:
parent
cfef629361
commit
87b5ac0c06
|
@ -44,7 +44,7 @@ func WithAudit(i Interface, ae *auditinternal.Event) Interface {
|
||||||
return &auditHandler{i, ae}
|
return &auditHandler{i, ae}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (handler auditHandler) Admit(a Attributes) error {
|
func (handler auditHandler) Admit(a Attributes, o ObjectInterfaces) error {
|
||||||
if !handler.Interface.Handles(a.GetOperation()) {
|
if !handler.Interface.Handles(a.GetOperation()) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -53,13 +53,13 @@ func (handler auditHandler) Admit(a Attributes) error {
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
if mutator, ok := handler.Interface.(MutationInterface); ok {
|
if mutator, ok := handler.Interface.(MutationInterface); ok {
|
||||||
err = mutator.Admit(a)
|
err = mutator.Admit(a, o)
|
||||||
handler.logAnnotations(a)
|
handler.logAnnotations(a)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (handler auditHandler) Validate(a Attributes) error {
|
func (handler auditHandler) Validate(a Attributes, o ObjectInterfaces) error {
|
||||||
if !handler.Interface.Handles(a.GetOperation()) {
|
if !handler.Interface.Handles(a.GetOperation()) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ func (handler auditHandler) Validate(a Attributes) error {
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
if validator, ok := handler.Interface.(ValidationInterface); ok {
|
if validator, ok := handler.Interface.(ValidationInterface); ok {
|
||||||
err = validator.Validate(a)
|
err = validator.Validate(a, o)
|
||||||
handler.logAnnotations(a)
|
handler.logAnnotations(a)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -45,14 +45,14 @@ var _ Interface = &fakeHandler{}
|
||||||
var _ MutationInterface = &fakeHandler{}
|
var _ MutationInterface = &fakeHandler{}
|
||||||
var _ ValidationInterface = &fakeHandler{}
|
var _ ValidationInterface = &fakeHandler{}
|
||||||
|
|
||||||
func (h fakeHandler) Admit(a Attributes) error {
|
func (h fakeHandler) Admit(a Attributes, o ObjectInterfaces) error {
|
||||||
for k, v := range h.admitAnnotations {
|
for k, v := range h.admitAnnotations {
|
||||||
a.AddAnnotation(k, v)
|
a.AddAnnotation(k, v)
|
||||||
}
|
}
|
||||||
return h.admit
|
return h.admit
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h fakeHandler) Validate(a Attributes) error {
|
func (h fakeHandler) Validate(a Attributes, o ObjectInterfaces) error {
|
||||||
for k, v := range h.validateAnnotations {
|
for k, v := range h.validateAnnotations {
|
||||||
a.AddAnnotation(k, v)
|
a.AddAnnotation(k, v)
|
||||||
}
|
}
|
||||||
|
@ -149,13 +149,13 @@ func TestWithAudit(t *testing.T) {
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
auditMutator, ok := auditHandler.(MutationInterface)
|
auditMutator, ok := auditHandler.(MutationInterface)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
assert.Equal(t, mutator.Admit(a), auditMutator.Admit(a), tcName+": WithAudit decorator should not effect the return value")
|
assert.Equal(t, mutator.Admit(a, nil), auditMutator.Admit(a, nil), tcName+": WithAudit decorator should not effect the return value")
|
||||||
|
|
||||||
validator, ok := handler.(ValidationInterface)
|
validator, ok := handler.(ValidationInterface)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
auditValidator, ok := auditHandler.(ValidationInterface)
|
auditValidator, ok := auditHandler.(ValidationInterface)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
assert.Equal(t, validator.Validate(a), auditValidator.Validate(a), tcName+": WithAudit decorator should not effect the return value")
|
assert.Equal(t, validator.Validate(a, nil), auditValidator.Validate(a, nil), tcName+": WithAudit decorator should not effect the return value")
|
||||||
|
|
||||||
annotations := make(map[string]string, len(tc.admitAnnotations)+len(tc.validateAnnotations))
|
annotations := make(map[string]string, len(tc.admitAnnotations)+len(tc.validateAnnotations))
|
||||||
for k, v := range tc.admitAnnotations {
|
for k, v := range tc.admitAnnotations {
|
||||||
|
|
|
@ -26,13 +26,13 @@ func NewChainHandler(handlers ...Interface) chainAdmissionHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Admit performs an admission control check using a chain of handlers, and returns immediately on first error
|
// Admit performs an admission control check using a chain of handlers, and returns immediately on first error
|
||||||
func (admissionHandler chainAdmissionHandler) Admit(a Attributes) error {
|
func (admissionHandler chainAdmissionHandler) Admit(a Attributes, o ObjectInterfaces) error {
|
||||||
for _, handler := range admissionHandler {
|
for _, handler := range admissionHandler {
|
||||||
if !handler.Handles(a.GetOperation()) {
|
if !handler.Handles(a.GetOperation()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if mutator, ok := handler.(MutationInterface); ok {
|
if mutator, ok := handler.(MutationInterface); ok {
|
||||||
err := mutator.Admit(a)
|
err := mutator.Admit(a, o)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -42,13 +42,13 @@ func (admissionHandler chainAdmissionHandler) Admit(a Attributes) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate performs an admission control check using a chain of handlers, and returns immediately on first error
|
// Validate performs an admission control check using a chain of handlers, and returns immediately on first error
|
||||||
func (admissionHandler chainAdmissionHandler) Validate(a Attributes) error {
|
func (admissionHandler chainAdmissionHandler) Validate(a Attributes, o ObjectInterfaces) error {
|
||||||
for _, handler := range admissionHandler {
|
for _, handler := range admissionHandler {
|
||||||
if !handler.Handles(a.GetOperation()) {
|
if !handler.Handles(a.GetOperation()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if validator, ok := handler.(ValidationInterface); ok {
|
if validator, ok := handler.(ValidationInterface); ok {
|
||||||
err := validator.Validate(a)
|
err := validator.Validate(a, o)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ type FakeHandler struct {
|
||||||
validate, validateCalled bool
|
validate, validateCalled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *FakeHandler) Admit(a Attributes) (err error) {
|
func (h *FakeHandler) Admit(a Attributes, o ObjectInterfaces) (err error) {
|
||||||
h.admitCalled = true
|
h.admitCalled = true
|
||||||
if h.admit {
|
if h.admit {
|
||||||
return nil
|
return nil
|
||||||
|
@ -39,7 +39,7 @@ func (h *FakeHandler) Admit(a Attributes) (err error) {
|
||||||
return fmt.Errorf("Don't admit")
|
return fmt.Errorf("Don't admit")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *FakeHandler) Validate(a Attributes) (err error) {
|
func (h *FakeHandler) Validate(a Attributes, o ObjectInterfaces) (err error) {
|
||||||
h.validateCalled = true
|
h.validateCalled = true
|
||||||
if h.validate {
|
if h.validate {
|
||||||
return nil
|
return nil
|
||||||
|
@ -119,7 +119,7 @@ func TestAdmitAndValidate(t *testing.T) {
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Logf("testcase = %s", test.name)
|
t.Logf("testcase = %s", test.name)
|
||||||
// call admit and check that validate was not called at all
|
// 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, false, nil))
|
err := test.chain.Admit(NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil), nil)
|
||||||
accepted := (err == nil)
|
accepted := (err == nil)
|
||||||
if accepted != test.accept {
|
if accepted != test.accept {
|
||||||
t.Errorf("unexpected result of admit call: %v", accepted)
|
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
|
// 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, false, nil))
|
err = test.chain.Validate(NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil), nil)
|
||||||
accepted = (err == nil)
|
accepted = (err == nil)
|
||||||
if accepted != test.accept {
|
if accepted != test.accept {
|
||||||
t.Errorf("unexpected result of validate call: %v\n", accepted)
|
t.Errorf("unexpected result of validate call: %v\n", accepted)
|
||||||
|
|
|
@ -85,7 +85,9 @@ type WantExternalKubeInformerFactory struct {
|
||||||
func (self *WantExternalKubeInformerFactory) SetExternalKubeInformerFactory(sf informers.SharedInformerFactory) {
|
func (self *WantExternalKubeInformerFactory) SetExternalKubeInformerFactory(sf informers.SharedInformerFactory) {
|
||||||
self.sf = sf
|
self.sf = sf
|
||||||
}
|
}
|
||||||
func (self *WantExternalKubeInformerFactory) Admit(a admission.Attributes) error { return nil }
|
func (self *WantExternalKubeInformerFactory) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
func (self *WantExternalKubeInformerFactory) Handles(o admission.Operation) bool { return false }
|
func (self *WantExternalKubeInformerFactory) Handles(o admission.Operation) bool { return false }
|
||||||
func (self *WantExternalKubeInformerFactory) ValidateInitialization() error { return nil }
|
func (self *WantExternalKubeInformerFactory) ValidateInitialization() error { return nil }
|
||||||
|
|
||||||
|
@ -98,7 +100,9 @@ type WantExternalKubeClientSet struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *WantExternalKubeClientSet) SetExternalKubeClientSet(cs kubernetes.Interface) { self.cs = cs }
|
func (self *WantExternalKubeClientSet) SetExternalKubeClientSet(cs kubernetes.Interface) { self.cs = cs }
|
||||||
func (self *WantExternalKubeClientSet) Admit(a admission.Attributes) error { return nil }
|
func (self *WantExternalKubeClientSet) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
func (self *WantExternalKubeClientSet) Handles(o admission.Operation) bool { return false }
|
func (self *WantExternalKubeClientSet) Handles(o admission.Operation) bool { return false }
|
||||||
func (self *WantExternalKubeClientSet) ValidateInitialization() error { return nil }
|
func (self *WantExternalKubeClientSet) ValidateInitialization() error { return nil }
|
||||||
|
|
||||||
|
@ -111,7 +115,9 @@ type WantAuthorizerAdmission struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *WantAuthorizerAdmission) SetAuthorizer(a authorizer.Authorizer) { self.auth = a }
|
func (self *WantAuthorizerAdmission) SetAuthorizer(a authorizer.Authorizer) { self.auth = a }
|
||||||
func (self *WantAuthorizerAdmission) Admit(a admission.Attributes) error { return nil }
|
func (self *WantAuthorizerAdmission) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
func (self *WantAuthorizerAdmission) Handles(o admission.Operation) bool { return false }
|
func (self *WantAuthorizerAdmission) Handles(o admission.Operation) bool { return false }
|
||||||
func (self *WantAuthorizerAdmission) ValidateInitialization() error { return nil }
|
func (self *WantAuthorizerAdmission) ValidateInitialization() error { return nil }
|
||||||
|
|
||||||
|
@ -131,7 +137,9 @@ type clientCertWanter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *clientCertWanter) SetClientCert(cert, key []byte) { s.gotCert, s.gotKey = cert, key }
|
func (s *clientCertWanter) SetClientCert(cert, key []byte) { s.gotCert, s.gotKey = cert, key }
|
||||||
func (s *clientCertWanter) Admit(a admission.Attributes) error { return nil }
|
func (s *clientCertWanter) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
func (s *clientCertWanter) Handles(o admission.Operation) bool { return false }
|
func (s *clientCertWanter) Handles(o admission.Operation) bool { return false }
|
||||||
func (s *clientCertWanter) ValidateInitialization() error { return nil }
|
func (s *clientCertWanter) ValidateInitialization() error { return nil }
|
||||||
|
|
||||||
|
@ -141,7 +149,9 @@ type WantSchemeAdmission struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *WantSchemeAdmission) SetScheme(s *runtime.Scheme) { self.scheme = s }
|
func (self *WantSchemeAdmission) SetScheme(s *runtime.Scheme) { self.scheme = s }
|
||||||
func (self *WantSchemeAdmission) Admit(a admission.Attributes) error { return nil }
|
func (self *WantSchemeAdmission) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
func (self *WantSchemeAdmission) Handles(o admission.Operation) bool { return false }
|
func (self *WantSchemeAdmission) Handles(o admission.Operation) bool { return false }
|
||||||
func (self *WantSchemeAdmission) ValidateInitialization() error { return nil }
|
func (self *WantSchemeAdmission) ValidateInitialization() error { return nil }
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,20 @@ type Attributes interface {
|
||||||
AddAnnotation(key, value string) error
|
AddAnnotation(key, value string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ObjectInterfaces is an interface used by AdmissionController to get object interfaces
|
||||||
|
// such as Converter or Defaulter. These interfaces are normally coming from Request Scope
|
||||||
|
// to handle special cases like CRDs.
|
||||||
|
type ObjectInterfaces interface {
|
||||||
|
// GetObjectCreater is the ObjectCreator appropriate for the requested object.
|
||||||
|
GetObjectCreater() runtime.ObjectCreater
|
||||||
|
// GetObjectTyper is the ObjectTyper appropriate for the requested object.
|
||||||
|
GetObjectTyper() runtime.ObjectTyper
|
||||||
|
// GetObjectDefaulter is the ObjectDefaulter appropriate for the requested object.
|
||||||
|
GetObjectDefaulter() runtime.ObjectDefaulter
|
||||||
|
// GetObjectConvertor is the ObjectConvertor appropriate for the requested object.
|
||||||
|
GetObjectConvertor() runtime.ObjectConvertor
|
||||||
|
}
|
||||||
|
|
||||||
// privateAnnotationsGetter is a private interface which allows users to get annotations from Attributes.
|
// privateAnnotationsGetter is a private interface which allows users to get annotations from Attributes.
|
||||||
type privateAnnotationsGetter interface {
|
type privateAnnotationsGetter interface {
|
||||||
getAnnotations() map[string]string
|
getAnnotations() map[string]string
|
||||||
|
@ -84,7 +98,7 @@ type MutationInterface interface {
|
||||||
Interface
|
Interface
|
||||||
|
|
||||||
// Admit makes an admission decision based on the request attributes
|
// Admit makes an admission decision based on the request attributes
|
||||||
Admit(a Attributes) (err error)
|
Admit(a Attributes, o ObjectInterfaces) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidationInterface is an abstract, pluggable interface for Admission Control decisions.
|
// ValidationInterface is an abstract, pluggable interface for Admission Control decisions.
|
||||||
|
@ -92,7 +106,7 @@ type ValidationInterface interface {
|
||||||
Interface
|
Interface
|
||||||
|
|
||||||
// Validate makes an admission decision based on the request attributes. It is NOT allowed to mutate
|
// Validate makes an admission decision based on the request attributes. It is NOT allowed to mutate
|
||||||
Validate(a Attributes) (err error)
|
Validate(a Attributes, o ObjectInterfaces) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Operation is the type of resource operation being checked for admission control
|
// Operation is the type of resource operation being checked for admission control
|
||||||
|
|
|
@ -75,27 +75,27 @@ type pluginHandlerWithMetrics struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Admit performs a mutating admission control check and emit metrics.
|
// Admit performs a mutating admission control check and emit metrics.
|
||||||
func (p pluginHandlerWithMetrics) Admit(a admission.Attributes) error {
|
func (p pluginHandlerWithMetrics) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
mutatingHandler, ok := p.Interface.(admission.MutationInterface)
|
mutatingHandler, ok := p.Interface.(admission.MutationInterface)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
err := mutatingHandler.Admit(a)
|
err := mutatingHandler.Admit(a, o)
|
||||||
p.observer(time.Since(start), err != nil, a, stepAdmit, p.extraLabels...)
|
p.observer(time.Since(start), err != nil, a, stepAdmit, p.extraLabels...)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate performs a non-mutating admission control check and emits metrics.
|
// Validate performs a non-mutating admission control check and emits metrics.
|
||||||
func (p pluginHandlerWithMetrics) Validate(a admission.Attributes) error {
|
func (p pluginHandlerWithMetrics) Validate(a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
validatingHandler, ok := p.Interface.(admission.ValidationInterface)
|
validatingHandler, ok := p.Interface.(admission.ValidationInterface)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
err := validatingHandler.Validate(a)
|
err := validatingHandler.Validate(a, o)
|
||||||
p.observer(time.Since(start), err != nil, a, stepValidate, p.extraLabels...)
|
p.observer(time.Since(start), err != nil, a, stepValidate, p.extraLabels...)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,8 @@ var (
|
||||||
func TestObserveAdmissionStep(t *testing.T) {
|
func TestObserveAdmissionStep(t *testing.T) {
|
||||||
Metrics.reset()
|
Metrics.reset()
|
||||||
handler := WithStepMetrics(&mutatingAndValidatingFakeHandler{admission.NewHandler(admission.Create), true, true})
|
handler := WithStepMetrics(&mutatingAndValidatingFakeHandler{admission.NewHandler(admission.Create), true, true})
|
||||||
handler.(admission.MutationInterface).Admit(attr)
|
handler.(admission.MutationInterface).Admit(attr, nil)
|
||||||
handler.(admission.ValidationInterface).Validate(attr)
|
handler.(admission.ValidationInterface).Validate(attr, nil)
|
||||||
wantLabels := map[string]string{
|
wantLabels := map[string]string{
|
||||||
"operation": string(admission.Create),
|
"operation": string(admission.Create),
|
||||||
"type": "admit",
|
"type": "admit",
|
||||||
|
@ -52,8 +52,8 @@ func TestObserveAdmissionStep(t *testing.T) {
|
||||||
func TestObserveAdmissionController(t *testing.T) {
|
func TestObserveAdmissionController(t *testing.T) {
|
||||||
Metrics.reset()
|
Metrics.reset()
|
||||||
handler := WithControllerMetrics(&mutatingAndValidatingFakeHandler{admission.NewHandler(admission.Create), true, true}, "a")
|
handler := WithControllerMetrics(&mutatingAndValidatingFakeHandler{admission.NewHandler(admission.Create), true, true}, "a")
|
||||||
handler.(admission.MutationInterface).Admit(attr)
|
handler.(admission.MutationInterface).Admit(attr, nil)
|
||||||
handler.(admission.ValidationInterface).Validate(attr)
|
handler.(admission.ValidationInterface).Validate(attr, nil)
|
||||||
wantLabels := map[string]string{
|
wantLabels := map[string]string{
|
||||||
"name": "a",
|
"name": "a",
|
||||||
"operation": string(admission.Create),
|
"operation": string(admission.Create),
|
||||||
|
@ -144,7 +144,7 @@ func TestWithMetrics(t *testing.T) {
|
||||||
h := WithMetrics(test.handler, Metrics.ObserveAdmissionController, test.name)
|
h := WithMetrics(test.handler, Metrics.ObserveAdmissionController, test.name)
|
||||||
|
|
||||||
// test mutation
|
// test mutation
|
||||||
err := h.(admission.MutationInterface).Admit(admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil))
|
err := h.(admission.MutationInterface).Admit(admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil), nil)
|
||||||
if test.admit && err != nil {
|
if test.admit && err != nil {
|
||||||
t.Errorf("expected admit to succeed, but failed: %v", err)
|
t.Errorf("expected admit to succeed, but failed: %v", err)
|
||||||
continue
|
continue
|
||||||
|
@ -169,7 +169,7 @@ func TestWithMetrics(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// test validation
|
// test validation
|
||||||
err = h.(admission.ValidationInterface).Validate(admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil))
|
err = h.(admission.ValidationInterface).Validate(admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil), nil)
|
||||||
if test.validate && err != nil {
|
if test.validate && err != nil {
|
||||||
t.Errorf("expected admit to succeed, but failed: %v", err)
|
t.Errorf("expected admit to succeed, but failed: %v", err)
|
||||||
continue
|
continue
|
||||||
|
@ -196,14 +196,14 @@ type mutatingAndValidatingFakeHandler struct {
|
||||||
validate bool
|
validate bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *mutatingAndValidatingFakeHandler) Admit(a admission.Attributes) (err error) {
|
func (h *mutatingAndValidatingFakeHandler) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
|
||||||
if h.admit {
|
if h.admit {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return fmt.Errorf("don't admit")
|
return fmt.Errorf("don't admit")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *mutatingAndValidatingFakeHandler) Validate(a admission.Attributes) (err error) {
|
func (h *mutatingAndValidatingFakeHandler) Validate(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
|
||||||
if h.validate {
|
if h.validate {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -215,7 +215,7 @@ type validatingFakeHandler struct {
|
||||||
validate bool
|
validate bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *validatingFakeHandler) Validate(a admission.Attributes) (err error) {
|
func (h *validatingFakeHandler) Validate(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
|
||||||
if h.validate {
|
if h.validate {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,7 @@ type mutatingFakeHandler struct {
|
||||||
admit bool
|
admit bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *mutatingFakeHandler) Admit(a admission.Attributes) (err error) {
|
func (h *mutatingFakeHandler) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
|
||||||
if h.admit {
|
if h.admit {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,39 +17,25 @@ limitations under the License.
|
||||||
package generic
|
package generic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apiserver/pkg/admission"
|
||||||
)
|
)
|
||||||
|
|
||||||
// convertor converts objects to the desired version.
|
|
||||||
type convertor struct {
|
|
||||||
Scheme *runtime.Scheme
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvertToGVK converts object to the desired gvk.
|
// ConvertToGVK converts object to the desired gvk.
|
||||||
func (c *convertor) ConvertToGVK(obj runtime.Object, gvk schema.GroupVersionKind) (runtime.Object, error) {
|
func ConvertToGVK(obj runtime.Object, gvk schema.GroupVersionKind, o admission.ObjectInterfaces) (runtime.Object, error) {
|
||||||
// Unlike other resources, custom resources do not have internal version, so
|
// Unlike other resources, custom resources do not have internal version, so
|
||||||
// if obj is a custom resource, it should not need conversion.
|
// if obj is a custom resource, it should not need conversion.
|
||||||
if obj.GetObjectKind().GroupVersionKind() == gvk {
|
if obj.GetObjectKind().GroupVersionKind() == gvk {
|
||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
out, err := c.Scheme.New(gvk)
|
out, err := o.GetObjectCreater().New(gvk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = c.Scheme.Convert(obj, out, nil)
|
err = o.GetObjectConvertor().Convert(obj, out, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate checks if the conversion has a scheme.
|
|
||||||
func (c *convertor) Validate() error {
|
|
||||||
if c.Scheme == nil {
|
|
||||||
return fmt.Errorf("the convertor requires a scheme")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apiserver/pkg/admission"
|
||||||
"k8s.io/apiserver/pkg/apis/example"
|
"k8s.io/apiserver/pkg/apis/example"
|
||||||
examplev1 "k8s.io/apiserver/pkg/apis/example/v1"
|
examplev1 "k8s.io/apiserver/pkg/apis/example/v1"
|
||||||
example2v1 "k8s.io/apiserver/pkg/apis/example2/v1"
|
example2v1 "k8s.io/apiserver/pkg/apis/example2/v1"
|
||||||
|
@ -41,7 +42,7 @@ func initiateScheme(t *testing.T) *runtime.Scheme {
|
||||||
|
|
||||||
func TestConvertToGVK(t *testing.T) {
|
func TestConvertToGVK(t *testing.T) {
|
||||||
scheme := initiateScheme(t)
|
scheme := initiateScheme(t)
|
||||||
c := convertor{Scheme: scheme}
|
o := &admission.SchemeBasedObjectInterfaces{scheme}
|
||||||
table := map[string]struct {
|
table := map[string]struct {
|
||||||
obj runtime.Object
|
obj runtime.Object
|
||||||
gvk schema.GroupVersionKind
|
gvk schema.GroupVersionKind
|
||||||
|
@ -122,7 +123,7 @@ func TestConvertToGVK(t *testing.T) {
|
||||||
|
|
||||||
for name, test := range table {
|
for name, test := range table {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
actual, err := c.ConvertToGVK(test.obj, test.gvk)
|
actual, err := ConvertToGVK(test.obj, test.gvk, o)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,6 @@ type Webhook struct {
|
||||||
|
|
||||||
hookSource Source
|
hookSource Source
|
||||||
clientManager *webhook.ClientManager
|
clientManager *webhook.ClientManager
|
||||||
convertor *convertor
|
|
||||||
namespaceMatcher *namespace.Matcher
|
namespaceMatcher *namespace.Matcher
|
||||||
dispatcher Dispatcher
|
dispatcher Dispatcher
|
||||||
}
|
}
|
||||||
|
@ -79,7 +78,6 @@ func NewWebhook(handler *admission.Handler, configFile io.Reader, sourceFactory
|
||||||
Handler: handler,
|
Handler: handler,
|
||||||
sourceFactory: sourceFactory,
|
sourceFactory: sourceFactory,
|
||||||
clientManager: &cm,
|
clientManager: &cm,
|
||||||
convertor: &convertor{},
|
|
||||||
namespaceMatcher: &namespace.Matcher{},
|
namespaceMatcher: &namespace.Matcher{},
|
||||||
dispatcher: dispatcherFactory(&cm),
|
dispatcher: dispatcherFactory(&cm),
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -100,9 +98,6 @@ func (a *Webhook) SetServiceResolver(sr webhook.ServiceResolver) {
|
||||||
|
|
||||||
// SetScheme sets a serializer(NegotiatedSerializer) which is derived from the scheme
|
// SetScheme sets a serializer(NegotiatedSerializer) which is derived from the scheme
|
||||||
func (a *Webhook) SetScheme(scheme *runtime.Scheme) {
|
func (a *Webhook) SetScheme(scheme *runtime.Scheme) {
|
||||||
if scheme != nil {
|
|
||||||
a.convertor.Scheme = scheme
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetExternalKubeClientSet implements the WantsExternalKubeInformerFactory interface.
|
// SetExternalKubeClientSet implements the WantsExternalKubeInformerFactory interface.
|
||||||
|
@ -132,9 +127,6 @@ func (a *Webhook) ValidateInitialization() error {
|
||||||
if err := a.clientManager.Validate(); err != nil {
|
if err := a.clientManager.Validate(); err != nil {
|
||||||
return fmt.Errorf("clientManager is not properly setup: %v", err)
|
return fmt.Errorf("clientManager is not properly setup: %v", err)
|
||||||
}
|
}
|
||||||
if err := a.convertor.Validate(); err != nil {
|
|
||||||
return fmt.Errorf("convertor is not properly setup: %v", err)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +148,7 @@ func (a *Webhook) ShouldCallHook(h *v1beta1.Webhook, attr admission.Attributes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispatch is called by the downstream Validate or Admit methods.
|
// Dispatch is called by the downstream Validate or Admit methods.
|
||||||
func (a *Webhook) Dispatch(attr admission.Attributes) error {
|
func (a *Webhook) Dispatch(attr admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
if rules.IsWebhookConfigurationResource(attr) {
|
if rules.IsWebhookConfigurationResource(attr) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -188,14 +180,14 @@ func (a *Webhook) Dispatch(attr admission.Attributes) error {
|
||||||
Attributes: attr,
|
Attributes: attr,
|
||||||
}
|
}
|
||||||
if oldObj := attr.GetOldObject(); oldObj != nil {
|
if oldObj := attr.GetOldObject(); oldObj != nil {
|
||||||
out, err := a.convertor.ConvertToGVK(oldObj, attr.GetKind())
|
out, err := ConvertToGVK(oldObj, attr.GetKind(), o)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apierrors.NewInternalError(err)
|
return apierrors.NewInternalError(err)
|
||||||
}
|
}
|
||||||
versionedAttr.VersionedOldObject = out
|
versionedAttr.VersionedOldObject = out
|
||||||
}
|
}
|
||||||
if obj := attr.GetObject(); obj != nil {
|
if obj := attr.GetObject(); obj != nil {
|
||||||
out, err := a.convertor.ConvertToGVK(obj, attr.GetKind())
|
out, err := ConvertToGVK(obj, attr.GetKind(), o)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apierrors.NewInternalError(err)
|
return apierrors.NewInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,6 @@ func (a *Plugin) ValidateInitialization() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Admit makes an admission decision based on the request attributes.
|
// Admit makes an admission decision based on the request attributes.
|
||||||
func (a *Plugin) Admit(attr admission.Attributes) error {
|
func (a *Plugin) Admit(attr admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
return a.Webhook.Dispatch(attr)
|
return a.Webhook.Dispatch(attr, o)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,23 +23,15 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"k8s.io/api/admission/v1beta1"
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
webhooktesting "k8s.io/apiserver/pkg/admission/plugin/webhook/testing"
|
webhooktesting "k8s.io/apiserver/pkg/admission/plugin/webhook/testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestAdmit tests that MutatingWebhook#Admit works as expected
|
// TestAdmit tests that MutatingWebhook#Admit works as expected
|
||||||
func TestAdmit(t *testing.T) {
|
func TestAdmit(t *testing.T) {
|
||||||
scheme := runtime.NewScheme()
|
|
||||||
require.NoError(t, v1beta1.AddToScheme(scheme))
|
|
||||||
require.NoError(t, corev1.AddToScheme(scheme))
|
|
||||||
|
|
||||||
testServer := webhooktesting.NewTestServer(t)
|
testServer := webhooktesting.NewTestServer(t)
|
||||||
testServer.StartTLS()
|
testServer.StartTLS()
|
||||||
defer testServer.Close()
|
defer testServer.Close()
|
||||||
|
@ -48,6 +40,8 @@ func TestAdmit(t *testing.T) {
|
||||||
t.Fatalf("this should never happen? %v", err)
|
t.Fatalf("this should never happen? %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
objectInterfaces := webhooktesting.NewObjectInterfacesForTest()
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
stopCh := make(chan struct{})
|
||||||
defer close(stopCh)
|
defer close(stopCh)
|
||||||
|
|
||||||
|
@ -66,7 +60,6 @@ func TestAdmit(t *testing.T) {
|
||||||
|
|
||||||
wh.SetAuthenticationInfoResolverWrapper(webhooktesting.Wrapper(webhooktesting.NewAuthenticationInfoResolver(new(int32))))
|
wh.SetAuthenticationInfoResolverWrapper(webhooktesting.Wrapper(webhooktesting.NewAuthenticationInfoResolver(new(int32))))
|
||||||
wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL))
|
wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL))
|
||||||
wh.SetScheme(scheme)
|
|
||||||
wh.SetExternalKubeClientSet(client)
|
wh.SetExternalKubeClientSet(client)
|
||||||
wh.SetExternalKubeInformerFactory(informer)
|
wh.SetExternalKubeInformerFactory(informer)
|
||||||
|
|
||||||
|
@ -85,7 +78,7 @@ func TestAdmit(t *testing.T) {
|
||||||
attr = webhooktesting.NewAttribute(ns, tt.AdditionalLabels, tt.IsDryRun)
|
attr = webhooktesting.NewAttribute(ns, tt.AdditionalLabels, tt.IsDryRun)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = wh.Admit(attr)
|
err = wh.Admit(attr, objectInterfaces)
|
||||||
if tt.ExpectAllow != (err == nil) {
|
if tt.ExpectAllow != (err == nil) {
|
||||||
t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err)
|
t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err)
|
||||||
}
|
}
|
||||||
|
@ -118,10 +111,6 @@ func TestAdmit(t *testing.T) {
|
||||||
|
|
||||||
// TestAdmitCachedClient tests that MutatingWebhook#Admit should cache restClient
|
// TestAdmitCachedClient tests that MutatingWebhook#Admit should cache restClient
|
||||||
func TestAdmitCachedClient(t *testing.T) {
|
func TestAdmitCachedClient(t *testing.T) {
|
||||||
scheme := runtime.NewScheme()
|
|
||||||
require.NoError(t, v1beta1.AddToScheme(scheme))
|
|
||||||
require.NoError(t, corev1.AddToScheme(scheme))
|
|
||||||
|
|
||||||
testServer := webhooktesting.NewTestServer(t)
|
testServer := webhooktesting.NewTestServer(t)
|
||||||
testServer.StartTLS()
|
testServer.StartTLS()
|
||||||
defer testServer.Close()
|
defer testServer.Close()
|
||||||
|
@ -130,6 +119,8 @@ func TestAdmitCachedClient(t *testing.T) {
|
||||||
t.Fatalf("this should never happen? %v", err)
|
t.Fatalf("this should never happen? %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
objectInterfaces := webhooktesting.NewObjectInterfacesForTest()
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
stopCh := make(chan struct{})
|
||||||
defer close(stopCh)
|
defer close(stopCh)
|
||||||
|
|
||||||
|
@ -138,7 +129,6 @@ func TestAdmitCachedClient(t *testing.T) {
|
||||||
t.Fatalf("Failed to create mutating webhook: %v", err)
|
t.Fatalf("Failed to create mutating webhook: %v", err)
|
||||||
}
|
}
|
||||||
wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL))
|
wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL))
|
||||||
wh.SetScheme(scheme)
|
|
||||||
|
|
||||||
for _, tt := range webhooktesting.NewCachedClientTestcases(serverURL) {
|
for _, tt := range webhooktesting.NewCachedClientTestcases(serverURL) {
|
||||||
ns := "webhook-test"
|
ns := "webhook-test"
|
||||||
|
@ -158,7 +148,7 @@ func TestAdmitCachedClient(t *testing.T) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = wh.Admit(webhooktesting.NewAttribute(ns, nil, false))
|
err = wh.Admit(webhooktesting.NewAttribute(ns, nil, false), objectInterfaces)
|
||||||
if tt.ExpectAllow != (err == nil) {
|
if tt.ExpectAllow != (err == nil) {
|
||||||
t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err)
|
t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -649,3 +649,10 @@ func newMatchEverythingRules() []registrationv1beta1.RuleWithOperations {
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewObjectInterfacesForTest returns an ObjectInterfaces appropriate for test cases in this file.
|
||||||
|
func NewObjectInterfacesForTest() admission.ObjectInterfaces {
|
||||||
|
scheme := runtime.NewScheme()
|
||||||
|
corev1.AddToScheme(scheme)
|
||||||
|
return &admission.SchemeBasedObjectInterfaces{scheme}
|
||||||
|
}
|
||||||
|
|
|
@ -59,6 +59,6 @@ func NewValidatingAdmissionWebhook(configFile io.Reader) (*Plugin, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate makes an admission decision based on the request attributes.
|
// Validate makes an admission decision based on the request attributes.
|
||||||
func (a *Plugin) Validate(attr admission.Attributes) error {
|
func (a *Plugin) Validate(attr admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
return a.Webhook.Dispatch(attr)
|
return a.Webhook.Dispatch(attr, o)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,25 +22,19 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"k8s.io/api/admission/v1beta1"
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
webhooktesting "k8s.io/apiserver/pkg/admission/plugin/webhook/testing"
|
webhooktesting "k8s.io/apiserver/pkg/admission/plugin/webhook/testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestValidate tests that ValidatingWebhook#Validate works as expected
|
// TestValidate tests that ValidatingWebhook#Validate works as expected
|
||||||
func TestValidate(t *testing.T) {
|
func TestValidate(t *testing.T) {
|
||||||
scheme := runtime.NewScheme()
|
|
||||||
require.NoError(t, v1beta1.AddToScheme(scheme))
|
|
||||||
require.NoError(t, corev1.AddToScheme(scheme))
|
|
||||||
|
|
||||||
testServer := webhooktesting.NewTestServer(t)
|
testServer := webhooktesting.NewTestServer(t)
|
||||||
testServer.StartTLS()
|
testServer.StartTLS()
|
||||||
defer testServer.Close()
|
defer testServer.Close()
|
||||||
|
|
||||||
|
objectInterfaces := webhooktesting.NewObjectInterfacesForTest()
|
||||||
|
|
||||||
serverURL, err := url.ParseRequestURI(testServer.URL)
|
serverURL, err := url.ParseRequestURI(testServer.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("this should never happen? %v", err)
|
t.Fatalf("this should never happen? %v", err)
|
||||||
|
@ -61,7 +55,6 @@ func TestValidate(t *testing.T) {
|
||||||
|
|
||||||
wh.SetAuthenticationInfoResolverWrapper(webhooktesting.Wrapper(webhooktesting.NewAuthenticationInfoResolver(new(int32))))
|
wh.SetAuthenticationInfoResolverWrapper(webhooktesting.Wrapper(webhooktesting.NewAuthenticationInfoResolver(new(int32))))
|
||||||
wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL))
|
wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL))
|
||||||
wh.SetScheme(scheme)
|
|
||||||
wh.SetExternalKubeClientSet(client)
|
wh.SetExternalKubeClientSet(client)
|
||||||
wh.SetExternalKubeInformerFactory(informer)
|
wh.SetExternalKubeInformerFactory(informer)
|
||||||
|
|
||||||
|
@ -74,7 +67,7 @@ func TestValidate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
attr := webhooktesting.NewAttribute(ns, nil, tt.IsDryRun)
|
attr := webhooktesting.NewAttribute(ns, nil, tt.IsDryRun)
|
||||||
err = wh.Validate(attr)
|
err = wh.Validate(attr, objectInterfaces)
|
||||||
if tt.ExpectAllow != (err == nil) {
|
if tt.ExpectAllow != (err == nil) {
|
||||||
t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err)
|
t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err)
|
||||||
}
|
}
|
||||||
|
@ -102,10 +95,6 @@ func TestValidate(t *testing.T) {
|
||||||
|
|
||||||
// TestValidateCachedClient tests that ValidatingWebhook#Validate should cache restClient
|
// TestValidateCachedClient tests that ValidatingWebhook#Validate should cache restClient
|
||||||
func TestValidateCachedClient(t *testing.T) {
|
func TestValidateCachedClient(t *testing.T) {
|
||||||
scheme := runtime.NewScheme()
|
|
||||||
require.NoError(t, v1beta1.AddToScheme(scheme))
|
|
||||||
require.NoError(t, corev1.AddToScheme(scheme))
|
|
||||||
|
|
||||||
testServer := webhooktesting.NewTestServer(t)
|
testServer := webhooktesting.NewTestServer(t)
|
||||||
testServer.StartTLS()
|
testServer.StartTLS()
|
||||||
defer testServer.Close()
|
defer testServer.Close()
|
||||||
|
@ -114,6 +103,8 @@ func TestValidateCachedClient(t *testing.T) {
|
||||||
t.Fatalf("this should never happen? %v", err)
|
t.Fatalf("this should never happen? %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
objectInterfaces := webhooktesting.NewObjectInterfacesForTest()
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
stopCh := make(chan struct{})
|
||||||
defer close(stopCh)
|
defer close(stopCh)
|
||||||
|
|
||||||
|
@ -122,7 +113,6 @@ func TestValidateCachedClient(t *testing.T) {
|
||||||
t.Fatalf("Failed to create validating webhook: %v", err)
|
t.Fatalf("Failed to create validating webhook: %v", err)
|
||||||
}
|
}
|
||||||
wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL))
|
wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL))
|
||||||
wh.SetScheme(scheme)
|
|
||||||
|
|
||||||
for _, tt := range webhooktesting.NewCachedClientTestcases(serverURL) {
|
for _, tt := range webhooktesting.NewCachedClientTestcases(serverURL) {
|
||||||
ns := "webhook-test"
|
ns := "webhook-test"
|
||||||
|
@ -142,7 +132,7 @@ func TestValidateCachedClient(t *testing.T) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = wh.Validate(webhooktesting.NewAttribute(ns, nil, false))
|
err = wh.Validate(webhooktesting.NewAttribute(ns, nil, false), objectInterfaces)
|
||||||
if tt.ExpectAllow != (err == nil) {
|
if tt.ExpectAllow != (err == nil) {
|
||||||
t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err)
|
t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package admission
|
||||||
|
|
||||||
|
import "k8s.io/apimachinery/pkg/runtime"
|
||||||
|
|
||||||
|
type SchemeBasedObjectInterfaces struct {
|
||||||
|
Scheme *runtime.Scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SchemeBasedObjectInterfaces) GetObjectCreater() runtime.ObjectCreater { return r.Scheme }
|
||||||
|
func (r *SchemeBasedObjectInterfaces) GetObjectTyper() runtime.ObjectTyper { return r.Scheme }
|
||||||
|
func (r *SchemeBasedObjectInterfaces) GetObjectDefaulter() runtime.ObjectDefaulter { return r.Scheme }
|
||||||
|
func (r *SchemeBasedObjectInterfaces) GetObjectConvertor() runtime.ObjectConvertor { return r.Scheme }
|
|
@ -76,7 +76,7 @@ import (
|
||||||
|
|
||||||
type alwaysMutatingDeny struct{}
|
type alwaysMutatingDeny struct{}
|
||||||
|
|
||||||
func (alwaysMutatingDeny) Admit(a admission.Attributes) (err error) {
|
func (alwaysMutatingDeny) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
|
||||||
return admission.NewForbidden(a, errors.New("Mutating admission control is denying all modifications"))
|
return admission.NewForbidden(a, errors.New("Mutating admission control is denying all modifications"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ func (alwaysMutatingDeny) Handles(operation admission.Operation) bool {
|
||||||
|
|
||||||
type alwaysValidatingDeny struct{}
|
type alwaysValidatingDeny struct{}
|
||||||
|
|
||||||
func (alwaysValidatingDeny) Validate(a admission.Attributes) (err error) {
|
func (alwaysValidatingDeny) Validate(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
|
||||||
return admission.NewForbidden(a, errors.New("Validating admission control is denying all modifications"))
|
return admission.NewForbidden(a, errors.New("Validating admission control is denying all modifications"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ func createHandler(r rest.NamedCreater, scope RequestScope, admit admission.Inte
|
||||||
userInfo, _ := request.UserFrom(ctx)
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
admissionAttributes := admission.NewAttributesRecord(obj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), 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) {
|
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && mutatingAdmission.Handles(admission.Create) {
|
||||||
err = mutatingAdmission.Admit(admissionAttributes)
|
err = mutatingAdmission.Admit(admissionAttributes, &scope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scope.err(err, w, req)
|
scope.err(err, w, req)
|
||||||
return
|
return
|
||||||
|
@ -154,7 +154,7 @@ func createHandler(r rest.NamedCreater, scope RequestScope, admit admission.Inte
|
||||||
ctx,
|
ctx,
|
||||||
name,
|
name,
|
||||||
obj,
|
obj,
|
||||||
rest.AdmissionToValidateObjectFunc(admit, admissionAttributes),
|
rest.AdmissionToValidateObjectFunc(admit, admissionAttributes, &scope),
|
||||||
options,
|
options,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -119,13 +119,13 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestSco
|
||||||
userInfo, _ := request.UserFrom(ctx)
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
attrs := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, dryrun.IsDryRun(options.DryRun), 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 mutatingAdmission, ok := admit.(admission.MutationInterface); ok {
|
||||||
if err := mutatingAdmission.Admit(attrs); err != nil {
|
if err := mutatingAdmission.Admit(attrs, &scope); err != nil {
|
||||||
scope.err(err, w, req)
|
scope.err(err, w, req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if validatingAdmission, ok := admit.(admission.ValidationInterface); ok {
|
if validatingAdmission, ok := admit.(admission.ValidationInterface); ok {
|
||||||
if err := validatingAdmission.Validate(attrs); err != nil {
|
if err := validatingAdmission.Validate(attrs, &scope); err != nil {
|
||||||
scope.err(err, w, req)
|
scope.err(err, w, req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -269,7 +269,7 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestSco
|
||||||
userInfo, _ := request.UserFrom(ctx)
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
attrs := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, "", scope.Resource, scope.Subresource, admission.Delete, dryrun.IsDryRun(options.DryRun), userInfo)
|
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 {
|
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok {
|
||||||
err = mutatingAdmission.Admit(attrs)
|
err = mutatingAdmission.Admit(attrs, &scope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scope.err(err, w, req)
|
scope.err(err, w, req)
|
||||||
return
|
return
|
||||||
|
@ -277,7 +277,7 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestSco
|
||||||
}
|
}
|
||||||
|
|
||||||
if validatingAdmission, ok := admit.(admission.ValidationInterface); ok {
|
if validatingAdmission, ok := admit.(admission.ValidationInterface); ok {
|
||||||
err = validatingAdmission.Validate(attrs)
|
err = validatingAdmission.Validate(attrs, &scope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scope.err(err, w, req)
|
scope.err(err, w, req)
|
||||||
return
|
return
|
||||||
|
|
|
@ -191,10 +191,12 @@ func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface
|
||||||
subresource: scope.Subresource,
|
subresource: scope.Subresource,
|
||||||
dryRun: dryrun.IsDryRun(options.DryRun),
|
dryRun: dryrun.IsDryRun(options.DryRun),
|
||||||
|
|
||||||
|
objectInterfaces: &scope,
|
||||||
|
|
||||||
hubGroupVersion: scope.HubGroupVersion,
|
hubGroupVersion: scope.HubGroupVersion,
|
||||||
|
|
||||||
createValidation: withAuthorization(rest.AdmissionToValidateObjectFunc(admit, staticCreateAttributes), scope.Authorizer, createAuthorizerAttributes),
|
createValidation: withAuthorization(rest.AdmissionToValidateObjectFunc(admit, staticCreateAttributes, &scope), scope.Authorizer, createAuthorizerAttributes),
|
||||||
updateValidation: rest.AdmissionToValidateObjectUpdateFunc(admit, staticUpdateAttributes),
|
updateValidation: rest.AdmissionToValidateObjectUpdateFunc(admit, staticUpdateAttributes, &scope),
|
||||||
admissionCheck: mutatingAdmission,
|
admissionCheck: mutatingAdmission,
|
||||||
|
|
||||||
codec: codec,
|
codec: codec,
|
||||||
|
@ -257,6 +259,8 @@ type patcher struct {
|
||||||
subresource string
|
subresource string
|
||||||
dryRun bool
|
dryRun bool
|
||||||
|
|
||||||
|
objectInterfaces admission.ObjectInterfaces
|
||||||
|
|
||||||
hubGroupVersion schema.GroupVersion
|
hubGroupVersion schema.GroupVersion
|
||||||
|
|
||||||
// Validation functions
|
// Validation functions
|
||||||
|
@ -507,7 +511,7 @@ func (p *patcher) applyAdmission(ctx context.Context, patchedObject runtime.Obje
|
||||||
}
|
}
|
||||||
if p.admissionCheck != nil && p.admissionCheck.Handles(operation) {
|
if p.admissionCheck != nil && p.admissionCheck.Handles(operation) {
|
||||||
attributes := p.admissionAttributes(ctx, patchedObject, currentObject, operation)
|
attributes := p.admissionAttributes(ctx, patchedObject, currentObject, operation)
|
||||||
return patchedObject, p.admissionCheck.Admit(attributes)
|
return patchedObject, p.admissionCheck.Admit(attributes, p.objectInterfaces)
|
||||||
}
|
}
|
||||||
return patchedObject, nil
|
return patchedObject, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,13 @@ func (scope *RequestScope) AllowsStreamSchema(s string) bool {
|
||||||
return s == "watch"
|
return s == "watch"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ admission.ObjectInterfaces = &RequestScope{}
|
||||||
|
|
||||||
|
func (r *RequestScope) GetObjectCreater() runtime.ObjectCreater { return r.Creater }
|
||||||
|
func (r *RequestScope) GetObjectTyper() runtime.ObjectTyper { return r.Typer }
|
||||||
|
func (r *RequestScope) GetObjectDefaulter() runtime.ObjectDefaulter { return r.Defaulter }
|
||||||
|
func (r *RequestScope) GetObjectConvertor() runtime.ObjectConvertor { return r.Convertor }
|
||||||
|
|
||||||
// ConnectResource returns a function that handles a connect request on a rest.Storage object.
|
// ConnectResource returns a function that handles a connect request on a rest.Storage object.
|
||||||
func ConnectResource(connecter rest.Connecter, scope RequestScope, admit admission.Interface, restPath string, isSubresource bool) http.HandlerFunc {
|
func ConnectResource(connecter rest.Connecter, scope RequestScope, admit admission.Interface, restPath string, isSubresource bool) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, req *http.Request) {
|
return func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
@ -131,14 +138,14 @@ func ConnectResource(connecter rest.Connecter, scope RequestScope, admit admissi
|
||||||
userInfo, _ := request.UserFrom(ctx)
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
// TODO: remove the mutating admission here as soon as we have ported all plugin that handle CONNECT
|
// TODO: remove the mutating admission here as soon as we have ported all plugin that handle CONNECT
|
||||||
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok {
|
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok {
|
||||||
err = mutatingAdmission.Admit(admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, false, userInfo))
|
err = mutatingAdmission.Admit(admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, false, userInfo), &scope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scope.err(err, w, req)
|
scope.err(err, w, req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if validatingAdmission, ok := admit.(admission.ValidationInterface); ok {
|
if validatingAdmission, ok := admit.(admission.ValidationInterface); ok {
|
||||||
err = validatingAdmission.Validate(admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, false, userInfo))
|
err = validatingAdmission.Validate(admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, false, userInfo), &scope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scope.err(err, w, req)
|
scope.err(err, w, req)
|
||||||
return
|
return
|
||||||
|
|
|
@ -365,6 +365,7 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
||||||
creater := runtime.ObjectCreater(scheme)
|
creater := runtime.ObjectCreater(scheme)
|
||||||
defaulter := runtime.ObjectDefaulter(scheme)
|
defaulter := runtime.ObjectDefaulter(scheme)
|
||||||
convertor := runtime.UnsafeObjectConvertor(scheme)
|
convertor := runtime.UnsafeObjectConvertor(scheme)
|
||||||
|
objectInterfaces := &admission.SchemeBasedObjectInterfaces{scheme}
|
||||||
kind := examplev1.SchemeGroupVersion.WithKind("Pod")
|
kind := examplev1.SchemeGroupVersion.WithKind("Pod")
|
||||||
resource := examplev1.SchemeGroupVersion.WithResource("pods")
|
resource := examplev1.SchemeGroupVersion.WithResource("pods")
|
||||||
schemaReferenceObj := &examplev1.Pod{}
|
schemaReferenceObj := &examplev1.Pod{}
|
||||||
|
@ -441,6 +442,8 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
||||||
kind: kind,
|
kind: kind,
|
||||||
resource: resource,
|
resource: resource,
|
||||||
|
|
||||||
|
objectInterfaces: objectInterfaces,
|
||||||
|
|
||||||
hubGroupVersion: hubVersion,
|
hubGroupVersion: hubVersion,
|
||||||
|
|
||||||
createValidation: rest.ValidateAllObjectFunc,
|
createValidation: rest.ValidateAllObjectFunc,
|
||||||
|
@ -944,6 +947,6 @@ func (f mutateObjectUpdateFunc) Handles(operation admission.Operation) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f mutateObjectUpdateFunc) Admit(a admission.Attributes) (err error) {
|
func (f mutateObjectUpdateFunc) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
|
||||||
return f(a.GetObject(), a.GetOldObject())
|
return f(a.GetObject(), a.GetOldObject())
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,11 +138,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())
|
return nil, fmt.Errorf("unexpected error when extracting UID from oldObj: %v", err.Error())
|
||||||
} else if !isNotZeroObject {
|
} else if !isNotZeroObject {
|
||||||
if mutatingAdmission.Handles(admission.Create) {
|
if mutatingAdmission.Handles(admission.Create) {
|
||||||
return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo))
|
return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo), &scope)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if mutatingAdmission.Handles(admission.Update) {
|
if mutatingAdmission.Handles(admission.Update) {
|
||||||
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, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, dryrun.IsDryRun(options.DryRun), userInfo), &scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newObj, nil
|
return newObj, nil
|
||||||
|
@ -172,11 +172,11 @@ func UpdateResource(r rest.Updater, scope RequestScope, admit admission.Interfac
|
||||||
rest.DefaultUpdatedObjectInfo(obj, transformers...),
|
rest.DefaultUpdatedObjectInfo(obj, transformers...),
|
||||||
withAuthorization(rest.AdmissionToValidateObjectFunc(
|
withAuthorization(rest.AdmissionToValidateObjectFunc(
|
||||||
admit,
|
admit,
|
||||||
admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo)),
|
admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo), &scope),
|
||||||
scope.Authorizer, createAuthorizerAttributes),
|
scope.Authorizer, createAuthorizerAttributes),
|
||||||
rest.AdmissionToValidateObjectUpdateFunc(
|
rest.AdmissionToValidateObjectUpdateFunc(
|
||||||
admit,
|
admit,
|
||||||
admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, dryrun.IsDryRun(options.DryRun), userInfo)),
|
admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, dryrun.IsDryRun(options.DryRun), userInfo), &scope),
|
||||||
false,
|
false,
|
||||||
options,
|
options,
|
||||||
)
|
)
|
||||||
|
|
|
@ -160,7 +160,7 @@ type NamespaceScopedStrategy interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdmissionToValidateObjectFunc converts validating admission to a rest validate object func
|
// AdmissionToValidateObjectFunc converts validating admission to a rest validate object func
|
||||||
func AdmissionToValidateObjectFunc(admit admission.Interface, staticAttributes admission.Attributes) ValidateObjectFunc {
|
func AdmissionToValidateObjectFunc(admit admission.Interface, staticAttributes admission.Attributes, o admission.ObjectInterfaces) ValidateObjectFunc {
|
||||||
validatingAdmission, ok := admit.(admission.ValidationInterface)
|
validatingAdmission, ok := admit.(admission.ValidationInterface)
|
||||||
if !ok {
|
if !ok {
|
||||||
return func(obj runtime.Object) error { return nil }
|
return func(obj runtime.Object) error { return nil }
|
||||||
|
@ -181,6 +181,6 @@ func AdmissionToValidateObjectFunc(admit admission.Interface, staticAttributes a
|
||||||
if !validatingAdmission.Handles(finalAttributes.GetOperation()) {
|
if !validatingAdmission.Handles(finalAttributes.GetOperation()) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return validatingAdmission.Validate(finalAttributes)
|
return validatingAdmission.Validate(finalAttributes, o)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -256,7 +256,7 @@ func (i *wrappedUpdatedObjectInfo) UpdatedObject(ctx context.Context, oldObj run
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdmissionToValidateObjectUpdateFunc converts validating admission to a rest validate object update func
|
// AdmissionToValidateObjectUpdateFunc converts validating admission to a rest validate object update func
|
||||||
func AdmissionToValidateObjectUpdateFunc(admit admission.Interface, staticAttributes admission.Attributes) ValidateObjectUpdateFunc {
|
func AdmissionToValidateObjectUpdateFunc(admit admission.Interface, staticAttributes admission.Attributes, o admission.ObjectInterfaces) ValidateObjectUpdateFunc {
|
||||||
validatingAdmission, ok := admit.(admission.ValidationInterface)
|
validatingAdmission, ok := admit.(admission.ValidationInterface)
|
||||||
if !ok {
|
if !ok {
|
||||||
return func(obj, old runtime.Object) error { return nil }
|
return func(obj, old runtime.Object) error { return nil }
|
||||||
|
@ -277,6 +277,6 @@ func AdmissionToValidateObjectUpdateFunc(admit admission.Interface, staticAttrib
|
||||||
if !validatingAdmission.Handles(finalAttributes.GetOperation()) {
|
if !validatingAdmission.Handles(finalAttributes.GetOperation()) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return validatingAdmission.Validate(finalAttributes)
|
return validatingAdmission.Validate(finalAttributes, o)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue