diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go index 09cb37a..7524ca3 100644 --- a/internal/cmd/cmd.go +++ b/internal/cmd/cmd.go @@ -10,6 +10,7 @@ import ( "go.uber.org/zap/zapcore" clientset "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" "github.com/go-logr/zapr" "github.com/peterbourgon/ff/v3" @@ -32,87 +33,129 @@ var ( ref = "refs/refname" ) -// Run encapsulates all settings related to kubelet-csr-approver +// Config stores all parameters needed to configure a controller-manager +type Config struct { + logLevel int + metricsAddr string + probeAddr string + RegexStr string + MaxSec int + K8sConfig *rest.Config + DNSResolver controller.HostResolver +} + +// Run will start the controller with the default settings func Run() int { - flashLogger := flash.New() + config := prepareCmdlineConfig() + mgr, errorCode := CreateControllerManager(config) - fs := flag.NewFlagSet("kubelet-csr-approver", flag.ExitOnError) + if errorCode != 0 { + return errorCode + } - var ( - logLevel = fs.Int("level", 0, "level ranges from -5 (Fatal) to 10 (Verbose)") - metricsAddr = fs.String("metrics-bind-address", ":8080", "address the metric endpoint binds to.") - probeAddr = fs.String("health-probe-bind-address", ":8081", "address the probe endpoint binds to.") - regexStr = fs.String("provider-regex", "", "provider-specified regex to validate CSR SAN names against") - maxSec = fs.Int("max-expiration-sec", 367*24*3600, "maximum seconds a CSR can request a cerficate for. defaults to 367 days") - ) + z := mgr.GetLogger() + z.V(1).Info("starting controller-runtime manager") - err := ff.Parse(fs, os.Args[1:], ff.WithEnvVarNoPrefix()) - if err != nil { - fmt.Printf("unable to parse args/envs, exiting. error message: %v", err) - return 2 + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + z.Error(err, "problem running manager") + return 1 } + return 0 +} + +// CreateControllerManager permits creation/customization of the controller-manager +func CreateControllerManager(config *Config) (mgr ctrl.Manager, code int) { + mgr = nil + // logger initialization - if *logLevel < -5 || *logLevel > 10 { + flashLogger := flash.New() + if config.logLevel < -5 || config.logLevel > 10 { flashLogger.Fatal(fmt.Errorf("log level should be between -5 and 10 (included)")) } - *logLevel *= -1 // we inverse the level for the logging behavior between zap and logr.Logger to match - flashLogger.SetLevel(zapcore.Level(*logLevel)) + config.logLevel *= -1 // we inverse the level for the logging behavior between zap and logr.Logger to match + flashLogger.SetLevel(zapcore.Level(config.logLevel)) z := zapr.NewLogger(flashLogger.Desugar()) z.V(0).Info("Kubelet-CSR-Approver controller starting.", "commit", commit, "ref", ref) - if *regexStr == "" { + if config.RegexStr == "" { z.V(-5).Info("the provider-spefic regex must be specified, exiting") - return 10 + + return mgr, 10 } - providerRegexp := regexp.MustCompile(*regexStr) + providerRegexp := regexp.MustCompile(config.RegexStr) - if *maxSec < 0 || *maxSec > 367*24*3600 { + if config.MaxSec < 0 || config.MaxSec > 367*24*3600 { err := fmt.Errorf("the maximum expiration seconds env variable cannot be lower than 0 nor greater than 367 days") z.Error(err, "reduce the maxExpirationSec value") - return 10 + return mgr, 10 } ctrl.SetLogger(z) - mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ - MetricsBindAddress: *metricsAddr, - HealthProbeBindAddress: *probeAddr, + mgr, err := ctrl.NewManager(config.K8sConfig, ctrl.Options{ + MetricsBindAddress: config.metricsAddr, + HealthProbeBindAddress: config.probeAddr, }) if err != nil { z.Error(err, "unable to start manager") - return 1 + return mgr, 10 } csrController := controller.CertificateSigningRequestReconciler{ - ClientSet: clientset.NewForConfigOrDie(mgr.GetConfig()), + ClientSet: clientset.NewForConfigOrDie(config.K8sConfig), Client: mgr.GetClient(), Scheme: mgr.GetScheme(), ProviderRegexp: providerRegexp.MatchString, - MaxExpirationSeconds: int32(*maxSec), - Resolver: net.DefaultResolver, + MaxExpirationSeconds: int32(config.MaxSec), + Resolver: config.DNSResolver, } if err = csrController.SetupWithManager(mgr); err != nil { z.Error(err, "unable to create controller", "controller", "CertificateSigningRequest") - return 1 + return mgr, 10 } if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { z.Error(err, "unable to set up health check") - return 1 + return mgr, 10 } - z.V(1).Info("starting controller-runtime manager") + return mgr, 0 +} - if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { - z.Error(err, "problem running manager") - return 1 +func prepareCmdlineConfig() *Config { + fs := flag.NewFlagSet("kubelet-csr-approver", flag.ExitOnError) + + var ( + logLevel = fs.Int("level", 0, "level ranges from -5 (Fatal) to 10 (Verbose)") + metricsAddr = fs.String("metrics-bind-address", ":8080", "address the metric endpoint binds to.") + probeAddr = fs.String("health-probe-bind-address", ":8081", "address the probe endpoint binds to.") + regexStr = fs.String("provider-regex", "", "provider-specified regex to validate CSR SAN names against") + maxSec = fs.Int("max-expiration-sec", 367*24*3600, "maximum seconds a CSR can request a cerficate for. defaults to 367 days") + ) + + err := ff.Parse(fs, os.Args[1:], ff.WithEnvVarNoPrefix()) + if err != nil { + fmt.Printf("unable to parse args/envs, exiting. error message: %v", err) + + os.Exit(2) } - return 0 + config := Config{ + logLevel: *logLevel, + metricsAddr: *metricsAddr, + probeAddr: *probeAddr, + RegexStr: *regexStr, + MaxSec: *maxSec, + } + + config.DNSResolver = net.DefaultResolver + config.K8sConfig = ctrl.GetConfigOrDie() + + return &config } diff --git a/internal/controller/testenv_setup_test.go b/internal/controller/testenv_setup_test.go index 35e0fdf..3e094e5 100644 --- a/internal/controller/testenv_setup_test.go +++ b/internal/controller/testenv_setup_test.go @@ -21,7 +21,6 @@ import ( "encoding/pem" "net" "os" - "regexp" "testing" "time" @@ -32,6 +31,7 @@ import ( "log" mockdns "github.com/foxcpp/go-mockdns" + "github.com/postfinance/kubelet-csr-approver/internal/cmd" "github.com/postfinance/kubelet-csr-approver/internal/controller" "github.com/thanhpk/randstr" @@ -40,7 +40,6 @@ import ( clientset "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" - ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest" ) @@ -153,13 +152,6 @@ func createControlPlaneUser(t *testing.T, username string, groups []string) (*re } func packageSetup() { - - testNodeIps := []string{"192.168.14.34"} - for _, ip := range testNodeIps { - testNodeIpAddresses = append(testNodeIpAddresses, net.ParseIP(ip)) - } - testNodeName = randstr.String(4, "0123456789abcdefghijklmnopqrstuvwxyz") + ".test.ch" - testContext, testContextCancel = context.WithCancel(context.Background()) log.Println("Setting up the testing K8s Control plane -- envtest") testEnv = &envtest.Environment{} @@ -173,13 +165,13 @@ func packageSetup() { if err != nil { log.Fatalf("Could not create a k8sClient, exiting. Error output:\n %v", err) } + adminClientset = clientset.NewForConfigOrDie(cfg) - mgr, err := ctrl.NewManager(cfg, ctrl.Options{}) - if err != nil { - log.Fatalf("unable to create controller-runtime manager. Error:\n%v", err) + testNodeIps := []string{"192.168.14.34"} + for _, ip := range testNodeIps { + testNodeIpAddresses = append(testNodeIpAddresses, net.ParseIP(ip)) } - - provRegexp := regexp.MustCompile(`^\w*\.test\.ch$`) + testNodeName = randstr.String(4, "0123456789abcdefghijklmnopqrstuvwxyz") + ".test.ch" dnsResolver = mockdns.Resolver{ Zones: map[string]mockdns.Zone{ testNodeName + ".": { @@ -188,16 +180,17 @@ func packageSetup() { }, } - adminClientset = clientset.NewForConfigOrDie(cfg) - csrController := controller.CertificateSigningRequestReconciler{ - ClientSet: adminClientset, - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - ProviderRegexp: provRegexp.MatchString, - Resolver: &dnsResolver, - MaxExpirationSeconds: 367 * 24 * 3600, + testingConfig := cmd.Config{ + RegexStr: `^\w*\.test\.ch$`, + MaxSec: 367 * 24 * 3600, + K8sConfig: cfg, + DNSResolver: &dnsResolver, + } + + mgr, errorCode := cmd.CreateControllerManager(&testingConfig) + if errorCode != 0 { + log.Fatalf("unable to create controller-runtime manager. Error:\n%v", errorCode) } - csrController.SetupWithManager(mgr) go mgr.Start(testContext) }