github.com/operator-framework/operator-lifecycle-manager@v0.30.0/cmd/olm/main.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"flag"
     6  	"fmt"
     7  	"net/http"
     8  	"os"
     9  	"strings"
    10  	"time"
    11  
    12  	configclientset "github.com/openshift/client-go/config/clientset/versioned"
    13  	configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
    14  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/validatingroundtripper"
    15  	"github.com/sirupsen/logrus"
    16  	"github.com/spf13/pflag"
    17  	corev1 "k8s.io/api/core/v1"
    18  	"k8s.io/client-go/metadata"
    19  	"k8s.io/klog"
    20  	ctrl "sigs.k8s.io/controller-runtime"
    21  
    22  	"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
    23  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm"
    24  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/openshift"
    25  	"github.com/operator-framework/operator-lifecycle-manager/pkg/feature"
    26  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
    27  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorstatus"
    28  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer"
    29  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/server"
    30  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/signals"
    31  	"github.com/operator-framework/operator-lifecycle-manager/pkg/metrics"
    32  	olmversion "github.com/operator-framework/operator-lifecycle-manager/pkg/version"
    33  )
    34  
    35  const (
    36  	defaultWakeupInterval          = 5 * time.Minute
    37  	defaultOperatorName            = ""
    38  	defaultPackageServerStatusName = ""
    39  )
    40  
    41  // config flags defined globally so that they appear on the test binary as well
    42  var (
    43  	wakeupInterval = pflag.Duration(
    44  		"interval", defaultWakeupInterval, "wake up interval")
    45  
    46  	watchedNamespaces = pflag.String(
    47  		"watchedNamespaces", "", "comma separated list of namespaces for olm operator to watch. "+
    48  			"If not set, or set to the empty string (e.g. `-watchedNamespaces=\"\"`), "+
    49  			"olm operator will watch all namespaces in the cluster.")
    50  
    51  	writeStatusName = pflag.String(
    52  		"writeStatusName", defaultOperatorName, "ClusterOperator name in which to write status, set to \"\" to disable.")
    53  
    54  	writePackageServerStatusName = pflag.String(
    55  		"writePackageServerStatusName", defaultPackageServerStatusName, "ClusterOperator name in which to write status for package API server, set to \"\" to disable.")
    56  
    57  	debug = pflag.Bool(
    58  		"debug", false, "use debug log level")
    59  
    60  	version = pflag.Bool("version", false, "displays olm version")
    61  
    62  	tlsKeyPath = pflag.String(
    63  		"tls-key", "", "Path to use for private key (requires tls-cert)")
    64  
    65  	protectedCopiedCSVNamespaces = pflag.String("protectedCopiedCSVNamespaces",
    66  		"", "A comma-delimited set of namespaces where global Copied CSVs will always appear, even if Copied CSVs are disabled")
    67  
    68  	tlsCertPath = pflag.String(
    69  		"tls-cert", "", "Path to use for certificate key (requires tls-key)")
    70  
    71  	_ = pflag.Bool("profiling", false, "deprecated")
    72  
    73  	clientCAPath = pflag.String("client-ca", "", "path to watch for client ca bundle")
    74  
    75  	namespace = pflag.String(
    76  		"namespace", "", "namespace where cleanup runs")
    77  )
    78  
    79  func init() {
    80  	metrics.RegisterOLM()
    81  
    82  	// Add feature gates before parsing
    83  	feature.AddFlag(pflag.CommandLine)
    84  }
    85  
    86  // main function - entrypoint to OLM operator
    87  func main() {
    88  	// Get exit signal context
    89  	ctx, cancel := context.WithCancel(signals.Context())
    90  	defer cancel()
    91  
    92  	klogFlags := flag.NewFlagSet("klog", flag.ExitOnError)
    93  	klog.InitFlags(klogFlags)
    94  
    95  	pflag.Parse()
    96  
    97  	// Parse the command-line flags.
    98  
    99  	// Check if version flag was set
   100  	if *version {
   101  		fmt.Print(olmversion.String())
   102  
   103  		// Exit early
   104  		os.Exit(0)
   105  	}
   106  
   107  	// `namespaces` will always contain at least one entry: if `*watchedNamespaces` is
   108  	// the empty string, the resulting array will be `[]string{""}`.
   109  	namespaces := strings.Split(*watchedNamespaces, ",")
   110  	for _, ns := range namespaces {
   111  		if ns == corev1.NamespaceAll {
   112  			namespaces = []string{corev1.NamespaceAll}
   113  			break
   114  		}
   115  	}
   116  
   117  	// Set log level to debug if `debug` flag set
   118  	logger := logrus.New()
   119  	if *debug {
   120  		logger.SetLevel(logrus.DebugLevel)
   121  		klogVerbosity := klogFlags.Lookup("v")
   122  		klogVerbosity.Value.Set("99")
   123  	}
   124  	logger.Infof("log level %s", logger.Level)
   125  
   126  	listenAndServe, err := server.GetListenAndServeFunc(server.WithLogger(logger), server.WithTLS(tlsCertPath, tlsKeyPath, clientCAPath), server.WithDebug(*debug))
   127  	if err != nil {
   128  		logger.Fatalf("Error setting up health/metric/pprof service: %v", err)
   129  	}
   130  
   131  	go func() {
   132  		if err := listenAndServe(); err != nil && err != http.ErrServerClosed {
   133  			logger.Error(err)
   134  		}
   135  	}()
   136  
   137  	mgr, err := Manager(ctx, *debug)
   138  	if err != nil {
   139  		logger.WithError(err).Fatal("error configuring controller manager")
   140  	}
   141  	config := mgr.GetConfig()
   142  
   143  	// create a config that validates we're creating objects with labels
   144  	validatingConfig := validatingroundtripper.Wrap(config)
   145  
   146  	versionedConfigClient, err := configclientset.NewForConfig(config)
   147  	if err != nil {
   148  		logger.WithError(err).Fatal("error configuring openshift proxy client")
   149  	}
   150  	configClient, err := configv1client.NewForConfig(config)
   151  	if err != nil {
   152  		logger.WithError(err).Fatal("error configuring config client")
   153  	}
   154  	opClient, err := operatorclient.NewClientFromRestConfig(validatingConfig)
   155  	if err != nil {
   156  		logger.WithError(err).Fatal("error configuring operator client")
   157  	}
   158  	crClient, err := versioned.NewForConfig(config)
   159  	if err != nil {
   160  		logger.WithError(err).Fatal("error configuring custom resource client")
   161  	}
   162  	metadataClient, err := metadata.NewForConfig(config)
   163  	if err != nil {
   164  		logger.WithError(err).Fatal("error configuring metadata client")
   165  	}
   166  
   167  	// Create a new instance of the operator.
   168  	op, err := olm.NewOperator(
   169  		ctx,
   170  		olm.WithLogger(logger),
   171  		olm.WithWatchedNamespaces(namespaces...),
   172  		olm.WithResyncPeriod(queueinformer.ResyncWithJitter(*wakeupInterval, 0.2)),
   173  		olm.WithExternalClient(crClient),
   174  		olm.WithMetadataClient(metadataClient),
   175  		olm.WithOperatorClient(opClient),
   176  		olm.WithRestConfig(validatingConfig),
   177  		olm.WithConfigClient(versionedConfigClient),
   178  		olm.WithProtectedCopiedCSVNamespaces(*protectedCopiedCSVNamespaces),
   179  	)
   180  	if err != nil {
   181  		logger.WithError(err).Fatal("error configuring operator")
   182  		return
   183  	}
   184  
   185  	op.Run(ctx)
   186  	<-op.Ready()
   187  
   188  	// Emit CSV metric
   189  	if err = op.EnsureCSVMetric(); err != nil {
   190  		logger.WithError(err).Fatal("error emitting metrics for existing CSV")
   191  	}
   192  
   193  	if *writeStatusName != "" {
   194  		reconciler, err := openshift.NewClusterOperatorReconciler(
   195  			openshift.WithClient(mgr.GetClient()),
   196  			openshift.WithScheme(mgr.GetScheme()),
   197  			openshift.WithLog(ctrl.Log.WithName("controllers").WithName("clusteroperator")),
   198  			openshift.WithName(*writeStatusName),
   199  			openshift.WithNamespace(*namespace),
   200  			openshift.WithSyncChannel(op.AtLevel()),
   201  			openshift.WithOLMOperator(),
   202  		)
   203  		if err != nil {
   204  			logger.WithError(err).Fatal("error configuring openshift integration")
   205  			return
   206  		}
   207  
   208  		if err := reconciler.SetupWithManager(mgr); err != nil {
   209  			logger.WithError(err).Fatal("error configuring openshift integration")
   210  			return
   211  		}
   212  	}
   213  
   214  	if *writePackageServerStatusName != "" {
   215  		logger.Info("Initializing cluster operator monitor for package server")
   216  
   217  		names := *writePackageServerStatusName
   218  		discovery := opClient.KubernetesInterface().Discovery()
   219  		monitor, sender := operatorstatus.NewMonitor(logger, discovery, configClient, names)
   220  
   221  		handler := operatorstatus.NewCSVWatchNotificationHandler(logger, op.GetCSVSetGenerator(), op.GetReplaceFinder(), sender)
   222  		op.RegisterCSVWatchNotification(handler)
   223  
   224  		go monitor.Run(op.Done())
   225  	}
   226  
   227  	// Start the controller manager
   228  	if err := mgr.Start(ctx); err != nil {
   229  		logger.WithError(err).Fatal("controller manager stopped")
   230  	}
   231  
   232  	<-op.Done()
   233  }