Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ FROM --platform=$BUILDPLATFORM golang:1.24-alpine AS builder
COPY . /app/
WORKDIR /app/

RUN go mod download
RUN go mod download -x

ARG TARGETOS TARGETARCH
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o ./bin/version-checker ./cmd/.
Expand Down
88 changes: 67 additions & 21 deletions cmd/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,27 @@ package app
import (
"context"
"fmt"
"net/http"

logrusr "github.com/bombsimon/logrusr/v4"
"github.com/sirupsen/logrus"

"github.com/spf13/cobra"

"github.com/go-chi/transport"
"github.com/hashicorp/go-cleanhttp"

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

ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/cache"
ctrmetrics "sigs.k8s.io/controller-runtime/pkg/metrics"

"github.com/jetstack/version-checker/pkg/api"
"github.com/jetstack/version-checker/pkg/client"
"github.com/jetstack/version-checker/pkg/controller"
"github.com/jetstack/version-checker/pkg/metrics"
"sigs.k8s.io/controller-runtime/pkg/metrics/server"
)

const (
Expand All @@ -38,23 +45,61 @@ func NewCommand(ctx context.Context) *cobra.Command {
return fmt.Errorf("failed to parse --log-level %q: %s",
opts.LogLevel, err)
}
log := newLogger(logLevel)

log := newLogger(logLevel).WithField("component", "controller")
ctrl.SetLogger(logrusr.New(log.WithField("controller", "manager").Logger))

defaultTestAllInfoMsg := fmt.Sprintf(`only containers with the annotation "%s/${my-container}=true" will be parsed`, api.EnableAnnotationKey)
if opts.DefaultTestAll {
defaultTestAllInfoMsg = fmt.Sprintf(`all containers will be tested, unless they have the annotation "%s/${my-container}=false"`, api.EnableAnnotationKey)
}

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

kubeClient, err := kubernetes.NewForConfig(restConfig)
log.Infof("flag --test-all-containers=%t %s", opts.DefaultTestAll, defaultTestAllInfoMsg)

mgr, err := ctrl.NewManager(restConfig, ctrl.Options{
LeaderElection: false,
Metrics: server.Options{
BindAddress: opts.MetricsServingAddress,
SecureServing: false,
},
GracefulShutdownTimeout: &opts.GracefulShutdownTimeout,
Cache: cache.Options{SyncPeriod: &opts.CacheSyncPeriod},
PprofBindAddress: opts.PprofBindAddress,
})
if err != nil {
return fmt.Errorf("failed to build kubernetes client: %s", err)
return err
}

metricsServer := metrics.NewServer(log)
if err := metricsServer.Run(opts.MetricsServingAddress); err != nil {
return fmt.Errorf("failed to start metrics server: %s", err)
// Liveness probe
if err := mgr.AddMetricsServerExtraHandler("/healthz",
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("ok"))
})); err != nil {
log.Fatal("Unable to set up health check:", err)
}

// Readiness probe
if err := mgr.AddMetricsServerExtraHandler("/readyz",
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
if mgr.GetCache().WaitForCacheSync(context.Background()) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("ready"))
} else {
http.Error(w, "cache not synced", http.StatusServiceUnavailable)
}
}),
); err != nil {
log.Fatal("Unable to set up ready check:", err)
}

metricsServer := metrics.New(log, ctrmetrics.Registry, mgr.GetCache())

opts.Client.Transport = transport.Chain(
cleanhttp.DefaultTransport(),
metricsServer.RoundTripper,
Expand All @@ -65,23 +110,24 @@ func NewCommand(ctx context.Context) *cobra.Command {
return fmt.Errorf("failed to setup image registry clients: %s", err)
}

defer func() {
if err := metricsServer.Shutdown(); err != nil {
log.Error(err)
}
}()
c := controller.NewPodReconciler(opts.CacheTimeout,
metricsServer,
client,
mgr.GetClient(),
log,
opts.DefaultTestAll,
)

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

log.Infof("flag --test-all-containers=%t %s", opts.DefaultTestAll, defaultTestAllInfoMsg)

c := controller.New(opts.CacheTimeout, metricsServer,
client, kubeClient, log, opts.DefaultTestAll)

return c.Run(ctx, opts.CacheTimeout/2)
// Start the manager and all controllers
log.Info("Starting controller manager")
if err := mgr.Start(ctx); err != nil {
return err
}
return nil
},
}

