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  }