1
16
17 package admission
18
19 import (
20 "context"
21
22 . "github.com/onsi/ginkgo/v2"
23 . "github.com/onsi/gomega"
24
25 jsonpatch "gomodules.xyz/jsonpatch/v2"
26 admissionv1 "k8s.io/api/admission/v1"
27 )
28
29 var _ = Describe("Multi-Handler Admission Webhooks", func() {
30 alwaysAllow := &fakeHandler{
31 fn: func(ctx context.Context, req Request) Response {
32 return Response{
33 AdmissionResponse: admissionv1.AdmissionResponse{
34 Allowed: true,
35 },
36 }
37 },
38 }
39 alwaysDeny := &fakeHandler{
40 fn: func(ctx context.Context, req Request) Response {
41 return Response{
42 AdmissionResponse: admissionv1.AdmissionResponse{
43 Allowed: false,
44 },
45 }
46 },
47 }
48
49 Context("with validating handlers", func() {
50 It("should deny the request if any handler denies the request", func() {
51 By("setting up a handler with accept and deny")
52 handler := MultiValidatingHandler(alwaysAllow, alwaysDeny)
53
54 By("checking that the handler denies the request")
55 resp := handler.Handle(context.Background(), Request{})
56 Expect(resp.Allowed).To(BeFalse())
57 })
58
59 It("should allow the request if all handlers allow the request", func() {
60 By("setting up a handler with only accept")
61 handler := MultiValidatingHandler(alwaysAllow, alwaysAllow)
62
63 By("checking that the handler allows the request")
64 resp := handler.Handle(context.Background(), Request{})
65 Expect(resp.Allowed).To(BeTrue())
66 })
67 })
68
69 Context("with mutating handlers", func() {
70 patcher1 := &fakeHandler{
71 fn: func(ctx context.Context, req Request) Response {
72 return Response{
73 Patches: []jsonpatch.JsonPatchOperation{
74 {
75 Operation: "add",
76 Path: "/metadata/annotation/new-key",
77 Value: "new-value",
78 },
79 {
80 Operation: "replace",
81 Path: "/spec/replicas",
82 Value: "2",
83 },
84 },
85 AdmissionResponse: admissionv1.AdmissionResponse{
86 Allowed: true,
87 PatchType: func() *admissionv1.PatchType { pt := admissionv1.PatchTypeJSONPatch; return &pt }(),
88 },
89 }
90 },
91 }
92 patcher2 := &fakeHandler{
93 fn: func(ctx context.Context, req Request) Response {
94 return Response{
95 Patches: []jsonpatch.JsonPatchOperation{
96 {
97 Operation: "add",
98 Path: "/metadata/annotation/hello",
99 Value: "world",
100 },
101 },
102 AdmissionResponse: admissionv1.AdmissionResponse{
103 Allowed: true,
104 PatchType: func() *admissionv1.PatchType { pt := admissionv1.PatchTypeJSONPatch; return &pt }(),
105 },
106 }
107 },
108 }
109
110 It("should not return any patches if the request is denied", func() {
111 By("setting up a webhook with some patches and a deny")
112 handler := MultiMutatingHandler(patcher1, patcher2, alwaysDeny)
113
114 By("checking that the handler denies the request and produces no patches")
115 resp := handler.Handle(context.Background(), Request{})
116 Expect(resp.Allowed).To(BeFalse())
117 Expect(resp.Patches).To(BeEmpty())
118 })
119
120 It("should produce all patches if the requests are all allowed", func() {
121 By("setting up a webhook with some patches")
122 handler := MultiMutatingHandler(patcher1, patcher2, alwaysAllow)
123
124 By("checking that the handler accepts the request and returns all patches")
125 resp := handler.Handle(context.Background(), Request{})
126 Expect(resp.Allowed).To(BeTrue())
127 Expect(resp.Patch).To(Equal([]byte(
128 `[{"op":"add","path":"/metadata/annotation/new-key","value":"new-value"},` +
129 `{"op":"replace","path":"/spec/replicas","value":"2"},{"op":"add","path":"/metadata/annotation/hello","value":"world"}]`)))
130 })
131 })
132 })
133
View as plain text