@@ -21,6 +21,8 @@ const (
2121 defaultCaPath = "/etc/certs/ca.crt"
2222 webhookServiceName = "devbox-server"
2323 devContainerWebhookCfgName = "devcontainer-mutate-webhooks"
24+ imageManagerWebhookCfgName = "imagemanager-mutate-webhooks"
25+ imageManagerWebhookPrefix = "imagemanager-webhook"
2426 mutatingWebhookNamePrefix = "devcontainer-webhook"
2527 helmRelease = "meta.helm.sh/release-name"
2628 helmReleaseNamespace = "meta.helm.sh/release-namespace"
3133 webhookServiceNamespace = & constants .Namespace
3234 webhookPath = "/webhook/devcontainer"
3335 WebhookPort int32 = 8083
36+
37+ imageManagerWebhookPath = "/webhook/imagemanager"
3438 // WebhookServerListenAddress = webhookServiceName + ":" + strconv.Itoa(int(WebhookPort))
3539
3640 // codecs is the codec factory used by the deserialzer
@@ -202,7 +206,150 @@ func (wh *Webhook) DeleteDevContainerMutatingWebhook() error {
202206 return nil
203207}
204208
209+ func (wh * Webhook ) CreateOrUpdateImageManagerMutatingWebhook () error {
210+ failurePolicy := admissionregv1 .Fail
211+ matchPolicy := admissionregv1 .Exact
212+ webhookTimeout := int32 (30 )
213+
214+ caBundle , err := os .ReadFile (defaultCaPath )
215+ if err != nil {
216+ return err
217+ }
218+
219+ mwhLabels := map [string ]string {"velero.io/exclude-from-backup" : "true" }
220+ mwh := admissionregv1.MutatingWebhookConfiguration {
221+ ObjectMeta : metav1.ObjectMeta {
222+ Name : imageManagerWebhookCfgName ,
223+ Labels : mwhLabels ,
224+ },
225+ Webhooks : []admissionregv1.MutatingWebhook {},
226+ }
227+ imwh := admissionregv1.MutatingWebhook {
228+ Name : imageManagerWebhookName (),
229+ ClientConfig : admissionregv1.WebhookClientConfig {
230+ CABundle : caBundle ,
231+ Service : & admissionregv1.ServiceReference {
232+ Namespace : * webhookServiceNamespace ,
233+ Name : webhookServiceName ,
234+ Path : & imageManagerWebhookPath ,
235+ Port : & WebhookPort ,
236+ },
237+ },
238+ FailurePolicy : & failurePolicy ,
239+ MatchPolicy : & matchPolicy ,
240+ Rules : []admissionregv1.RuleWithOperations {
241+ {
242+ Operations : []admissionregv1.OperationType {admissionregv1 .Create },
243+ Rule : admissionregv1.Rule {
244+ APIGroups : []string {"app.bytetrade.io" },
245+ APIVersions : []string {"*" },
246+ Resources : []string {"imagemanagers" },
247+ },
248+ },
249+ },
250+ ObjectSelector : & metav1.LabelSelector {
251+ MatchExpressions : []metav1.LabelSelectorRequirement {
252+ {
253+ Key : constants .DevOwnerLabel ,
254+ Operator : metav1 .LabelSelectorOpIn ,
255+ Values : []string {constants .Owner },
256+ },
257+ },
258+ },
259+ SideEffects : func () * admissionregv1.SideEffectClass {
260+ sideEffect := admissionregv1 .SideEffectClassNoneOnDryRun
261+ return & sideEffect
262+ }(),
263+ TimeoutSeconds : & webhookTimeout ,
264+ AdmissionReviewVersions : []string {"v1" },
265+ }
266+ mwh .Webhooks = append (mwh .Webhooks , imwh )
267+ if _ , err = wh .KubeClient .AdmissionregistrationV1 ().MutatingWebhookConfigurations ().Create (context .TODO (), & mwh , metav1.CreateOptions {}); err != nil {
268+ if apierrors .IsAlreadyExists (err ) {
269+ err = retry .RetryOnConflict (retry .DefaultRetry , func () error {
270+ existing , err := wh .KubeClient .AdmissionregistrationV1 ().MutatingWebhookConfigurations ().Get (context .TODO (), mwh .Name , metav1.GetOptions {})
271+ if err != nil {
272+ klog .Error ("Error getting MutatingWebhookConfiguration " , err )
273+ return err
274+ }
275+ found := false
276+ for i , w := range existing .Webhooks {
277+ if w .Name == imwh .Name {
278+ found = true
279+ existing .Webhooks [i ] = imwh
280+ break
281+ }
282+ }
283+ if ! found {
284+ existing .Webhooks = append (existing .Webhooks , imwh )
285+ }
286+ _ , err = wh .KubeClient .AdmissionregistrationV1 ().MutatingWebhookConfigurations ().Update (context .TODO (), existing , metav1.UpdateOptions {})
287+ if err != nil && ! apierrors .IsConflict (err ) {
288+ klog .Error ("Error updating MutatingWebhookConfiguration " , err )
289+ }
290+ return err
291+ })
292+ if err != nil {
293+ klog .Error ("Error updating MutatingWebhookConfiguration " , err )
294+ return err
295+ }
296+ } else {
297+ klog .Error ("Error creating MutatingWebhookConfiguration " , err )
298+ return err
299+ }
300+ }
301+ klog .Infof ("Finished creating MutatingWebhookConfiguration %s" , imageManagerWebhookCfgName )
302+ return nil
303+ }
304+
305+ func (wh * Webhook ) DeleteImageManagerMutatingWebhook () error {
306+ imwhName := imageManagerWebhookName ()
307+ existing , err := wh .KubeClient .AdmissionregistrationV1 ().MutatingWebhookConfigurations ().Get (context .TODO (), imageManagerWebhookCfgName , metav1.GetOptions {})
308+ if err != nil {
309+ if apierrors .IsNotFound (err ) {
310+ klog .Info ("webhook configuration not found, " , imageManagerWebhookCfgName )
311+ return nil
312+ }
313+ return err
314+ }
315+ for i , w := range existing .Webhooks {
316+ if w .Name == imwhName {
317+ if len (existing .Webhooks ) == 1 {
318+ err = wh .KubeClient .AdmissionregistrationV1 ().MutatingWebhookConfigurations ().Delete (context .TODO (), imageManagerWebhookCfgName , metav1.DeleteOptions {})
319+ if err != nil {
320+ klog .Info ("delete webhook configuration error, " , err )
321+ return err
322+ }
323+ } else {
324+ return retry .RetryOnConflict (retry .DefaultRetry , func () error {
325+ updating , err := wh .KubeClient .AdmissionregistrationV1 ().MutatingWebhookConfigurations ().Get (context .TODO (), imageManagerWebhookCfgName , metav1.GetOptions {})
326+ if err != nil {
327+ if apierrors .IsNotFound (err ) {
328+ klog .Info ("webhook configuration not found, " , imageManagerWebhookCfgName )
329+ return nil
330+ }
331+ return err
332+ }
333+ updating .Webhooks = append (existing .Webhooks [:i ], existing .Webhooks [i + 1 :]... )
334+ klog .Info ("removing the webhook, " , imwhName )
335+ _ , err = wh .KubeClient .AdmissionregistrationV1 ().MutatingWebhookConfigurations ().Update (context .Background (), updating , metav1.UpdateOptions {})
336+ if ! apierrors .IsConflict (err ) {
337+ klog .Error ("Error updating MutatingWebhookConfiguration " , err )
338+ }
339+ return err
340+ })
341+ }
342+ }
343+ }
344+ klog .Infof ("success to clean imagemanager webhook" )
345+ return nil
346+ }
347+
205348func mutatingWebhookName () string {
206349 // should be a domain with at least three segments separated by dots
207350 return mutatingWebhookNamePrefix + "." + constants .Namespace + ".ns"
208351}
352+
353+ func imageManagerWebhookName () string {
354+ return imageManagerWebhookPrefix + "." + constants .Namespace + ".ns"
355+ }
0 commit comments