github.com/verrazzano/verrazzano@v1.7.0/platform-operator/internal/operatorinit/run_webhook.go (about) 1 // Copyright (c) 2022, 2023, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package operatorinit 5 6 import ( 7 "fmt" 8 "os" 9 10 "github.com/verrazzano/verrazzano/pkg/bom" 11 "github.com/verrazzano/verrazzano/pkg/constants" 12 "github.com/verrazzano/verrazzano/pkg/k8sutil" 13 installv1alpha1 "github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1alpha1" 14 installv1beta1 "github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1beta1" 15 "github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/webhooks" 16 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/validator" 17 internalconfig "github.com/verrazzano/verrazzano/platform-operator/internal/config" 18 "github.com/verrazzano/verrazzano/platform-operator/internal/k8s/certificate" 19 "github.com/verrazzano/verrazzano/platform-operator/internal/k8s/netpolicy" 20 21 "github.com/pkg/errors" 22 "go.uber.org/zap" 23 apiextensionsv1client "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1" 24 "k8s.io/apimachinery/pkg/runtime" 25 "k8s.io/client-go/dynamic" 26 "k8s.io/client-go/kubernetes" 27 "k8s.io/client-go/rest" 28 ctrl "sigs.k8s.io/controller-runtime" 29 "sigs.k8s.io/controller-runtime/pkg/client" 30 "sigs.k8s.io/controller-runtime/pkg/manager" 31 "sigs.k8s.io/controller-runtime/pkg/webhook" 32 ) 33 34 // WebhookInit Webhook init container entry point 35 func WebhookInit(config internalconfig.OperatorConfig, log *zap.SugaredLogger) error { 36 log.Debug("Creating certificates used by webhooks") 37 38 conf, err := k8sutil.GetConfigFromController() 39 if err != nil { 40 return err 41 } 42 43 kubeClient, err := kubernetes.NewForConfig(conf) 44 if err != nil { 45 return err 46 } 47 48 // Create the webhook certificates and secrets 49 if err := certificate.CreateWebhookCertificates(log, kubeClient, config.CertDir); err != nil { 50 return err 51 } 52 53 return nil 54 } 55 56 // StartWebhookServers Webhook startup entry point 57 func StartWebhookServers(config internalconfig.OperatorConfig, log *zap.SugaredLogger, scheme *runtime.Scheme) error { 58 log.Debug("Creating certificates used by webhooks") 59 60 mgr, err := ctrl.NewManager(k8sutil.GetConfigOrDieFromController(), ctrl.Options{ 61 Scheme: scheme, 62 MetricsBindAddress: config.MetricsAddr, 63 Port: 9443, 64 LeaderElection: config.LeaderElectionEnabled, 65 LeaderElectionNamespace: constants.VerrazzanoInstallNamespace, 66 LeaderElectionID: "3ec4d295.verrazzano.io", 67 }) 68 if err != nil { 69 return fmt.Errorf("Error creating controller runtime manager: %v", err) 70 } 71 72 if err := updateWebhooks(log, mgr, config); err != nil { 73 return err 74 } 75 76 installv1alpha1.SetComponentValidator(validator.ComponentValidatorImpl{}) 77 installv1beta1.SetComponentValidator(validator.ComponentValidatorImpl{}) 78 79 // +kubebuilder:scaffold:builder 80 log.Info("Starting webhook controller-runtime manager") 81 if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { 82 return fmt.Errorf("Failed starting webhook controller-runtime manager: %v", err) 83 } 84 return nil 85 } 86 87 // updateWebhooks Updates the webhook configurations and sets up the controllerruntime Manager for the webhook 88 func updateWebhooks(log *zap.SugaredLogger, mgr manager.Manager, config internalconfig.OperatorConfig) error { 89 log.Infof("Start called for pod %s", os.Getenv("HOSTNAME")) 90 conf, err := k8sutil.GetConfigFromController() 91 if err != nil { 92 return fmt.Errorf("Failed to get kubeconfig: %v", err) 93 } 94 95 kubeClient, err := kubernetes.NewForConfig(conf) 96 if err != nil { 97 return fmt.Errorf("Failed to get clientset: %v", err) 98 } 99 dynamicClient, err := dynamic.NewForConfig(conf) 100 if err != nil { 101 return fmt.Errorf("Failed to create Kubernetes dynamic client: %v", err) 102 } 103 104 if err := updateWebhookConfigurations(kubeClient, log, conf, config); err != nil { 105 return err 106 } 107 if err := createOrUpdateNetworkPolicies(conf, log, kubeClient); err != nil { 108 return err 109 } 110 if err := setupWebhooksWithManager(log, mgr, kubeClient, dynamicClient, config); err != nil { 111 return err 112 } 113 return nil 114 } 115 116 // setupWebhooksWithManager Sets up the webhook with the controllerruntime Manager instance 117 func setupWebhooksWithManager(log *zap.SugaredLogger, mgr manager.Manager, kubeClient *kubernetes.Clientset, dynamicClient dynamic.Interface, config internalconfig.OperatorConfig) error { 118 // Setup the validation webhook 119 log.Debug("Setting up Verrazzano webhook with manager") 120 if err := (&installv1alpha1.Verrazzano{}).SetupWebhookWithManager(mgr, log); err != nil { 121 return fmt.Errorf("Failed to setup install.v1alpha1.Verrazzano webhook with manager: %v", err) 122 } 123 if err := (&installv1beta1.Verrazzano{}).SetupWebhookWithManager(mgr, log); err != nil { 124 return fmt.Errorf("Failed to setup install.v1beta1.Verrazzano webhook with manager: %v", err) 125 } 126 127 mgr.GetWebhookServer().CertDir = config.CertDir 128 129 // register MySQL backup job mutating webhook 130 mgr.GetWebhookServer().Register( 131 constants.MysqlBackupMutatingWebhookPath, 132 &webhook.Admission{ 133 Handler: &webhooks.MySQLBackupJobWebhook{ 134 Client: mgr.GetClient(), 135 KubeClient: kubeClient, 136 DynamicClient: dynamicClient, 137 Defaulters: []webhooks.MySQLDefaulter{}, 138 }, 139 }, 140 ) 141 142 // register requirements validator webhooks. 143 mgr.GetWebhookServer().Register(webhooks.RequirementsV1beta1Path, &webhook.Admission{Handler: &webhooks.RequirementsValidatorV1beta1{}}) 144 mgr.GetWebhookServer().Register(webhooks.RequirementsV1alpha1Path, &webhook.Admission{Handler: &webhooks.RequirementsValidatorV1alpha1{}}) 145 146 // register MySQL install values webhooks 147 bomFile, err := bom.NewBom(internalconfig.GetDefaultBOMFilePath()) 148 if err != nil { 149 return err 150 } 151 mgr.GetWebhookServer().Register(webhooks.MysqlInstallValuesV1beta1path, &webhook.Admission{Handler: &webhooks.MysqlValuesValidatorV1beta1{BomVersion: bomFile.GetVersion()}}) 152 mgr.GetWebhookServer().Register(webhooks.MysqlInstallValuesV1alpha1path, &webhook.Admission{Handler: &webhooks.MysqlValuesValidatorV1alpha1{BomVersion: bomFile.GetVersion()}}) 153 154 return nil 155 } 156 157 // updateWebhookConfigurations Creates or updates the webhook configurations as needed 158 func updateWebhookConfigurations(kubeClient *kubernetes.Clientset, log *zap.SugaredLogger, conf *rest.Config, operatorConfig internalconfig.OperatorConfig) error { 159 log.Debug("Delete old VPO webhook configuration") 160 if err := deleteValidatingWebhookConfiguration(kubeClient, certificate.OldOperatorName); err != nil { 161 return fmt.Errorf("Failed to delete old webhook configuration: %v", err) 162 } 163 164 log.Debug("Updating VPO webhook configuration") 165 166 if err := updateValidatingWebhookConfiguration(kubeClient, certificate.OperatorName); err != nil { 167 return fmt.Errorf("Failed to update validation webhook configuration: %v", err) 168 } 169 170 log.Debug("Updating conversion webhook") 171 apixClient, err := apiextensionsv1client.NewForConfig(conf) 172 if err != nil { 173 return fmt.Errorf("Failed to get apix clientset: %v", err) 174 } 175 176 if err := updateConversionWebhookConfiguration(apixClient, kubeClient); err != nil { 177 return fmt.Errorf("Failed to update conversion webhook: %v", err) 178 } 179 180 if err := updateMutatingWebhookConfiguration(kubeClient, constants.MysqlBackupMutatingWebhookName); err != nil { 181 return fmt.Errorf("Failed to update pod mutating webhook configuration: %v", err) 182 } 183 184 log.Debug("Updating Requirements webhook configuration") 185 if err := updateValidatingWebhookConfiguration(kubeClient, webhooks.RequirementsWebhook); err != nil { 186 return fmt.Errorf("Failed to update requirements validation webhook configuration: %v", err) 187 } 188 189 log.Debug("Updating MySQL install values webhook configuration") 190 if err := updateValidatingWebhookConfiguration(kubeClient, webhooks.MysqlInstallValuesWebhook); err != nil { 191 return fmt.Errorf("Failed to update validation webhook configuration: %v", err) 192 } 193 194 return nil 195 } 196 197 // createOrUpdateNetworkPolicies Create or update the network policies required by the operator and webhooks 198 func createOrUpdateNetworkPolicies(conf *rest.Config, log *zap.SugaredLogger, kubeClient *kubernetes.Clientset) error { 199 c, err := client.New(conf, client.Options{}) 200 if err != nil { 201 return errors.Wrap(err, "Failed to get controller-runtime client") 202 } 203 204 log.Debug("Creating or updating network policies") 205 var netPolErrors []error 206 _, netPolErrors = netpolicy.CreateOrUpdateNetworkPolicies(kubeClient, c) 207 if len(netPolErrors) > 0 { 208 // Seems like this could make for an unreadable set of errors; may need to revisit 209 return fmt.Errorf("Failed to create or update network policies: %v", netPolErrors) 210 } 211 return nil 212 }