cmd/eno-reconciler/main.go (102 lines of code) (raw):

package main import ( "flag" "fmt" "os" "time" "github.com/go-logr/zapr" "go.uber.org/zap" "go.uber.org/zap/zapcore" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/rest" ctrl "sigs.k8s.io/controller-runtime" "github.com/Azure/eno/internal/controllers/liveness" "github.com/Azure/eno/internal/controllers/reconciliation" "github.com/Azure/eno/internal/flowcontrol" "github.com/Azure/eno/internal/k8s" "github.com/Azure/eno/internal/manager" ) func main() { if err := run(); err != nil { fmt.Fprintf(os.Stderr, "error: %s\n", err) os.Exit(1) } } func run() error { ctx := ctrl.SetupSignalHandler() var ( debugLogging bool remoteKubeconfigFile string remoteQPS float64 compositionSelector string compositionNamespace string namespaceCreationGracePeriod time.Duration namespaceCleanup bool mgrOpts = &manager.Options{ Rest: ctrl.GetConfigOrDie(), } recOpts = reconciliation.Options{} ) flag.BoolVar(&debugLogging, "debug", true, "Enable debug logging") flag.StringVar(&remoteKubeconfigFile, "remote-kubeconfig", "", "Path to the kubeconfig of the apiserver where the resources will be reconciled. The config from the environment is used if this is not provided") flag.Float64Var(&remoteQPS, "remote-qps", 50, "Max requests per second to the remote apiserver") flag.DurationVar(&recOpts.Timeout, "timeout", time.Minute, "Per-resource reconciliation timeout. Avoids cases where client retries/timeouts are configured poorly and the loop gets blocked") flag.DurationVar(&recOpts.ReadinessPollInterval, "readiness-poll-interval", time.Second*5, "Interval at which non-ready resources will be checked for readiness") flag.DurationVar(&recOpts.MinReconcileInterval, "min-reconcile-interval", time.Second, "Minimum value of eno.azure.com/reconcile-interval that will be honored by the controller") flag.BoolVar(&recOpts.DisableServerSideApply, "disable-ssa", false, "Use non-strategic three-way merge patches instead of server-side apply") flag.StringVar(&compositionSelector, "composition-label-selector", labels.Everything().String(), "Optional label selector for compositions to be reconciled") flag.StringVar(&compositionNamespace, "composition-namespace", metav1.NamespaceAll, "Optional namespace to limit compositions that will be reconciled") flag.DurationVar(&namespaceCreationGracePeriod, "ns-creation-grace-period", time.Second, "A namespace is assumed to be missing if it doesn't exist once one of its resources has existed for this long") flag.BoolVar(&namespaceCleanup, "namespace-cleanup", true, "Clean up orphaned resources caused by namespace force-deletions") mgrOpts.Bind(flag.CommandLine) flag.Parse() zapCfg := zap.NewProductionConfig() if debugLogging { zapCfg.Level = zap.NewAtomicLevelAt(zapcore.DebugLevel) } zl, err := zapCfg.Build() if err != nil { return err } logger := zapr.NewLogger(zl) mgrOpts.CompositionNamespace = compositionNamespace if compositionSelector != "" { var err error mgrOpts.CompositionSelector, err = labels.Parse(compositionSelector) if err != nil { return fmt.Errorf("invalid composition label selector: %w", err) } } else { mgrOpts.CompositionSelector = labels.Everything() } mgrOpts.Rest.UserAgent = "eno-reconciler" mgr, err := manager.NewReconciler(logger, mgrOpts) if err != nil { return fmt.Errorf("constructing manager: %w", err) } if namespaceCleanup { err = liveness.NewNamespaceController(mgr, 5, namespaceCreationGracePeriod) if err != nil { return fmt.Errorf("constructing namespace liveness controller: %w", err) } } remoteConfig := rest.CopyConfig(mgr.GetConfig()) if remoteKubeconfigFile != "" { if remoteConfig, err = k8s.GetRESTConfig(remoteKubeconfigFile); err != nil { return err } } if remoteQPS >= 0 { remoteConfig.QPS = float32(remoteQPS) } // Burst of 1 allows the first write to happen immediately, while subsequent writes are debounced/batched at writeBatchInterval. // This provides quick feedback in cases where only a few resources have changed. writeBuffer := flowcontrol.NewResourceSliceWriteBufferForManager(mgr) recOpts.Manager = mgr recOpts.WriteBuffer = writeBuffer recOpts.Downstream = remoteConfig err = reconciliation.New(mgr, recOpts) if err != nil { return fmt.Errorf("constructing reconciliation controller: %w", err) } return mgr.Start(ctx) }