Skip to content

Commit 9932d88

Browse files
committed
Move over to controller-runtime over doing it ourselves
1 parent 355e219 commit 9932d88

36 files changed

+881
-822
lines changed

Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ FROM --platform=$BUILDPLATFORM golang:1.24-alpine AS builder
33
COPY . /app/
44
WORKDIR /app/
55

6-
RUN go mod download
6+
RUN go mod download -x
77

88
ARG TARGETOS TARGETARCH
99
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o ./bin/version-checker ./cmd/.

cmd/app/app.go

+69-25
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,27 @@ package app
33
import (
44
"context"
55
"fmt"
6+
"net/http"
67

8+
logrusr "github.com/bombsimon/logrusr/v4"
79
"github.com/sirupsen/logrus"
10+
811
"github.com/spf13/cobra"
912

1013
"github.com/go-chi/transport"
1114
"github.com/hashicorp/go-cleanhttp"
1215

13-
"k8s.io/client-go/kubernetes"
1416
_ "k8s.io/client-go/plugin/pkg/client/auth" // Load all auth plugins
1517

18+
ctrl "sigs.k8s.io/controller-runtime"
19+
"sigs.k8s.io/controller-runtime/pkg/cache"
20+
ctrmetrics "sigs.k8s.io/controller-runtime/pkg/metrics"
21+
1622
"github.com/jetstack/version-checker/pkg/api"
1723
"github.com/jetstack/version-checker/pkg/client"
1824
"github.com/jetstack/version-checker/pkg/controller"
1925
"github.com/jetstack/version-checker/pkg/metrics"
26+
"sigs.k8s.io/controller-runtime/pkg/metrics/server"
2027
)
2128

2229
const (
@@ -33,55 +40,92 @@ func NewCommand(ctx context.Context) *cobra.Command {
3340
RunE: func(_ *cobra.Command, _ []string) error {
3441
opts.complete()
3542

36-
logLevel, err := logrus.ParseLevel(opts.LogLevel)
37-
if err != nil {
38-
return fmt.Errorf("failed to parse --log-level %q: %s",
39-
opts.LogLevel, err)
43+
log := logrus.New().WithField("component", "controller")
44+
45+
defaultTestAllInfoMsg := fmt.Sprintf(`only containers with the annotation "%s/${my-container}=true" will be parsed`, api.EnableAnnotationKey)
46+
if opts.DefaultTestAll {
47+
defaultTestAllInfoMsg = fmt.Sprintf(`all containers will be tested, unless they have the annotation "%s/${my-container}=false"`, api.EnableAnnotationKey)
4048
}
41-
log := newLogger(logLevel)
4249

4350
restConfig, err := opts.kubeConfigFlags.ToRESTConfig()
4451
if err != nil {
4552
return fmt.Errorf("failed to build kubernetes rest config: %s", err)
4653
}
4754

48-
kubeClient, err := kubernetes.NewForConfig(restConfig)
55+
log.Infof("flag --test-all-containers=%t %s", opts.DefaultTestAll, defaultTestAllInfoMsg)
56+
57+
mgr, err := ctrl.NewManager(restConfig, ctrl.Options{
58+
Logger: logrusr.New(log.WithField("controller", "manager").Logger),
59+
LeaderElection: false,
60+
// TODO: See if we can get newer/better solution
61+
Metrics: server.Options{
62+
BindAddress: opts.MetricsServingAddress,
63+
SecureServing: false,
64+
},
65+
GracefulShutdownTimeout: &opts.GracefulShutdownTimeout,
66+
Cache: cache.Options{SyncPeriod: &opts.CacheSyncPeriod},
67+
})
4968
if err != nil {
50-
return fmt.Errorf("failed to build kubernetes client: %s", err)
69+
return err
70+
}
71+
72+
// Liveness probe
73+
if err := mgr.AddMetricsServerExtraHandler("/healthz",
74+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
75+
w.WriteHeader(http.StatusOK)
76+
_, _ = w.Write([]byte("ok"))
77+
})); err != nil {
78+
log.Fatal("Unable to set up health check:", err)
5179
}
5280

53-
metricsServer := metrics.NewServer(log)
54-
if err := metricsServer.Run(opts.MetricsServingAddress); err != nil {
55-
return fmt.Errorf("failed to start metrics server: %s", err)
81+
// Readiness probe
82+
if err := mgr.AddMetricsServerExtraHandler("/readyz",
83+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
84+
if mgr.GetCache().WaitForCacheSync(context.Background()) {
85+
w.WriteHeader(http.StatusOK)
86+
_, _ = w.Write([]byte("ready"))
87+
} else {
88+
http.Error(w, "cache not synced", http.StatusServiceUnavailable)
89+
}
90+
}),
91+
); err != nil {
92+
log.Fatal("Unable to set up ready check:", err)
5693
}
5794

95+
metricsServer := metrics.New(log, ctrmetrics.Registry)
96+
5897
opts.Client.Transport = transport.Chain(
5998
cleanhttp.DefaultTransport(),
6099
metricsServer.RoundTripper,
61100
)
62101

102+
// nodeController := controller.NewNodeReconciler(log, mgr.GetClient())
103+
// if err := nodeController.SetupWithManager(mgr); err != nil {
104+
// }
105+
63106
client, err := client.New(ctx, log, opts.Client)
64107
if err != nil {
65108
return fmt.Errorf("failed to setup image registry clients: %s", err)
66109
}
67110

68-
defer func() {
69-
if err := metricsServer.Shutdown(); err != nil {
70-
log.Error(err)
71-
}
72-
}()
111+
c := controller.NewPodReconciler(opts.CacheTimeout,
112+
metricsServer,
113+
client,
114+
mgr.GetClient(),
115+
log,
116+
opts.DefaultTestAll,
117+
)
73118

74-
defaultTestAllInfoMsg := fmt.Sprintf(`only containers with the annotation "%s/${my-container}=true" will be parsed`, api.EnableAnnotationKey)
75-
if opts.DefaultTestAll {
76-
defaultTestAllInfoMsg = fmt.Sprintf(`all containers will be tested, unless they have the annotation "%s/${my-container}=false"`, api.EnableAnnotationKey)
119+
if err := c.SetupWithManager(mgr); err != nil {
120+
return err
77121
}
78122

79-
log.Infof("flag --test-all-containers=%t %s", opts.DefaultTestAll, defaultTestAllInfoMsg)
80-
81-
c := controller.New(opts.CacheTimeout, metricsServer,
82-
client, kubeClient, log, opts.DefaultTestAll)
83-
84-
return c.Run(ctx, opts.CacheTimeout/2)
123+
// Start the manager and all controllers
124+
log.Info("Starting controller manager")
125+
if err := mgr.Start(ctx); err != nil {
126+
return err
127+
}
128+
return nil
85129
},
86130
}
87131

cmd/app/helpers.go

-15
This file was deleted.

cmd/app/options.go

