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
38 changes: 19 additions & 19 deletions cmd/reloader/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,15 @@ func newReloaderCommand() *cobra.Command {
}

func run(cmd *cobra.Command, args []string) error {
if err := config.ApplyFlags(cfg); err != nil {
// Configure logging first so ApplyFlags can surface namespace-scope warnings
// through a ready logger instead of returning them to the caller.
log, err := configureLogging(config.LoggingFlags())
if err != nil {
return fmt.Errorf("configuring logging: %w", err)
}
controllerruntime.SetLogger(log)

if err := config.ApplyFlags(cfg, log); err != nil {
return fmt.Errorf("applying flags: %w", err)
}

Expand All @@ -72,19 +80,12 @@ func run(cmd *cobra.Command, args []string) error {
}
}

log, err := configureLogging(cfg.LogFormat, cfg.LogLevel)
if err != nil {
return fmt.Errorf("configuring logging: %w", err)
}

controllerruntime.SetLogger(log)

log.Info("Starting Reloader")

if cfg.WatchedNamespace != "" {
log.Info("watching single namespace", "namespace", cfg.WatchedNamespace)
} else {
if cfg.IsGlobalMode() {
log.Info("watching all namespaces")
} else {
log.Info("watching scoped namespaces", "namespaces", cfg.WatchedNamespaces)
}

if len(cfg.NamespaceSelectors) > 0 {
Expand Down Expand Up @@ -149,14 +150,13 @@ func run(cmd *cobra.Command, args []string) error {
return fmt.Errorf("setting up reconcilers: %w", err)
}

// Skip metadata publisher when ConfigMaps are ignored (no RBAC permissions)
if !cfg.IsResourceIgnored("configmaps") {
if err := mgr.Add(metadata.Runnable(mgr.GetClient(), cfg, log)); err != nil {
log.Error(err, "Failed to add metadata publisher")
// Non-fatal, continue starting
}
} else {
log.Info("skipping metadata publisher (configmaps ignored)")
// Meta-info is internal instance metadata and is always published. The
// publisher builds its own uncached client (see metadata.Runnable) because
// the ConfigMap lives in Reloader's own namespace, which the manager cache
// does not cover in scoped mode.
if err := mgr.Add(metadata.Runnable(mgr.GetConfig(), mgr.GetScheme(), cfg, log)); err != nil {
log.Error(err, "Failed to add metadata publisher")
// Non-fatal, continue starting
}

if cfg.EnablePProf {
Expand Down
3 changes: 2 additions & 1 deletion deployments/kubernetes/chart/reloader/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,12 @@ helm uninstall {{RELEASE_NAME}} -n {{NAMESPACE}}
| `reloader.reloadOnDelete` | Enable reload on delete events. Valid value are either `true` or `false` | boolean | `false` |
| `reloader.syncAfterRestart` | Enable sync after Reloader restarts for **Add** events, works only when reloadOnCreate is `true`. Valid value are either `true` or `false` | boolean | `false` |
| `reloader.reloadStrategy` | Strategy to trigger resource restart, set to either `default`, `env-vars` or `annotations` | enumeration | `default` |
| `reloader.ignoreNamespaces` | List of comma separated namespaces to ignore, if multiple are provided, they are combined with the AND operator | string | `""` |
| `reloader.ignoreNamespaces` | List of comma separated namespaces to ignore, if multiple are provided, they are combined with the AND operator. Only honored when `reloader.watchGlobally` is `true`; in single-namespace and scoped (`reloader.namespaces`) modes the watched set is already explicit and this value is ignored. | string | `""` |
Comment thread
msafwankarim marked this conversation as resolved.
| `reloader.namespaceSelector` | List of comma separated k8s label selectors for namespaces selection. The parameter only used when `reloader.watchGlobally` is `true`. See [LIST and WATCH filtering](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#list-and-watch-filtering) for more details on label-selector | string | `""` |
| `reloader.resourceLabelSelector` | List of comma separated label selectors, if multiple are provided they are combined with the AND operator | string | `""` |
| `reloader.logFormat` | Set type of log format. Value could be either `json` or `""` | string | `""` |
| `reloader.watchGlobally` | Allow Reloader to watch in all namespaces (`true`) or just in a single namespace (`false`) | boolean | `true` |
| `reloader.namespaces` | Explicit namespaces to watch (scoped mode). When non-empty and `reloader.watchGlobally` is `false`, Reloader watches exactly these namespaces and the chart creates a namespace-scoped Role + RoleBinding in each (no ClusterRole). The release namespace is not watched for reloads unless you list it explicitly; the chart only grants it a minimal Role for Reloader's internal meta-info ConfigMap (and leader-election in HA). Accepts either a YAML list (`["team-a","team-b"]`) or a comma-separated string (`"team-a,team-b"`). | list/string | `[]` |
| `reloader.enableHA` | Enable leadership election allowing you to run multiple replicas | boolean | `false` |
| `reloader.enablePProf` | Enables pprof for profiling | boolean | `false` |
| `reloader.pprofAddr` | Address to start pprof server on | string | `:6060` |
Expand Down
225 changes: 225 additions & 0 deletions deployments/kubernetes/chart/reloader/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,231 @@ Create the namespace selector if it does not watch globally
{{- end -}}
{{- end -}}

{{/*
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 is not necessarily
global mode: with watchGlobally=false it becomes single-namespace mode (the release
namespace, injected via --namespaces by reloader-effectiveNamespaces-csv); only with
watchGlobally=true does empty mean watch-all.
Returns a JSON-encoded list; consumers use mustFromJson to iterate.
*/}}
{{- define "reloader-watchNamespaces" -}}
{{- $ns := .Values.reloader.namespaces | default list -}}
{{- if kindIs "string" $ns -}}
{{- $ns = splitList "," $ns -}}
{{- end -}}
{{- $clean := list -}}
{{- range $ns -}}
{{- $t := . | toString | trim -}}
{{- if $t -}}
{{- $clean = append $clean $t -}}
{{- end -}}
{{- end -}}
{{- $clean | uniq | sortAlpha | toJson -}}
{{- end -}}

{{/*
Comma-joined form of reloader-watchNamespaces, for the --namespaces CLI flag.
*/}}
{{- define "reloader-watchNamespaces-csv" -}}
{{- include "reloader-watchNamespaces" . | mustFromJson | join "," -}}
{{- end -}}

{{/*
The effective watched namespaces for the --namespaces CLI flag — the single
chart-side source of truth for watch scope, so the binary never has to fall back
to the KUBERNETES_NAMESPACE env:
- scoped mode -> the cleaned reloader.namespaces list
- single-namespace mode -> the release namespace (watchGlobally=false, no list)
- global mode -> empty (no --namespaces flag; watch all)
Returns a comma-joined string ("" in global mode).
*/}}
{{- define "reloader-effectiveNamespaces-csv" -}}
{{- $watch := include "reloader-watchNamespaces" . | mustFromJson -}}
{{- if $watch -}}
{{- $watch | join "," -}}
{{- else if not .Values.reloader.watchGlobally -}}
{{- .Values.namespace | default .Release.Namespace -}}
{{- end -}}
{{- end -}}

{{/*
Whether Reloader runs in scoped mode. This is the single source of truth for the
scoped-vs-global decision: it is true only when the cleaned watch list
(reloader-watchNamespaces) is non-empty. Gate on this rather than the raw
.Values.reloader.namespaces, which is truthy even for values like " , " that trim
to an empty list (those must fall through to global/single-namespace mode).
Returns "true" (truthy) or "" (falsy).
*/}}
{{- define "reloader-isScoped" -}}
{{- if include "reloader-watchNamespaces" . | mustFromJson -}}
true
{{- end -}}
{{- end -}}

{{/*
Fails the render on an inconsistent namespace configuration: reloader.namespaces
(scoped mode) requires reloader.watchGlobally=false. Included from deployment.yaml
so it is validated once regardless of which templates render.
*/}}
{{- define "reloader-validate-namespaces" -}}
{{- if and .Values.reloader.watchGlobally (include "reloader-isScoped" .) -}}
{{- fail "reloader.namespaces is set but reloader.watchGlobally is true; set reloader.watchGlobally=false to use scoped namespace mode." -}}
{{- end -}}
{{- end -}}

{{/*
RBAC rules Reloader needs in its own (release) namespace, independent of the
watched namespaces. Reloader publishes an internal meta-info ConfigMap there in
every mode, so configmap write access is always granted. In scoped mode the
release namespace is not covered by the watch RBAC, so under HA the leader-election
leases and the events it emits are granted here too; in global/single mode those
are already covered by the ClusterRole or the single-namespace Role.
Expects the root context ($) as its argument.
*/}}
{{- define "reloader-release-rules" }}
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- create
- update
- patch
{{- if and (include "reloader-isScoped" .) .Values.reloader.enableHA }}
- apiGroups:
- "coordination.k8s.io"
resources:
- leases
verbs:
- create
- get
- update
- apiGroups:
- ""
- "events.k8s.io"
resources:
- events
verbs:
- create
- patch
- update
{{- end }}
{{- 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
the rule set is defined once. Expects the root context ($) as its argument.
*/}}
{{- define "reloader-namespaced-rules" }}
- apiGroups:
- ""
resources:
{{- if .Values.reloader.ignoreSecrets }}{{- else }}
- secrets
{{- end }}
{{- if .Values.reloader.ignoreConfigMaps }}{{- else }}
- configmaps
{{- end }}
verbs:
- list
- get
- watch
{{- if and (.Capabilities.APIVersions.Has "apps.openshift.io/v1") (.Values.reloader.isOpenshift) }}
- apiGroups:
- "apps.openshift.io"
- ""
resources:
- deploymentconfigs
verbs:
- list
- get
- update
- patch
{{- end }}
{{- if and (.Capabilities.APIVersions.Has "argoproj.io/v1alpha1") (.Values.reloader.isArgoRollouts) }}
- apiGroups:
- "argoproj.io"
resources:
- rollouts
verbs:
- list
- get
- watch
- update
- patch
{{- end }}
- apiGroups:
- "apps"
resources:
- deployments
- daemonsets
- statefulsets
verbs:
- list
- get
- watch
- update
- patch
{{- if .Values.reloader.ignoreCronJobs }}{{- else }}
- apiGroups:
- "batch"
resources:
- cronjobs
verbs:
- list
- get
- watch
- update
- patch
{{- end }}
{{- if .Values.reloader.ignoreJobs }}{{- else }}
- apiGroups:
- "batch"
resources:
- jobs
verbs:
- create
- delete
- list
- get
- watch
{{- end }}
{{- if .Values.reloader.enableHA }}
- apiGroups:
- "coordination.k8s.io"
resources:
- leases
verbs:
- create
- get
- update
{{- end}}
{{- if .Values.reloader.enableCSIIntegration }}
- apiGroups:
- "secrets-store.csi.x-k8s.io"
resources:
- secretproviderclasspodstatuses
- secretproviderclasses
verbs:
- list
- get
- watch
{{- end}}
- apiGroups:
- ""
- "events.k8s.io"
resources:
- events
verbs:
- create
- patch
- update
{{- end -}}

{{/*
Normalizes global.imagePullSecrets to a list of objects with name fields.
Supports both of these in values.yaml:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ rules:
verbs:
- list
- get
- watch
- update
- patch
- watch
{{- if .Values.reloader.ignoreCronJobs }}{{- else }}
- apiGroups:
- "batch"
Expand Down Expand Up @@ -124,9 +124,11 @@ rules:
{{- end}}
- apiGroups:
- ""
- "events.k8s.io"
resources:
- events
verbs:
- create
- patch
- update
{{- end }}
16 changes: 7 additions & 9 deletions deployments/kubernetes/chart/reloader/templates/deployment.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{{- include "reloader-validate-namespaces" . -}}
apiVersion: apps/v1
kind: Deployment
metadata:
Expand Down Expand Up @@ -143,12 +144,6 @@ spec:
fieldRef:
fieldPath: {{ $value | quote}}
{{- end }}
{{- end }}
{{- if eq .Values.reloader.watchGlobally false }}
- name: KUBERNETES_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
{{- end }}

- name: RELOADER_NAMESPACE
Expand Down Expand Up @@ -215,7 +210,7 @@ spec:
{{- . | toYaml | nindent 10 }}
{{- end }}
{{- end }}
{{- if or (.Values.reloader.logFormat) (.Values.reloader.logLevel) (.Values.reloader.ignoreSecrets) (.Values.reloader.ignoreNamespaces) (include "reloader-namespaceSelector" .) (.Values.reloader.resourceLabelSelector) (.Values.reloader.ignoreConfigMaps) (.Values.reloader.custom_annotations) (eq .Values.reloader.isArgoRollouts true) (eq .Values.reloader.reloadOnCreate true) (eq .Values.reloader.reloadOnDelete true) (ne .Values.reloader.reloadStrategy "default") (.Values.reloader.enableHA) (.Values.reloader.autoReloadAll) (.Values.reloader.ignoreJobs) (.Values.reloader.ignoreCronJobs) (.Values.reloader.enableCSIIntegration)}}
{{- if or (.Values.reloader.logFormat) (.Values.reloader.logLevel) (.Values.reloader.ignoreSecrets) (and .Values.reloader.ignoreNamespaces .Values.reloader.watchGlobally) (include "reloader-effectiveNamespaces-csv" .) (include "reloader-namespaceSelector" .) (.Values.reloader.resourceLabelSelector) (.Values.reloader.ignoreConfigMaps) (.Values.reloader.custom_annotations) (eq .Values.reloader.isArgoRollouts true) (eq .Values.reloader.reloadOnCreate true) (eq .Values.reloader.reloadOnDelete true) (ne .Values.reloader.reloadStrategy "default") (.Values.reloader.enableHA) (.Values.reloader.autoReloadAll) (.Values.reloader.ignoreJobs) (.Values.reloader.ignoreCronJobs) (.Values.reloader.enableCSIIntegration)}}
args:
{{- if .Values.reloader.logFormat }}
- "--log-format={{ .Values.reloader.logFormat }}"
Expand All @@ -236,7 +231,10 @@ spec:
{{- else if .Values.reloader.ignoreCronJobs }}
- "--ignored-workload-types=cronjobs"
{{- end }}
{{- if .Values.reloader.ignoreNamespaces }}
{{- if (include "reloader-effectiveNamespaces-csv" .) }}
- "--namespaces={{ include "reloader-effectiveNamespaces-csv" . }}"
{{- end }}
{{- if and .Values.reloader.ignoreNamespaces .Values.reloader.watchGlobally }}
- "--namespaces-to-ignore={{ .Values.reloader.ignoreNamespaces }}"
{{- end }}
{{- if (include "reloader-namespaceSelector" .) }}
Expand All @@ -252,7 +250,7 @@ spec:
{{- end }}
{{- end }}
{{- if .Values.reloader.enableCSIIntegration }}
- "--enable-csi-integration"
- "--enable-csi-integration=true"
{{- end }}
{{- if .Values.reloader.custom_annotations }}
{{- if .Values.reloader.custom_annotations.configmap }}
Expand Down
Loading
Loading