mirror of
https://github.com/stakater/Reloader.git
synced 2026-08-20 04:26:28 +00:00
added support for multiple watch namespaces
This commit is contained in:
@@ -54,7 +54,8 @@ func newReloaderCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
func run(cmd *cobra.Command, args []string) error {
|
||||
if err := config.ApplyFlags(cfg); err != nil {
|
||||
scopeWarnings, err := config.ApplyFlags(cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("applying flags: %w", err)
|
||||
}
|
||||
|
||||
@@ -81,9 +82,9 @@ func run(cmd *cobra.Command, args []string) error {
|
||||
|
||||
log.Info("Starting Reloader")
|
||||
|
||||
// Enforce master-parity scope semantics before reconcilers/manager read the
|
||||
// config: selector and ignore lists are only honored in global mode.
|
||||
for _, w := range cfg.ApplyNamespaceScope() {
|
||||
// Namespace-scope semantics are enforced in ApplyFlags; surface any warnings
|
||||
// it produced now that logging is configured.
|
||||
for _, w := range scopeWarnings {
|
||||
log.Info(w)
|
||||
}
|
||||
|
||||
|
||||
@@ -89,13 +89,12 @@ Create the namespace selector if it does not watch globally
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Effective set of namespaces to watch in scoped mode: the release namespace
|
||||
(always included so the meta-info ConfigMap, HA leases and events keep working)
|
||||
plus the user-supplied reloader.namespaces, deduped and sorted.
|
||||
Namespaces to watch in scoped mode: exactly the user-supplied reloader.namespaces,
|
||||
trimmed, de-duped and sorted. The release namespace is intentionally NOT added here
|
||||
— Reloader watches only what the user asked for (an empty result means global mode).
|
||||
Returns a JSON-encoded list; consumers use mustFromJson to iterate.
|
||||
*/}}
|
||||
{{- define "reloader-watchNamespaces" -}}
|
||||
{{- $relNs := .Values.namespace | default .Release.Namespace -}}
|
||||
{{- $ns := .Values.reloader.namespaces | default list -}}
|
||||
{{- if kindIs "string" $ns -}}
|
||||
{{- $ns = splitList "," $ns -}}
|
||||
@@ -107,8 +106,7 @@ Returns a JSON-encoded list; consumers use mustFromJson to iterate.
|
||||
{{- $clean = append $clean $t -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- $all := concat (list $relNs) $clean | uniq | sortAlpha -}}
|
||||
{{- $all | toJson -}}
|
||||
{{- $clean | uniq | sortAlpha | toJson -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
@@ -118,6 +116,18 @@ Comma-joined form of reloader-watchNamespaces, for the --namespaces CLI flag.
|
||||
{{- include "reloader-watchNamespaces" . | mustFromJson | join "," -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Namespaces that need namespaced RBAC in scoped mode: the watched namespaces plus
|
||||
the release namespace, so leader-election leases, the meta-info ConfigMap and
|
||||
events keep working there even though it is not watched for reloads.
|
||||
Returns a JSON-encoded list; consumers use mustFromJson to iterate.
|
||||
*/}}
|
||||
{{- define "reloader-rbacNamespaces" -}}
|
||||
{{- $relNs := .Values.namespace | default .Release.Namespace -}}
|
||||
{{- $watch := include "reloader-watchNamespaces" . | mustFromJson -}}
|
||||
{{- concat (list $relNs) $watch | uniq | sortAlpha | toJson -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
The namespaced RBAC rules granted to Reloader in every watched namespace.
|
||||
Shared between the single-namespace Role and the per-namespace scoped Roles so
|
||||
|
||||
@@ -56,7 +56,6 @@ rules:
|
||||
{{- if and (.Capabilities.APIVersions.Has "argoproj.io/v1alpha1") (.Values.reloader.isArgoRollouts) }}
|
||||
- apiGroups:
|
||||
- "argoproj.io"
|
||||
- ""
|
||||
resources:
|
||||
- rollouts
|
||||
verbs:
|
||||
|
||||
@@ -241,7 +241,7 @@ spec:
|
||||
- "--namespaces-to-ignore={{ .Values.reloader.ignoreNamespaces }}"
|
||||
{{- end }}
|
||||
{{- if (include "reloader-namespaceSelector" .) }}
|
||||
- "--namespace-selector=\"{{ include "reloader-namespaceSelector" . }}\""
|
||||
- "--namespace-selector={{ include "reloader-namespaceSelector" . }}"
|
||||
{{- end }}
|
||||
{{- if .Values.reloader.resourceLabelSelector }}
|
||||
- "--resource-label-selector={{ .Values.reloader.resourceLabelSelector }}"
|
||||
@@ -275,6 +275,26 @@ spec:
|
||||
{{- if .Values.reloader.custom_annotations.configmap_auto }}
|
||||
- "--configmap-auto-annotation"
|
||||
- "{{ .Values.reloader.custom_annotations.configmap_auto }}"
|
||||
{{- end }}
|
||||
{{- if .Values.reloader.custom_annotations.configmap_exclude }}
|
||||
- "--configmap-exclude-annotation"
|
||||
- "{{ .Values.reloader.custom_annotations.configmap_exclude }}"
|
||||
{{- end }}
|
||||
{{- if .Values.reloader.custom_annotations.secret_exclude }}
|
||||
- "--secret-exclude-annotation"
|
||||
- "{{ .Values.reloader.custom_annotations.secret_exclude }}"
|
||||
{{- end }}
|
||||
{{- if .Values.reloader.custom_annotations.secretproviderclass }}
|
||||
- "--secretproviderclass-annotation"
|
||||
- "{{ .Values.reloader.custom_annotations.secretproviderclass }}"
|
||||
{{- end }}
|
||||
{{- if .Values.reloader.custom_annotations.secretproviderclass_auto }}
|
||||
- "--secretproviderclass-auto-annotation"
|
||||
- "{{ .Values.reloader.custom_annotations.secretproviderclass_auto }}"
|
||||
{{- end }}
|
||||
{{- if .Values.reloader.custom_annotations.secretproviderclass_exclude }}
|
||||
- "--secretproviderclass-exclude-annotation"
|
||||
- "{{ .Values.reloader.custom_annotations.secretproviderclass_exclude }}"
|
||||
{{- end }}
|
||||
{{- if .Values.reloader.custom_annotations.search }}
|
||||
- "--auto-search-annotation"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
{{- $apiVersion = "rbac.authorization.k8s.io/v1beta1" }}
|
||||
{{- end }}
|
||||
{{- if .Values.reloader.namespaces }}
|
||||
{{- range $ns := (include "reloader-watchNamespaces" . | mustFromJson) }}
|
||||
{{- range $ns := (include "reloader-rbacNamespaces" . | mustFromJson) }}
|
||||
apiVersion: {{ $apiVersion }}
|
||||
kind: Role
|
||||
metadata:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
{{- $apiVersion = "rbac.authorization.k8s.io/v1beta1" }}
|
||||
{{- end }}
|
||||
{{- if .Values.reloader.namespaces }}
|
||||
{{- range $ns := (include "reloader-watchNamespaces" . | mustFromJson) }}
|
||||
{{- range $ns := (include "reloader-rbacNamespaces" . | mustFromJson) }}
|
||||
apiVersion: {{ $apiVersion }}
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
|
||||
@@ -223,6 +223,11 @@ reloader:
|
||||
# custom_annotations:
|
||||
# configmap: "my.company.com/configmap"
|
||||
# secret: "my.company.com/secret"
|
||||
# configmap_exclude: "my.company.com/configmap-exclude"
|
||||
# secret_exclude: "my.company.com/secret-exclude"
|
||||
# secretproviderclass: "my.company.com/secretproviderclass"
|
||||
# secretproviderclass_auto: "my.company.com/secretproviderclass-auto"
|
||||
# secretproviderclass_exclude: "my.company.com/secretproviderclass-exclude"
|
||||
# ignore: "my.company.com/reloader-ignore"
|
||||
custom_annotations: {}
|
||||
|
||||
|
||||
@@ -264,9 +264,11 @@ func BindFlags(fs *pflag.FlagSet, cfg *Config) {
|
||||
_ = v.BindEnv("alert-proxy", "ALERT_PROXY", "ALERT_WEBHOOK_PROXY")
|
||||
}
|
||||
|
||||
// ApplyFlags applies flag values from viper to the config struct.
|
||||
// Call this after parsing flags.
|
||||
func ApplyFlags(cfg *Config) error {
|
||||
// ApplyFlags applies flag values from viper to the config struct. Call this
|
||||
// after parsing flags. It returns any human-readable warnings produced while
|
||||
// finalizing namespace scope (see ApplyNamespaceScope) so the caller can log
|
||||
// them once a logger is available.
|
||||
func ApplyFlags(cfg *Config) ([]string, error) {
|
||||
// Boolean flags
|
||||
cfg.AutoReloadAll = v.GetBool("auto-reload-all")
|
||||
cfg.SyncAfterRestart = v.GetBool("sync-after-restart")
|
||||
@@ -365,7 +367,7 @@ func ApplyFlags(cfg *Config) error {
|
||||
joinedNS := strings.Join(nsSelectors, ",")
|
||||
selector, err := labels.Parse(joinedNS)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid selector %q: %w", joinedNS, err)
|
||||
return nil, fmt.Errorf("invalid selector %q: %w", joinedNS, err)
|
||||
}
|
||||
cfg.NamespaceSelectors = []labels.Selector{selector}
|
||||
}
|
||||
@@ -373,7 +375,7 @@ func ApplyFlags(cfg *Config) error {
|
||||
joinedRes := strings.Join(resSelectors, ",")
|
||||
selector, err := labels.Parse(joinedRes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid selector %q: %w", joinedRes, err)
|
||||
return nil, fmt.Errorf("invalid selector %q: %w", joinedRes, err)
|
||||
}
|
||||
cfg.ResourceSelectors = []labels.Selector{selector}
|
||||
}
|
||||
@@ -389,7 +391,11 @@ func ApplyFlags(cfg *Config) error {
|
||||
cfg.LeaderElection.RetryPeriod = 2 * time.Second
|
||||
}
|
||||
|
||||
return nil
|
||||
// Enforce namespace-scope semantics here so the finalized config is
|
||||
// self-consistent for every caller: selector/ignore lists are only honored
|
||||
// in global mode. Warnings are returned for the caller to log once logging
|
||||
// is set up.
|
||||
return cfg.ApplyNamespaceScope(), nil
|
||||
}
|
||||
|
||||
// parseBoolString parses a string as a boolean, defaulting to false.
|
||||
|
||||
@@ -92,7 +92,7 @@ func TestBindFlags_DefaultValues(t *testing.T) {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ func TestBindFlags_CustomValues(t *testing.T) {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ func TestApplyFlags_SecretProviderClassAnnotations(t *testing.T) {
|
||||
if err := fs.Parse(nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
defaults := DefaultAnnotations()
|
||||
@@ -195,7 +195,7 @@ func TestApplyFlags_SecretProviderClassAnnotations(t *testing.T) {
|
||||
if err := fs.Parse(args); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
if cfg.Annotations.SecretProviderClassAuto != "spc.example.com/auto" {
|
||||
@@ -218,7 +218,7 @@ func TestApplyFlags_ExcludeAnnotations(t *testing.T) {
|
||||
if err := fs.Parse(nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
defaults := DefaultAnnotations()
|
||||
@@ -241,7 +241,7 @@ func TestApplyFlags_ExcludeAnnotations(t *testing.T) {
|
||||
if err := fs.Parse(args); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
if cfg.Annotations.ConfigmapExclude != "cm.example.com/exclude" {
|
||||
@@ -261,7 +261,7 @@ func TestApplyFlags_IgnoreAnnotation(t *testing.T) {
|
||||
if err := fs.Parse(nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
if cfg.Annotations.Ignore != DefaultAnnotations().Ignore {
|
||||
@@ -276,7 +276,7 @@ func TestApplyFlags_IgnoreAnnotation(t *testing.T) {
|
||||
if err := fs.Parse([]string{"--ignore-annotation=my.company.com/reloader-ignore"}); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
if cfg.Annotations.Ignore != "my.company.com/reloader-ignore" {
|
||||
@@ -313,7 +313,7 @@ func TestApplyFlags_BooleanStrings(t *testing.T) {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
err := ApplyFlags(cfg)
|
||||
_, err := ApplyFlags(cfg)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ApplyFlags() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
@@ -343,7 +343,7 @@ func TestApplyFlags_CommaSeparatedLists(t *testing.T) {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
|
||||
@@ -378,7 +378,7 @@ func TestApplyFlags_Selectors(t *testing.T) {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
|
||||
@@ -409,7 +409,7 @@ func TestApplyFlags_InvalidSelector(t *testing.T) {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
err := ApplyFlags(cfg)
|
||||
_, err := ApplyFlags(cfg)
|
||||
if err == nil {
|
||||
t.Error("ApplyFlags() should return error for invalid selector")
|
||||
}
|
||||
@@ -461,7 +461,7 @@ func TestApplyFlags_AlertingEnvVars(t *testing.T) {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
|
||||
@@ -494,7 +494,7 @@ func TestApplyFlags_LegacyProxyEnvVar(t *testing.T) {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
|
||||
@@ -511,7 +511,7 @@ func TestApplyFlagsCSIIntegration(t *testing.T) {
|
||||
if err := fs.Parse([]string{"--enable-csi-integration=true"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !cfg.CSIIntegrationEnabled {
|
||||
@@ -592,7 +592,7 @@ func TestApplyFlags_NamespacesScoped(t *testing.T) {
|
||||
if err := fs.Parse([]string{"--namespaces=team-a,team-b"}); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
|
||||
@@ -617,7 +617,7 @@ func TestApplyFlags_NamespacesFromEnv(t *testing.T) {
|
||||
if err := fs.Parse([]string{}); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
|
||||
@@ -636,7 +636,7 @@ func TestApplyFlags_NamespacesGlobal(t *testing.T) {
|
||||
if err := fs.Parse([]string{}); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
|
||||
@@ -657,7 +657,7 @@ func TestApplyFlags_NamespacesTrimsEmptyEntries(t *testing.T) {
|
||||
if err := fs.Parse([]string{"--namespaces=team-a, ,team-b,"}); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
|
||||
@@ -682,7 +682,7 @@ func TestApplyFlags_NamespacesAllEmptyIsGlobal(t *testing.T) {
|
||||
if err := fs.Parse([]string{"--namespaces=, ,"}); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
if err := ApplyFlags(cfg); err != nil {
|
||||
if _, err := ApplyFlags(cfg); err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
|
||||
@@ -693,3 +693,64 @@ func TestApplyFlags_NamespacesAllEmptyIsGlobal(t *testing.T) {
|
||||
t.Errorf("all-empty namespaces should be global mode")
|
||||
}
|
||||
}
|
||||
|
||||
// ApplyFlags must finalize a self-consistent config: in scoped mode it enforces
|
||||
// namespace-scope semantics (clears selector/ignore lists) and returns warnings,
|
||||
// without the caller having to invoke ApplyNamespaceScope separately.
|
||||
func TestApplyFlags_ScopedClearsSelectorsAndIgnores(t *testing.T) {
|
||||
resetViper()
|
||||
cfg := NewDefault()
|
||||
fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
|
||||
BindFlags(fs, cfg)
|
||||
|
||||
if err := fs.Parse([]string{
|
||||
"--namespaces=team-a",
|
||||
"--namespace-selector=env=prod",
|
||||
"--namespaces-to-ignore=kube-system",
|
||||
}); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
warnings, err := ApplyFlags(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
|
||||
if len(cfg.NamespaceSelectors) != 0 || len(cfg.NamespaceSelectorStrings) != 0 {
|
||||
t.Errorf("scoped mode should clear namespace selectors, got %v", cfg.NamespaceSelectorStrings)
|
||||
}
|
||||
if len(cfg.IgnoredNamespaces) != 0 {
|
||||
t.Errorf("scoped mode should clear ignored namespaces, got %v", cfg.IgnoredNamespaces)
|
||||
}
|
||||
if len(warnings) != 2 {
|
||||
t.Errorf("expected 2 scope warnings, got %v", warnings)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyFlags_GlobalKeepsSelectorsNoWarnings(t *testing.T) {
|
||||
resetViper()
|
||||
t.Setenv("KUBERNETES_NAMESPACE", "")
|
||||
cfg := NewDefault()
|
||||
fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
|
||||
BindFlags(fs, cfg)
|
||||
|
||||
if err := fs.Parse([]string{
|
||||
"--namespace-selector=env=prod",
|
||||
"--namespaces-to-ignore=kube-system",
|
||||
}); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
warnings, err := ApplyFlags(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("ApplyFlags() error = %v", err)
|
||||
}
|
||||
|
||||
if !cfg.IsGlobalMode() {
|
||||
t.Fatalf("no --namespaces should be global mode")
|
||||
}
|
||||
if len(cfg.NamespaceSelectors) != 1 || len(cfg.IgnoredNamespaces) != 1 {
|
||||
t.Errorf("global mode should keep selectors and ignored namespaces")
|
||||
}
|
||||
if len(warnings) != 0 {
|
||||
t.Errorf("global mode should produce no warnings, got %v", warnings)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,9 +66,18 @@ type ManagerOptions struct {
|
||||
Collectors *metrics.Collectors
|
||||
}
|
||||
|
||||
// NewManager creates a new controller-runtime manager with the given options.
|
||||
// This follows controller-runtime and operator-sdk conventions for leader election.
|
||||
// NewManager creates a new controller-runtime manager using the ambient cluster
|
||||
// configuration (in-cluster or kubeconfig). It follows controller-runtime and
|
||||
// operator-sdk conventions for leader election.
|
||||
func NewManager(opts ManagerOptions) (ctrl.Manager, error) {
|
||||
return NewManagerWithRestConfig(opts, ctrl.GetConfigOrDie())
|
||||
}
|
||||
|
||||
// NewManagerWithRestConfig creates a new controller-runtime manager with the
|
||||
// given rest.Config. NewManager delegates here; tests can call it directly with
|
||||
// a pre-existing cluster configuration (set cfg.MetricsAddr/HealthAddr to "0" to
|
||||
// disable those servers and avoid port conflicts).
|
||||
func NewManagerWithRestConfig(opts ManagerOptions, restConfig *rest.Config) (ctrl.Manager, error) {
|
||||
cfg := opts.Config
|
||||
le := cfg.LeaderElection
|
||||
|
||||
@@ -100,7 +109,7 @@ func NewManager(opts ManagerOptions) (ctrl.Manager, error) {
|
||||
opts.Log.Info("namespace filtering enabled", "namespaces", cfg.WatchedNamespaces)
|
||||
}
|
||||
|
||||
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), mgrOpts)
|
||||
mgr, err := ctrl.NewManager(restConfig, mgrOpts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating manager: %w", err)
|
||||
}
|
||||
@@ -119,43 +128,6 @@ func NewManager(opts ManagerOptions) (ctrl.Manager, error) {
|
||||
return mgr, nil
|
||||
}
|
||||
|
||||
// NewManagerWithRestConfig creates a new controller-runtime manager with the given rest.Config.
|
||||
// This is useful for testing where you have a pre-existing cluster configuration.
|
||||
func NewManagerWithRestConfig(opts ManagerOptions, restConfig *rest.Config) (ctrl.Manager, error) {
|
||||
cfg := opts.Config
|
||||
le := cfg.LeaderElection
|
||||
|
||||
mgrOpts := ctrl.Options{
|
||||
Scheme: runtimeScheme,
|
||||
Metrics: ctrlmetrics.Options{
|
||||
BindAddress: "0", // Disable metrics server in tests
|
||||
},
|
||||
HealthProbeBindAddress: "0", // Disable health probes in tests
|
||||
|
||||
// Leader election configuration
|
||||
LeaderElection: cfg.EnableHA,
|
||||
LeaderElectionID: le.LockName,
|
||||
LeaderElectionNamespace: le.Namespace,
|
||||
LeaderElectionReleaseOnCancel: le.ReleaseOnCancel,
|
||||
LeaseDuration: &le.LeaseDuration,
|
||||
RenewDeadline: &le.RenewDeadline,
|
||||
RetryPeriod: &le.RetryPeriod,
|
||||
}
|
||||
|
||||
if nsScope := buildDefaultNamespaces(cfg.WatchedNamespaces); nsScope != nil {
|
||||
mgrOpts.Cache = cache.Options{
|
||||
DefaultNamespaces: nsScope,
|
||||
}
|
||||
}
|
||||
|
||||
mgr, err := ctrl.NewManager(restConfig, mgrOpts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating manager: %w", err)
|
||||
}
|
||||
|
||||
return mgr, nil
|
||||
}
|
||||
|
||||
// SetupReconcilers sets up all reconcilers with the manager.
|
||||
func SetupReconcilers(mgr ctrl.Manager, cfg *config.Config, log logr.Logger, collectors *metrics.Collectors) error {
|
||||
registry := workload.NewRegistry(
|
||||
|
||||
Reference in New Issue
Block a user