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 }