github.com/cilium/cilium@v1.16.2/pkg/clustermesh/mcsapi/cell.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package mcsapi
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  
    11  	"github.com/cilium/hive/cell"
    12  	"github.com/sirupsen/logrus"
    13  	"github.com/spf13/pflag"
    14  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    15  	"k8s.io/apimachinery/pkg/runtime"
    16  	"k8s.io/apimachinery/pkg/runtime/schema"
    17  	ctrlRuntime "sigs.k8s.io/controller-runtime"
    18  	mcsapiv1alpha1 "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1"
    19  	mcsapicontrollers "sigs.k8s.io/mcs-api/pkg/controllers"
    20  
    21  	"github.com/cilium/cilium/pkg/clustermesh/common"
    22  	"github.com/cilium/cilium/pkg/clustermesh/types"
    23  	k8sClient "github.com/cilium/cilium/pkg/k8s/client"
    24  )
    25  
    26  var Cell = cell.Module(
    27  	"mcsapi",
    28  	"Multi-Cluster Services API",
    29  	cell.Config(MCSAPIConfig{}),
    30  	cell.Invoke(initMCSAPIController),
    31  )
    32  
    33  type mcsAPIParams struct {
    34  	cell.In
    35  
    36  	common.Config
    37  	Cfg MCSAPIConfig
    38  
    39  	// ClusterInfo is the id/name of the local cluster.
    40  	ClusterInfo types.ClusterInfo
    41  
    42  	Clientset          k8sClient.Clientset
    43  	CtrlRuntimeManager ctrlRuntime.Manager
    44  	Scheme             *runtime.Scheme
    45  
    46  	Logger logrus.FieldLogger
    47  }
    48  
    49  type MCSAPIConfig struct {
    50  	// ClusterMeshEnableEndpointSync enables the MCS API support
    51  	ClusterMeshEnableMCSAPI bool `mapstructure:"clustermesh-enable-mcs-api"`
    52  }
    53  
    54  // Flags adds the flags used by ClientConfig.
    55  func (cfg MCSAPIConfig) Flags(flags *pflag.FlagSet) {
    56  	flags.BoolVar(&cfg.ClusterMeshEnableMCSAPI,
    57  		"clustermesh-enable-mcs-api",
    58  		false,
    59  		"Whether or not the MCS API support is enabled.",
    60  	)
    61  }
    62  
    63  var requiredGVK = []schema.GroupVersionKind{
    64  	mcsapiv1alpha1.SchemeGroupVersion.WithKind("serviceimports"),
    65  	mcsapiv1alpha1.SchemeGroupVersion.WithKind("serviceexports"),
    66  }
    67  
    68  func checkCRD(ctx context.Context, clientset k8sClient.Clientset, gvk schema.GroupVersionKind) error {
    69  	if !clientset.IsEnabled() {
    70  		return nil
    71  	}
    72  
    73  	crd, err := clientset.ApiextensionsV1().CustomResourceDefinitions().Get(ctx, gvk.GroupKind().String(), metav1.GetOptions{})
    74  	if err != nil {
    75  		return err
    76  	}
    77  
    78  	found := false
    79  	for _, v := range crd.Spec.Versions {
    80  		if v.Name == gvk.Version {
    81  			found = true
    82  			break
    83  		}
    84  	}
    85  	if !found {
    86  		return fmt.Errorf("CRD %q does not have version %q", gvk.GroupKind().String(), gvk.Version)
    87  	}
    88  
    89  	return nil
    90  }
    91  
    92  func checkRequiredCRDs(ctx context.Context, clientset k8sClient.Clientset) error {
    93  	var res error
    94  	for _, gvk := range requiredGVK {
    95  		if err := checkCRD(ctx, clientset, gvk); err != nil {
    96  			res = errors.Join(res, err)
    97  		}
    98  	}
    99  	return res
   100  }
   101  
   102  func initMCSAPIController(params mcsAPIParams) error {
   103  	if !params.Clientset.IsEnabled() || params.ClusterMeshConfig == "" || !params.Cfg.ClusterMeshEnableMCSAPI {
   104  		return nil
   105  	}
   106  
   107  	params.Logger.WithField("requiredGVK", requiredGVK).Info("Checking for required MCS-API resources")
   108  	if err := checkRequiredCRDs(context.Background(), params.Clientset); err != nil {
   109  		params.Logger.WithError(err).Error("Required MCS-API resources are not found, please refer to docs for installation instructions")
   110  		return err
   111  	}
   112  	if err := mcsapiv1alpha1.AddToScheme(params.Scheme); err != nil {
   113  		return err
   114  	}
   115  
   116  	if err := newMCSAPIServiceReconciler(params.CtrlRuntimeManager, params.Logger, params.ClusterInfo.Name).SetupWithManager(params.CtrlRuntimeManager); err != nil {
   117  		return fmt.Errorf("Failed to register MCSAPIServiceReconciler: %w", err)
   118  	}
   119  
   120  	// Upstream controller that we use as is to update the ServiceImport
   121  	// objects with the IPs of the derived Services.
   122  	svcReconciler := mcsapicontrollers.ServiceReconciler{
   123  		Client: params.CtrlRuntimeManager.GetClient(),
   124  		Log:    params.CtrlRuntimeManager.GetLogger(),
   125  	}
   126  	if err := svcReconciler.SetupWithManager(params.CtrlRuntimeManager); err != nil {
   127  		return fmt.Errorf("Failed to register mcsapicontrollers.ServiceReconciler: %w", err)
   128  	}
   129  
   130  	params.Logger.Info("Multi-Cluster Services API support enabled")
   131  	return nil
   132  }