Unverified Commit 4e76bb48 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #58679 from CaoShuFeng/admission_webhook

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. support annotations for admission webhook Depends on: https://github.com/kubernetes/kubernetes/pull/58143 **Release note**: ```release-note Support annotations for remote admission webhooks. ```
parents 0cb018fe 0ebfc3e0
...@@ -92,6 +92,12 @@ type AdmissionResponse struct { ...@@ -92,6 +92,12 @@ type AdmissionResponse struct {
// PatchType indicates the form the Patch will take. Currently we only support "JSONPatch". // PatchType indicates the form the Patch will take. Currently we only support "JSONPatch".
// +optional // +optional
PatchType *PatchType PatchType *PatchType
// AuditAnnotations is an unstructured key value map set by remote admission controller (e.g. error=image-blacklisted).
// MutatingAdmissionWebhook and ValidatingAdmissionWebhook admission controller will prefix the keys with
// admission webhook name (e.g. imagepolicy.example.com/error=image-blacklisted). AuditAnnotations will be provided by
// the admission webhook to add additional context to the audit log for this request.
// +optional
AuditAnnotations map[string]string
} }
// PatchType is the type of patch being used to represent the mutated object // PatchType is the type of patch being used to represent the mutated object
......
...@@ -129,6 +129,7 @@ func autoConvert_v1beta1_AdmissionResponse_To_admission_AdmissionResponse(in *v1 ...@@ -129,6 +129,7 @@ func autoConvert_v1beta1_AdmissionResponse_To_admission_AdmissionResponse(in *v1
out.Result = (*v1.Status)(unsafe.Pointer(in.Result)) out.Result = (*v1.Status)(unsafe.Pointer(in.Result))
out.Patch = *(*[]byte)(unsafe.Pointer(&in.Patch)) out.Patch = *(*[]byte)(unsafe.Pointer(&in.Patch))
out.PatchType = (*admission.PatchType)(unsafe.Pointer(in.PatchType)) out.PatchType = (*admission.PatchType)(unsafe.Pointer(in.PatchType))
out.AuditAnnotations = *(*map[string]string)(unsafe.Pointer(&in.AuditAnnotations))
return nil return nil
} }
...@@ -143,6 +144,7 @@ func autoConvert_admission_AdmissionResponse_To_v1beta1_AdmissionResponse(in *ad ...@@ -143,6 +144,7 @@ func autoConvert_admission_AdmissionResponse_To_v1beta1_AdmissionResponse(in *ad
out.Result = (*v1.Status)(unsafe.Pointer(in.Result)) out.Result = (*v1.Status)(unsafe.Pointer(in.Result))
out.Patch = *(*[]byte)(unsafe.Pointer(&in.Patch)) out.Patch = *(*[]byte)(unsafe.Pointer(&in.Patch))
out.PatchType = (*v1beta1.PatchType)(unsafe.Pointer(in.PatchType)) out.PatchType = (*v1beta1.PatchType)(unsafe.Pointer(in.PatchType))
out.AuditAnnotations = *(*map[string]string)(unsafe.Pointer(&in.AuditAnnotations))
return nil return nil
} }
......
...@@ -68,6 +68,13 @@ func (in *AdmissionResponse) DeepCopyInto(out *AdmissionResponse) { ...@@ -68,6 +68,13 @@ func (in *AdmissionResponse) DeepCopyInto(out *AdmissionResponse) {
*out = new(PatchType) *out = new(PatchType)
**out = **in **out = **in
} }
if in.AuditAnnotations != nil {
in, out := &in.AuditAnnotations, &out.AuditAnnotations
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return return
} }
......
...@@ -20,6 +20,7 @@ go_library( ...@@ -20,6 +20,7 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/github.com/gogo/protobuf/proto:go_default_library", "//vendor/github.com/gogo/protobuf/proto:go_default_library",
"//vendor/github.com/gogo/protobuf/sortkeys:go_default_library",
], ],
) )
......
...@@ -39,6 +39,8 @@ import k8s_io_apimachinery_pkg_apis_meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v ...@@ -39,6 +39,8 @@ import k8s_io_apimachinery_pkg_apis_meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v
import k8s_io_apimachinery_pkg_types "k8s.io/apimachinery/pkg/types" import k8s_io_apimachinery_pkg_types "k8s.io/apimachinery/pkg/types"
import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
import strings "strings" import strings "strings"
import reflect "reflect" import reflect "reflect"
...@@ -199,6 +201,28 @@ func (m *AdmissionResponse) MarshalTo(dAtA []byte) (int, error) { ...@@ -199,6 +201,28 @@ func (m *AdmissionResponse) MarshalTo(dAtA []byte) (int, error) {
i = encodeVarintGenerated(dAtA, i, uint64(len(*m.PatchType))) i = encodeVarintGenerated(dAtA, i, uint64(len(*m.PatchType)))
i += copy(dAtA[i:], *m.PatchType) i += copy(dAtA[i:], *m.PatchType)
} }
if len(m.AuditAnnotations) > 0 {
keysForAuditAnnotations := make([]string, 0, len(m.AuditAnnotations))
for k := range m.AuditAnnotations {
keysForAuditAnnotations = append(keysForAuditAnnotations, string(k))
}
github_com_gogo_protobuf_sortkeys.Strings(keysForAuditAnnotations)
for _, k := range keysForAuditAnnotations {
dAtA[i] = 0x32
i++
v := m.AuditAnnotations[string(k)]
mapSize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + len(v) + sovGenerated(uint64(len(v)))
i = encodeVarintGenerated(dAtA, i, uint64(mapSize))
dAtA[i] = 0xa
i++
i = encodeVarintGenerated(dAtA, i, uint64(len(k)))
i += copy(dAtA[i:], k)
dAtA[i] = 0x12
i++
i = encodeVarintGenerated(dAtA, i, uint64(len(v)))
i += copy(dAtA[i:], v)
}
}
return i, nil return i, nil
} }
...@@ -311,6 +335,14 @@ func (m *AdmissionResponse) Size() (n int) { ...@@ -311,6 +335,14 @@ func (m *AdmissionResponse) Size() (n int) {
l = len(*m.PatchType) l = len(*m.PatchType)
n += 1 + l + sovGenerated(uint64(l)) n += 1 + l + sovGenerated(uint64(l))
} }
if len(m.AuditAnnotations) > 0 {
for k, v := range m.AuditAnnotations {
_ = k
_ = v
mapEntrySize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + len(v) + sovGenerated(uint64(len(v)))
n += mapEntrySize + 1 + sovGenerated(uint64(mapEntrySize))
}
}
return n return n
} }
...@@ -364,12 +396,23 @@ func (this *AdmissionResponse) String() string { ...@@ -364,12 +396,23 @@ func (this *AdmissionResponse) String() string {
if this == nil { if this == nil {
return "nil" return "nil"
} }
keysForAuditAnnotations := make([]string, 0, len(this.AuditAnnotations))
for k := range this.AuditAnnotations {
keysForAuditAnnotations = append(keysForAuditAnnotations, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForAuditAnnotations)
mapStringForAuditAnnotations := "map[string]string{"
for _, k := range keysForAuditAnnotations {
mapStringForAuditAnnotations += fmt.Sprintf("%v: %v,", k, this.AuditAnnotations[k])
}
mapStringForAuditAnnotations += "}"
s := strings.Join([]string{`&AdmissionResponse{`, s := strings.Join([]string{`&AdmissionResponse{`,
`UID:` + fmt.Sprintf("%v", this.UID) + `,`, `UID:` + fmt.Sprintf("%v", this.UID) + `,`,
`Allowed:` + fmt.Sprintf("%v", this.Allowed) + `,`, `Allowed:` + fmt.Sprintf("%v", this.Allowed) + `,`,
`Result:` + strings.Replace(fmt.Sprintf("%v", this.Result), "Status", "k8s_io_apimachinery_pkg_apis_meta_v1.Status", 1) + `,`, `Result:` + strings.Replace(fmt.Sprintf("%v", this.Result), "Status", "k8s_io_apimachinery_pkg_apis_meta_v1.Status", 1) + `,`,
`Patch:` + valueToStringGenerated(this.Patch) + `,`, `Patch:` + valueToStringGenerated(this.Patch) + `,`,
`PatchType:` + valueToStringGenerated(this.PatchType) + `,`, `PatchType:` + valueToStringGenerated(this.PatchType) + `,`,
`AuditAnnotations:` + mapStringForAuditAnnotations + `,`,
`}`, `}`,
}, "") }, "")
return s return s
...@@ -910,6 +953,122 @@ func (m *AdmissionResponse) Unmarshal(dAtA []byte) error { ...@@ -910,6 +953,122 @@ func (m *AdmissionResponse) Unmarshal(dAtA []byte) error {
s := PatchType(dAtA[iNdEx:postIndex]) s := PatchType(dAtA[iNdEx:postIndex])
m.PatchType = &s m.PatchType = &s
iNdEx = postIndex iNdEx = postIndex
case 6:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field AuditAnnotations", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
var keykey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
keykey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
var stringLenmapkey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLenmapkey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLenmapkey := int(stringLenmapkey)
if intStringLenmapkey < 0 {
return ErrInvalidLengthGenerated
}
postStringIndexmapkey := iNdEx + intStringLenmapkey
if postStringIndexmapkey > l {
return io.ErrUnexpectedEOF
}
mapkey := string(dAtA[iNdEx:postStringIndexmapkey])
iNdEx = postStringIndexmapkey
if m.AuditAnnotations == nil {
m.AuditAnnotations = make(map[string]string)
}
if iNdEx < postIndex {
var valuekey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
valuekey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
var stringLenmapvalue uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLenmapvalue |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLenmapvalue := int(stringLenmapvalue)
if intStringLenmapvalue < 0 {
return ErrInvalidLengthGenerated
}
postStringIndexmapvalue := iNdEx + intStringLenmapvalue
if postStringIndexmapvalue > l {
return io.ErrUnexpectedEOF
}
mapvalue := string(dAtA[iNdEx:postStringIndexmapvalue])
iNdEx = postStringIndexmapvalue
m.AuditAnnotations[mapkey] = mapvalue
} else {
var mapvalue string
m.AuditAnnotations[mapkey] = mapvalue
}
iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:]) skippy, err := skipGenerated(dAtA[iNdEx:])
...@@ -1157,51 +1316,55 @@ func init() { ...@@ -1157,51 +1316,55 @@ func init() {
} }
var fileDescriptorGenerated = []byte{ var fileDescriptorGenerated = []byte{
// 728 bytes of a gzipped FileDescriptorProto // 800 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0x4f, 0x4f, 0xdb, 0x48, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcf, 0x6f, 0xe3, 0x44,
0x14, 0x8f, 0x21, 0xff, 0x3c, 0x41, 0x0b, 0xcc, 0x5e, 0xac, 0x68, 0xe5, 0xb0, 0x1c, 0x56, 0xac, 0x14, 0x8e, 0x37, 0x3f, 0x3d, 0xa9, 0xd8, 0xec, 0x00, 0x92, 0x15, 0x21, 0x27, 0xf4, 0x80, 0x8a,
0x04, 0xe3, 0x05, 0xed, 0x22, 0xb4, 0xda, 0x0b, 0x16, 0x68, 0x85, 0x56, 0x02, 0x34, 0x90, 0x55, 0xb4, 0x1d, 0xd3, 0x0a, 0x56, 0xd5, 0x8a, 0x4b, 0xcc, 0x46, 0xa8, 0x42, 0x6a, 0xab, 0x69, 0x83,
0xdb, 0x43, 0xa5, 0x89, 0xf3, 0x48, 0xdc, 0xc4, 0x1e, 0xd7, 0x33, 0x0e, 0xe5, 0xd6, 0x8f, 0xd0, 0x80, 0x03, 0xd2, 0xc4, 0x9e, 0x26, 0x26, 0xf1, 0x8c, 0xf1, 0x8c, 0x53, 0x72, 0x43, 0x5c, 0xb9,
0x6f, 0xd2, 0x0f, 0xd1, 0x0b, 0x47, 0x8e, 0x9c, 0xa2, 0x92, 0x7e, 0x80, 0xde, 0x39, 0x55, 0x1e, 0xf0, 0x3f, 0x71, 0xe9, 0xb1, 0xc7, 0x9e, 0x22, 0x1a, 0xfe, 0x00, 0xee, 0x3d, 0x21, 0x8f, 0xc7,
0x8f, 0xe3, 0x94, 0x96, 0x96, 0x56, 0x3d, 0x65, 0xde, 0x7b, 0xbf, 0xdf, 0xef, 0xc5, 0xbf, 0xf7, 0x71, 0x48, 0x5b, 0x68, 0xd1, 0x9e, 0x32, 0xef, 0xbd, 0xef, 0xfb, 0x9e, 0xe7, 0x7b, 0x2f, 0x03,
0x66, 0xd0, 0xfe, 0x60, 0x47, 0x10, 0x9f, 0x3b, 0x83, 0xa4, 0x03, 0x71, 0x08, 0x12, 0x84, 0x33, 0xfa, 0x93, 0x03, 0x81, 0x02, 0xee, 0x4c, 0x92, 0x21, 0x8d, 0x19, 0x95, 0x54, 0x38, 0x33, 0xca,
0x82, 0xb0, 0xcb, 0x63, 0x47, 0x17, 0x58, 0xe4, 0x3b, 0xac, 0x1b, 0xf8, 0x42, 0xf8, 0x3c, 0x74, 0x7c, 0x1e, 0x3b, 0xba, 0x40, 0xa2, 0xc0, 0x21, 0x7e, 0x18, 0x08, 0x11, 0x70, 0xe6, 0xcc, 0xf6,
0x46, 0x9b, 0x1d, 0x90, 0x6c, 0xd3, 0xe9, 0x41, 0x08, 0x31, 0x93, 0xd0, 0x25, 0x51, 0xcc, 0x25, 0x86, 0x54, 0x92, 0x3d, 0x67, 0x44, 0x19, 0x8d, 0x89, 0xa4, 0x3e, 0x8a, 0x62, 0x2e, 0x39, 0xfc,
0xc7, 0xbf, 0x64, 0x68, 0xc2, 0x22, 0x9f, 0x4c, 0xd1, 0x44, 0xa3, 0x9b, 0x1b, 0x3d, 0x5f, 0xf6, 0x20, 0x43, 0x23, 0x12, 0x05, 0x68, 0x85, 0x46, 0x1a, 0xdd, 0xde, 0x1d, 0x05, 0x72, 0x9c, 0x0c,
0x93, 0x0e, 0xf1, 0x78, 0xe0, 0xf4, 0x78, 0x8f, 0x3b, 0x8a, 0xd4, 0x49, 0xce, 0x54, 0xa4, 0x02, 0x91, 0xc7, 0x43, 0x67, 0xc4, 0x47, 0xdc, 0x51, 0xa4, 0x61, 0x72, 0xae, 0x22, 0x15, 0xa8, 0x53,
0x75, 0xca, 0xc4, 0x9a, 0xeb, 0xb3, 0xad, 0x13, 0xd9, 0x87, 0x50, 0xfa, 0x1e, 0x93, 0x59, 0xff, 0x26, 0xd6, 0x7e, 0xb9, 0xde, 0x3a, 0x91, 0x63, 0xca, 0x64, 0xe0, 0x11, 0x99, 0xf5, 0xdf, 0x6c,
0xbb, 0xad, 0x9b, 0x7f, 0x16, 0xe8, 0x80, 0x79, 0x7d, 0x3f, 0x84, 0xf8, 0xc2, 0x89, 0x06, 0xbd, 0xdd, 0xfe, 0xb4, 0x40, 0x87, 0xc4, 0x1b, 0x07, 0x8c, 0xc6, 0x73, 0x27, 0x9a, 0x8c, 0xd2, 0x84,
0x34, 0x21, 0x9c, 0x00, 0x24, 0xfb, 0x1c, 0xcb, 0xb9, 0x8f, 0x15, 0x27, 0xa1, 0xf4, 0x03, 0xf8, 0x70, 0x42, 0x2a, 0xc9, 0x7d, 0x2c, 0xe7, 0x21, 0x56, 0x9c, 0x30, 0x19, 0x84, 0xf4, 0x0e, 0xe1,
0x84, 0xb0, 0xfd, 0x35, 0x82, 0xf0, 0xfa, 0x10, 0xb0, 0xbb, 0xbc, 0xd5, 0xf7, 0x15, 0xb4, 0xb4, 0xd5, 0x7f, 0x11, 0x84, 0x37, 0xa6, 0x21, 0xd9, 0xe4, 0x6d, 0xff, 0x55, 0x05, 0xad, 0x5e, 0xee,
0x9b, 0x3b, 0x42, 0xe1, 0x79, 0x02, 0x42, 0x62, 0x17, 0xcd, 0x27, 0x7e, 0xd7, 0x32, 0x56, 0x8c, 0x08, 0xa6, 0x3f, 0x26, 0x54, 0x48, 0xe8, 0x82, 0x72, 0x12, 0xf8, 0x96, 0xd1, 0x35, 0x76, 0x4c,
0x35, 0xd3, 0xfd, 0xe3, 0x72, 0xdc, 0x2a, 0x4d, 0xc6, 0xad, 0xf9, 0xf6, 0xc1, 0xde, 0xed, 0xb8, 0xf7, 0x93, 0xcb, 0x45, 0xa7, 0xb4, 0x5c, 0x74, 0xca, 0x83, 0xc3, 0x37, 0xb7, 0x8b, 0xce, 0x87,
0xf5, 0xeb, 0x7d, 0x8d, 0xe4, 0x45, 0x04, 0x82, 0xb4, 0x0f, 0xf6, 0x68, 0x4a, 0xc6, 0x8f, 0x50, 0x0f, 0x35, 0x92, 0xf3, 0x88, 0x0a, 0x34, 0x38, 0x7c, 0x83, 0x53, 0x32, 0xfc, 0x06, 0x54, 0x26,
0x79, 0xe0, 0x87, 0x5d, 0x6b, 0x6e, 0xc5, 0x58, 0x6b, 0x6c, 0x6d, 0x93, 0x62, 0x02, 0x53, 0x1a, 0x01, 0xf3, 0xad, 0x67, 0x5d, 0x63, 0xa7, 0xb9, 0xff, 0x0a, 0x15, 0x13, 0x58, 0xd1, 0x50, 0x34,
0x89, 0x06, 0xbd, 0x34, 0x21, 0x48, 0x6a, 0x03, 0x19, 0x6d, 0x92, 0x7f, 0x63, 0x9e, 0x44, 0xff, 0x19, 0xa5, 0x09, 0x81, 0x52, 0x1b, 0xd0, 0x6c, 0x0f, 0x7d, 0x19, 0xf3, 0x24, 0xfa, 0x9a, 0xc6,
0x43, 0x9c, 0xfe, 0x99, 0xff, 0xfc, 0xb0, 0xeb, 0x2e, 0xe8, 0xe6, 0xe5, 0x34, 0xa2, 0x4a, 0x11, 0xe9, 0xc7, 0x7c, 0x15, 0x30, 0xdf, 0xdd, 0xd2, 0xcd, 0x2b, 0x69, 0x84, 0x95, 0x22, 0x1c, 0x83,
0xf7, 0x51, 0x3d, 0x06, 0xc1, 0x93, 0xd8, 0x03, 0x6b, 0x5e, 0xa9, 0xff, 0xfd, 0xed, 0xea, 0x54, 0x46, 0x4c, 0x05, 0x4f, 0x62, 0x8f, 0x5a, 0x65, 0xa5, 0xfe, 0xfa, 0xe9, 0xea, 0x58, 0x2b, 0xb8,
0x2b, 0xb8, 0x4b, 0xba, 0x43, 0x3d, 0xcf, 0xd0, 0xa9, 0x3a, 0xfe, 0x0b, 0x35, 0x44, 0xd2, 0xc9, 0x2d, 0xdd, 0xa1, 0x91, 0x67, 0xf0, 0x4a, 0x1d, 0x7e, 0x06, 0x9a, 0x22, 0x19, 0xe6, 0x05, 0xab,
0x0b, 0x56, 0x59, 0xf9, 0xf1, 0xb3, 0x26, 0x34, 0x4e, 0x8a, 0x12, 0x9d, 0xc5, 0xe1, 0x15, 0x54, 0xa2, 0xfc, 0x78, 0x57, 0x13, 0x9a, 0xa7, 0x45, 0x09, 0xaf, 0xe3, 0x60, 0x17, 0x54, 0x18, 0x09,
0x0e, 0x59, 0x00, 0x56, 0x45, 0xe1, 0xa7, 0x9f, 0x70, 0xc8, 0x02, 0xa0, 0xaa, 0x82, 0x1d, 0x64, 0xa9, 0x55, 0x55, 0xf8, 0xd5, 0x15, 0x8e, 0x48, 0x48, 0xb1, 0xaa, 0x40, 0x07, 0x98, 0xe9, 0xaf,
0xa6, 0xbf, 0x22, 0x62, 0x1e, 0x58, 0x55, 0x05, 0x5b, 0xd6, 0x30, 0xf3, 0x30, 0x2f, 0xd0, 0x02, 0x88, 0x88, 0x47, 0xad, 0x9a, 0x82, 0xbd, 0xd0, 0x30, 0xf3, 0x28, 0x2f, 0xe0, 0x02, 0x03, 0x3f,
0x83, 0xff, 0x41, 0x26, 0x8f, 0xd2, 0xc1, 0xf9, 0x3c, 0xb4, 0x6a, 0x8a, 0x60, 0xe7, 0x84, 0xa3, 0x07, 0x26, 0x8f, 0xd2, 0xc1, 0x05, 0x9c, 0x59, 0x75, 0x45, 0xb0, 0x73, 0xc2, 0x71, 0x5e, 0xb8,
0xbc, 0x70, 0x3b, 0x1b, 0xd0, 0x82, 0x80, 0x4f, 0x51, 0x3d, 0x11, 0x10, 0x1f, 0x84, 0x67, 0xdc, 0x5d, 0x0f, 0x70, 0x41, 0x80, 0x67, 0xa0, 0x91, 0x08, 0x1a, 0x1f, 0xb2, 0x73, 0x6e, 0x35, 0x94,
0xaa, 0x2b, 0xc7, 0x7e, 0x23, 0xb3, 0x37, 0xe2, 0xa3, 0x25, 0x4e, 0x9d, 0x6a, 0x6b, 0x74, 0xe1, 0x63, 0x1f, 0xa1, 0xf5, 0x7f, 0xc4, 0x3f, 0x96, 0x38, 0x75, 0x6a, 0xa0, 0xd1, 0x85, 0x3b, 0x79,
0x4e, 0x9e, 0xa1, 0x53, 0x25, 0xdc, 0x46, 0x55, 0xde, 0x79, 0x06, 0x9e, 0xb4, 0x4c, 0xa5, 0xb9, 0x06, 0xaf, 0x94, 0xe0, 0x00, 0xd4, 0xf8, 0xf0, 0x07, 0xea, 0x49, 0xcb, 0x54, 0x9a, 0xbb, 0x0f,
0x71, 0xef, 0x14, 0xf4, 0x0e, 0x12, 0xca, 0xce, 0xf7, 0x5f, 0x48, 0x08, 0xd3, 0x01, 0xb8, 0x3f, 0x4e, 0x41, 0xef, 0x20, 0xc2, 0xe4, 0xa2, 0xff, 0x93, 0xa4, 0x2c, 0x1d, 0x80, 0xfb, 0x8e, 0x96,
0x69, 0xe9, 0xea, 0x91, 0x12, 0xa1, 0x5a, 0x0c, 0x3f, 0x45, 0x26, 0x1f, 0x76, 0xb3, 0xa4, 0x85, 0xae, 0x1d, 0x2b, 0x11, 0xac, 0xc5, 0xe0, 0xf7, 0xc0, 0xe4, 0x53, 0x3f, 0x4b, 0x5a, 0xe0, 0xff,
0xbe, 0x47, 0x79, 0x6a, 0xe5, 0x51, 0xae, 0x43, 0x0b, 0xc9, 0xd5, 0xd7, 0x73, 0x68, 0x79, 0x66, 0x28, 0xaf, 0xac, 0x3c, 0xce, 0x75, 0x70, 0x21, 0xb9, 0xfd, 0x4b, 0x05, 0xbc, 0x58, 0xdb, 0x78,
0xe3, 0x45, 0xc4, 0x43, 0x01, 0x3f, 0x64, 0xe5, 0x7f, 0x47, 0x35, 0x36, 0x1c, 0xf2, 0x73, 0xc8, 0x11, 0x71, 0x26, 0xe8, 0x5b, 0x59, 0xf9, 0x8f, 0x41, 0x9d, 0x4c, 0xa7, 0xfc, 0x82, 0x66, 0x5b,
0xb6, 0xbe, 0xee, 0x2e, 0x6a, 0x9d, 0xda, 0x6e, 0x96, 0xa6, 0x79, 0x1d, 0x1f, 0xa3, 0xaa, 0x90, 0xdf, 0x70, 0x9f, 0x6b, 0x9d, 0x7a, 0x2f, 0x4b, 0xe3, 0xbc, 0x0e, 0x4f, 0x40, 0x4d, 0x48, 0x22,
0x4c, 0x26, 0x42, 0x6f, 0xf0, 0xfa, 0xc3, 0x36, 0xf8, 0x44, 0x71, 0x5c, 0x94, 0xda, 0x46, 0x41, 0x13, 0xa1, 0x37, 0xf8, 0xe5, 0xe3, 0x36, 0xf8, 0x54, 0x71, 0x5c, 0x90, 0xda, 0x86, 0xa9, 0x48,
0x24, 0x43, 0x49, 0xb5, 0x0e, 0x6e, 0xa1, 0x4a, 0xc4, 0xa4, 0xd7, 0x57, 0x5b, 0xba, 0xe0, 0x9a, 0xa6, 0x12, 0x6b, 0x1d, 0xd8, 0x01, 0xd5, 0x88, 0x48, 0x6f, 0xac, 0xb6, 0x74, 0xcb, 0x35, 0x97,
0x93, 0x71, 0xab, 0x72, 0x9c, 0x26, 0x68, 0x96, 0xc7, 0x3b, 0xc8, 0x54, 0x87, 0xd3, 0x8b, 0x28, 0x8b, 0x4e, 0xf5, 0x24, 0x4d, 0xe0, 0x2c, 0x0f, 0x0f, 0x80, 0xa9, 0x0e, 0x67, 0xf3, 0x28, 0x5f,
0x5f, 0xcd, 0x66, 0x6a, 0xd2, 0x71, 0x9e, 0xbc, 0x9d, 0x0d, 0x68, 0x01, 0x5e, 0x7d, 0x63, 0xa0, 0xcd, 0x76, 0x6a, 0xd2, 0x49, 0x9e, 0xbc, 0x5d, 0x0f, 0x70, 0x01, 0x86, 0xbf, 0x1a, 0xa0, 0x45,
0xc5, 0x19, 0xc7, 0x46, 0x3e, 0x9c, 0xe3, 0x36, 0xaa, 0xc5, 0xd9, 0x6b, 0xa1, 0x3c, 0x6b, 0x6c, 0x12, 0x3f, 0x90, 0x3d, 0xc6, 0xb8, 0x54, 0x4b, 0x22, 0xac, 0x5a, 0xb7, 0xbc, 0xd3, 0xdc, 0xef,
0x11, 0xf2, 0xa5, 0x37, 0x96, 0xdc, 0x7d, 0x63, 0xdc, 0x46, 0xea, 0x8b, 0x0e, 0x68, 0xae, 0x85, 0xa3, 0x7f, 0x7b, 0x59, 0xd1, 0x1d, 0x9f, 0x51, 0x6f, 0x43, 0xa7, 0xcf, 0x64, 0x3c, 0x77, 0x2d,
0x1f, 0xab, 0xbb, 0xad, 0x46, 0xa2, 0x5f, 0x0e, 0xe7, 0xc1, 0xba, 0x19, 0xcd, 0x5d, 0xd0, 0x97, 0x6d, 0x54, 0x6b, 0xb3, 0x8c, 0xef, 0x34, 0x6e, 0x7f, 0x01, 0xde, 0xbf, 0x57, 0x04, 0xb6, 0x40,
0x59, 0x45, 0x74, 0x2a, 0xe7, 0x6e, 0x5c, 0xde, 0xd8, 0xa5, 0xab, 0x1b, 0xbb, 0x74, 0x7d, 0x63, 0x79, 0x42, 0xe7, 0xd9, 0x08, 0x71, 0x7a, 0x84, 0xef, 0x81, 0xea, 0x8c, 0x4c, 0x13, 0xaa, 0xc6,
0x97, 0x5e, 0x4e, 0x6c, 0xe3, 0x72, 0x62, 0x1b, 0x57, 0x13, 0xdb, 0xb8, 0x9e, 0xd8, 0xc6, 0xdb, 0x61, 0xe2, 0x2c, 0x78, 0xfd, 0xec, 0xc0, 0xd8, 0xfe, 0xdd, 0x00, 0xcf, 0xd7, 0x3e, 0x6e, 0x16,
0x89, 0x6d, 0xbc, 0x7a, 0x67, 0x97, 0x9e, 0xd4, 0xb4, 0xf0, 0x87, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd0, 0x0b, 0x38, 0x00, 0xf5, 0x38, 0x7b, 0x00, 0x95, 0x46, 0x73, 0x1f, 0x3d, 0xfa, 0x72, 0x8a,
0xb6, 0xe9, 0xbc, 0x6f, 0x7a, 0x06, 0x00, 0x00, 0xe5, 0x36, 0xd3, 0x51, 0xeb, 0x00, 0xe7, 0x5a, 0xf0, 0x5b, 0xf5, 0x5c, 0xa9, 0xdb, 0xeb, 0xc7,
0xd0, 0x79, 0xa2, 0x69, 0xee, 0x96, 0x7e, 0x9f, 0x54, 0x84, 0x57, 0x72, 0xee, 0xee, 0xe5, 0x8d,
0x5d, 0xba, 0xba, 0xb1, 0x4b, 0xd7, 0x37, 0x76, 0xe9, 0xe7, 0xa5, 0x6d, 0x5c, 0x2e, 0x6d, 0xe3,
0x6a, 0x69, 0x1b, 0xd7, 0x4b, 0xdb, 0xf8, 0x63, 0x69, 0x1b, 0xbf, 0xfd, 0x69, 0x97, 0xbe, 0xab,
0x6b, 0xe1, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x8d, 0xe4, 0x17, 0xc7, 0x4d, 0x07, 0x00, 0x00,
} }
...@@ -96,6 +96,13 @@ message AdmissionResponse { ...@@ -96,6 +96,13 @@ message AdmissionResponse {
// The type of Patch. Currently we only allow "JSONPatch". // The type of Patch. Currently we only allow "JSONPatch".
// +optional // +optional
optional string patchType = 5; optional string patchType = 5;
// AuditAnnotations is an unstructured key value map set by remote admission controller (e.g. error=image-blacklisted).
// MutatingAdmissionWebhook and ValidatingAdmissionWebhook admission controller will prefix the keys with
// admission webhook name (e.g. imagepolicy.example.com/error=image-blacklisted). AuditAnnotations will be provided by
// the admission webhook to add additional context to the audit log for this request.
// +optional
map<string, string> auditAnnotations = 6;
} }
// AdmissionReview describes an admission review request/response. // AdmissionReview describes an admission review request/response.
......
...@@ -94,6 +94,13 @@ type AdmissionResponse struct { ...@@ -94,6 +94,13 @@ type AdmissionResponse struct {
// The type of Patch. Currently we only allow "JSONPatch". // The type of Patch. Currently we only allow "JSONPatch".
// +optional // +optional
PatchType *PatchType `json:"patchType,omitempty" protobuf:"bytes,5,opt,name=patchType"` PatchType *PatchType `json:"patchType,omitempty" protobuf:"bytes,5,opt,name=patchType"`
// AuditAnnotations is an unstructured key value map set by remote admission controller (e.g. error=image-blacklisted).
// MutatingAdmissionWebhook and ValidatingAdmissionWebhook admission controller will prefix the keys with
// admission webhook name (e.g. imagepolicy.example.com/error=image-blacklisted). AuditAnnotations will be provided by
// the admission webhook to add additional context to the audit log for this request.
// +optional
AuditAnnotations map[string]string `json:"auditAnnotations,omitempty" protobuf:"bytes,6,opt,name=auditAnnotations"`
} }
// PatchType is the type of patch being used to represent the mutated object // PatchType is the type of patch being used to represent the mutated object
......
...@@ -46,12 +46,13 @@ func (AdmissionRequest) SwaggerDoc() map[string]string { ...@@ -46,12 +46,13 @@ func (AdmissionRequest) SwaggerDoc() map[string]string {
} }
var map_AdmissionResponse = map[string]string{ var map_AdmissionResponse = map[string]string{
"": "AdmissionResponse describes an admission response.", "": "AdmissionResponse describes an admission response.",
"uid": "UID is an identifier for the individual request/response. This should be copied over from the corresponding AdmissionRequest.", "uid": "UID is an identifier for the individual request/response. This should be copied over from the corresponding AdmissionRequest.",
"allowed": "Allowed indicates whether or not the admission request was permitted.", "allowed": "Allowed indicates whether or not the admission request was permitted.",
"status": "Result contains extra details into why an admission request was denied. This field IS NOT consulted in any way if \"Allowed\" is \"true\".", "status": "Result contains extra details into why an admission request was denied. This field IS NOT consulted in any way if \"Allowed\" is \"true\".",
"patch": "The patch body. Currently we only support \"JSONPatch\" which implements RFC 6902.", "patch": "The patch body. Currently we only support \"JSONPatch\" which implements RFC 6902.",
"patchType": "The type of Patch. Currently we only allow \"JSONPatch\".", "patchType": "The type of Patch. Currently we only allow \"JSONPatch\".",
"auditAnnotations": "AuditAnnotations is an unstructured key value map set by remote admission controller (e.g. error=image-blacklisted). MutatingAdmissionWebhook and ValidatingAdmissionWebhook admission controller will prefix the keys with admission webhook name (e.g. imagepolicy.example.com/error=image-blacklisted). AuditAnnotations will be provided by the admission webhook to add additional context to the audit log for this request.",
} }
func (AdmissionResponse) SwaggerDoc() map[string]string { func (AdmissionResponse) SwaggerDoc() map[string]string {
......
...@@ -64,6 +64,13 @@ func (in *AdmissionResponse) DeepCopyInto(out *AdmissionResponse) { ...@@ -64,6 +64,13 @@ func (in *AdmissionResponse) DeepCopyInto(out *AdmissionResponse) {
*out = new(PatchType) *out = new(PatchType)
**out = **in **out = **in
} }
if in.AuditAnnotations != nil {
in, out := &in.AuditAnnotations, &out.AuditAnnotations
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return return
} }
......
...@@ -51,6 +51,7 @@ go_test( ...@@ -51,6 +51,7 @@ go_test(
"//staging/src/k8s.io/apiserver/pkg/apis/example:go_default_library", "//staging/src/k8s.io/apiserver/pkg/apis/example:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/apis/example/v1:go_default_library", "//staging/src/k8s.io/apiserver/pkg/apis/example/v1:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/apis/example2/v1:go_default_library", "//staging/src/k8s.io/apiserver/pkg/apis/example2/v1:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/github.com/stretchr/testify/require:go_default_library", "//vendor/github.com/stretchr/testify/require:go_default_library",
], ],
) )
......
...@@ -102,6 +102,13 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *v1beta ...@@ -102,6 +102,13 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *v1beta
return &webhookerrors.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Webhook response was absent")} return &webhookerrors.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Webhook response was absent")}
} }
for k, v := range response.Response.AuditAnnotations {
key := h.Name + "/" + k
if err := attr.AddAnnotation(key, v); err != nil {
glog.Warningf("Failed to set admission audit annotation %s to %s for mutating webhook %s: %v", key, v, h.Name, err)
}
}
if !response.Response.Allowed { if !response.Response.Allowed {
return webhookerrors.ToStatusErr(h.Name, response.Response.Result) return webhookerrors.ToStatusErr(h.Name, response.Response.Result)
} }
......
...@@ -22,6 +22,7 @@ import ( ...@@ -22,6 +22,7 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"k8s.io/api/admission/v1beta1" "k8s.io/api/admission/v1beta1"
...@@ -102,6 +103,16 @@ func TestAdmit(t *testing.T) { ...@@ -102,6 +103,16 @@ func TestAdmit(t *testing.T) {
if _, isStatusErr := err.(*errors.StatusError); err != nil && !isStatusErr { if _, isStatusErr := err.(*errors.StatusError); err != nil && !isStatusErr {
t.Errorf("%s: expected a StatusError, got %T", tt.Name, err) t.Errorf("%s: expected a StatusError, got %T", tt.Name, err)
} }
fakeAttr, ok := attr.(*webhooktesting.FakeAttributes)
if !ok {
t.Errorf("Unexpected error, failed to convert attr to webhooktesting.FakeAttributes")
continue
}
if len(tt.ExpectAnnotations) == 0 {
assert.Empty(t, fakeAttr.GetAnnotations(), tt.Name+": annotations not set as expected.")
} else {
assert.Equal(t, tt.ExpectAnnotations, fakeAttr.GetAnnotations(), tt.Name+": annotations not set as expected.")
}
} }
} }
......
...@@ -18,6 +18,7 @@ package testing ...@@ -18,6 +18,7 @@ package testing
import ( import (
"net/url" "net/url"
"sync"
registrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" registrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
...@@ -95,7 +96,37 @@ func newAttributesRecord(object metav1.Object, oldObject metav1.Object, kind sch ...@@ -95,7 +96,37 @@ func newAttributesRecord(object metav1.Object, oldObject metav1.Object, kind sch
UID: "webhook-test", UID: "webhook-test",
} }
return admission.NewAttributesRecord(object.(runtime.Object), oldObject.(runtime.Object), kind, namespace, name, gvr, subResource, admission.Update, dryRun, &userInfo) return &FakeAttributes{
Attributes: admission.NewAttributesRecord(object.(runtime.Object), oldObject.(runtime.Object), kind, namespace, name, gvr, subResource, admission.Update, dryRun, &userInfo),
}
}
// FakeAttributes decorate admission.Attributes. It's used to trace the added annotations.
type FakeAttributes struct {
admission.Attributes
annotations map[string]string
mutex sync.Mutex
}
// AddAnnotation adds an annotation key value pair to FakeAttributes
func (f *FakeAttributes) AddAnnotation(k, v string) error {
f.mutex.Lock()
defer f.mutex.Unlock()
if err := f.Attributes.AddAnnotation(k, v); err != nil {
return err
}
if f.annotations == nil {
f.annotations = make(map[string]string)
}
f.annotations[k] = v
return nil
}
// GetAnnotations reads annotations from FakeAttributes
func (f *FakeAttributes) GetAnnotations() map[string]string {
f.mutex.Lock()
defer f.mutex.Unlock()
return f.annotations
} }
// NewAttribute returns static admission Attributes for testing. // NewAttribute returns static admission Attributes for testing.
...@@ -145,15 +176,16 @@ func (c urlConfigGenerator) ccfgURL(urlPath string) registrationv1beta1.WebhookC ...@@ -145,15 +176,16 @@ func (c urlConfigGenerator) ccfgURL(urlPath string) registrationv1beta1.WebhookC
// Test is a webhook test case. // Test is a webhook test case.
type Test struct { type Test struct {
Name string Name string
Webhooks []registrationv1beta1.Webhook Webhooks []registrationv1beta1.Webhook
Path string Path string
IsCRD bool IsCRD bool
IsDryRun bool IsDryRun bool
AdditionalLabels map[string]string AdditionalLabels map[string]string
ExpectLabels map[string]string ExpectLabels map[string]string
ExpectAllow bool ExpectAllow bool
ErrorContains string ErrorContains string
ExpectAnnotations map[string]string
} }
// NewNonMutatingTestCases returns test cases with a given base url. // NewNonMutatingTestCases returns test cases with a given base url.
...@@ -181,12 +213,13 @@ func NewNonMutatingTestCases(url *url.URL) []Test { ...@@ -181,12 +213,13 @@ func NewNonMutatingTestCases(url *url.URL) []Test {
{ {
Name: "match & allow", Name: "match & allow",
Webhooks: []registrationv1beta1.Webhook{{ Webhooks: []registrationv1beta1.Webhook{{
Name: "allow", Name: "allow.example.com",
ClientConfig: ccfgSVC("allow"), ClientConfig: ccfgSVC("allow"),
Rules: matchEverythingRules, Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{}, NamespaceSelector: &metav1.LabelSelector{},
}}, }},
ExpectAllow: true, ExpectAllow: true,
ExpectAnnotations: map[string]string{"allow.example.com/key1": "value1"},
}, },
{ {
Name: "match & disallow", Name: "match & disallow",
...@@ -312,12 +345,13 @@ func NewNonMutatingTestCases(url *url.URL) []Test { ...@@ -312,12 +345,13 @@ func NewNonMutatingTestCases(url *url.URL) []Test {
{ {
Name: "match & allow (url)", Name: "match & allow (url)",
Webhooks: []registrationv1beta1.Webhook{{ Webhooks: []registrationv1beta1.Webhook{{
Name: "allow", Name: "allow.example.com",
ClientConfig: ccfgURL("allow"), ClientConfig: ccfgURL("allow"),
Rules: matchEverythingRules, Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{}, NamespaceSelector: &metav1.LabelSelector{},
}}, }},
ExpectAllow: true, ExpectAllow: true,
ExpectAnnotations: map[string]string{"allow.example.com/key1": "value1"},
}, },
{ {
Name: "match & disallow (url)", Name: "match & disallow (url)",
...@@ -374,6 +408,16 @@ func NewNonMutatingTestCases(url *url.URL) []Test { ...@@ -374,6 +408,16 @@ func NewNonMutatingTestCases(url *url.URL) []Test {
IsDryRun: true, IsDryRun: true,
ErrorContains: "does not support dry run", ErrorContains: "does not support dry run",
}, },
{
Name: "illegal annotation format",
Webhooks: []registrationv1beta1.Webhook{{
Name: "invalidAnnotation",
ClientConfig: ccfgURL("invalidAnnotation"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
}},
ExpectAllow: true,
},
// No need to test everything with the url case, since only the // No need to test everything with the url case, since only the
// connection is different. // connection is different.
} }
...@@ -387,14 +431,15 @@ func NewMutatingTestCases(url *url.URL) []Test { ...@@ -387,14 +431,15 @@ func NewMutatingTestCases(url *url.URL) []Test {
{ {
Name: "match & remove label", Name: "match & remove label",
Webhooks: []registrationv1beta1.Webhook{{ Webhooks: []registrationv1beta1.Webhook{{
Name: "removeLabel", Name: "removelabel.example.com",
ClientConfig: ccfgSVC("removeLabel"), ClientConfig: ccfgSVC("removeLabel"),
Rules: matchEverythingRules, Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{}, NamespaceSelector: &metav1.LabelSelector{},
}}, }},
ExpectAllow: true, ExpectAllow: true,
AdditionalLabels: map[string]string{"remove": "me"}, AdditionalLabels: map[string]string{"remove": "me"},
ExpectLabels: map[string]string{"pod.name": "my-pod"}, ExpectLabels: map[string]string{"pod.name": "my-pod"},
ExpectAnnotations: map[string]string{"removelabel.example.com/key1": "value1"},
}, },
{ {
Name: "match & add label", Name: "match & add label",
...@@ -422,15 +467,16 @@ func NewMutatingTestCases(url *url.URL) []Test { ...@@ -422,15 +467,16 @@ func NewMutatingTestCases(url *url.URL) []Test {
{ {
Name: "match CRD & remove label", Name: "match CRD & remove label",
Webhooks: []registrationv1beta1.Webhook{{ Webhooks: []registrationv1beta1.Webhook{{
Name: "removeLabel", Name: "removelabel.example.com",
ClientConfig: ccfgSVC("removeLabel"), ClientConfig: ccfgSVC("removeLabel"),
Rules: matchEverythingRules, Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{}, NamespaceSelector: &metav1.LabelSelector{},
}}, }},
IsCRD: true, IsCRD: true,
ExpectAllow: true, ExpectAllow: true,
AdditionalLabels: map[string]string{"remove": "me"}, AdditionalLabels: map[string]string{"remove": "me"},
ExpectLabels: map[string]string{"crd.name": "my-test-crd"}, ExpectLabels: map[string]string{"crd.name": "my-test-crd"},
ExpectAnnotations: map[string]string{"removelabel.example.com/key1": "value1"},
}, },
{ {
Name: "match & invalid mutation", Name: "match & invalid mutation",
......
...@@ -83,6 +83,9 @@ func webhookHandler(w http.ResponseWriter, r *http.Request) { ...@@ -83,6 +83,9 @@ func webhookHandler(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(&v1beta1.AdmissionReview{ json.NewEncoder(w).Encode(&v1beta1.AdmissionReview{
Response: &v1beta1.AdmissionResponse{ Response: &v1beta1.AdmissionResponse{
Allowed: true, Allowed: true,
AuditAnnotations: map[string]string{
"key1": "value1",
},
}, },
}) })
case "/removeLabel": case "/removeLabel":
...@@ -93,6 +96,9 @@ func webhookHandler(w http.ResponseWriter, r *http.Request) { ...@@ -93,6 +96,9 @@ func webhookHandler(w http.ResponseWriter, r *http.Request) {
Allowed: true, Allowed: true,
PatchType: &pt, PatchType: &pt,
Patch: []byte(`[{"op": "remove", "path": "/metadata/labels/remove"}]`), Patch: []byte(`[{"op": "remove", "path": "/metadata/labels/remove"}]`),
AuditAnnotations: map[string]string{
"key1": "value1",
},
}, },
}) })
case "/addLabel": case "/addLabel":
...@@ -118,6 +124,16 @@ func webhookHandler(w http.ResponseWriter, r *http.Request) { ...@@ -118,6 +124,16 @@ func webhookHandler(w http.ResponseWriter, r *http.Request) {
case "/nilResponse": case "/nilResponse":
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(&v1beta1.AdmissionReview{}) json.NewEncoder(w).Encode(&v1beta1.AdmissionReview{})
case "/invalidAnnotation":
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(&v1beta1.AdmissionReview{
Response: &v1beta1.AdmissionResponse{
Allowed: true,
AuditAnnotations: map[string]string{
"invalid*key": "value1",
},
},
})
default: default:
http.NotFound(w, r) http.NotFound(w, r)
} }
......
...@@ -36,6 +36,7 @@ go_test( ...@@ -36,6 +36,7 @@ go_test(
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/testing:go_default_library", "//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/testing:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/github.com/stretchr/testify/require:go_default_library", "//vendor/github.com/stretchr/testify/require:go_default_library",
], ],
) )
......
...@@ -23,15 +23,15 @@ import ( ...@@ -23,15 +23,15 @@ import (
"time" "time"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/apiserver/pkg/admission/plugin/webhook/config"
"k8s.io/apiserver/pkg/admission/plugin/webhook/generic"
admissionv1beta1 "k8s.io/api/admission/v1beta1" admissionv1beta1 "k8s.io/api/admission/v1beta1"
"k8s.io/api/admissionregistration/v1beta1" "k8s.io/api/admissionregistration/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
utilruntime "k8s.io/apimachinery/pkg/util/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime"
admissionmetrics "k8s.io/apiserver/pkg/admission/metrics" admissionmetrics "k8s.io/apiserver/pkg/admission/metrics"
"k8s.io/apiserver/pkg/admission/plugin/webhook/config"
webhookerrors "k8s.io/apiserver/pkg/admission/plugin/webhook/errors" webhookerrors "k8s.io/apiserver/pkg/admission/plugin/webhook/errors"
"k8s.io/apiserver/pkg/admission/plugin/webhook/generic"
"k8s.io/apiserver/pkg/admission/plugin/webhook/request" "k8s.io/apiserver/pkg/admission/plugin/webhook/request"
) )
...@@ -116,6 +116,12 @@ func (d *validatingDispatcher) callHook(ctx context.Context, h *v1beta1.Webhook, ...@@ -116,6 +116,12 @@ func (d *validatingDispatcher) callHook(ctx context.Context, h *v1beta1.Webhook,
if response.Response == nil { if response.Response == nil {
return &webhookerrors.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Webhook response was absent")} return &webhookerrors.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Webhook response was absent")}
} }
for k, v := range response.Response.AuditAnnotations {
key := h.Name + "/" + k
if err := attr.AddAnnotation(key, v); err != nil {
glog.Warningf("Failed to set admission audit annotation %s to %s for validating webhook %s: %v", key, v, h.Name, err)
}
}
if response.Response.Allowed { if response.Response.Allowed {
return nil return nil
} }
......
...@@ -21,6 +21,7 @@ import ( ...@@ -21,6 +21,7 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"k8s.io/api/admission/v1beta1" "k8s.io/api/admission/v1beta1"
...@@ -72,7 +73,8 @@ func TestValidate(t *testing.T) { ...@@ -72,7 +73,8 @@ func TestValidate(t *testing.T) {
continue continue
} }
err = wh.Validate(webhooktesting.NewAttribute(ns, nil, tt.IsDryRun)) attr := webhooktesting.NewAttribute(ns, nil, tt.IsDryRun)
err = wh.Validate(attr)
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)
} }
...@@ -85,6 +87,16 @@ func TestValidate(t *testing.T) { ...@@ -85,6 +87,16 @@ func TestValidate(t *testing.T) {
if _, isStatusErr := err.(*errors.StatusError); err != nil && !isStatusErr { if _, isStatusErr := err.(*errors.StatusError); err != nil && !isStatusErr {
t.Errorf("%s: expected a StatusError, got %T", tt.Name, err) t.Errorf("%s: expected a StatusError, got %T", tt.Name, err)
} }
fakeAttr, ok := attr.(*webhooktesting.FakeAttributes)
if !ok {
t.Errorf("Unexpected error, failed to convert attr to webhooktesting.FakeAttributes")
continue
}
if len(tt.ExpectAnnotations) == 0 {
assert.Empty(t, fakeAttr.GetAnnotations(), tt.Name+": annotations not set as expected.")
} else {
assert.Equal(t, tt.ExpectAnnotations, fakeAttr.GetAnnotations(), tt.Name+": annotations not set as expected.")
}
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment