package main import ( "encoding/json" "errors" "flag" "io/ioutil" "math/rand" "os" "time" "k8s.io/apimachinery/pkg/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" typedcertificatesv1 "k8s.io/client-go/kubernetes/typed/certificates/v1" "k8s.io/klog/v2" "k8s.io/klog/v2/klogr" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/healthz" "git.giftfish.de/ston1th/cloud-controller-manager-pve/pkg/approver" pve "git.giftfish.de/ston1th/pve-go" ) type config struct { PVE pve.Config `json:"pve"` } var ( scheme = runtime.NewScheme() setupLog = ctrl.Log.WithName("setup") leaderElect bool healthAddr string cloudConfig string csrConcurrency int syncPeriod time.Duration ) const name = "pve-csr-approver-manager" func init() { _ = clientgoscheme.AddToScheme(scheme) } func main() { rand.Seed(time.Now().UnixNano()) klog.InitFlags(nil) ctrl.SetLogger(klogr.New()) initFlags() flag.Parse() rcfg := ctrl.GetConfigOrDie() rcfg.UserAgent = name mgr, err := ctrl.NewManager(rcfg, ctrl.Options{ Scheme: scheme, LeaderElection: leaderElect, LeaderElectionID: name, LeaderElectionResourceLock: "leases", HealthProbeBindAddress: healthAddr, MetricsBindAddress: "0", SyncPeriod: &syncPeriod, }) if err != nil { setupLog.Error(err, "unable to start manager") os.Exit(1) } var opts []pve.ClientOption cr, err := os.Open(cloudConfig) if err == nil { buf, _ := ioutil.ReadAll(cr) if len(buf) != 0 { var cfg config err = json.Unmarshal(buf, &cfg) if err != nil { setupLog.Error(err, "failed to read config file") os.Exit(1) } opts, err = pve.ClientOptionsFromConfig(cfg.PVE) if err != nil { setupLog.Error(err, "failed to create client options from file") os.Exit(1) } } } else { opts, err = pve.ClientOptionsFromEnv() if err != nil { setupLog.Error(err, "failed to create client options from env") os.Exit(1) } } if len(opts) == 0 { setupLog.Error(errors.New("missing pve config"), "") os.Exit(1) } pveClient := pve.NewClient(opts...) if err = (&approver.CSRReconciler{ Client: mgr.GetClient(), Log: ctrl.Log.WithName("controllers").WithName("approver"), Scheme: mgr.GetScheme(), PVEClient: pveClient, CSRClient: typedcertificatesv1.NewForConfigOrDie(rcfg), }).SetupWithManager(mgr, controller.Options{MaxConcurrentReconciles: csrConcurrency}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "approver") os.Exit(1) } if err := mgr.AddReadyzCheck("ping", healthz.Ping); err != nil { setupLog.Error(err, "unable to create ready check") os.Exit(1) } if err := mgr.AddHealthzCheck("ping", healthz.Ping); err != nil { setupLog.Error(err, "unable to create health check") os.Exit(1) } setupLog.Info("starting manager") if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { setupLog.Error(err, "problem running manager") os.Exit(1) } } func initFlags() { flag.BoolVar(&leaderElect, "leader-elect", true, "Enable leader election for controller manager. "+ "Enabling this will ensure there is only one active controller manager.") flag.StringVar(&cloudConfig, "cloud-config", "", "The path to the cloud provider configuration file. Empty string for no configuration file.", ) flag.StringVar(&healthAddr, "health-addr", ":9449", "The address the health endpoint binds to.", ) flag.IntVar(&csrConcurrency, "csr-concurrency", 1, "Number of CSRs to process simultaneously", ) flag.DurationVar(&syncPeriod, "sync-period", 10*time.Minute, "The minimum interval at which watched resources are reconciled (e.g. 15m)", ) }