Skip to content

Commit fede0e8

Browse files
committed
feat: use bci image and move to manager subcommand
Signed-off-by: Zespre Chang <zespre.chang@suse.com>
1 parent 3c6e197 commit fede0e8

27 files changed

+9163
-99
lines changed

Dockerfile

Lines changed: 0 additions & 33 deletions
This file was deleted.

Makefile

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ lint-config: golangci-lint ## Verify golangci-lint linter configuration
105105
##@ Build
106106

107107
.PHONY: build
108-
build: manifests generate fmt vet ## Build manager binary.
109-
go build -o bin/manager cmd/main.go
108+
build: manifests generate fmt vet ## Build upgrade-toolkit binary.
109+
go build -o bin/upgrade-toolkit cmd/main.go
110110

111111
.PHONY: run
112112
run: manifests generate fmt vet ## Run a controller from your host.
@@ -117,7 +117,7 @@ run: manifests generate fmt vet ## Run a controller from your host.
117117
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
118118
.PHONY: docker-build
119119
docker-build: ## Build docker image with the manager.
120-
$(CONTAINER_TOOL) build -t ${IMG} .
120+
$(CONTAINER_TOOL) build -t ${IMG} -f ./package/Dockerfile .
121121

122122
.PHONY: docker-push
123123
docker-push: ## Push docker image with the manager.
@@ -133,12 +133,12 @@ PLATFORMS ?= linux/arm64,linux/amd64
133133
.PHONY: docker-buildx
134134
docker-buildx: ## Build and push docker image for the manager for cross-platform support
135135
# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
136-
sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
136+
sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' ./package/Dockerfile > ./package/Dockerfile.cross
137137
- $(CONTAINER_TOOL) buildx create --name upgrade-toolkit-builder
138138
$(CONTAINER_TOOL) buildx use upgrade-toolkit-builder
139-
- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross .
139+
- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f ./package/Dockerfile.cross .
140140
- $(CONTAINER_TOOL) buildx rm upgrade-toolkit-builder
141-
rm Dockerfile.cross
141+
rm ./package/Dockerfile.cross
142142

143143
.PHONY: build-installer
144144
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.

cmd/main.go

