Skip to content

Commit 613dbc7

Browse files
author
Mengqi Yu
committed
inject client and decoder for webhook
1 parent 069efa2 commit 613dbc7

File tree

17 files changed

+169
-81
lines changed

17 files changed

+169
-81
lines changed

example/main.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ func main() {
8181
Operations(admissionregistrationv1beta1.Create, admissionregistrationv1beta1.Update).
8282
WithManager(mgr).
8383
ForType(&corev1.Pod{}).
84-
Build(&podAnnotator{client: mgr.GetClient(), decoder: mgr.GetAdmissionDecoder()})
84+
Handlers(&podAnnotator{}).
85+
Build()
8586
if err != nil {
8687
entryLog.Error(err, "unable to setup mutating webhook")
8788
os.Exit(1)
@@ -94,7 +95,8 @@ func main() {
9495
Operations(admissionregistrationv1beta1.Create, admissionregistrationv1beta1.Update).
9596
WithManager(mgr).
9697
ForType(&corev1.Pod{}).
97-
Build(&podValidator{client: mgr.GetClient(), decoder: mgr.GetAdmissionDecoder()})
98+
Handlers(&podValidator{}).
99+
Build()
98100
if err != nil {
99101
entryLog.Error(err, "unable to setup validating webhook")
100102
os.Exit(1)

example/mutatingwebhook.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,20 @@ import (
2424
corev1 "k8s.io/api/core/v1"
2525
"sigs.k8s.io/controller-runtime/pkg/client"
2626
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
27+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/types"
2728
)
2829

2930
// podAnnotator annotates Pods
3031
type podAnnotator struct {
3132
client client.Client
32-
decoder admission.Decoder
33+
decoder types.Decoder
3334
}
3435

3536
// Implement admission.Handler so the controller can handle admission request.
3637
var _ admission.Handler = &podAnnotator{}
3738

3839
// podAnnotator adds an annotation to every incoming pods.
39-
func (a *podAnnotator) Handle(ctx context.Context, req admission.Request) admission.Response {
40+
func (a *podAnnotator) Handle(ctx context.Context, req types.Request) types.Response {
4041
pod := &corev1.Pod{}
4142

4243
err := a.decoder.Decode(req, pod)

example/validatingwebhook.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,20 @@ import (
2424
corev1 "k8s.io/api/core/v1"
2525
"sigs.k8s.io/controller-runtime/pkg/client"
2626
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
27+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/types"
2728
)
2829

2930
// podValidator validates Pods
3031
type podValidator struct {
3132
client client.Client
32-
decoder admission.Decoder
33+
decoder types.Decoder
3334
}
3435

3536
// Implement admission.Handler so the controller can handle admission request.
3637
var _ admission.Handler = &podValidator{}
3738

3839
// podValidator admits a pod iff a specific annotation exists.
39-
func (v *podValidator) Handle(ctx context.Context, req admission.Request) admission.Response {
40+
func (v *podValidator) Handle(ctx context.Context, req types.Request) types.Response {
4041
pod := &corev1.Pod{}
4142

4243
err := v.decoder.Decode(req, pod)

pkg/manager/internal.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import (
2828
"sigs.k8s.io/controller-runtime/pkg/recorder"
2929
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
3030
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
31-
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
31+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/types"
3232
)
3333

3434
var log = logf.KBLog.WithName("manager")
@@ -41,7 +41,7 @@ type controllerManager struct {
4141
// to scheme.scheme.
4242
scheme *runtime.Scheme
4343
// admissionDecoder is used to decode an admission.Request.
44-
admissionDecoder admission.Decoder
44+
admissionDecoder types.Decoder
4545

4646
// runnables is the set of Controllers that the controllerManager injects deps into and Starts.
4747
runnables []Runnable
@@ -112,6 +112,9 @@ func (cm *controllerManager) SetFields(i interface{}) error {
112112
if _, err := inject.StopChannelInto(cm.stop, i); err != nil {
113113
return err
114114
}
115+
if _, err := inject.DecoderInto(cm.admissionDecoder, i); err != nil {
116+
return err
117+
}
115118
return nil
116119
}
117120

@@ -127,7 +130,7 @@ func (cm *controllerManager) GetScheme() *runtime.Scheme {
127130
return cm.scheme
128131
}
129132

130-
func (cm *controllerManager) GetAdmissionDecoder() admission.Decoder {
133+
func (cm *controllerManager) GetAdmissionDecoder() types.Decoder {
131134
return cm.admissionDecoder
132135
}
133136

pkg/manager/manager.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
internalrecorder "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
3232
"sigs.k8s.io/controller-runtime/pkg/recorder"
3333
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
34+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/types"
3435
)
3536

3637
// Manager initializes shared dependencies such as Caches and Clients, and provides them to Runnables.
@@ -56,7 +57,7 @@ type Manager interface {
5657
GetScheme() *runtime.Scheme
5758

5859
// GetAdmissionDecoder returns the runtime.Decoder based on the scheme.
59-
GetAdmissionDecoder() admission.Decoder
60+
GetAdmissionDecoder() types.Decoder
6061

6162
// GetClient returns a client configured with the Config
6263
GetClient() client.Client
@@ -95,7 +96,7 @@ type Options struct {
9596
newCache func(config *rest.Config, opts cache.Options) (cache.Cache, error)
9697
newClient func(config *rest.Config, options client.Options) (client.Client, error)
9798
newRecorderProvider func(config *rest.Config, scheme *runtime.Scheme) (recorder.Provider, error)
98-
newAdmissionDecoder func(scheme *runtime.Scheme) (admission.Decoder, error)
99+
newAdmissionDecoder func(scheme *runtime.Scheme) (types.Decoder, error)
99100
}
100101

101102
// Runnable allows a component to be started.

pkg/runtime/inject/inject.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"k8s.io/client-go/rest"
2222
"sigs.k8s.io/controller-runtime/pkg/cache"
2323
"sigs.k8s.io/controller-runtime/pkg/client"
24+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/types"
2425
)
2526

2627
// Cache is used by the ControllerManager to inject Cache into Sources, EventHandlers, Predicates, and
@@ -68,6 +69,21 @@ func ClientInto(client client.Client, i interface{}) (bool, error) {
6869
return false, nil
6970
}
7071

72+
// Decoder is used by the ControllerManager to inject client into Sources, EventHandlers, Predicates, and
73+
// Reconciles
74+
type Decoder interface {
75+
InjectDecoder(types.Decoder) error
76+
}
77+
78+
// DecoderInto will set client on i and return the result if it implements client. Returns
79+
//// false if i does not implement client.
80+
func DecoderInto(decoder types.Decoder, i interface{}) (bool, error) {
81+
if s, ok := i.(Decoder); ok {
82+
return true, s.InjectDecoder(decoder)
83+
}
84+
return false, nil
85+
}
86+
7187
// Scheme is used by the ControllerManager to inject Scheme into Sources, EventHandlers, Predicates, and
7288
// Reconciles
7389
type Scheme interface {

pkg/webhook/admission/builder/builder.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,17 @@ import (
3131

3232
// WebhookBuilder builds a webhook based on the provided options.
3333
type WebhookBuilder struct {
34-
// Name specifies the Name of the webhook. It must be unique in the http
34+
// name specifies the Name of the webhook. It must be unique in the http
3535
// server that serves all the webhooks.
3636
name string
3737

38-
// Path is the URL Path to register this webhook. e.g. "/feature-foo-mutating-pods".
38+
// path is the URL Path to register this webhook. e.g. "/feature-foo-mutating-pods".
3939
path string
4040

41-
// Type specifies the type of the webhook
41+
// handlers are handlers for handling admission request.
42+
handlers []admission.Handler
43+
44+
// t specifies the type of the webhook
4245
t *types.WebhookType
4346
// only one of operations and Rules can be set.
4447
operations []admissionregistrationv1beta1.OperationType
@@ -128,6 +131,12 @@ func (b *WebhookBuilder) WithManager(mgr manager.Manager) *WebhookBuilder {
128131
return b
129132
}
130133

134+
// Handlers sets the handlers of the webhook.
135+
func (b *WebhookBuilder) Handlers(handlers ...admission.Handler) *WebhookBuilder {
136+
b.handlers = handlers
137+
return b
138+
}
139+
131140
func (b *WebhookBuilder) validate() error {
132141
if b.t == nil {
133142
return errors.New("webhook type cannot be nil")
@@ -142,7 +151,7 @@ func (b *WebhookBuilder) validate() error {
142151
}
143152

144153
// Build creates the Webhook based on the options provided.
145-
func (b *WebhookBuilder) Build(handlers ...admission.Handler) (*admission.Webhook, error) {
154+
func (b *WebhookBuilder) Build() (*admission.Webhook, error) {
146155
err := b.validate()
147156
if err != nil {
148157
return nil, err
@@ -153,7 +162,7 @@ func (b *WebhookBuilder) Build(handlers ...admission.Handler) (*admission.Webhoo
153162
Type: *b.t,
154163
FailurePolicy: b.failurePolicy,
155164
NamespaceSelector: b.namespaceSelector,
156-
Handlers: handlers,
165+
Handlers: b.handlers,
157166
}
158167

159168
if len(b.path) == 0 {

pkg/webhook/admission/decode.go

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,16 @@ package admission
1919
import (
2020
"k8s.io/apimachinery/pkg/runtime"
2121
"k8s.io/apimachinery/pkg/runtime/serializer"
22+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/types"
2223
)
2324

24-
// Decoder is used to decode AdmissionRequest.
25-
type Decoder interface {
26-
// Decode decodes the raw byte object from the AdmissionRequest to the passed-in runtime.Object.
27-
Decode(Request, runtime.Object) error
28-
}
29-
3025
// DecodeFunc is a function that implements the Decoder interface.
31-
type DecodeFunc func(Request, runtime.Object) error
26+
type DecodeFunc func(types.Request, runtime.Object) error
3227

33-
var _ Decoder = DecodeFunc(nil)
28+
var _ types.Decoder = DecodeFunc(nil)
3429

3530
// Decode implements the Decoder interface.
36-
func (f DecodeFunc) Decode(req Request, obj runtime.Object) error {
31+
func (f DecodeFunc) Decode(req types.Request, obj runtime.Object) error {
3732
return f(req, obj)
3833
}
3934

@@ -42,12 +37,12 @@ type decoder struct {
4237
}
4338

4439
// NewDecoder creates a Decoder given the runtime.Scheme
45-
func NewDecoder(scheme *runtime.Scheme) (Decoder, error) {
40+
func NewDecoder(scheme *runtime.Scheme) (types.Decoder, error) {
4641
return decoder{codecs: serializer.NewCodecFactory(scheme)}, nil
4742
}
4843

4944
// Decode decodes the inlined object in the AdmissionRequest into the passed-in runtime.Object.
50-
func (d decoder) Decode(req Request, into runtime.Object) error {
45+
func (d decoder) Decode(req types.Request, into runtime.Object) error {
5146
deserializer := d.codecs.UniversalDeserializer()
5247
return runtime.DecodeInto(deserializer, req.AdmissionRequest.Object.Raw, into)
5348
}

pkg/webhook/admission/decode_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ import (
2424
corev1 "k8s.io/api/core/v1"
2525
"k8s.io/apimachinery/pkg/runtime"
2626
"k8s.io/client-go/kubernetes/scheme"
27+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/types"
2728
)
2829

2930
var _ = Describe("admission webhook decoder", func() {
30-
var decoder Decoder
31+
var decoder types.Decoder
3132
BeforeEach(func(done Done) {
3233
var err error
3334
decoder, err = NewDecoder(scheme.Scheme)
@@ -45,7 +46,7 @@ var _ = Describe("admission webhook decoder", func() {
4546
})
4647

4748
Describe("Decode", func() {
48-
req := Request{
49+
req := types.Request{
4950
AdmissionRequest: &admissionv1beta1.AdmissionRequest{
5051
Object: runtime.RawExtension{
5152
Raw: []byte(`{

pkg/webhook/admission/http.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
admissionv1beta1 "k8s.io/api/admission/v1beta1"
3030
"k8s.io/apimachinery/pkg/runtime"
3131
"k8s.io/apimachinery/pkg/runtime/serializer"
32+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/types"
3233
)
3334

3435
var admissionv1beta1scheme = runtime.NewScheme()
@@ -57,7 +58,7 @@ func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
5758
var body []byte
5859
var err error
5960

60-
var reviewResponse Response
61+
var reviewResponse types.Response
6162
if r.Body != nil {
6263
if body, err = ioutil.ReadAll(r.Body); err != nil {
6364
log.Error(err, "unable to read the body from the incoming request")
@@ -96,11 +97,11 @@ func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
9697
for k := range wh.KVMap {
9798
ctx = context.WithValue(ctx, ContextKey(k), wh.KVMap[k])
9899
}
99-
reviewResponse = wh.Handle(ctx, Request{AdmissionRequest: ar.Request})
100+
reviewResponse = wh.Handle(ctx, types.Request{AdmissionRequest: ar.Request})
100101
writeResponse(w, reviewResponse)
101102
}
102103

103-
func writeResponse(w io.Writer, response Response) {
104+
func writeResponse(w io.Writer, response types.Response) {
104105
encoder := json.NewEncoder(w)
105106
responseAdmissionReview := v1beta1.AdmissionReview{
106107
Response: response.Response,

pkg/webhook/admission/http_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
. "github.com/onsi/gomega"
2828

2929
admissionv1beta1 "k8s.io/api/admission/v1beta1"
30+
atypes "sigs.k8s.io/controller-runtime/pkg/webhook/admission/types"
3031
"sigs.k8s.io/controller-runtime/pkg/webhook/types"
3132
)
3233

@@ -154,10 +155,10 @@ func (nopCloser) Close() error { return nil }
154155
type fakeHandler struct {
155156
invoked bool
156157
valueFromContext string
157-
fn func(context.Context, Request) Response
158+
fn func(context.Context, atypes.Request) atypes.Response
158159
}
159160

160-
func (h *fakeHandler) Handle(ctx context.Context, req Request) Response {
161+
func (h *fakeHandler) Handle(ctx context.Context, req atypes.Request) atypes.Response {
161162
v := ctx.Value(ContextKey("foo"))
162163
if v != nil {
163164
typed, ok := v.(string)
@@ -169,7 +170,7 @@ func (h *fakeHandler) Handle(ctx context.Context, req Request) Response {
169170
if h.fn != nil {
170171
return h.fn(ctx, req)
171172
}
172-
return Response{Response: &admissionv1beta1.AdmissionResponse{
173+
return atypes.Response{Response: &admissionv1beta1.AdmissionResponse{
173174
Allowed: true,
174175
}}
175176
}

pkg/webhook/admission/response.go

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,16 @@ package admission
1919
import (
2020
"net/http"
2121

22-
"github.com/mattbaird/jsonpatch"
23-
2422
admissionv1beta1 "k8s.io/api/admission/v1beta1"
2523
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2624
"k8s.io/apimachinery/pkg/runtime"
2725
"sigs.k8s.io/controller-runtime/pkg/patch"
26+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/types"
2827
)
2928

30-
// Response is the output of admission.Handler
31-
type Response struct {
32-
// Patches are the JSON patches for mutating webhooks.
33-
// Using this instead of setting Response.Patch to minimize the overhead of serialization and deserialization.
34-
Patches []jsonpatch.JsonPatchOperation
35-
// Response is the admission response. Don't set the Patch field in it.
36-
Response *admissionv1beta1.AdmissionResponse
37-
}
38-
3929
// ErrorResponse creates a new Response for an error handling the request
40-
func ErrorResponse(code int32, err error) Response {
41-
return Response{
30+
func ErrorResponse(code int32, err error) types.Response {
31+
return types.Response{
4232
Response: &admissionv1beta1.AdmissionResponse{
4333
Allowed: false,
4434
Result: &metav1.Status{
@@ -50,8 +40,8 @@ func ErrorResponse(code int32, err error) Response {
5040
}
5141

5242
// ValidationResponse returns a response for admitting a request
53-
func ValidationResponse(allowed bool, reason string) Response {
54-
resp := Response{
43+
func ValidationResponse(allowed bool, reason string) types.Response {
44+
resp := types.Response{
5545
Response: &admissionv1beta1.AdmissionResponse{
5646
Allowed: allowed,
5747
},
@@ -65,12 +55,12 @@ func ValidationResponse(allowed bool, reason string) Response {
6555
}
6656

6757
// PatchResponse returns a new response with json patch
68-
func PatchResponse(original, current runtime.Object) Response {
58+
func PatchResponse(original, current runtime.Object) types.Response {
6959
patches, err := patch.NewJSONPatch(original, current)
7060
if err != nil {
7161
return ErrorResponse(http.StatusInternalServerError, err)
7262
}
73-
return Response{
63+
return types.Response{
7464
Patches: patches,
7565
Response: &admissionv1beta1.AdmissionResponse{
7666
Allowed: true,

0 commit comments

Comments
 (0)