github.com/ironcore-dev/gardener-extension-provider-ironcore@v0.3.2-0.20240314231816-8336447fb9a0/cmd/gardener-extension-provider-ironcore/app/app.go (about) 1 // SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and IronCore contributors 2 // SPDX-License-Identifier: Apache-2.0 3 4 package app 5 6 import ( 7 "context" 8 "fmt" 9 "os" 10 11 druidv1alpha1 "github.com/gardener/etcd-druid/api/v1alpha1" 12 extensionscontroller "github.com/gardener/gardener/extensions/pkg/controller" 13 controllercmd "github.com/gardener/gardener/extensions/pkg/controller/cmd" 14 "github.com/gardener/gardener/extensions/pkg/controller/controlplane/genericactuator" 15 "github.com/gardener/gardener/extensions/pkg/controller/heartbeat" 16 heartbeatcmd "github.com/gardener/gardener/extensions/pkg/controller/heartbeat/cmd" 17 "github.com/gardener/gardener/extensions/pkg/util" 18 webhookcmd "github.com/gardener/gardener/extensions/pkg/webhook/cmd" 19 "github.com/gardener/gardener/pkg/client/kubernetes" 20 gardenerhealthz "github.com/gardener/gardener/pkg/healthz" 21 machinev1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1" 22 "github.com/spf13/cobra" 23 corev1 "k8s.io/api/core/v1" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 autoscalingv1 "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1" 26 "k8s.io/component-base/version/verflag" 27 "sigs.k8s.io/controller-runtime/pkg/client" 28 "sigs.k8s.io/controller-runtime/pkg/cluster" 29 "sigs.k8s.io/controller-runtime/pkg/healthz" 30 "sigs.k8s.io/controller-runtime/pkg/manager" 31 32 ironcoreinstall "github.com/ironcore-dev/gardener-extension-provider-ironcore/pkg/apis/ironcore/install" 33 ironcorecmd "github.com/ironcore-dev/gardener-extension-provider-ironcore/pkg/cmd" 34 backupbucketcontroller "github.com/ironcore-dev/gardener-extension-provider-ironcore/pkg/controller/backupbucket" 35 backupentrycontroller "github.com/ironcore-dev/gardener-extension-provider-ironcore/pkg/controller/backupentry" 36 bastioncontroller "github.com/ironcore-dev/gardener-extension-provider-ironcore/pkg/controller/bastion" 37 ironcorecontrolplane "github.com/ironcore-dev/gardener-extension-provider-ironcore/pkg/controller/controlplane" 38 "github.com/ironcore-dev/gardener-extension-provider-ironcore/pkg/controller/healthcheck" 39 infrastructurecontroller "github.com/ironcore-dev/gardener-extension-provider-ironcore/pkg/controller/infrastructure" 40 workercontroller "github.com/ironcore-dev/gardener-extension-provider-ironcore/pkg/controller/worker" 41 ironcore "github.com/ironcore-dev/gardener-extension-provider-ironcore/pkg/ironcore" 42 ) 43 44 // NewControllerManagerCommand creates a new command for running a ironcore provider controller. 45 func NewControllerManagerCommand(ctx context.Context) *cobra.Command { 46 var ( 47 generalOpts = &controllercmd.GeneralOptions{} 48 restOpts = &controllercmd.RESTOptions{} 49 mgrOpts = &controllercmd.ManagerOptions{ 50 LeaderElection: true, 51 LeaderElectionID: controllercmd.LeaderElectionNameID(ironcore.ProviderName), 52 LeaderElectionNamespace: os.Getenv("LEADER_ELECTION_NAMESPACE"), 53 WebhookServerPort: 443, 54 WebhookCertDir: "/tmp/gardener-extensions-cert", 55 MetricsBindAddress: ":8080", 56 HealthBindAddress: ":8081", 57 } 58 configFileOpts = &ironcorecmd.ConfigOptions{} 59 60 // options for the backupbucket controller 61 backupBucketCtrlOpts = &controllercmd.ControllerOptions{ 62 MaxConcurrentReconciles: 5, 63 } 64 65 // options for the backupentry controller 66 backupEntryCtrlOpts = &controllercmd.ControllerOptions{ 67 MaxConcurrentReconciles: 5, 68 } 69 70 // options for the health care controller 71 healthCheckCtrlOpts = &controllercmd.ControllerOptions{ 72 MaxConcurrentReconciles: 5, 73 } 74 75 // options for the heartbeat controller 76 heartbeatCtrlOpts = &heartbeatcmd.Options{ 77 ExtensionName: ironcore.ProviderName, 78 RenewIntervalSeconds: 30, 79 Namespace: os.Getenv("LEADER_ELECTION_NAMESPACE"), 80 } 81 82 // options for the controlplane controller 83 controlPlaneCtrlOpts = &controllercmd.ControllerOptions{ 84 MaxConcurrentReconciles: 5, 85 } 86 87 // options for the infrastructure controller 88 infraCtrlOpts = &controllercmd.ControllerOptions{ 89 MaxConcurrentReconciles: 5, 90 } 91 reconcileOpts = &controllercmd.ReconcilerOptions{} 92 93 // options for the worker controller 94 workerCtrlOpts = &controllercmd.ControllerOptions{ 95 MaxConcurrentReconciles: 5, 96 } 97 98 // options for the webhook server 99 webhookServerOptions = &webhookcmd.ServerOptions{ 100 Namespace: os.Getenv("WEBHOOK_CONFIG_NAMESPACE"), 101 } 102 103 // options for the bastion controller 104 bastionCtrlOpts = &controllercmd.ControllerOptions{ 105 MaxConcurrentReconciles: 5, 106 } 107 108 controllerSwitches = ironcorecmd.ControllerSwitchOptions() 109 webhookSwitches = ironcorecmd.WebhookSwitchOptions() 110 webhookOptions = webhookcmd.NewAddToManagerOptions( 111 ironcore.ProviderName, 112 genericactuator.ShootWebhooksResourceName, 113 genericactuator.ShootWebhookNamespaceSelector(ironcore.Type), 114 webhookServerOptions, 115 webhookSwitches, 116 ) 117 118 aggOption = controllercmd.NewOptionAggregator( 119 generalOpts, 120 restOpts, 121 mgrOpts, 122 controllercmd.PrefixOption("controlplane-", controlPlaneCtrlOpts), 123 controllercmd.PrefixOption("infrastructure-", infraCtrlOpts), 124 controllercmd.PrefixOption("worker-", workerCtrlOpts), 125 controllercmd.PrefixOption("healthcheck-", healthCheckCtrlOpts), 126 controllercmd.PrefixOption("heartbeat-", heartbeatCtrlOpts), 127 controllercmd.PrefixOption("bastion-", bastionCtrlOpts), 128 controllercmd.PrefixOption("backupbucket-", backupBucketCtrlOpts), 129 controllercmd.PrefixOption("backupentry-", backupEntryCtrlOpts), 130 configFileOpts, 131 controllerSwitches, 132 reconcileOpts, 133 webhookOptions, 134 ) 135 ) 136 137 cmd := &cobra.Command{ 138 Use: fmt.Sprintf("%s-controller-manager", ironcore.ProviderName), 139 140 RunE: func(cmd *cobra.Command, args []string) error { 141 verflag.PrintAndExitIfRequested() 142 143 if err := aggOption.Complete(); err != nil { 144 return fmt.Errorf("error completing options: %w", err) 145 } 146 147 if err := heartbeatCtrlOpts.Validate(); err != nil { 148 return err 149 } 150 151 util.ApplyClientConnectionConfigurationToRESTConfig(configFileOpts.Completed().Config.ClientConnection, restOpts.Completed().Config) 152 153 mopts := mgrOpts.Completed().Options() 154 mopts.Client = client.Options{ 155 Cache: &client.CacheOptions{ 156 DisableFor: []client.Object{ 157 &corev1.Secret{}, 158 }, 159 }, 160 } 161 mgr, err := manager.New(restOpts.Completed().Config, mopts) 162 if err != nil { 163 return fmt.Errorf("could not instantiate manager: %w", err) 164 } 165 166 scheme := mgr.GetScheme() 167 if err := extensionscontroller.AddToScheme(scheme); err != nil { 168 return fmt.Errorf("could not update manager scheme: %w", err) 169 } 170 if err := ironcoreinstall.AddToScheme(scheme); err != nil { 171 return fmt.Errorf("could not update manager scheme: %w", err) 172 } 173 if err := druidv1alpha1.AddToScheme(scheme); err != nil { 174 return fmt.Errorf("could not update manager scheme: %w", err) 175 } 176 if err := autoscalingv1.AddToScheme(scheme); err != nil { 177 return fmt.Errorf("could not update manager scheme: %w", err) 178 } 179 if err := machinev1alpha1.AddToScheme(scheme); err != nil { 180 return fmt.Errorf("could not update manager scheme: %w", err) 181 } 182 183 // add common meta types to schema for controller-runtime to use v1.ListOptions 184 metav1.AddToGroupVersion(scheme, machinev1alpha1.SchemeGroupVersion) 185 186 log := mgr.GetLogger() 187 log.Info("Getting rest config for garden") 188 gardenRESTConfig, err := kubernetes.RESTConfigFromKubeconfigFile(os.Getenv("GARDEN_KUBECONFIG"), kubernetes.AuthTokenFile) 189 if err != nil { 190 return err 191 } 192 193 log.Info("Setting up cluster object for garden") 194 gardenCluster, err := cluster.New(gardenRESTConfig, func(opts *cluster.Options) { 195 opts.Scheme = kubernetes.GardenScheme 196 opts.Logger = log 197 }) 198 if err != nil { 199 return fmt.Errorf("failed creating garden cluster object: %w", err) 200 } 201 202 log.Info("Adding garden cluster to manager") 203 if err := mgr.Add(gardenCluster); err != nil { 204 return fmt.Errorf("failed adding garden cluster to manager: %w", err) 205 } 206 207 configFileOpts.Completed().ApplyHealthCheckConfig(&healthcheck.DefaultAddOptions.HealthCheckConfig) 208 healthCheckCtrlOpts.Completed().Apply(&healthcheck.DefaultAddOptions.Controller) 209 configFileOpts.Completed().ApplyBastionConfig(&bastioncontroller.DefaultAddOptions.BastionConfig) 210 heartbeatCtrlOpts.Completed().Apply(&heartbeat.DefaultAddOptions) 211 infraCtrlOpts.Completed().Apply(&infrastructurecontroller.DefaultAddOptions.Controller) 212 workerCtrlOpts.Completed().Apply(&workercontroller.DefaultAddOptions.Controller) 213 configFileOpts.Completed().ApplyBackupbucketConfig(&backupbucketcontroller.DefaultAddOptions.BackupBucketConfig) 214 bastionCtrlOpts.Completed().Apply(&bastioncontroller.DefaultAddOptions.Controller) 215 backupBucketCtrlOpts.Completed().Apply(&backupbucketcontroller.DefaultAddOptions.Controller) 216 backupEntryCtrlOpts.Completed().Apply(&backupentrycontroller.DefaultAddOptions.Controller) 217 reconcileOpts.Completed().Apply(&bastioncontroller.DefaultAddOptions.IgnoreOperationAnnotation) 218 reconcileOpts.Completed().Apply(&infrastructurecontroller.DefaultAddOptions.IgnoreOperationAnnotation) 219 reconcileOpts.Completed().Apply(&workercontroller.DefaultAddOptions.IgnoreOperationAnnotation) 220 reconcileOpts.Completed().Apply(&backupbucketcontroller.DefaultAddOptions.IgnoreOperationAnnotation) 221 reconcileOpts.Completed().Apply(&backupentrycontroller.DefaultAddOptions.IgnoreOperationAnnotation) 222 workercontroller.DefaultAddOptions.GardenCluster = gardenCluster 223 224 if _, err := webhookOptions.Completed().AddToManager(ctx, mgr, nil); err != nil { 225 return fmt.Errorf("could not add webhooks to manager: %w", err) 226 } 227 ironcorecontrolplane.DefaultAddOptions.WebhookServerNamespace = webhookOptions.Server.Namespace 228 229 if err := controllerSwitches.Completed().AddToManager(ctx, mgr); err != nil { 230 return fmt.Errorf("could not add controllers to manager: %w", err) 231 } 232 233 if err := mgr.AddReadyzCheck("informer-sync", gardenerhealthz.NewCacheSyncHealthz(mgr.GetCache())); err != nil { 234 return fmt.Errorf("could not add readycheck for informers: %w", err) 235 } 236 237 if err := mgr.AddHealthzCheck("ping", healthz.Ping); err != nil { 238 return fmt.Errorf("could not add health check to manager: %w", err) 239 } 240 241 if err := mgr.AddReadyzCheck("webhook-server", mgr.GetWebhookServer().StartedChecker()); err != nil { 242 return fmt.Errorf("could not add ready check for webhook server to manager: %w", err) 243 } 244 245 if err := mgr.Start(ctx); err != nil { 246 return fmt.Errorf("error running manager: %w", err) 247 } 248 249 return nil 250 }, 251 } 252 253 verflag.AddFlags(cmd.Flags()) 254 aggOption.AddFlags(cmd.Flags()) 255 256 return cmd 257 }