knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/webhook/resourcesemantics/conversion/reconciler.go (about) 1 /* 2 Copyright 2020 The Knative Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package conversion 18 19 import ( 20 "context" 21 "fmt" 22 23 "go.uber.org/zap" 24 apixv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 25 apixclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" 26 apixlisters "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/apimachinery/pkg/runtime/schema" 29 "k8s.io/apimachinery/pkg/types" 30 corelisters "k8s.io/client-go/listers/core/v1" 31 "knative.dev/pkg/controller" 32 "knative.dev/pkg/kmp" 33 "knative.dev/pkg/logging" 34 "knative.dev/pkg/ptr" 35 pkgreconciler "knative.dev/pkg/reconciler" 36 "knative.dev/pkg/system" 37 "knative.dev/pkg/webhook" 38 certresources "knative.dev/pkg/webhook/certificates/resources" 39 ) 40 41 type reconciler struct { 42 pkgreconciler.LeaderAwareFuncs 43 44 kinds map[schema.GroupKind]GroupKindConversion 45 path string 46 secretName string 47 withContext func(context.Context) context.Context 48 49 secretLister corelisters.SecretLister 50 crdLister apixlisters.CustomResourceDefinitionLister 51 client apixclient.Interface 52 } 53 54 var ( 55 _ webhook.ConversionController = (*reconciler)(nil) 56 _ controller.Reconciler = (*reconciler)(nil) 57 _ pkgreconciler.LeaderAware = (*reconciler)(nil) 58 ) 59 60 // Path implements webhook.ConversionController 61 func (r *reconciler) Path() string { 62 return r.path 63 } 64 65 // Reconciler implements controller.Reconciler 66 func (r *reconciler) Reconcile(ctx context.Context, key string) error { 67 logger := logging.FromContext(ctx) 68 69 if !r.IsLeaderFor(types.NamespacedName{Name: key}) { 70 return controller.NewSkipKey(key) 71 } 72 73 // Look up the webhook secret, and fetch the CA cert bundle. 74 secret, err := r.secretLister.Secrets(system.Namespace()).Get(r.secretName) 75 if err != nil { 76 logger.Errorw("Error fetching secret", zap.Error(err)) 77 return err 78 } 79 80 cacert, ok := secret.Data[certresources.CACert] 81 if !ok { 82 return fmt.Errorf("secret %q is missing %q key", r.secretName, certresources.CACert) 83 } 84 85 return r.reconcileCRD(ctx, cacert, key) 86 } 87 88 func (r *reconciler) reconcileCRD(ctx context.Context, cacert []byte, key string) error { 89 logger := logging.FromContext(ctx) 90 91 configuredCRD, err := r.crdLister.Get(key) 92 if err != nil { 93 return fmt.Errorf("error retrieving crd: %w", err) 94 } 95 96 crd := configuredCRD.DeepCopy() 97 98 if crd.Spec.Conversion == nil || 99 crd.Spec.Conversion.Strategy != apixv1.WebhookConverter || 100 crd.Spec.Conversion.Webhook.ClientConfig == nil || 101 crd.Spec.Conversion.Webhook.ClientConfig.Service == nil { 102 return fmt.Errorf("custom resource %q isn't configured for webhook conversion", key) 103 } 104 105 crd.Spec.Conversion.Webhook.ClientConfig.CABundle = cacert 106 crd.Spec.Conversion.Webhook.ClientConfig.Service.Path = ptr.String(r.path) 107 108 if ok, err := kmp.SafeEqual(configuredCRD, crd); err != nil { 109 return fmt.Errorf("error diffing custom resource definitions: %w", err) 110 } else if !ok { 111 logger.Infof("updating CRD") 112 crdClient := r.client.ApiextensionsV1().CustomResourceDefinitions() 113 if _, err := crdClient.Update(ctx, crd, metav1.UpdateOptions{}); err != nil { 114 return fmt.Errorf("failed to update webhook: %w", err) 115 } 116 } else { 117 logger.Info("CRD is up to date") 118 } 119 120 return nil 121 }