Skip to content

Commit 3dcfc81

Browse files
authored
Move over to controller-runtime over doing it ourselves (#348)
1 parent 5ca47dd commit 3dcfc81

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+3714
-1074
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
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

Lines changed: 67 additions & 21 deletions
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 (
@@ -38,23 +45,61 @@ func NewCommand(ctx context.Context) *cobra.Command {
3845
return fmt.Errorf("failed to parse --log-level %q: %s",
3946
opts.LogLevel, err)
4047
}
41-
log := newLogger(logLevel)
48+
49+
log := newLogger(logLevel).WithField("component", "controller")
50+
ctrl.SetLogger(logrusr.New(log.WithField("controller", "manager").Logger))
51+
52+
defaultTestAllInfoMsg := fmt.Sprintf(`only containers with the annotation "%s/${my-container}=true" will be parsed`, api.EnableAnnotationKey)
53+
if opts.DefaultTestAll {
54+
defaultTestAllInfoMsg = fmt.Sprintf(`all containers will be tested, unless they have the annotation "%s/${my-container}=false"`, api.EnableAnnotationKey)
55+
}
4256

4357
restConfig, err := opts.kubeConfigFlags.ToRESTConfig()
4458
if err != nil {
4559
return fmt.Errorf("failed to build kubernetes rest config: %s", err)
4660
}
4761

48-
kubeClient, err := kubernetes.NewForConfig(restConfig)
62+
log.Infof("flag --test-all-containers=%t %s", opts.DefaultTestAll, defaultTestAllInfoMsg)
63+
64+
mgr, err := ctrl.NewManager(restConfig, ctrl.Options{
65+
LeaderElection: false,
66+
Metrics: server.Options{
67+
BindAddress: opts.MetricsServingAddress,
68+
SecureServing: false,
69+
},
70+
GracefulShutdownTimeout: &opts.GracefulShutdownTimeout,
71+
Cache: cache.Options{SyncPeriod: &opts.CacheSyncPeriod},
72+
PprofBindAddress: opts.PprofBindAddress,
73+
})
4974
if err != nil {
50-
return fmt.Errorf("failed to build kubernetes client: %s", err)
75+
return err
5176
}
5277

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)
78+
// Liveness probe
79+
if err := mgr.AddMetricsServerExtraHandler("/healthz",
80+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
81+
w.WriteHeader(http.StatusOK)
82+
_, _ = w.Write([]byte("ok"))
83+
})); err != nil {
84+
log.Fatal("Unable to set up health check:", err)
5685
}
5786

87+
// Readiness probe
88+
if err := mgr.AddMetricsServerExtraHandler("/readyz",
89+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
90+
if mgr.GetCache().WaitForCacheSync(context.Background()) {
91+
w.WriteHeader(http.StatusOK)
92+
_, _ = w.Write([]byte("ready"))
93+
} else {
94+
http.Error(w, "cache not synced", http.StatusServiceUnavailable)
95+
}
96+
}),
97+
); err != nil {
98+
log.Fatal("Unable to set up ready check:", err)
99+
}
100+
101+
metricsServer := metrics.New(log, ctrmetrics.Registry, mgr.GetCache())
102+
58103
opts.Client.Transport = transport.Chain(
59104
cleanhttp.DefaultTransport(),
60105
metricsServer.RoundTripper,
@@ -65,23 +110,24 @@ func NewCommand(ctx context.Context) *cobra.Command {
65110
return fmt.Errorf("failed to setup image registry clients: %s", err)
66111
}
67112

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

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)
121+
if err := c.SetupWithManager(mgr); err != nil {
122+
return err
77123
}
78124

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)
125+
// Start the manager and all controllers
126+
log.Info("Starting controller manager")
127+
if err := mgr.Start(ctx); err != nil {
128+
return err
129+
}
130+
return nil
85131
},
86132
}
87133

cmd/app/options.go

Lines changed: 27 additions & 11 deletions
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,10 @@ type Options struct {
6868
CacheTimeout time.Duration
6969
LogLevel string
7070

71+
PprofBindAddress string
72+
GracefulShutdownTimeout time.Duration
73+
CacheSyncPeriod time.Duration
74+
7175
kubeConfigFlags *genericclioptions.ConfigFlags
7276
selfhosted selfhosted.Options
7377

@@ -105,6 +109,10 @@ func (o *Options) addAppFlags(fs *pflag.FlagSet) {
105109
"metrics-serving-address", "m", "0.0.0.0:8080",
106110
"Address to serve metrics on at the /metrics path.")
107111

112+
fs.StringVarP(&o.PprofBindAddress,
113+
"pprof-serving-address", "", "",
114+
"Address to serve pprof on for profiling.")
115+
108116
fs.BoolVarP(&o.DefaultTestAll,
109117
"test-all-containers", "a", false,
110118
"If enabled, all containers will be tested, unless they have the "+
@@ -118,6 +126,14 @@ func (o *Options) addAppFlags(fs *pflag.FlagSet) {
118126
fs.StringVarP(&o.LogLevel,
119127
"log-level", "v", "info",
120128
"Log level (debug, info, warn, error, fatal, panic).")
129+
130+
fs.DurationVarP(&o.GracefulShutdownTimeout,
131+
"graceful-shutdown-timeout", "", 10*time.Second,
132+
"Time that the manager should wait for all controller to shutdown.")
133+
134+
fs.DurationVarP(&o.CacheSyncPeriod,
135+
"cache-sync-period", "", 5*time.Hour,
136+
"The time in which all resources should be updated.")
121137
}
122138

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

cmd/app/options_test.go

Lines changed: 2 additions & 1 deletion
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()

deploy/charts/version-checker/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ A Helm chart for version-checker
2222
| additionalAnnotations | object | `{}` | Additional Annotations to apply to Service and Deployment/Pod Objects |
2323
| additionalLabels | object | `{}` | Additional Labels to apply to Service and Deployment/Pod Objects |
2424
| affinity | object | `{}` | Set affinity |
25+
| dashboards.enabled | bool | `false` | Deploy Grafana Dashboard(s) for version-checker |
26+
| dashboards.grafana | string | `""` | Grafana instance to associate the Dashboard with when using GrafanaOperator |
27+
| dashboards.labels | object | `{}` | Additional labels to add to the Grafana Dashboard |
2528
| docker.password | string | `nil` | Password to authenticate with docker registry |
2629
| docker.token | string | `nil` | Token to authenticate with docker registry. Cannot be used with `docker.username` / `docker.password`. |
2730
| docker.username | string | `nil` | Username to authenticate with docker registry |

0 commit comments

Comments
 (0)