Skip to content

Commit a4b82d9

Browse files
authored
Merge pull request #1158 from stakater/feat/takeover-v2
Feat/takeover v2
2 parents 2cbb771 + f11271b commit a4b82d9

142 files changed

Lines changed: 16612 additions & 13413 deletions

File tree

Some content is hidden

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

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ _gopath/
99
.vscode
1010
vendor
1111
dist
12-
Reloader
12+
/reloader
13+
/Reloader
1314
!**/chart/reloader
1415
!**/internal/reloader
1516
*.tgz

.goreleaser.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
builds:
2-
- env:
2+
- main: ./cmd/reloader
3+
binary: reloader
4+
env:
35
- CGO_ENABLED=0
46
goos:
57
- windows
@@ -11,6 +13,11 @@ builds:
1113
- arm
1214
- arm64
1315
- ppc64le
16+
ldflags:
17+
- -s -w
18+
- -X github.com/stakater/Reloader/internal/pkg/metadata.Version={{.Version}}
19+
- -X github.com/stakater/Reloader/internal/pkg/metadata.Commit={{.Commit}}
20+
- -X github.com/stakater/Reloader/internal/pkg/metadata.BuildDate={{.Date}}
1421
archives:
1522
- name_template: "{{ .ProjectName }}_v{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
1623
snapshot:

Dockerfile

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@ COPY go.sum go.sum
2424
RUN go mod download
2525

2626
# Copy the go source
27-
COPY main.go main.go
27+
COPY cmd/ cmd/
2828
COPY internal/ internal/
29-
COPY pkg/ pkg/
3029

3130
# Build
3231
RUN CGO_ENABLED=0 \
@@ -39,7 +38,7 @@ RUN CGO_ENABLED=0 \
3938
-X github.com/stakater/Reloader/pkg/common.Commit=${COMMIT} \
4039
-X github.com/stakater/Reloader/pkg/common.BuildDate=${BUILD_DATE} \
4140
-X github.com/stakater/Reloader/pkg/common.Edition=${EDITION}" \
42-
-installsuffix 'static' -mod=mod -a -o manager ./
41+
-installsuffix 'static' -mod=mod -a -o manager ./cmd/reloader
4342

4443
# Use distroless as minimal base image to package the manager binary
4544
# Refer to https://github.com/GoogleContainerTools/distroless for more details

Dockerfile.ubi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
ARG BUILDER_IMAGE
22
ARG BASE_IMAGE
33

4+
# First stage: Build the binary (using the standard Dockerfile as builder)
45
FROM --platform=${BUILDPLATFORM} ${BUILDER_IMAGE} AS SRC
56

67
FROM ${BASE_IMAGE:-registry.access.redhat.com/ubi9/ubi:9.8-1779374378} AS ubi

Makefile

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,17 @@ BUILD=
2323

2424
GOCMD = go
2525
GOFLAGS ?= $(GOFLAGS:)
26-
LDFLAGS =
2726
GOPROXY ?=
2827
GOPRIVATE ?=
2928

29+
# Version information for ldflags
30+
GIT_COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
31+
BUILD_DATE ?= $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
32+
LDFLAGS = -s -w \
33+
-X github.com/stakater/Reloader/internal/pkg/metadata.Version=$(VERSION) \
34+
-X github.com/stakater/Reloader/internal/pkg/metadata.Commit=$(GIT_COMMIT) \
35+
-X github.com/stakater/Reloader/internal/pkg/metadata.BuildDate=$(BUILD_DATE)
36+
3037
## Location to install dependencies to
3138
LOCALBIN ?= $(shell pwd)/bin
3239
$(LOCALBIN):
@@ -94,10 +101,10 @@ install:
94101
"$(GOCMD)" mod download
95102

96103
run:
97-
go run ./main.go
104+
go run ./cmd/reloader
98105

99106
build:
100-
"$(GOCMD)" build ${GOFLAGS} ${LDFLAGS} -o "${BINARY}"
107+
"$(GOCMD)" build ${GOFLAGS} -ldflags '${LDFLAGS}' -o "${BINARY}" ./cmd/reloader
101108

102109
lint: ## Run golangci-lint on the codebase
103110
go tool golangci-lint run ./...
@@ -141,7 +148,7 @@ manifest:
141148
docker manifest annotate --arch $(ARCH) $(REPOSITORY_GENERIC) $(REPOSITORY_ARCH)
142149

143150
test:
144-
"$(GOCMD)" test -timeout 1800s -v -count=1 ./internal/... ./pkg/... ./test/e2e/utils/...
151+
"$(GOCMD)" test -timeout 1800s -v -count=1 ./internal/... ./test/e2e/utils/...
145152

146153
##@ E2E Tests
147154

@@ -199,8 +206,8 @@ apply:
199206
deploy: binary-image push apply
200207

201208
.PHONY: k8s-manifests
202-
k8s-manifests: $(KUSTOMIZE) ## Generate k8s manifests using Kustomize from 'manifests' folder
203-
$(KUSTOMIZE) build ./deployments/kubernetes/ -o ./deployments/kubernetes/reloader.yaml
209+
k8s-manifests: ## Generate k8s manifests using Kustomize from 'manifests' folder
210+
go tool kustomize build ./deployments/kubernetes/ -o ./deployments/kubernetes/reloader.yaml
204211

205212
.PHONY: update-manifests-version
206213
update-manifests-version: ## Generate k8s manifests using Kustomize from 'manifests' folder