Lines changed: 120 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package main
1919
import (
2020
"crypto/tls"
2121
"flag"
22+
"fmt"
2223
"os"
2324

2425
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
@@ -58,53 +59,113 @@ func init() {
5859
// +kubebuilder:scaffold:scheme
5960
}
6061

61-
// nolint:gocyclo
62+
// Command interface for subcommands
63+
type Command interface {
64+
Name() string
65+
FlagSet() *flag.FlagSet
66+
Run() error
67+
}
68+
69+
var commands = []Command{
70+
&ManagerCommand{},
71+
// Add new commands here
72+
}
73+
6274
func main() {
63-
var metricsAddr string
64-
var metricsCertPath, metricsCertName, metricsCertKey string
65-
var webhookCertPath, webhookCertName, webhookCertKey string
66-
var enableLeaderElection bool
67-
var probeAddr string
68-
var secureMetrics bool
69-
var enableHTTP2 bool
75+
if len(os.Args) < 2 {
76+
printUsage()
77+
os.Exit(1)
78+
}
79+
80+
cmdName := os.Args[1]
81+
for _, cmd := range commands {
82+
if cmd.Name() == cmdName {
83+
_ = cmd.FlagSet().Parse(os.Args[2:])
84+
if err := cmd.Run(); err != nil {
85+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
86+
os.Exit(1)
87+
}
88+
return
89+
}
90+
}
91+
92+
fmt.Fprintf(os.Stderr, "Unknown command: %s\n", cmdName)
93+
printUsage()
94+
os.Exit(1)
95+
}
96+
97+
func printUsage() {
98+
fmt.Fprintf(os.Stderr, "Usage: %s <command>\n\nAvailable commands:\n", os.Args[0])
99+
for _, cmd := range commands {
100+
fmt.Fprintf(os.Stderr, " %s\n", cmd.Name())
101+
}
102+
}
103+
104+
// ManagerCommand implements the manager subcommand
105+
type ManagerCommand struct {
106+
metricsAddr string
107+
metricsCertPath string
108+
metricsCertName string
109+
metricsCertKey string
110+
webhookCertPath string
111+
webhookCertName string
112+
webhookCertKey string
113+
enableLeaderElection bool
114+
probeAddr string
115+
secureMetrics bool
116+
enableHTTP2 bool
117+
fs *flag.FlagSet
118+
zapOpts zap.Options
119+
}
120+
121+
func (c *ManagerCommand) Name() string {
122+
return "manager"
123+
}
124+
125+
func (c *ManagerCommand) FlagSet() *flag.FlagSet {
126+
if c.fs == nil {
127+
c.fs = flag.NewFlagSet("manager", flag.ExitOnError)
128+
c.fs.StringVar(&c.metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
129+
"Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.")
130+
c.fs.StringVar(&c.probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
131+
c.fs.BoolVar(&c.enableLeaderElection, "leader-elect", false,
132+
"Enable leader election for controller manager. "+
133+
"Enabling this will ensure there is only one active controller manager.")
134+
c.fs.BoolVar(&c.secureMetrics, "metrics-secure", true,
135+
"If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.")
136+
c.fs.StringVar(&c.webhookCertPath, "webhook-cert-path", "", "The directory that contains the webhook certificate.")
137+
c.fs.StringVar(&c.webhookCertName, "webhook-cert-name", "tls.crt", "The name of the webhook certificate file.")
138+
c.fs.StringVar(&c.webhookCertKey, "webhook-cert-key", "tls.key", "The name of the webhook key file.")
139+
c.fs.StringVar(&c.metricsCertPath, "metrics-cert-path", "",
140+
"The directory that contains the metrics server certificate.")
141+
c.fs.StringVar(&c.metricsCertName, "metrics-cert-name", "tls.crt", "The name of the metrics server certificate file.")
142+
c.fs.StringVar(&c.metricsCertKey, "metrics-cert-key", "tls.key", "The name of the metrics server key file.")
143+
c.fs.BoolVar(&c.enableHTTP2, "enable-http2", false,
144+
"If set, HTTP/2 will be enabled for the metrics and webhook servers")
145+
146+
c.zapOpts = zap.Options{Development: true}
147+
c.zapOpts.BindFlags(c.fs)
148+
}
149+
return c.fs
150+
}
151+
152+
func (c *ManagerCommand) Run() error {
153+
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&c.zapOpts)))
154+
70155
var tlsOpts []func(*tls.Config)
71-
flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
72-
"Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.")
73-
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
74-
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
75-
"Enable leader election for controller manager. "+
76-
"Enabling this will ensure there is only one active controller manager.")
77-
flag.BoolVar(&secureMetrics, "metrics-secure", true,
78-
"If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.")
79-
flag.StringVar(&webhookCertPath, "webhook-cert-path", "", "The directory that contains the webhook certificate.")
80-
flag.StringVar(&webhookCertName, "webhook-cert-name", "tls.crt", "The name of the webhook certificate file.")
81-
flag.StringVar(&webhookCertKey, "webhook-cert-key", "tls.key", "The name of the webhook key file.")
82-
flag.StringVar(&metricsCertPath, "metrics-cert-path", "",
83-
"The directory that contains the metrics server certificate.")
84-
flag.StringVar(&metricsCertName, "metrics-cert-name", "tls.crt", "The name of the metrics server certificate file.")
85-
flag.StringVar(&metricsCertKey, "metrics-cert-key", "tls.key", "The name of the metrics server key file.")
86-
flag.BoolVar(&enableHTTP2, "enable-http2", false,
87-
"If set, HTTP/2 will be enabled for the metrics and webhook servers")
88-
opts := zap.Options{
89-
Development: true,
90-
}
91-
opts.BindFlags(flag.CommandLine)
92-
flag.Parse()
93-
94-
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
95156

