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  }