github.com/percona/percona-xtradb-cluster-operator@v1.14.0/cmd/manager/main.go (about) 1 package main 2 3 import ( 4 "flag" 5 "os" 6 "runtime" 7 "strconv" 8 "strings" 9 10 "k8s.io/klog/v2" 11 12 certmgrscheme "github.com/cert-manager/cert-manager/pkg/client/clientset/versioned/scheme" 13 "github.com/go-logr/logr" 14 uzap "go.uber.org/zap" 15 "go.uber.org/zap/zapcore" 16 k8sruntime "k8s.io/apimachinery/pkg/runtime" 17 clientgoscheme "k8s.io/client-go/kubernetes/scheme" 18 _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" 19 ctrl "sigs.k8s.io/controller-runtime" 20 "sigs.k8s.io/controller-runtime/pkg/cache" 21 "sigs.k8s.io/controller-runtime/pkg/healthz" 22 "sigs.k8s.io/controller-runtime/pkg/log/zap" 23 metricsServer "sigs.k8s.io/controller-runtime/pkg/metrics/server" 24 ctrlWebhook "sigs.k8s.io/controller-runtime/pkg/webhook" 25 26 _ "github.com/Percona-Lab/percona-version-service/api" 27 "github.com/percona/percona-xtradb-cluster-operator/pkg/apis" 28 "github.com/percona/percona-xtradb-cluster-operator/pkg/controller" 29 "github.com/percona/percona-xtradb-cluster-operator/pkg/k8s" 30 "github.com/percona/percona-xtradb-cluster-operator/pkg/webhook" 31 "github.com/percona/percona-xtradb-cluster-operator/version" 32 ) 33 34 var ( 35 GitCommit string 36 GitBranch string 37 BuildTime string 38 scheme = k8sruntime.NewScheme() 39 setupLog = ctrl.Log.WithName("setup") 40 ) 41 42 func main() { 43 var metricsAddr string 44 var enableLeaderElection bool 45 var probeAddr string 46 47 flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") 48 flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") 49 flag.BoolVar(&enableLeaderElection, "leader-elect", true, 50 "Enable leader election for controller manager. "+ 51 "Enabling this will ensure there is only one active controller manager.") 52 53 opts := zap.Options{ 54 Encoder: getLogEncoder(setupLog), 55 Level: getLogLevel(setupLog), 56 } 57 opts.BindFlags(flag.CommandLine) 58 flag.Parse() 59 60 // The logger instantiated here can be changed to any logger 61 // implementing the logr.Logger interface. This logger will 62 // be propagated through the whole operator, generating 63 // uniform and structured logs. 64 ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) 65 klog.SetLogger(ctrl.Log) 66 67 sv, err := version.Server() 68 if err != nil { 69 setupLog.Error(err, "unable to define server version") 70 os.Exit(1) 71 } 72 setupLog.Info("Runs on", "platform", sv.Platform, "version", sv.Info) 73 74 setupLog.Info("Manager starting up", "gitCommit", GitCommit, "gitBranch", GitBranch, 75 "buildTime", BuildTime, "goVersion", runtime.Version(), "os", runtime.GOOS, "arch", runtime.GOARCH) 76 77 namespace, err := k8s.GetWatchNamespace() 78 if err != nil { 79 setupLog.Error(err, "failed to get watch namespace") 80 os.Exit(1) 81 } 82 operatorNamespace, err := k8s.GetOperatorNamespace() 83 if err != nil { 84 setupLog.Error(err, "failed to get operators' namespace") 85 os.Exit(1) 86 } 87 88 options := ctrl.Options{ 89 Scheme: scheme, 90 Metrics: metricsServer.Options{ 91 BindAddress: metricsAddr, 92 }, 93 HealthProbeBindAddress: probeAddr, 94 LeaderElection: enableLeaderElection, 95 LeaderElectionID: "08db1feb.percona.com", 96 WebhookServer: ctrlWebhook.NewServer(ctrlWebhook.Options{ 97 Port: 9443, 98 }), 99 } 100 101 // Add support for MultiNamespace set in WATCH_NAMESPACE 102 if len(namespace) > 0 { 103 namespaces := make(map[string]cache.Config) 104 for _, ns := range append(strings.Split(namespace, ","), operatorNamespace) { 105 namespaces[ns] = cache.Config{} 106 } 107 options.Cache.DefaultNamespaces = namespaces 108 } 109 110 // Get a config to talk to the apiserver 111 config, err := ctrl.GetConfig() 112 if err != nil { 113 setupLog.Error(err, "") 114 os.Exit(1) 115 } 116 117 mgr, err := ctrl.NewManager(config, options) 118 if err != nil { 119 setupLog.Error(err, "unable to start manager") 120 os.Exit(1) 121 } 122 123 setupLog.Info("Registering Components.") 124 125 // Setup Scheme for k8s resources 126 if err := clientgoscheme.AddToScheme(mgr.GetScheme()); err != nil { 127 setupLog.Error(err, "") 128 os.Exit(1) 129 } 130 131 // Setup Scheme for PXC resources 132 if err := apis.AddToScheme(mgr.GetScheme()); err != nil { 133 setupLog.Error(err, "") 134 os.Exit(1) 135 } 136 137 // Setup Scheme for cert-manager resources 138 if err := certmgrscheme.AddToScheme(mgr.GetScheme()); err != nil { 139 setupLog.Error(err, "") 140 os.Exit(1) 141 } 142 143 // Setup all Controllers 144 if err := controller.AddToManager(mgr); err != nil { 145 setupLog.Error(err, "") 146 os.Exit(1) 147 } 148 149 err = webhook.SetupWebhook(mgr) 150 if err != nil { 151 setupLog.Error(err, "set up validation webhook") 152 os.Exit(1) 153 } 154 155 if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { 156 setupLog.Error(err, "unable to set up health check") 157 os.Exit(1) 158 } 159 160 if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { 161 setupLog.Error(err, "unable to set up ready check") 162 os.Exit(1) 163 } 164 165 setupLog.Info("Starting the Cmd.") 166 167 ctx := k8s.StartStopSignalHandler(mgr.GetClient(), strings.Split(namespace, ",")) 168 169 // Start the Cmd 170 if err := mgr.Start(ctx); err != nil { 171 setupLog.Error(err, "manager exited non-zero") 172 os.Exit(1) 173 } 174 } 175 176 func getLogEncoder(log logr.Logger) zapcore.Encoder { 177 consoleEnc := zapcore.NewConsoleEncoder(uzap.NewDevelopmentEncoderConfig()) 178 179 s, found := os.LookupEnv("LOG_STRUCTURED") 180 if !found { 181 return consoleEnc 182 } 183 184 useJson, err := strconv.ParseBool(s) 185 if err != nil { 186 log.Info("Can't parse LOG_STRUCTURED env var, using console logger", "envVar", s) 187 return consoleEnc 188 } 189 if !useJson { 190 return consoleEnc 191 } 192 193 return zapcore.NewJSONEncoder(uzap.NewProductionEncoderConfig()) 194 } 195 196 func getLogLevel(log logr.Logger) zapcore.LevelEnabler { 197 l, found := os.LookupEnv("LOG_LEVEL") 198 if !found { 199 return zapcore.InfoLevel 200 } 201 202 switch strings.ToUpper(l) { 203 case "DEBUG": 204 return zapcore.DebugLevel 205 case "INFO": 206 return zapcore.InfoLevel 207 case "ERROR": 208 return zapcore.ErrorLevel 209 default: 210 log.Info("Unsupported log level", "level", l) 211 return zapcore.InfoLevel 212 } 213 }