cmd/reloader/main.go

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/http"
7+
_ "net/http/pprof"
8+
"os"
9+
"os/signal"
10+
"syscall"
11+
"time"
12+
13+
"github.com/go-logr/logr"
14+
"github.com/go-logr/zerologr"
15+
"github.com/rs/zerolog"
16+
"github.com/spf13/cobra"
17+
"k8s.io/client-go/discovery"
18+
controllerruntime "sigs.k8s.io/controller-runtime"
19+
20+
"github.com/stakater/Reloader/internal/pkg/config"
21+
"github.com/stakater/Reloader/internal/pkg/controller"
22+
"github.com/stakater/Reloader/internal/pkg/metadata"
23+
"github.com/stakater/Reloader/internal/pkg/metrics"
24+
"github.com/stakater/Reloader/internal/pkg/openshift"
25+
)
26+
27+
// Environment variable names for pod identity in HA mode.
28+
const (
29+
podNameEnv = "POD_NAME"
30+
podNamespaceEnv = "POD_NAMESPACE"
31+
)
32+
33+
// cfg holds the configuration for this reloader instance.
34+
var cfg *config.Config
35+
36+
func main() {
37+
if err := newReloaderCommand().Execute(); err != nil {
38+
os.Exit(1)
39+
}
40+
}
41+
42+
func newReloaderCommand() *cobra.Command {
43+
cfg = config.NewDefault()
44+
45+
cmd := &cobra.Command{
46+
Use: "reloader",
47+
Short: "A watcher for your Kubernetes cluster",
48+
RunE: run,
49+
}
50+
51+
config.BindFlags(cmd.PersistentFlags(), cfg)
52+
return cmd
53+
}
54+
55+
func run(cmd *cobra.Command, args []string) error {
56+
if err := config.ApplyFlags(cfg); err != nil {
57+
return fmt.Errorf("applying flags: %w", err)
58+
}
59+
60+
if err := cfg.Validate(); err != nil {
61+
return fmt.Errorf("validating config: %w", err)
62+
}
63+
64+
if cfg.EnableHA {
65+
if err := validateHAEnvs(); err != nil {
66+
return err
67+
}
68+
cfg.LeaderElection.Identity = os.Getenv(podNameEnv)
69+
if cfg.LeaderElection.Namespace == "" {
70+
cfg.LeaderElection.Namespace = os.Getenv(podNamespaceEnv)
71+
}
72+
}
73+
74+
log, err := configureLogging(cfg.LogFormat, cfg.LogLevel)
75+
if err != nil {
76+
return fmt.Errorf("configuring logging: %w", err)
77+
}
78+
79+
controllerruntime.SetLogger(log)
80+
81+
log.Info("Starting Reloader")
82+
83+
if cfg.WatchedNamespace != "" {
84+
log.Info("watching single namespace", "namespace", cfg.WatchedNamespace)
85+
} else {
86+
log.Info("watching all namespaces")
87+
}
88+
89+
if len(cfg.NamespaceSelectors) > 0 {
90+
log.Info("namespace-selector is set", "selectors", cfg.NamespaceSelectorStrings)
91+
}
92+
93+
if len(cfg.ResourceSelectors) > 0 {
94+
log.Info("resource-label-selector is set", "selectors", cfg.ResourceSelectorStrings)
95+
}
96+
97+
if cfg.WebhookURL != "" {
98+
log.Info("webhook-url is set, will only send webhook, no resources will be reloaded", "url", cfg.WebhookURL)
99+
}
100+
101+
if cfg.EnableHA {
102+
log.Info(
103+
"high-availability mode enabled",
104+
"leaderElectionID", cfg.LeaderElection.LockName,
105+
"leaderElectionNamespace", cfg.LeaderElection.Namespace,
106+
)
107+
}
108+
109+
collectors := metrics.SetupPrometheusEndpoint()
110+
111+
if config.ShouldAutoDetectOpenShift() {
112+
restConfig := controllerruntime.GetConfigOrDie()
113+
discoveryClient, err := discovery.NewDiscoveryClientForConfig(restConfig)
114+
if err != nil {
115+
log.V(1).Info("Failed to create discovery client for DeploymentConfig detection", "error", err)
116+
} else if openshift.HasDeploymentConfigSupport(discoveryClient, log) {
117+
cfg.DeploymentConfigEnabled = true
118+
}
119+
}
120+
121+
controller.AddOptionalSchemes(cfg.ArgoRolloutsEnabled, cfg.DeploymentConfigEnabled)
122+
123+
mgr, err := controller.NewManager(
124+
controller.ManagerOptions{
125+
Config: cfg,
126+
Log: log,
127+
Collectors: &collectors,
128+
},
129+
)
130+
if err != nil {
131+
return fmt.Errorf("creating manager: %w", err)
132+
}
133+
134+
if err := controller.SetupReconcilers(mgr, cfg, log, &collectors); err != nil {
135+
return fmt.Errorf("setting up reconcilers: %w", err)
136+
}
137+
138+
// Skip metadata publisher when ConfigMaps are ignored (no RBAC permissions)
139+
if !cfg.IsResourceIgnored("configmaps") {
140+
if err := mgr.Add(metadata.Runnable(mgr.GetClient(), cfg, log)); err != nil {
141+
log.Error(err, "Failed to add metadata publisher")
142+
// Non-fatal, continue starting
143+
}
144+
} else {
145+
log.Info("skipping metadata publisher (configmaps ignored)")
146+
}
147+
148+
if cfg.EnablePProf {
149+
go startPProfServer(log)
150+
}
151+
152+
ctx, cancel := context.WithCancel(context.Background())
153+
defer cancel()
154+
155+
sigCh := make(chan os.Signal, 1)
156+
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
157+
go func() {
158+
sig := <-sigCh
159+
log.Info("Received signal, shutting down", "signal", sig)
160+
cancel()
161+
}()
162+
163+
log.Info("Starting controller manager")
164+
if err := controller.RunManager(ctx, mgr, log); err != nil {
165+
return fmt.Errorf("manager exited with error: %w", err)
166+
}
167+
168+
log.Info("Reloader shutdown complete")
169+
return nil
170+
}
171+
172+
func configureLogging(logFormat, logLevel string) (logr.Logger, error) {
173+
// Parse log level
174+
var level zerolog.Level
175+
switch logLevel {
176+
case "trace":
177+
level = zerolog.TraceLevel
178+
case "debug":
179+
level = zerolog.DebugLevel
180+
case "info", "":
181+
level = zerolog.InfoLevel
182+
case "warn", "warning":
183+
level = zerolog.WarnLevel
184+
case "error":
185+
level = zerolog.ErrorLevel
186+
default:
187+
return logr.Logger{}, fmt.Errorf("unsupported log level: %q", logLevel)
188+
}
189+
190+
var zl zerolog.Logger
191+
switch logFormat {
192+
case "json":
193+
zl = zerolog.New(os.Stdout).Level(level).With().Timestamp().Logger()
194+
case "":
195+
// Human-readable console output
196+
zl = zerolog.New(
197+
zerolog.ConsoleWriter{
198+
Out: os.Stdout,
199+
TimeFormat: time.RFC3339,
200+
},
201+
).Level(level).With().Timestamp().Logger()
202+
default:
203+
return logr.Logger{}, fmt.Errorf("unsupported log format: %q", logFormat)
204+
}
205+
206+
return zerologr.New(&zl), nil
207+
}
208+
209+
func validateHAEnvs() error {
210+
podName := os.Getenv(podNameEnv)
211+
podNamespace := os.Getenv(podNamespaceEnv)
212+
213+
if podName == "" {
214+
return fmt.Errorf("%s not set, cannot run in HA mode", podNameEnv)
215+
}
216+
if podNamespace == "" {
217+
return fmt.Errorf("%s not set, cannot run in HA mode", podNamespaceEnv)
218+
}
219+
return nil
220+
}
221+
222+
func startPProfServer(log logr.Logger) {
223+
log.Info("Starting pprof server", "addr", cfg.PProfAddr)
224+
if err := http.ListenAndServe(cfg.PProfAddr, nil); err != nil {
225+
log.Error(err, "Failed to start pprof server")
226+
}
227+
}