96157
// if the enable-http2 flag is false (the default), http/2 should be disabled
97158
// due to its vulnerabilities. More specifically, disabling http/2 will
98159
// prevent from being vulnerable to the HTTP/2 Stream Cancellation and
99160
// Rapid Reset CVEs. For more information see:
100161
// - https://github.com/advisories/GHSA-qppj-fm5r-hxr3
101162
// - https://github.com/advisories/GHSA-4374-p667-p6c8
102-
disableHTTP2 := func(c *tls.Config) {
163+
disableHTTP2 := func(config *tls.Config) {
103164
setupLog.Info("disabling http/2")
104-
c.NextProtos = []string{"http/1.1"}
165+
config.NextProtos = []string{"http/1.1"}
105166
}
106167

107-
if !enableHTTP2 {
168+
if !c.enableHTTP2 {
108169
tlsOpts = append(tlsOpts, disableHTTP2)
109170
}
110171

@@ -114,13 +175,13 @@ func main() {
114175
TLSOpts: webhookTLSOpts,
115176
}
116177

117-
if len(webhookCertPath) > 0 {
178+
if len(c.webhookCertPath) > 0 {
118179
setupLog.Info("Initializing webhook certificate watcher using provided certificates",
119-
"webhook-cert-path", webhookCertPath, "webhook-cert-name", webhookCertName, "webhook-cert-key", webhookCertKey)
180+
"webhook-cert-path", c.webhookCertPath, "webhook-cert-name", c.webhookCertName, "webhook-cert-key", c.webhookCertKey)
120181

121-
webhookServerOptions.CertDir = webhookCertPath
122-
webhookServerOptions.CertName = webhookCertName
123-
webhookServerOptions.KeyName = webhookCertKey
182+
webhookServerOptions.CertDir = c.webhookCertPath
183+
webhookServerOptions.CertName = c.webhookCertName
184+
webhookServerOptions.KeyName = c.webhookCertKey
124185
}
125186

126187
webhookServer := webhook.NewServer(webhookServerOptions)
@@ -130,12 +191,12 @@ func main() {
130191
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.21.0/pkg/metrics/server
131192
// - https://book.kubebuilder.io/reference/metrics.html
132193
metricsServerOptions := metricsserver.Options{
133-
BindAddress: metricsAddr,
134-
SecureServing: secureMetrics,
194+
BindAddress: c.metricsAddr,
195+
SecureServing: c.secureMetrics,
135196
TLSOpts: tlsOpts,
136197
}
137198

138-
if secureMetrics {
199+
if c.secureMetrics {
139200
// FilterProvider is used to protect the metrics endpoint with authn/authz.
140201
// These configurations ensure that only authorized users and service accounts
141202
// can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info:
@@ -151,13 +212,13 @@ func main() {
151212
// - [METRICS-WITH-CERTS] at config/default/kustomization.yaml to generate and use certificates
152213
// managed by cert-manager for the metrics server.
153214
// - [PROMETHEUS-WITH-CERTS] at config/prometheus/kustomization.yaml for TLS certification.
154-
if len(metricsCertPath) > 0 {
215+
if len(c.metricsCertPath) > 0 {
155216
setupLog.Info("Initializing metrics certificate watcher using provided certificates",
156-
"metrics-cert-path", metricsCertPath, "metrics-cert-name", metricsCertName, "metrics-cert-key", metricsCertKey)
217+
"metrics-cert-path", c.metricsCertPath, "metrics-cert-name", c.metricsCertName, "metrics-cert-key", c.metricsCertKey)
157218

158-
metricsServerOptions.CertDir = metricsCertPath
159-
metricsServerOptions.CertName = metricsCertName
160-
metricsServerOptions.KeyName = metricsCertKey
219+
metricsServerOptions.CertDir = c.metricsCertPath
220+
metricsServerOptions.CertName = c.metricsCertName
221+
metricsServerOptions.KeyName = c.metricsCertKey
161222
}
162223

163224
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
@@ -171,8 +232,8 @@ func main() {
171232
Scheme: scheme,
172233
Metrics: metricsServerOptions,
173234
WebhookServer: webhookServer,
174-
HealthProbeBindAddress: probeAddr,
175-
LeaderElection: enableLeaderElection,
235+
HealthProbeBindAddress: c.probeAddr,
236+
LeaderElection: c.enableLeaderElection,
176237
LeaderElectionID: "3509939c.harvesterhci.io",
177238
// LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
178239
// when the Manager ends. This requires the binary to immediately end when the
@@ -188,7 +249,7 @@ func main() {
188249
})
189250
if err != nil {
190251
setupLog.Error(err, "unable to start manager")
191-
os.Exit(1)
252+
return err
192253
}
193254

194255
ctx := ctrl.SetupSignalHandler()
@@ -199,38 +260,40 @@ func main() {
199260
Log: logf.FromContext(ctx).WithName("upgrade-plan-controller"),
200261
}).SetupWithManager(mgr); err != nil {
201262
setupLog.Error(err, "unable to create controller", "controller", "UpgradePlan")
202-
os.Exit(1)
263+
return err
203264
}
204265
if err := (&controller.VersionReconciler{
205266
Client: mgr.GetClient(),
206267
Scheme: mgr.GetScheme(),
207268
Log: logf.FromContext(ctx).WithName("version-controller"),
208269
}).SetupWithManager(mgr); err != nil {
209270
setupLog.Error(err, "unable to create controller", "controller", "Version")
210-
os.Exit(1)
271+
return err
211272
}
212273
if err := (&controller.JobReconciler{
213274
Client: mgr.GetClient(),
214275
Scheme: mgr.GetScheme(),
215276
Log: logf.FromContext(ctx).WithName("job-controller"),
216277
}).SetupWithManager(mgr); err != nil {
217278
setupLog.Error(err, "unable to create controller", "controller", "Job")
218-
os.Exit(1)
279+
return err
219280
}
220281
// +kubebuilder:scaffold:builder
221282

222283
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
223284
setupLog.Error(err, "unable to set up health check")
224-
os.Exit(1)
285+
return err
225286
}
226287
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
227288
setupLog.Error(err, "unable to set up ready check")
228-
os.Exit(1)
289+
return err
229290
}
230291

231292
setupLog.Info("starting manager")
232293
if err := mgr.Start(ctx); err != nil {
233294
setupLog.Error(err, "problem running manager")
234-
os.Exit(1)
295+
return err
235296
}
297+
298+
return nil
236299
}

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ require (
7777
github.com/rancher/lasso v0.2.3 // indirect
7878
github.com/rancher/wrangler v1.1.2 // indirect
7979
github.com/rancher/wrangler/v3 v3.2.2 // indirect
80-
github.com/shopspring/decimal v1.4.0 // indirect
8180
github.com/sirupsen/logrus v1.9.3 // indirect
8281
github.com/spf13/cobra v1.8.1 // indirect
8382
github.com/spf13/pflag v1.0.6 // indirect

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,6 @@ github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99
278278
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
279279
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
280280
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
281-
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
282-
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
283281
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
284282
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
285283
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=

0 commit comments

Comments
 (0)