mirror of
https://github.com/siderolabs/sidero.git
synced 2025-10-18 19:11:10 +02:00
245 lines
7.8 KiB
Go
245 lines
7.8 KiB
Go
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"flag"
|
|
"os"
|
|
|
|
debug "github.com/siderolabs/go-debug"
|
|
"github.com/spf13/pflag"
|
|
corev1 "k8s.io/api/core/v1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
|
cgrecord "k8s.io/client-go/tools/record"
|
|
"k8s.io/component-base/logs"
|
|
logsv1 "k8s.io/component-base/logs/api/v1"
|
|
capiv1 "sigs.k8s.io/cluster-api/api/v1beta1"
|
|
"sigs.k8s.io/cluster-api/controllers/remote"
|
|
"sigs.k8s.io/cluster-api/util/flags"
|
|
ctrl "sigs.k8s.io/controller-runtime"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
"sigs.k8s.io/controller-runtime/pkg/controller"
|
|
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
|
|
|
infrav1alpha2 "github.com/siderolabs/sidero/app/caps-controller-manager/api/v1alpha2"
|
|
infrav1alpha3 "github.com/siderolabs/sidero/app/caps-controller-manager/api/v1alpha3"
|
|
"github.com/siderolabs/sidero/app/caps-controller-manager/controllers"
|
|
metalv1 "github.com/siderolabs/sidero/app/sidero-controller-manager/api/v1alpha2"
|
|
// +kubebuilder:scaffold:imports
|
|
)
|
|
|
|
const (
|
|
defaultMaxConcurrentReconciles = 10
|
|
debugAddr = ":9994"
|
|
)
|
|
|
|
var (
|
|
scheme = runtime.NewScheme()
|
|
setupLog = ctrl.Log.WithName("setup")
|
|
)
|
|
|
|
//nolint:wsl
|
|
func init() {
|
|
_ = clientgoscheme.AddToScheme(scheme)
|
|
_ = capiv1.AddToScheme(scheme)
|
|
_ = infrav1alpha2.AddToScheme(scheme)
|
|
_ = infrav1alpha3.AddToScheme(scheme)
|
|
_ = metalv1.AddToScheme(scheme)
|
|
// +kubebuilder:scaffold:scheme
|
|
}
|
|
|
|
var (
|
|
healthAddr string
|
|
enableLeaderElection bool
|
|
webhookPort int
|
|
webhookCertDir string
|
|
tlsOptions = flags.TLSOptions{}
|
|
diagnosticsOptions = flags.DiagnosticsOptions{}
|
|
logOptions = logs.NewOptions()
|
|
)
|
|
|
|
// InitFlags initializes the flags.
|
|
func InitFlags(fs *pflag.FlagSet) {
|
|
logsv1.AddFlags(logOptions, fs)
|
|
|
|
fs.BoolVar(&enableLeaderElection, "enable-leader-election", false,
|
|
"Enable leader election for controller manager. "+
|
|
"Enabling this will ensure there is only one active controller manager.")
|
|
fs.IntVar(&webhookPort, "webhook-port", 9443, "Webhook Server port, disabled by default. When enabled, the manager will only work as webhook server, no reconcilers are installed.")
|
|
fs.StringVar(&webhookCertDir, "webhook-cert-dir", "/tmp/k8s-webhook-server/serving-certs/",
|
|
"Webhook cert dir, only used when webhook-port is specified.")
|
|
fs.StringVar(&healthAddr, "health-addr", ":9440",
|
|
"The address the health endpoint binds to.")
|
|
|
|
flags.AddDiagnosticsOptions(fs, &diagnosticsOptions)
|
|
flags.AddTLSOptions(fs, &tlsOptions)
|
|
}
|
|
|
|
func main() {
|
|
InitFlags(pflag.CommandLine)
|
|
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
|
|
pflag.Parse()
|
|
|
|
if err := logsv1.ValidateAndApply(logOptions, nil); err != nil {
|
|
setupLog.Error(err, "unable to start manager")
|
|
os.Exit(1)
|
|
}
|
|
|
|
diagnosticsOpts := flags.GetDiagnosticsOptions(diagnosticsOptions)
|
|
|
|
tlsOptionOverrides, err := flags.GetTLSOptionOverrideFuncs(tlsOptions)
|
|
if err != nil {
|
|
setupLog.Error(err, "unable to add TLS settings to the webhook server")
|
|
os.Exit(1)
|
|
}
|
|
|
|
go func() {
|
|
debugLogFunc := func(msg string) {
|
|
setupLog.Info(msg)
|
|
}
|
|
if err := debug.ListenAndServe(context.TODO(), debugAddr, debugLogFunc); err != nil {
|
|
setupLog.Error(err, "failed to start debug server")
|
|
os.Exit(1)
|
|
}
|
|
}()
|
|
|
|
// Machine and cluster operations can create enough events to trigger the event recorder spam filter
|
|
// Setting the burst size higher ensures all events will be recorded and submitted to the API
|
|
broadcaster := cgrecord.NewBroadcasterWithCorrelatorOptions(cgrecord.CorrelatorOptions{
|
|
BurstSize: 100,
|
|
})
|
|
|
|
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
|
|
Scheme: scheme,
|
|
Metrics: diagnosticsOpts,
|
|
LeaderElection: enableLeaderElection,
|
|
LeaderElectionID: "controller-leader-election-capm",
|
|
EventBroadcaster: broadcaster,
|
|
HealthProbeBindAddress: healthAddr,
|
|
Client: client.Options{
|
|
Cache: &client.CacheOptions{
|
|
DisableFor: []client.Object{
|
|
&corev1.ConfigMap{},
|
|
&corev1.Secret{},
|
|
},
|
|
},
|
|
},
|
|
WebhookServer: webhook.NewServer(
|
|
webhook.Options{
|
|
Port: webhookPort,
|
|
CertDir: webhookCertDir,
|
|
TLSOpts: tlsOptionOverrides,
|
|
},
|
|
),
|
|
})
|
|
if err != nil {
|
|
setupLog.Error(err, "unable to start manager")
|
|
os.Exit(1)
|
|
}
|
|
|
|
ctx := ctrl.SetupSignalHandler()
|
|
|
|
// Set up a ClusterCacheTracker to provide to controllers
|
|
// requiring a connection to a remote cluster
|
|
tracker, err := remote.NewClusterCacheTracker(mgr, remote.ClusterCacheTrackerOptions{
|
|
Indexes: []remote.Index{remote.NodeProviderIDIndex},
|
|
ClientUncachedObjects: []client.Object{},
|
|
})
|
|
if err != nil {
|
|
setupLog.Error(err, "unable to create cluster cache tracker")
|
|
os.Exit(1)
|
|
}
|
|
|
|
if err := (&remote.ClusterCacheReconciler{
|
|
Client: mgr.GetClient(),
|
|
Tracker: tracker,
|
|
}).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: defaultMaxConcurrentReconciles}); err != nil {
|
|
setupLog.Error(err, "unable to create controller", "controller", "ClusterCacheReconciler")
|
|
os.Exit(1)
|
|
}
|
|
|
|
recorder := mgr.GetEventRecorderFor("caps-controller-manager")
|
|
|
|
if err = (&controllers.MetalClusterReconciler{
|
|
Client: mgr.GetClient(),
|
|
Log: ctrl.Log.WithName("controllers").WithName("MetalCluster"),
|
|
Scheme: mgr.GetScheme(),
|
|
}).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: defaultMaxConcurrentReconciles}); err != nil {
|
|
setupLog.Error(err, "unable to create controller", "controller", "MetalCluster")
|
|
os.Exit(1)
|
|
}
|
|
|
|
if err = (&controllers.MetalMachineReconciler{
|
|
Client: mgr.GetClient(),
|
|
Log: ctrl.Log.WithName("controllers").WithName("MetalMachine"),
|
|
Scheme: mgr.GetScheme(),
|
|
Recorder: recorder,
|
|
Tracker: tracker,
|
|
}).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: defaultMaxConcurrentReconciles}); err != nil {
|
|
setupLog.Error(err, "unable to create controller", "controller", "MetalMachine")
|
|
os.Exit(1)
|
|
}
|
|
|
|
if err = (&controllers.ServerBindingReconciler{
|
|
Client: mgr.GetClient(),
|
|
Log: ctrl.Log.WithName("controllers").WithName("ServerBinding"),
|
|
Scheme: mgr.GetScheme(),
|
|
Recorder: recorder,
|
|
}).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: defaultMaxConcurrentReconciles}); err != nil {
|
|
setupLog.Error(err, "unable to create controller", "controller", "ServerBinding")
|
|
os.Exit(1)
|
|
}
|
|
|
|
// +kubebuilder:scaffold:builder
|
|
|
|
setupWebhooks(mgr)
|
|
setupChecks(mgr)
|
|
|
|
setupLog.Info("starting manager")
|
|
|
|
if err := mgr.Start(ctx); err != nil {
|
|
setupLog.Error(err, "problem running manager")
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func setupWebhooks(mgr ctrl.Manager) {
|
|
var err error
|
|
|
|
if err = (&infrav1alpha3.MetalCluster{}).SetupWebhookWithManager(mgr); err != nil {
|
|
setupLog.Error(err, "unable to create webhook", "webhook", "MetalCluster")
|
|
os.Exit(1)
|
|
}
|
|
|
|
if err = (&infrav1alpha3.MetalMachine{}).SetupWebhookWithManager(mgr); err != nil {
|
|
setupLog.Error(err, "unable to create webhook", "webhook", "MetalMachine")
|
|
os.Exit(1)
|
|
}
|
|
|
|
if err = (&infrav1alpha3.MetalMachineTemplate{}).SetupWebhookWithManager(mgr); err != nil {
|
|
setupLog.Error(err, "unable to create webhook", "webhook", "MetalMachineTemplate")
|
|
os.Exit(1)
|
|
}
|
|
|
|
if err = (&infrav1alpha3.ServerBinding{}).SetupWebhookWithManager(mgr); err != nil {
|
|
setupLog.Error(err, "unable to create webhook", "webhook", "ServerBinding")
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func setupChecks(mgr ctrl.Manager) {
|
|
if err := mgr.AddReadyzCheck("webhook", mgr.GetWebhookServer().StartedChecker()); err != nil {
|
|
setupLog.Error(err, "unable to create ready check")
|
|
os.Exit(1)
|
|
}
|
|
|
|
if err := mgr.AddHealthzCheck("webhook", mgr.GetWebhookServer().StartedChecker()); err != nil {
|
|
setupLog.Error(err, "unable to create health check")
|
|
os.Exit(1)
|
|
}
|
|
}
|