+22-11
Original file line numberDiff line numberDiff line change
@@ -22,30 +22,30 @@ const (
2222
envPrefix = "VERSION_CHECKER"
2323

2424
envACRUsername = "ACR_USERNAME"
25-
envACRPassword = "ACR_PASSWORD"
26-
envACRRefreshToken = "ACR_REFRESH_TOKEN"
25+
envACRPassword = "ACR_PASSWORD" // #nosec G101
26+
envACRRefreshToken = "ACR_REFRESH_TOKEN" // #nosec G101
2727

2828
envDockerUsername = "DOCKER_USERNAME"
29-
envDockerPassword = "DOCKER_PASSWORD"
30-
envDockerToken = "DOCKER_TOKEN"
29+
envDockerPassword = "DOCKER_PASSWORD" // #nosec G101
30+
envDockerToken = "DOCKER_TOKEN" // #nosec G101
3131

3232
envECRIamRoleArn = "ECR_IAM_ROLE_ARN"
33-
envECRAccessKeyID = "ECR_ACCESS_KEY_ID"
34-
envECRSecretAccessKey = "ECR_SECRET_ACCESS_KEY"
35-
envECRSessionToken = "ECR_SESSION_TOKEN"
33+
envECRAccessKeyID = "ECR_ACCESS_KEY_ID" // #nosec G101
34+
envECRSecretAccessKey = "ECR_SECRET_ACCESS_KEY" // #nosec G101
35+
envECRSessionToken = "ECR_SESSION_TOKEN" // #nosec G101
3636

37-
envGCRAccessToken = "GCR_TOKEN"
37+
envGCRAccessToken = "GCR_TOKEN" // #nosec G101
3838

39-
envGHCRAccessToken = "GHCR_TOKEN"
39+
envGHCRAccessToken = "GHCR_TOKEN" // #nosec G101
4040
envGHCRHostname = "GHCR_HOSTNAME"
4141

42-
envQuayToken = "QUAY_TOKEN"
42+
envQuayToken = "QUAY_TOKEN" // #nosec G101
4343

4444
envSelfhostedPrefix = "SELFHOSTED"
4545
envSelfhostedUsername = "USERNAME"
4646
envSelfhostedPassword = "PASSWORD"
4747
envSelfhostedHost = "HOST"
48-
envSelfhostedBearer = "TOKEN"
48+
envSelfhostedBearer = "TOKEN" // #nosec G101
4949
envSelfhostedTokenPath = "TOKEN_PATH"
5050
envSelfhostedInsecure = "INSECURE"
5151
envSelfhostedCAPath = "CA_PATH"
@@ -68,6 +68,9 @@ type Options struct {
6868
CacheTimeout time.Duration
6969
LogLevel string
7070

71+
GracefulShutdownTimeout time.Duration
72+
CacheSyncPeriod time.Duration
73+
7174
kubeConfigFlags *genericclioptions.ConfigFlags
7275
selfhosted selfhosted.Options
7376

@@ -118,6 +121,14 @@ func (o *Options) addAppFlags(fs *pflag.FlagSet) {
118121
fs.StringVarP(&o.LogLevel,
119122
"log-level", "v", "info",
120123
"Log level (debug, info, warn, error, fatal, panic).")
124+
125+
fs.DurationVarP(&o.GracefulShutdownTimeout,
126+
"graceful-shutdown-timeout", "", 10*time.Second,
127+
"Time that the manager should wait for all controller to shutdown.")
128+
129+
fs.DurationVarP(&o.CacheSyncPeriod,
130+
"cache-sync-period", "", 5*time.Hour,
131+
"The time in which all resources should be updated.")
121132
}
122133

123134
func (o *Options) addAuthFlags(fs *pflag.FlagSet) {

cmd/app/options_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,9 @@ func TestComplete(t *testing.T) {
170170

171171
for name, test := range tests {
172172
t.Run(name, func(t *testing.T) {
173+
os.Clearenv()
173174
for _, env := range test.envs {
174-
os.Setenv(env[0], env[1])
175+
t.Setenv(env[0], env[1])
175176
}
176177
o := new(Options)
177178
o.complete()

go.mod

+23-7
Original file line numberDiff line numberDiff line change
@@ -28,48 +28,62 @@ require (
2828
)
2929

3030
require (
31-
github.com/aws/aws-sdk-go-v2/config v1.29.9
32-
github.com/aws/aws-sdk-go-v2/credentials v1.17.62
31+
github.com/aws/aws-sdk-go-v2/config v1.29.11
32+
github.com/aws/aws-sdk-go-v2/credentials v1.17.64
3333
github.com/aws/aws-sdk-go-v2/service/ecr v1.43.0
34+
github.com/bombsimon/logrusr/v4 v4.1.0
3435
github.com/go-chi/transport v0.5.0
36+
github.com/go-logr/logr v1.4.2
3537
github.com/gofri/go-github-ratelimit v1.1.1
3638
github.com/google/go-cmp v0.7.0
3739
github.com/google/go-containerregistry v0.20.3
40+
github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20250225234217-098045d5e61f
3841
github.com/google/go-github/v70 v70.0.0
3942
github.com/hashicorp/go-cleanhttp v0.5.2
4043
github.com/jarcoal/httpmock v1.3.1
4144
github.com/patrickmn/go-cache v2.1.0+incompatible
4245
github.com/stretchr/testify v1.10.0
46+
go.uber.org/goleak v1.3.0
47+
sigs.k8s.io/controller-runtime v0.20.4
4348
)
4449

4550
require (
51+
cloud.google.com/go/compute/metadata v0.6.0 // indirect
52+
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
4653
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
4754
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
55+
github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 // indirect
56+
github.com/Azure/go-autorest/autorest/azure/cli v0.4.7 // indirect
4857
github.com/Azure/go-autorest/autorest/date v0.3.1 // indirect
4958
github.com/Azure/go-autorest/logger v0.2.2 // indirect
5059
github.com/Azure/go-autorest/tracing v0.6.1 // indirect
5160
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
5261
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
5362
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
5463
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
64+
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.32.1 // indirect
5565
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
5666
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
57-
github.com/aws/aws-sdk-go-v2/service/sso v1.25.1 // indirect
58-
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1 // indirect
67+
github.com/aws/aws-sdk-go-v2/service/sso v1.25.2 // indirect
68+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.2 // indirect
5969
github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 // indirect
6070
github.com/aws/smithy-go v1.22.3 // indirect
71+
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.9.1 // indirect
6172
github.com/beorn7/perks v1.0.1 // indirect
6273
github.com/blang/semver/v4 v4.0.0 // indirect
6374
github.com/cespare/xxhash/v2 v2.3.0 // indirect
75+
github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect
6476
github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect
6577
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
66-
github.com/docker/cli v28.0.2+incompatible // indirect
78+
github.com/dimchansky/utfbom v1.1.1 // indirect
79+
github.com/docker/cli v28.0.4+incompatible // indirect
6780
github.com/docker/distribution v2.8.3+incompatible // indirect
6881
github.com/docker/docker-credential-helpers v0.9.3 // indirect
6982
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
83+
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
84+
github.com/fsnotify/fsnotify v1.8.0 // indirect
7085
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
7186
github.com/go-errors/errors v1.5.1 // indirect
72-
github.com/go-logr/logr v1.4.2 // indirect
7387
github.com/go-openapi/jsonpointer v0.21.1 // indirect
7488
github.com/go-openapi/jsonreference v0.21.0 // indirect
7589
github.com/go-openapi/swag v0.23.1 // indirect
@@ -78,6 +92,7 @@ require (
7892
github.com/golang/protobuf v1.5.4 // indirect
7993
github.com/google/btree v1.1.3 // indirect
8094
github.com/google/gnostic-models v0.6.9 // indirect
95+
github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20250225234217-098045d5e61f // indirect
8196
github.com/google/go-querystring v1.1.0 // indirect
8297
github.com/google/gofuzz v1.2.0 // indirect
8398
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
@@ -114,11 +129,12 @@ require (
114129
golang.org/x/term v0.30.0 // indirect
115130
golang.org/x/text v0.23.0 // indirect
116131
golang.org/x/time v0.11.0 // indirect
132+
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
117133
google.golang.org/protobuf v1.36.6 // indirect
118134
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
119135
gopkg.in/inf.v0 v0.9.1 // indirect
120136
gopkg.in/yaml.v3 v3.0.1 // indirect
121-
gotest.tools/v3 v3.1.0 // indirect
137+
k8s.io/apiextensions-apiserver v0.32.3 // indirect
122138
k8s.io/klog/v2 v2.130.1 // indirect
123139
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
124140
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect

0 commit comments

Comments
 (0)