Expand Down
38 changes: 27 additions & 11 deletions cmd/app/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,30 @@ const (
envPrefix = "VERSION_CHECKER"

envACRUsername = "ACR_USERNAME"
envACRPassword = "ACR_PASSWORD"
envACRRefreshToken = "ACR_REFRESH_TOKEN"
envACRPassword = "ACR_PASSWORD" // #nosec G101
envACRRefreshToken = "ACR_REFRESH_TOKEN" // #nosec G101

envDockerUsername = "DOCKER_USERNAME"
envDockerPassword = "DOCKER_PASSWORD"
envDockerToken = "DOCKER_TOKEN"
envDockerPassword = "DOCKER_PASSWORD" // #nosec G101
envDockerToken = "DOCKER_TOKEN" // #nosec G101

envECRIamRoleArn = "ECR_IAM_ROLE_ARN"
envECRAccessKeyID = "ECR_ACCESS_KEY_ID"
envECRSecretAccessKey = "ECR_SECRET_ACCESS_KEY"
envECRSessionToken = "ECR_SESSION_TOKEN"
envECRAccessKeyID = "ECR_ACCESS_KEY_ID" // #nosec G101
envECRSecretAccessKey = "ECR_SECRET_ACCESS_KEY" // #nosec G101
envECRSessionToken = "ECR_SESSION_TOKEN" // #nosec G101

envGCRAccessToken = "GCR_TOKEN"
envGCRAccessToken = "GCR_TOKEN" // #nosec G101

envGHCRAccessToken = "GHCR_TOKEN"
envGHCRAccessToken = "GHCR_TOKEN" // #nosec G101
envGHCRHostname = "GHCR_HOSTNAME"

envQuayToken = "QUAY_TOKEN"
envQuayToken = "QUAY_TOKEN" // #nosec G101

envSelfhostedPrefix = "SELFHOSTED"
envSelfhostedUsername = "USERNAME"
envSelfhostedPassword = "PASSWORD"
envSelfhostedHost = "HOST"
envSelfhostedBearer = "TOKEN"
envSelfhostedBearer = "TOKEN" // #nosec G101
envSelfhostedTokenPath = "TOKEN_PATH"
envSelfhostedInsecure = "INSECURE"
envSelfhostedCAPath = "CA_PATH"
Expand All @@ -68,6 +68,10 @@ type Options struct {
CacheTimeout time.Duration
LogLevel string

PprofBindAddress string
GracefulShutdownTimeout time.Duration
CacheSyncPeriod time.Duration

kubeConfigFlags *genericclioptions.ConfigFlags
selfhosted selfhosted.Options

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

fs.StringVarP(&o.PprofBindAddress,
"pprof-serving-address", "", "",
"Address to serve pprof on for profiling.")

fs.BoolVarP(&o.DefaultTestAll,
"test-all-containers", "a", false,
"If enabled, all containers will be tested, unless they have the "+
Expand All @@ -118,6 +126,14 @@ func (o *Options) addAppFlags(fs *pflag.FlagSet) {
fs.StringVarP(&o.LogLevel,
"log-level", "v", "info",
"Log level (debug, info, warn, error, fatal, panic).")

fs.DurationVarP(&o.GracefulShutdownTimeout,
"graceful-shutdown-timeout", "", 10*time.Second,
"Time that the manager should wait for all controller to shutdown.")

fs.DurationVarP(&o.CacheSyncPeriod,
"cache-sync-period", "", 5*time.Hour,
"The time in which all resources should be updated.")
}

func (o *Options) addAuthFlags(fs *pflag.FlagSet) {
Expand Down
3 changes: 2 additions & 1 deletion cmd/app/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,9 @@ func TestComplete(t *testing.T) {

for name, test := range tests {
t.Run(name, func(t *testing.T) {
os.Clearenv()
for _, env := range test.envs {
os.Setenv(env[0], env[1])
t.Setenv(env[0], env[1])
}
o := new(Options)
o.complete()
Expand Down
3 changes: 3 additions & 0 deletions deploy/charts/version-checker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ A Helm chart for version-checker
| additionalAnnotations | object | `{}` | Additional Annotations to apply to Service and Deployment/Pod Objects |
| additionalLabels | object | `{}` | Additional Labels to apply to Service and Deployment/Pod Objects |
| affinity | object | `{}` | Set affinity |
| dashboards.enabled | bool | `false` | Deploy Grafana Dashboard(s) for version-checker |
| dashboards.grafana | string | `""` | Grafana instance to associate the Dashboard with when using GrafanaOperator |
| dashboards.labels | object | `{}` | Additional labels to add to the Grafana Dashboard |
| docker.password | string | `nil` | Password to authenticate with docker registry |
| docker.token | string | `nil` | Token to authenticate with docker registry. Cannot be used with `docker.username` / `docker.password`. |
| docker.username | string | `nil` | Username to authenticate with docker registry |
Expand Down
Loading
Loading