Skip to content

Commit 67d7d12

Browse files
committed
fix(controller): accept legacy manifest flags
1 parent 395b5aa commit 67d7d12

2 files changed

Lines changed: 219 additions & 100 deletions

File tree

kubernetes/cmd/controller/main.go

Lines changed: 113 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -130,109 +130,122 @@ func init() {
130130
// +kubebuilder:scaffold:scheme
131131
}
132132

133-
// nolint:gocyclo
134-
func main() {
135-
var metricsAddr string
136-
var metricsCertPath, metricsCertName, metricsCertKey string
137-
var webhookCertPath, webhookCertName, webhookCertKey string
138-
var enableLeaderElection bool
139-
var probeAddr string
140-
var secureMetrics bool
141-
var enableHTTP2 bool
142-
var allowWeakTLSKeyLengths bool
143-
var tlsOpts []func(*tls.Config)
144-
145-
// Log file options
146-
var enableFileLog bool
147-
var logFilePath string
148-
var logMaxSize int
149-
var logMaxBackups int
150-
var logMaxAge int
151-
var logCompress bool
152-
153-
// Kubernetes client rate limiter options
154-
var kubeClientQPS float64
155-
var kubeClientBurst int
156-
157-
// Controller concurrency options
158-
var concurrencyConfig ConcurrencyConfig
133+
type controllerOptions struct {
134+
metricsAddr string
135+
metricsCertPath string
136+
metricsCertName string
137+
metricsCertKey string
138+
webhookCertPath string
139+
webhookCertName string
140+
webhookCertKey string
141+
enableLeaderElection bool
142+
probeAddr string
143+
secureMetrics bool
144+
enableHTTP2 bool
145+
allowWeakTLSKeyLengths bool
146+
enableFileLog bool
147+
logFilePath string
148+
logMaxSize int
149+
logMaxBackups int
150+
logMaxAge int
151+
logCompress bool
152+
kubeClientQPS float64
153+
kubeClientBurst int
154+
concurrencyConfig ConcurrencyConfig
155+
imageCommitterImage string
156+
commitJobTimeout time.Duration
157+
snapshotRegistry string
158+
snapshotRegistryInsecure bool
159+
snapshotPushSecret string
160+
resumePullSecret string
161+
zapOptions zap.Options
162+
legacyKlogVerbosity string
163+
}
159164

160-
flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
165+
func (o *controllerOptions) bindFlags(fs *flag.FlagSet) {
166+
fs.StringVar(&o.metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
161167
"Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.")
162-
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
163-
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
168+
fs.StringVar(&o.probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
169+
fs.BoolVar(&o.enableLeaderElection, "leader-elect", false,
164170
"Enable leader election for controller manager. "+
165171
"Enabling this will ensure there is only one active controller manager.")
166-
flag.BoolVar(&secureMetrics, "metrics-secure", true,
172+
fs.BoolVar(&o.secureMetrics, "metrics-secure", true,
167173
"If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.")
168-
flag.StringVar(&webhookCertPath, "webhook-cert-path", "", "The directory that contains the webhook certificate.")
169-
flag.StringVar(&webhookCertName, "webhook-cert-name", "tls.crt", "The name of the webhook certificate file.")
170-
flag.StringVar(&webhookCertKey, "webhook-cert-key", "tls.key", "The name of the webhook key file.")
171-
flag.StringVar(&metricsCertPath, "metrics-cert-path", "",
174+
fs.StringVar(&o.webhookCertPath, "webhook-cert-path", "", "The directory that contains the webhook certificate.")
175+
fs.StringVar(&o.webhookCertName, "webhook-cert-name", "tls.crt", "The name of the webhook certificate file.")
176+
fs.StringVar(&o.webhookCertKey, "webhook-cert-key", "tls.key", "The name of the webhook key file.")
177+
fs.StringVar(&o.metricsCertPath, "metrics-cert-path", "",
172178
"The directory that contains the metrics server certificate.")
173-
flag.StringVar(&metricsCertName, "metrics-cert-name", "tls.crt", "The name of the metrics server certificate file.")
174-
flag.StringVar(&metricsCertKey, "metrics-cert-key", "tls.key", "The name of the metrics server key file.")
175-
flag.BoolVar(&enableHTTP2, "enable-http2", false,
179+
fs.StringVar(&o.metricsCertName, "metrics-cert-name", "tls.crt", "The name of the metrics server certificate file.")
180+
fs.StringVar(&o.metricsCertKey, "metrics-cert-key", "tls.key", "The name of the metrics server key file.")
181+
fs.BoolVar(&o.enableHTTP2, "enable-http2", false,
176182
"If set, HTTP/2 will be enabled for the metrics and webhook servers")
177-
flag.BoolVar(
178-
&allowWeakTLSKeyLengths,
183+
fs.BoolVar(
184+
&o.allowWeakTLSKeyLengths,
179185
"allow-weak-tls-keylengths",
180186
false,
181187
"If set, allows TLS certificates below NIST 2030 minimum key/hash lengths (not recommended).",
182188
)
183189

184190
// Log file flags
185-
flag.BoolVar(&enableFileLog, "enable-file-log", false, "Enable log output to file")
186-
flag.StringVar(&logFilePath, "log-file-path", "/var/log/sandbox-controller/controller.log", "Path to the log file")
187-
flag.IntVar(&logMaxSize, "log-max-size", 100, "Maximum size in megabytes of the log file before it gets rotated")
188-
flag.IntVar(&logMaxBackups, "log-max-backups", 10, "Maximum number of old log files to retain")
189-
flag.IntVar(&logMaxAge, "log-max-age", 30, "Maximum number of days to retain old log files")
190-
flag.BoolVar(&logCompress, "log-compress", true, "Compress determines if the rotated log files should be compressed using gzip")
191-
flag.Float64Var(&kubeClientQPS, "kube-client-qps", 100, "QPS for Kubernetes client rate limiter.")
192-
flag.IntVar(&kubeClientBurst, "kube-client-burst", 200, "Burst for Kubernetes client rate limiter.")
193-
flag.Var(&concurrencyConfig, "concurrency", "Controller concurrency settings in format: controller1=N;controller2=M. "+
191+
fs.BoolVar(&o.enableFileLog, "enable-file-log", false, "Enable log output to file")
192+
fs.StringVar(&o.logFilePath, "log-file-path", "/var/log/sandbox-controller/controller.log", "Path to the log file")
193+
fs.IntVar(&o.logMaxSize, "log-max-size", 100, "Maximum size in megabytes of the log file before it gets rotated")
194+
fs.IntVar(&o.logMaxBackups, "log-max-backups", 10, "Maximum number of old log files to retain")
195+
fs.IntVar(&o.logMaxAge, "log-max-age", 30, "Maximum number of days to retain old log files")
196+
fs.BoolVar(&o.logCompress, "log-compress", true, "Compress determines if the rotated log files should be compressed using gzip")
197+
fs.Float64Var(&o.kubeClientQPS, "kube-client-qps", 100, "QPS for Kubernetes client rate limiter.")
198+
fs.IntVar(&o.kubeClientBurst, "kube-client-burst", 200, "Burst for Kubernetes client rate limiter.")
199+
fs.Var(&o.concurrencyConfig, "concurrency", "Controller concurrency settings in format: controller1=N;controller2=M. "+
194200
"Available controllers: batchsandbox, pool. "+
195201
"Example: --concurrency='batchsandbox=32;pool=128'")
196202

197203
// Image committer
198-
var imageCommitterImage string
199-
flag.StringVar(&imageCommitterImage, "image-committer-image", "image-committer:dev", "The image used for commit operations (contains nerdctl tool).")
204+
fs.StringVar(&o.imageCommitterImage, "image-committer-image", "image-committer:dev", "The image used for commit operations (contains nerdctl tool).")
200205

201206
// Commit job timeout
202-
var commitJobTimeout time.Duration
203-
flag.DurationVar(&commitJobTimeout, "commit-job-timeout", 10*time.Minute, "The timeout duration for commit jobs.")
207+
fs.DurationVar(&o.commitJobTimeout, "commit-job-timeout", 10*time.Minute, "The timeout duration for commit jobs.")
204208

205-
var snapshotRegistry string
206-
flag.StringVar(&snapshotRegistry, "snapshot-registry", "", "OCI registry for snapshot images (e.g., registry.example.com/snapshots).")
209+
fs.StringVar(&o.snapshotRegistry, "snapshot-registry", "", "OCI registry for snapshot images (e.g., registry.example.com/snapshots).")
207210

208-
var snapshotRegistryInsecure bool
209-
flag.BoolVar(&snapshotRegistryInsecure, "snapshot-registry-insecure", false, "Use insecure registry mode when pushing snapshot images.")
211+
fs.BoolVar(&o.snapshotRegistryInsecure, "snapshot-registry-insecure", false, "Use insecure registry mode when pushing snapshot images.")
210212

211-
var snapshotPushSecret string
212-
flag.StringVar(&snapshotPushSecret, "snapshot-push-secret", "", "K8s Secret name for pushing snapshots to registry.")
213+
fs.StringVar(&o.snapshotPushSecret, "snapshot-push-secret", "", "K8s Secret name for pushing snapshots to registry.")
213214

214-
var resumePullSecret string
215-
flag.StringVar(&resumePullSecret, "resume-pull-secret", "", "K8s Secret name for pulling snapshot images during resume.")
215+
fs.StringVar(&o.resumePullSecret, "resume-pull-secret", "", "K8s Secret name for pulling snapshot images during resume.")
216216

217-
opts := zap.Options{}
218-
opts.BindFlags(flag.CommandLine)
217+
o.zapOptions.BindFlags(fs)
218+
if fs.Lookup("v") == nil {
219+
fs.StringVar(&o.legacyKlogVerbosity, "v", "", "Deprecated compatibility flag for older controller manifests; use --zap-log-level instead.")
220+
}
221+
}
222+
223+
// nolint:gocyclo
224+
func main() {
225+
var tlsOpts []func(*tls.Config)
226+
227+
options := &controllerOptions{}
228+
options.bindFlags(flag.CommandLine)
219229

220230
flag.Parse()
221231

222232
// Setup logger with file rotation support
223233
logOpts := logging.Options{
224-
Development: opts.Development,
225-
EnableFileOutput: enableFileLog,
226-
LogFilePath: logFilePath,
227-
MaxSize: logMaxSize,
228-
MaxBackups: logMaxBackups,
229-
MaxAge: logMaxAge,
230-
Compress: logCompress,
231-
ZapOptions: opts,
234+
Development: options.zapOptions.Development,
235+
EnableFileOutput: options.enableFileLog,
236+
LogFilePath: options.logFilePath,
237+
MaxSize: options.logMaxSize,
238+
MaxBackups: options.logMaxBackups,
239+
MaxAge: options.logMaxAge,
240+
Compress: options.logCompress,
241+
ZapOptions: options.zapOptions,
232242
}
233243

234244
logger := logging.NewLoggerWithZapOptions(logOpts)
235245
ctrl.SetLogger(logger)
246+
if options.legacyKlogVerbosity != "" {
247+
setupLog.Info("deprecated --v flag ignored; use --zap-log-level instead", "v", options.legacyKlogVerbosity)
248+
}
236249

237250
// if the enable-http2 flag is false (the default), http/2 should be disabled
238251
// due to its vulnerabilities. More specifically, disabling http/2 will
@@ -249,7 +262,7 @@ func main() {
249262
c.MinVersion = tls.VersionTLS12
250263
})
251264

252-
if !enableHTTP2 {
265+
if !options.enableHTTP2 {
253266
tlsOpts = append(tlsOpts, disableHTTP2)
254267
}
255268

@@ -259,10 +272,10 @@ func main() {
259272
// Initial webhook TLS options
260273
webhookTLSOpts := tlsOpts
261274

262-
if len(webhookCertPath) > 0 {
263-
webhookCertFile := filepath.Join(webhookCertPath, webhookCertName)
264-
webhookKeyFile := filepath.Join(webhookCertPath, webhookCertKey)
265-
if !allowWeakTLSKeyLengths {
275+
if len(options.webhookCertPath) > 0 {
276+
webhookCertFile := filepath.Join(options.webhookCertPath, options.webhookCertName)
277+
webhookKeyFile := filepath.Join(options.webhookCertPath, options.webhookCertKey)
278+
if !options.allowWeakTLSKeyLengths {
266279
if err := cryptoutil.ValidateCertificateKeyPair(webhookCertFile, webhookKeyFile); err != nil {
267280
setupLog.Error(err, "Webhook certificate does not meet NIST minimum key/hash requirements",
268281
"webhook-cert-file", webhookCertFile, "webhook-key-file", webhookKeyFile)
@@ -271,7 +284,7 @@ func main() {
271284
}
272285

273286
setupLog.Info("Initializing webhook certificate watcher using provided certificates",
274-
"webhook-cert-path", webhookCertPath, "webhook-cert-name", webhookCertName, "webhook-cert-key", webhookCertKey)
287+
"webhook-cert-path", options.webhookCertPath, "webhook-cert-name", options.webhookCertName, "webhook-cert-key", options.webhookCertKey)
275288

276289
var err error
277290
webhookCertWatcher, err = certwatcher.New(
@@ -289,7 +302,7 @@ func main() {
289302
if err != nil {
290303
return nil, err
291304
}
292-
if allowWeakTLSKeyLengths {
305+
if options.allowWeakTLSKeyLengths {
293306
return cert, nil
294307
}
295308
if err := cryptoutil.ValidateTLSCertificate(webhookCertFile, cert); err != nil {
@@ -309,12 +322,12 @@ func main() {
309322
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.21.0/pkg/metrics/server
310323
// - https://book.kubebuilder.io/reference/metrics.html
311324
metricsServerOptions := metricsserver.Options{
312-
BindAddress: metricsAddr,
313-
SecureServing: secureMetrics,
325+
BindAddress: options.metricsAddr,
326+
SecureServing: options.secureMetrics,
314327
TLSOpts: tlsOpts,
315328
}
316329

317-
if secureMetrics {
330+
if options.secureMetrics {
318331
// FilterProvider is used to protect the metrics endpoint with authn/authz.
319332
// These configurations ensure that only authorized users and service accounts
320333
// can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info:
@@ -330,10 +343,10 @@ func main() {
330343
// - [METRICS-WITH-CERTS] at config/default/kustomization.yaml to generate and use certificates
331344
// managed by cert-manager for the metrics server.
332345
// - [PROMETHEUS-WITH-CERTS] at config/prometheus/kustomization.yaml for TLS certification.
333-
if len(metricsCertPath) > 0 {
334-
metricsCertFile := filepath.Join(metricsCertPath, metricsCertName)
335-
metricsKeyFile := filepath.Join(metricsCertPath, metricsCertKey)
336-
if !allowWeakTLSKeyLengths && metricsAddr != "0" && secureMetrics {
346+
if len(options.metricsCertPath) > 0 {
347+
metricsCertFile := filepath.Join(options.metricsCertPath, options.metricsCertName)
348+
metricsKeyFile := filepath.Join(options.metricsCertPath, options.metricsCertKey)
349+
if !options.allowWeakTLSKeyLengths && options.metricsAddr != "0" && options.secureMetrics {
337350
if err := cryptoutil.ValidateCertificateKeyPair(metricsCertFile, metricsKeyFile); err != nil {
338351
setupLog.Error(err, "Metrics certificate does not meet NIST minimum key/hash requirements",
339352
"metrics-cert-file", metricsCertFile, "metrics-key-file", metricsKeyFile)
@@ -342,7 +355,7 @@ func main() {
342355
}
343356

344357
setupLog.Info("Initializing metrics certificate watcher using provided certificates",
345-
"metrics-cert-path", metricsCertPath, "metrics-cert-name", metricsCertName, "metrics-cert-key", metricsCertKey)
358+
"metrics-cert-path", options.metricsCertPath, "metrics-cert-name", options.metricsCertName, "metrics-cert-key", options.metricsCertKey)
346359

347360
var err error
348361
metricsCertWatcher, err = certwatcher.New(
@@ -360,7 +373,7 @@ func main() {
360373
if err != nil {
361374
return nil, err
362375
}
363-
if allowWeakTLSKeyLengths {
376+
if options.allowWeakTLSKeyLengths {
364377
return cert, nil
365378
}
366379
if err := cryptoutil.ValidateTLSCertificate(metricsCertFile, cert); err != nil {
@@ -373,19 +386,19 @@ func main() {
373386

374387
config := ctrl.GetConfigOrDie()
375388
// Set client rate limiter if specified
376-
if kubeClientQPS > 0 {
377-
config.QPS = float32(kubeClientQPS)
389+
if options.kubeClientQPS > 0 {
390+
config.QPS = float32(options.kubeClientQPS)
378391
}
379-
if kubeClientBurst > 0 {
380-
config.Burst = kubeClientBurst
392+
if options.kubeClientBurst > 0 {
393+
config.Burst = options.kubeClientBurst
381394
}
382395

383396
mgr, err := ctrl.NewManager(config, ctrl.Options{
384397
Scheme: scheme,
385398
Metrics: metricsServerOptions,
386399
WebhookServer: webhookServer,
387-
HealthProbeBindAddress: probeAddr,
388-
LeaderElection: enableLeaderElection,
400+
HealthProbeBindAddress: options.probeAddr,
401+
LeaderElection: options.enableLeaderElection,
389402
LeaderElectionID: "2fa1c467.opensandbox.io",
390403
// LeaderElectionReleaseOnCancel causes the leader to voluntarily release the lease
391404
// when the Manager is stopped, allowing a new leader to acquire it without waiting
@@ -407,8 +420,8 @@ func main() {
407420
batchSandboxKindName = strings.ToLower(getKindFromType(&sandboxv1alpha1.BatchSandbox{}))
408421
poolKindName = strings.ToLower(getKindFromType(&sandboxv1alpha1.Pool{}))
409422
)
410-
batchSandboxConcurrency := concurrencyConfig.Get(batchSandboxKindName, defaultBatchSandboxConcurrency)
411-
poolConcurrency := concurrencyConfig.Get(poolKindName, defaultPoolConcurrency)
423+
batchSandboxConcurrency := options.concurrencyConfig.Get(batchSandboxKindName, defaultBatchSandboxConcurrency)
424+
poolConcurrency := options.concurrencyConfig.Get(poolKindName, defaultPoolConcurrency)
412425
setupLog.Info("controller concurrency configured", batchSandboxKindName, batchSandboxConcurrency, poolKindName, poolConcurrency)
413426

414427
profileStore := poolassign.NewProfileStore()
@@ -422,7 +435,7 @@ func main() {
422435
Client: mgr.GetClient(),
423436
Scheme: mgr.GetScheme(),
424437
Recorder: mgr.GetEventRecorderFor("batchsandbox-controller"),
425-
ResumePullSecret: resumePullSecret,
438+
ResumePullSecret: options.resumePullSecret,
426439
ProfileStore: profileStore,
427440
}).SetupWithManager(mgr, batchSandboxConcurrency); err != nil {
428441
setupLog.Error(err, "unable to create controller", "controller", "BatchSandbox")
@@ -442,11 +455,11 @@ func main() {
442455
Client: mgr.GetClient(),
443456
Scheme: mgr.GetScheme(),
444457
Recorder: mgr.GetEventRecorderFor("sandboxsnapshot-controller"),
445-
ImageCommitterImage: imageCommitterImage,
446-
CommitJobTimeout: commitJobTimeout,
447-
SnapshotRegistry: snapshotRegistry,
448-
SnapshotRegistryInsecure: snapshotRegistryInsecure,
449-
SnapshotPushSecret: snapshotPushSecret,
458+
ImageCommitterImage: options.imageCommitterImage,
459+
CommitJobTimeout: options.commitJobTimeout,
460+
SnapshotRegistry: options.snapshotRegistry,
461+
SnapshotRegistryInsecure: options.snapshotRegistryInsecure,
462+
SnapshotPushSecret: options.snapshotPushSecret,
450463
}).SetupWithManager(mgr); err != nil {
451464
setupLog.Error(err, "unable to create controller", "controller", "SandboxSnapshot")
452465
os.Exit(1)

0 commit comments

Comments
 (0)