@@ -19,12 +19,17 @@ package main
19
19
import (
20
20
"context"
21
21
"flag"
22
+ "fmt"
23
+ "net/http"
22
24
"os"
23
25
24
26
"github.com/go-logr/logr"
27
+
28
+ admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
25
29
appsv1 "k8s.io/api/apps/v1"
26
30
corev1 "k8s.io/api/core/v1"
27
31
"k8s.io/apimachinery/pkg/api/errors"
32
+ apitypes "k8s.io/apimachinery/pkg/types"
28
33
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
29
34
"sigs.k8s.io/controller-runtime/pkg/client"
30
35
"sigs.k8s.io/controller-runtime/pkg/client/config"
@@ -35,11 +40,13 @@ import (
35
40
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
36
41
"sigs.k8s.io/controller-runtime/pkg/runtime/signals"
37
42
"sigs.k8s.io/controller-runtime/pkg/source"
43
+ "sigs.k8s.io/controller-runtime/pkg/webhook"
44
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
45
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission/builder"
46
+ "sigs.k8s.io/controller-runtime/pkg/webhook/types"
38
47
)
39
48
40
- var (
41
- log = logf .Log .WithName ("example-controller" )
42
- )
49
+ var log = logf .Log .WithName ("example-controller" )
43
50
44
51
func main () {
45
52
flag .Parse ()
@@ -75,6 +82,64 @@ func main() {
75
82
os .Exit (1 )
76
83
}
77
84
85
+ // Setup webhooks
86
+ mutatingWebhook , err := builder .NewWebhookBuilder ().
87
+ Name ("mutating.k8s.io" ).
88
+ Type (types .WebhookTypeMutating ).
89
+ Path ("/mutating-pods" ).
90
+ Operations (admissionregistrationv1beta1 .Create , admissionregistrationv1beta1 .Update ).
91
+ WithManager (mgr ).
92
+ ForType (& corev1.Pod {}).
93
+ Build (& podAnnotator {client : mgr .GetClient (), decoder : mgr .GetAdmissionDecoder ()})
94
+ if err != nil {
95
+ entryLog .Error (err , "unable to setup mutating webhook" )
96
+ os .Exit (1 )
97
+ }
98
+
99
+ validatingWebhook , err := builder .NewWebhookBuilder ().
100
+ Name ("validating.k8s.io" ).
101
+ Type (types .WebhookTypeValidating ).
102
+ Path ("/validating-pods" ).
103
+ Operations (admissionregistrationv1beta1 .Create , admissionregistrationv1beta1 .Update ).
104
+ WithManager (mgr ).
105
+ ForType (& corev1.Pod {}).
106
+ Build (& podValidator {client : mgr .GetClient (), decoder : mgr .GetAdmissionDecoder ()})
107
+ if err != nil {
108
+ entryLog .Error (err , "unable to setup validating webhook" )
109
+ os .Exit (1 )
110
+ }
111
+
112
+ as , err := webhook .NewServer ("foo-admission-server" , mgr , webhook.ServerOptions {
113
+ Port : 443 ,
114
+ CertDir : "/tmp/cert" ,
115
+ Client : mgr .GetClient (),
116
+ KVMap : map [string ]interface {}{"foo" : "bar" },
117
+ BootstrapOptions : & webhook.BootstrapOptions {
118
+ Secret : & apitypes.NamespacedName {
119
+ Namespace : "default" ,
120
+ Name : "foo-admission-server-secret" ,
121
+ },
122
+
123
+ Service : & apitypes.NamespacedName {
124
+ Namespace : "default" ,
125
+ Name : "foo-admission-server-service" ,
126
+ },
127
+ // Labels should select the pods that runs this webhook server.
128
+ Labels : map [string ]string {
129
+ "app" : "foo-admission-server" ,
130
+ },
131
+ },
132
+ })
133
+ if err != nil {
134
+ entryLog .Error (err , "unable to create a new webhook server" )
135
+ os .Exit (1 )
136
+ }
137
+ err = as .Register (mutatingWebhook , validatingWebhook )
138
+ if err != nil {
139
+ entryLog .Error (err , "unable to register webhooks in the admission server" )
140
+ os .Exit (1 )
141
+ }
142
+
78
143
if err := mgr .Start (signals .SetupSignalHandler ()); err != nil {
79
144
entryLog .Error (err , "unable to run manager" )
80
145
os .Exit (1 )
@@ -83,6 +148,7 @@ func main() {
83
148
84
149
// reconcileReplicaSet reconciles ReplicaSets
85
150
type reconcileReplicaSet struct {
151
+ // client can be used to retrieve objects from the APIServer.
86
152
client client.Client
87
153
log logr.Logger
88
154
}
@@ -128,3 +194,73 @@ func (r *reconcileReplicaSet) Reconcile(request reconcile.Request) (reconcile.Re
128
194
129
195
return reconcile.Result {}, nil
130
196
}
197
+
198
+ // podAnnotator annotates Pods
199
+ type podAnnotator struct {
200
+ client client.Client
201
+ decoder admission.Decoder
202
+ }
203
+
204
+ // Implement admission.Handler so the controller can handle admission request.
205
+ var _ admission.Handler = & podAnnotator {}
206
+
207
+ // podAnnotator adds an annotation to every incoming pods.
208
+ func (a * podAnnotator ) Handle (_ context.Context , req admission.Request ) admission.Response {
209
+ pod := & corev1.Pod {}
210
+
211
+ err := a .decoder .Decode (req , pod )
212
+ if err != nil {
213
+ return admission .ErrorResponse (http .StatusBadRequest , err )
214
+ }
215
+ copy := pod .DeepCopy ()
216
+
217
+ err = mutatePodsFn (copy )
218
+ if err != nil {
219
+ return admission .ErrorResponse (http .StatusInternalServerError , err )
220
+ }
221
+ return admission .PatchResponse (pod , copy )
222
+ }
223
+
224
+ // mutatePodsFn add an annotation to the given pod
225
+ func mutatePodsFn (pod * corev1.Pod ) error {
226
+ anno := pod .GetAnnotations ()
227
+ anno ["example-mutating-admission-webhhok" ] = "foo"
228
+ pod .SetAnnotations (anno )
229
+ return nil
230
+ }
231
+
232
+ // podValidator validates Pods
233
+ type podValidator struct {
234
+ client client.Client
235
+ decoder admission.Decoder
236
+ }
237
+
238
+ // Implement admission.Handler so the controller can handle admission request.
239
+ var _ admission.Handler = & podValidator {}
240
+
241
+ // podValidator admits a pod iff a specific annotation exists.
242
+ func (v * podValidator ) Handle (_ context.Context , req admission.Request ) admission.Response {
243
+ pod := & corev1.Pod {}
244
+
245
+ err := v .decoder .Decode (req , pod )
246
+ if err != nil {
247
+ return admission .ErrorResponse (http .StatusBadRequest , err )
248
+ }
249
+
250
+ allowed , reason , err := validatePodsFn (pod )
251
+ if err != nil {
252
+ return admission .ErrorResponse (http .StatusInternalServerError , err )
253
+ }
254
+ return admission .ValidationResponse (allowed , reason )
255
+ }
256
+
257
+ func validatePodsFn (pod * corev1.Pod ) (bool , string , error ) {
258
+ anno := pod .GetAnnotations ()
259
+ key := "example-mutating-admission-webhhok"
260
+ _ , found := anno [key ]
261
+ if found {
262
+ return found , "" , nil
263
+ } else {
264
+ return found , fmt .Sprintf ("failed to find annotation with key: %v" , key ), nil
265
+ }
266
+ }
0 commit comments