Skip to content

Commit fabe80d

Browse files
author
Mengqi Yu
committed
drop KVMap, cleanup godoc and tweak defaulting
1 parent 3657798 commit fabe80d

12 files changed

+120
-145
lines changed

example/main.go

-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ func main() {
102102
as, err := webhook.NewServer("foo-admission-server", mgr, webhook.ServerOptions{
103103
Port: 9876,
104104
CertDir: "/tmp/cert",
105-
KVMap: map[string]interface{}{"foo": "bar"},
106105
BootstrapOptions: &webhook.BootstrapOptions{
107106
Secret: &apitypes.NamespacedName{
108107
Namespace: "default",

example/mutatingwebhook.go

+26-12
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ package main
1818

1919
import (
2020
"context"
21-
"fmt"
2221
"net/http"
2322

2423
corev1 "k8s.io/api/core/v1"
2524
"sigs.k8s.io/controller-runtime/pkg/client"
25+
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
2626
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
2727
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/types"
2828
)
@@ -46,24 +46,38 @@ func (a *podAnnotator) Handle(ctx context.Context, req types.Request) types.Resp
4646
}
4747
copy := pod.DeepCopy()
4848

49-
err = mutatePodsFn(ctx, copy)
49+
err = a.mutatePodsFn(ctx, copy)
5050
if err != nil {
5151
return admission.ErrorResponse(http.StatusInternalServerError, err)
5252
}
5353
return admission.PatchResponse(pod, copy)
5454
}
5555

5656
// mutatePodsFn add an annotation to the given pod
57-
func mutatePodsFn(ctx context.Context, pod *corev1.Pod) error {
58-
v, ok := ctx.Value(admission.StringKey("foo")).(string)
59-
if !ok {
60-
return fmt.Errorf("the value associated with %v is expected to be a string", "foo")
57+
func (a *podAnnotator) mutatePodsFn(ctx context.Context, pod *corev1.Pod) error {
58+
if pod.Annotations == nil {
59+
pod.Annotations = map[string]string{}
6160
}
62-
anno := pod.Annotations
63-
if anno == nil {
64-
anno = map[string]string{}
65-
}
66-
anno["example-mutating-admission-webhook"] = v
67-
pod.Annotations = anno
61+
pod.Annotations["example-mutating-admission-webhook"] = "foo"
62+
return nil
63+
}
64+
65+
// podValidator implements inject.Client.
66+
// A client will be automatically injected.
67+
var _ inject.Client = &podValidator{}
68+
69+
// InjectClient injects the client.
70+
func (v *podAnnotator) InjectClient(c client.Client) error {
71+
v.client = c
72+
return nil
73+
}
74+
75+
// podValidator implements inject.Decoder.
76+
// A decoder will be automatically injected.
77+
var _ inject.Decoder = &podValidator{}
78+
79+
// InjectDecoder injects the decoder.
80+
func (v *podAnnotator) InjectDecoder(d types.Decoder) error {
81+
v.decoder = d
6882
return nil
6983
}

example/validatingwebhook.go

+27-12
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
corev1 "k8s.io/api/core/v1"
2525
"sigs.k8s.io/controller-runtime/pkg/client"
26+
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
2627
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
2728
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/types"
2829
)
@@ -45,30 +46,44 @@ func (v *podValidator) Handle(ctx context.Context, req types.Request) types.Resp
4546
return admission.ErrorResponse(http.StatusBadRequest, err)
4647
}
4748

48-
allowed, reason, err := validatePodsFn(ctx, pod)
49+
allowed, reason, err := v.validatePodsFn(ctx, pod)
4950
if err != nil {
5051
return admission.ErrorResponse(http.StatusInternalServerError, err)
5152
}
5253
return admission.ValidationResponse(allowed, reason)
5354
}
5455

55-
func validatePodsFn(ctx context.Context, pod *corev1.Pod) (bool, string, error) {
56-
v, ok := ctx.Value(admission.StringKey("foo")).(string)
57-
if !ok {
58-
return false, "",
59-
fmt.Errorf("the value associated with key %q is expected to be a string", v)
60-
}
61-
annotations := pod.GetAnnotations()
56+
func (v *podValidator) validatePodsFn(ctx context.Context, pod *corev1.Pod) (bool, string, error) {
6257
key := "example-mutating-admission-webhook"
63-
anno, found := annotations[key]
58+
anno, found := pod.Annotations[key]
6459
switch {
6560
case !found:
6661
return found, fmt.Sprintf("failed to find annotation with key: %q", key), nil
67-
case found && anno == v:
62+
case found && anno == "foo":
6863
return found, "", nil
69-
case found && anno != v:
64+
case found && anno != "foo":
7065
return false,
71-
fmt.Sprintf("the value associate with key %q is expected to be %q, but got %q", "foo", v, anno), nil
66+
fmt.Sprintf("the value associate with key %q is expected to be %q, but got %q", key, "foo", anno), nil
7267
}
7368
return false, "", nil
7469
}
70+
71+
// podValidator implements inject.Client.
72+
// A client will be automatically injected.
73+
var _ inject.Client = &podValidator{}
74+
75+
// InjectClient injects the client.
76+
func (v *podValidator) InjectClient(c client.Client) error {
77+
v.client = c
78+
return nil
79+
}
80+
81+
// podValidator implements inject.Decoder.
82+
// A decoder will be automatically injected.
83+
var _ inject.Decoder = &podValidator{}
84+
85+
// InjectDecoder injects the decoder.
86+
func (v *podValidator) InjectDecoder(d types.Decoder) error {
87+
v.decoder = d
88+
return nil
89+
}

pkg/webhook/admission/builder/builder.go

+26-25
Original file line numberDiff line numberDiff line change
@@ -31,33 +31,40 @@ 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
35-
// server that serves all the webhooks.
34+
// name specifies the name of the webhook. It must be unique among all webhooks.
3635
name string
3736

38-
// path is the URL Path to register this webhook. e.g. "/feature-foo-mutating-pods".
37+
// path is the URL Path to register this webhook. e.g. "/mutate-pods".
3938
path string
4039

41-
// handlers are handlers for handling admission request.
40+
// handlers handle admission requests.
41+
// A WebhookBuilder may have multiple handlers.
42+
// For example, handlers[0] mutates a pod for feature foo.
43+
// handlers[1] mutates a pod for a different feature bar.
4244
handlers []admission.Handler
4345

44-
// t specifies the type of the webhook
46+
// t specifies the type of the webhook.
47+
// Currently, Mutating and Validating are supported.
4548
t *types.WebhookType
49+
50+
// operations define the operations this webhook cares.
4651
// only one of operations and Rules can be set.
4752
operations []admissionregistrationv1beta1.OperationType
48-
49-
// resources that this webhook cares.
53+
// apiType represents the resource that this webhook cares.
5054
// Only one of apiType and Rules can be set.
5155
apiType runtime.Object
52-
rules []admissionregistrationv1beta1.RuleWithOperations
56+
// rules contain a list of admissionregistrationv1beta1.RuleWithOperations
57+
// It overrides operations and apiType.
58+
rules []admissionregistrationv1beta1.RuleWithOperations
5359

54-
// This field maps to the FailurePolicy in the admissionregistrationv1beta1.Webhook
60+
// failurePolicy maps to the FailurePolicy in the admissionregistrationv1beta1.Webhook
5561
failurePolicy *admissionregistrationv1beta1.FailurePolicyType
5662

57-
// This field maps to the NamespaceSelector in the admissionregistrationv1beta1.Webhook
63+
// namespaceSelector maps to the NamespaceSelector in the admissionregistrationv1beta1.Webhook
5864
namespaceSelector *metav1.LabelSelector
5965

6066
// manager is the manager for the webhook.
67+
// It is used for provisioning various dependencies for the webhook. e.g. RESTMapper.
6168
manager manager.Manager
6269
}
6370

@@ -66,7 +73,7 @@ func NewWebhookBuilder() *WebhookBuilder {
6673
return &WebhookBuilder{}
6774
}
6875

69-
// Name sets the Name of the webhook.
76+
// Name sets the name of the webhook.
7077
// This is optional
7178
func (b *WebhookBuilder) Name(name string) *WebhookBuilder {
7279
b.name = name
@@ -89,8 +96,11 @@ func (b *WebhookBuilder) Validating() *WebhookBuilder {
8996
return b
9097
}
9198

92-
// Path sets the Path for the webhook.
93-
// This is optional
99+
// Path sets the path for the webhook.
100+
// Path needs to be unique among different webhooks.
101+
// This is optional. If not set, it will be built from the type and resource name.
102+
// For example, a webhook that mutates pods has a default path of "/mutate-pods"
103+
// If the defaulting logic can't find a unique path for it, user need to set it manually.
94104
func (b *WebhookBuilder) Path(path string) *WebhookBuilder {
95105
b.path = path
96106
return b
@@ -105,15 +115,15 @@ func (b *WebhookBuilder) Operations(ops ...admissionregistrationv1beta1.Operatio
105115
}
106116

107117
// ForType sets the type of resources that the webhook will operate.
108-
// This cannot be use with Rules.
118+
// It will be overridden by Rules if Rules are not empty.
109119
func (b *WebhookBuilder) ForType(obj runtime.Object) *WebhookBuilder {
110120
b.apiType = obj
111121
return b
112122
}
113123

114124
// Rules sets the RuleWithOperations for the webhook.
115125
// It overrides ForType and Operations.
116-
// This is optional and for advanced user
126+
// This is optional and for advanced user.
117127
func (b *WebhookBuilder) Rules(rules ...admissionregistrationv1beta1.RuleWithOperations) *WebhookBuilder {
118128
b.rules = rules
119129
return b
@@ -134,7 +144,7 @@ func (b *WebhookBuilder) NamespaceSelector(namespaceSelector *metav1.LabelSelect
134144
return b
135145
}
136146

137-
// WithManager set the manager for the webhook for provisioning client etc.
147+
// WithManager set the manager for the webhook for provisioning various dependencies. e.g. client etc.
138148
func (b *WebhookBuilder) WithManager(mgr manager.Manager) *WebhookBuilder {
139149
b.manager = mgr
140150
return b
@@ -208,14 +218,5 @@ func (b *WebhookBuilder) Build() (*admission.Webhook, error) {
208218
}
209219
}
210220

211-
if len(b.path) == 0 {
212-
if *b.t == types.WebhookTypeMutating {
213-
b.path = "/mutate-" + w.Rules[0].Resources[0]
214-
} else if *b.t == types.WebhookTypeValidating {
215-
b.path = "/validate-" + w.Rules[0].Resources[0]
216-
}
217-
}
218-
w.Path = b.path
219-
220221
return w, nil
221222
}

pkg/webhook/admission/http.go

+3-15
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+
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
3233
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/types"
3334
)
3435

@@ -40,20 +41,11 @@ func init() {
4041
}
4142

4243
func addToScheme(scheme *runtime.Scheme) {
43-
err := admissionv1beta1.AddToScheme(scheme)
44-
// TODO: switch to use Must in
45-
// https://github.com/kubernetes/kubernetes/blob/fbb2dfcc6ad345b0ca3fe09cb4bc2a23ec0781d5/staging/src/k8s.io/apimachinery/pkg/util/runtime/runtime.go#L164-L169
46-
// after the apimachinery repo in vendor has been updated to 1.11 or later.
47-
if err != nil {
48-
panic(err)
49-
}
44+
utilruntime.Must(admissionv1beta1.AddToScheme(scheme))
5045
}
5146

5247
var _ http.Handler = &Webhook{}
5348

54-
// ContextKey is a type alias of string and is used as the key in context.
55-
type ContextKey string
56-
5749
func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
5850
var body []byte
5951
var err error
@@ -93,11 +85,7 @@ func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
9385
}
9486

9587
// TODO: add panic-recovery for Handle
96-
ctx := context.Background()
97-
for k := range wh.KVMap {
98-
ctx = context.WithValue(ctx, ContextKey(k), wh.KVMap[k])
99-
}
100-
reviewResponse = wh.Handle(ctx, types.Request{AdmissionRequest: ar.Request})
88+
reviewResponse = wh.Handle(context.Background(), types.Request{AdmissionRequest: ar.Request})
10189
writeResponse(w, reviewResponse)
10290
}
10391

pkg/webhook/admission/http_test.go

+2-12
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,13 @@ var _ = Describe("admission webhook http handler", func() {
133133
wh := &Webhook{
134134
Type: types.WebhookTypeValidating,
135135
Handlers: []Handler{h},
136-
KVMap: map[string]interface{}{"foo": "bar"},
137136
}
138137
expected := []byte(`{"response":{"uid":"","allowed":true}}
139138
`)
140139
It("should return a response successfully", func() {
141140
wh.ServeHTTP(w, req)
142141
Expect(w.Body.Bytes()).To(Equal(expected))
143142
Expect(h.invoked).To(BeTrue())
144-
Expect(h.valueFromContext).To(Equal("bar"))
145143
})
146144
})
147145
})
@@ -153,19 +151,11 @@ type nopCloser struct {
153151
func (nopCloser) Close() error { return nil }
154152

155153
type fakeHandler struct {
156-
invoked bool
157-
valueFromContext string
158-
fn func(context.Context, atypes.Request) atypes.Response
154+
invoked bool
155+
fn func(context.Context, atypes.Request) atypes.Response
159156
}
160157

161158
func (h *fakeHandler) Handle(ctx context.Context, req atypes.Request) atypes.Response {
162-
v := ctx.Value(ContextKey("foo"))
163-
if v != nil {
164-
typed, ok := v.(string)
165-
if ok {
166-
h.valueFromContext = typed
167-
}
168-
}
169159
h.invoked = true
170160
if h.fn != nil {
171161
return h.fn(ctx, req)

pkg/webhook/admission/response.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import (
2626
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/types"
2727
)
2828

29-
// ErrorResponse creates a new Response for an error handling the request
29+
// ErrorResponse creates a new Response for error-handling a request.
3030
func ErrorResponse(code int32, err error) types.Response {
3131
return types.Response{
3232
Response: &admissionv1beta1.AdmissionResponse{
@@ -39,7 +39,7 @@ func ErrorResponse(code int32, err error) types.Response {
3939
}
4040
}
4141

42-
// ValidationResponse returns a response for admitting a request
42+
// ValidationResponse returns a response for admitting a request.
4343
func ValidationResponse(allowed bool, reason string) types.Response {
4444
resp := types.Response{
4545
Response: &admissionv1beta1.AdmissionResponse{
@@ -54,7 +54,7 @@ func ValidationResponse(allowed bool, reason string) types.Response {
5454
return resp
5555
}
5656

57-
// PatchResponse returns a new response with json patch
57+
// PatchResponse returns a new response with json patch.
5858
func PatchResponse(original, current runtime.Object) types.Response {
5959
patches, err := patch.NewJSONPatch(original, current)
6060
if err != nil {

0 commit comments

Comments
 (0)