github.com/k8snetworkplumbingwg/sriov-network-operator@v1.2.1-0.20240408194816-2d2e5a45d453/main.go (about)

     1  /*
     2  Copyright 2021.
     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 main
    18  
    19  import (
    20  	"context"
    21  	"flag"
    22  	"os"
    23  
    24  	// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
    25  	// to ensure that exec-entrypoint and run can make use of them.
    26  	netattdefv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
    27  	openshiftconfigv1 "github.com/openshift/api/config/v1"
    28  	mcfgv1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1"
    29  
    30  	// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
    31  	// to ensure that exec-entrypoint and run can make use of them.
    32  	// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
    33  	_ "k8s.io/client-go/plugin/pkg/client/auth"
    34  
    35  	corev1 "k8s.io/api/core/v1"
    36  	"k8s.io/apimachinery/pkg/runtime"
    37  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    38  	"k8s.io/client-go/kubernetes"
    39  	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
    40  	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
    41  	ctrl "sigs.k8s.io/controller-runtime"
    42  	"sigs.k8s.io/controller-runtime/pkg/cache"
    43  	"sigs.k8s.io/controller-runtime/pkg/client"
    44  	"sigs.k8s.io/controller-runtime/pkg/healthz"
    45  	"sigs.k8s.io/controller-runtime/pkg/metrics/server"
    46  	"sigs.k8s.io/controller-runtime/pkg/webhook"
    47  
    48  	sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
    49  	"github.com/k8snetworkplumbingwg/sriov-network-operator/controllers"
    50  	"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/featuregate"
    51  	"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/leaderelection"
    52  
    53  	snolog "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/log"
    54  	"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/platforms"
    55  	"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/utils"
    56  	"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars"
    57  	//+kubebuilder:scaffold:imports
    58  )
    59  
    60  var (
    61  	scheme   = runtime.NewScheme()
    62  	setupLog = ctrl.Log.WithName("setup")
    63  )
    64  
    65  func init() {
    66  	utilruntime.Must(clientgoscheme.AddToScheme(scheme))
    67  
    68  	utilruntime.Must(sriovnetworkv1.AddToScheme(scheme))
    69  	utilruntime.Must(netattdefv1.AddToScheme(scheme))
    70  	utilruntime.Must(mcfgv1.AddToScheme(scheme))
    71  	utilruntime.Must(openshiftconfigv1.AddToScheme(scheme))
    72  	//+kubebuilder:scaffold:scheme
    73  }
    74  
    75  func main() {
    76  	var metricsAddr string
    77  	var enableLeaderElection bool
    78  	var probeAddr string
    79  
    80  	flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
    81  	flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
    82  	flag.BoolVar(&enableLeaderElection, "leader-elect", false,
    83  		"Enable leader election for controller manager. "+
    84  			"Enabling this will ensure there is only one active controller manager.")
    85  	snolog.BindFlags(flag.CommandLine)
    86  	flag.Parse()
    87  	snolog.InitLog()
    88  
    89  	restConfig := ctrl.GetConfigOrDie()
    90  
    91  	kubeClient, err := client.New(restConfig, client.Options{Scheme: scheme})
    92  	if err != nil {
    93  		setupLog.Error(err, "couldn't create client")
    94  		os.Exit(1)
    95  	}
    96  
    97  	if vars.ResourcePrefix == "" {
    98  		setupLog.Error(nil, "RESOURCE_PREFIX environment variable can't be empty")
    99  		os.Exit(1)
   100  	}
   101  
   102  	le := leaderelection.GetLeaderElectionConfig(kubeClient, enableLeaderElection)
   103  
   104  	mgr, err := ctrl.NewManager(restConfig, ctrl.Options{
   105  		Scheme:                 scheme,
   106  		Metrics:                server.Options{BindAddress: metricsAddr},
   107  		WebhookServer:          webhook.NewServer(webhook.Options{Port: 9443}),
   108  		HealthProbeBindAddress: probeAddr,
   109  		LeaderElection:         enableLeaderElection,
   110  		LeaseDuration:          &le.LeaseDuration,
   111  		RenewDeadline:          &le.RenewDeadline,
   112  		RetryPeriod:            &le.RetryPeriod,
   113  		LeaderElectionID:       "a56def2a.openshift.io",
   114  		Cache:                  cache.Options{DefaultNamespaces: map[string]cache.Config{vars.Namespace: {}}},
   115  	})
   116  	if err != nil {
   117  		setupLog.Error(err, "unable to start manager")
   118  		os.Exit(1)
   119  	}
   120  	mgrGlobal, err := ctrl.NewManager(restConfig, ctrl.Options{
   121  		Scheme:  scheme,
   122  		Metrics: server.Options{BindAddress: "0"},
   123  	})
   124  	if err != nil {
   125  		setupLog.Error(err, "unable to start global manager")
   126  		os.Exit(1)
   127  	}
   128  
   129  	err = mgrGlobal.GetCache().IndexField(context.Background(), &sriovnetworkv1.SriovNetwork{}, "spec.networkNamespace", func(o client.Object) []string {
   130  		return []string{o.(*sriovnetworkv1.SriovNetwork).Spec.NetworkNamespace}
   131  	})
   132  	if err != nil {
   133  		setupLog.Error(err, "unable to create index field for cache")
   134  		os.Exit(1)
   135  	}
   136  
   137  	err = mgrGlobal.GetCache().IndexField(context.Background(), &sriovnetworkv1.SriovIBNetwork{}, "spec.networkNamespace", func(o client.Object) []string {
   138  		return []string{o.(*sriovnetworkv1.SriovIBNetwork).Spec.NetworkNamespace}
   139  	})
   140  	if err != nil {
   141  		setupLog.Error(err, "unable to create index field for cache")
   142  		os.Exit(1)
   143  	}
   144  
   145  	if err := initNicIDMap(); err != nil {
   146  		setupLog.Error(err, "unable to init NicIdMap")
   147  		os.Exit(1)
   148  	}
   149  
   150  	// Initial global info
   151  	vars.Config = restConfig
   152  	vars.Scheme = mgrGlobal.GetScheme()
   153  
   154  	platformsHelper, err := platforms.NewDefaultPlatformHelper()
   155  	if err != nil {
   156  		setupLog.Error(err, "couldn't create openshift context")
   157  		os.Exit(1)
   158  	}
   159  
   160  	featureGate := featuregate.New()
   161  
   162  	if err = (&controllers.SriovNetworkReconciler{
   163  		Client: mgrGlobal.GetClient(),
   164  		Scheme: mgrGlobal.GetScheme(),
   165  	}).SetupWithManager(mgrGlobal); err != nil {
   166  		setupLog.Error(err, "unable to create controller", "controller", "SriovNetwork")
   167  		os.Exit(1)
   168  	}
   169  	if err = (&controllers.SriovIBNetworkReconciler{
   170  		Client: mgrGlobal.GetClient(),
   171  		Scheme: mgrGlobal.GetScheme(),
   172  	}).SetupWithManager(mgrGlobal); err != nil {
   173  		setupLog.Error(err, "unable to create controller", "controller", "SriovIBNetwork")
   174  		os.Exit(1)
   175  	}
   176  	if err = (&controllers.SriovNetworkNodePolicyReconciler{
   177  		Client:      mgr.GetClient(),
   178  		Scheme:      mgr.GetScheme(),
   179  		FeatureGate: featureGate,
   180  	}).SetupWithManager(mgr); err != nil {
   181  		setupLog.Error(err, "unable to create controller", "controller", "SriovNetworkNodePolicy")
   182  		os.Exit(1)
   183  	}
   184  	if err = (&controllers.SriovOperatorConfigReconciler{
   185  		Client:         mgr.GetClient(),
   186  		Scheme:         mgr.GetScheme(),
   187  		PlatformHelper: platformsHelper,
   188  		FeatureGate:    featureGate,
   189  	}).SetupWithManager(mgr); err != nil {
   190  		setupLog.Error(err, "unable to create controller", "controller", "SriovOperatorConfig")
   191  		os.Exit(1)
   192  	}
   193  	if err = (&controllers.SriovNetworkPoolConfigReconciler{
   194  		Client:         mgr.GetClient(),
   195  		Scheme:         mgr.GetScheme(),
   196  		PlatformHelper: platformsHelper,
   197  	}).SetupWithManager(mgr); err != nil {
   198  		setupLog.Error(err, "unable to create controller", "controller", "SriovNetworkPoolConfig")
   199  		os.Exit(1)
   200  	}
   201  
   202  	// we need a client that doesn't use the local cache for the objects
   203  	drainKClient, err := client.New(restConfig, client.Options{
   204  		Scheme: scheme,
   205  		Cache: &client.CacheOptions{
   206  			DisableFor: []client.Object{
   207  				&sriovnetworkv1.SriovNetworkNodeState{},
   208  				&corev1.Node{},
   209  				&mcfgv1.MachineConfigPool{},
   210  			},
   211  		},
   212  	})
   213  	if err != nil {
   214  		setupLog.Error(err, "unable to create drain kubernetes client")
   215  		os.Exit(1)
   216  	}
   217  
   218  	drainController, err := controllers.NewDrainReconcileController(drainKClient,
   219  		mgr.GetScheme(),
   220  		mgr.GetEventRecorderFor("SR-IOV operator"),
   221  		platformsHelper)
   222  	if err != nil {
   223  		setupLog.Error(err, "unable to create controller", "controller", "DrainReconcile")
   224  		os.Exit(1)
   225  	}
   226  
   227  	if err = drainController.SetupWithManager(mgr); err != nil {
   228  		setupLog.Error(err, "unable to setup controller with manager", "controller", "DrainReconcile")
   229  		os.Exit(1)
   230  	}
   231  	// +kubebuilder:scaffold:builder
   232  
   233  	if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
   234  		setupLog.Error(err, "unable to set up health check")
   235  		os.Exit(1)
   236  	}
   237  	if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
   238  		setupLog.Error(err, "unable to set up ready check")
   239  		os.Exit(1)
   240  	}
   241  
   242  	stopCh := ctrl.SetupSignalHandler()
   243  	go func() {
   244  		if err := mgrGlobal.Start(stopCh); err != nil {
   245  			setupLog.Error(err, "Manager Global exited non-zero")
   246  			os.Exit(1)
   247  		}
   248  	}()
   249  
   250  	// Remove all finalizers after controller is shut down
   251  	defer utils.Shutdown()
   252  
   253  	setupLog.Info("starting manager")
   254  	if err := mgr.Start(stopCh); err != nil {
   255  		setupLog.Error(err, "problem running manager")
   256  		os.Exit(1)
   257  	}
   258  }
   259  
   260  func initNicIDMap() error {
   261  	kubeclient := kubernetes.NewForConfigOrDie(ctrl.GetConfigOrDie())
   262  	if err := sriovnetworkv1.InitNicIDMapFromConfigMap(kubeclient, vars.Namespace); err != nil {
   263  		return err
   264  	}
   265  
   266  	return nil
   267  }