deployments/kubernetes/chart/reloader/templates/clusterrole.yaml

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ rules:
5656
{{- if and (.Capabilities.APIVersions.Has "argoproj.io/v1alpha1") (.Values.reloader.isArgoRollouts) }}
5757
- apiGroups:
5858
- "argoproj.io"
59-
- ""
6059
resources:
6160
- rollouts
6261
verbs:
6362
- list
6463
- get
64+
- watch
6565
- update
6666
- patch
6767
{{- end }}
@@ -76,6 +76,7 @@ rules:
7676
- get
7777
- update
7878
- patch
79+
- watch
7980
{{- if .Values.reloader.ignoreCronJobs }}{{- else }}
8081
- apiGroups:
8182
- "batch"
@@ -84,6 +85,9 @@ rules:
8485
verbs:
8586
- list
8687
- get
88+
- watch
89+
- update
90+
- patch
8791
{{- end }}
8892
{{- if .Values.reloader.ignoreJobs }}{{- else }}
8993
- apiGroups:
@@ -95,6 +99,7 @@ rules:
9599
- delete
96100
- list
97101
- get
102+
- watch
98103
{{- end}}
99104
{{- if .Values.reloader.enableHA }}
100105
- apiGroups:
@@ -105,17 +110,6 @@ rules:
105110
- create
106111
- get
107112
- update
108-
{{- end}}
109-
{{- if .Values.reloader.enableCSIIntegration }}
110-
- apiGroups:
111-
- "secrets-store.csi.x-k8s.io"
112-
resources:
113-
- secretproviderclasspodstatuses
114-
- secretproviderclasses
115-
verbs:
116-
- list
117-
- get
118-
- watch
119113
{{- end}}
120114
- apiGroups:
121115
- ""

0 commit comments

Comments
 (0)