mirror of
https://github.com/stakater/Reloader.git
synced 2026-02-14 18:09:50 +00:00
Compare commits
6 Commits
merge-1002
...
v1.4.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db275d516e | ||
|
|
eabf88515a | ||
|
|
3a1cc8f348 | ||
|
|
dd0807e951 | ||
|
|
b8edc25177 | ||
|
|
f9d658d3b4 |
@@ -1,3 +1,3 @@
|
||||
# Code of Conduct
|
||||
|
||||
Reloader follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
|
||||
Reloader follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md).
|
||||
|
||||
@@ -2,7 +2,7 @@ ARG BUILDER_IMAGE
|
||||
ARG BASE_IMAGE
|
||||
|
||||
# Build the manager binary
|
||||
FROM --platform=${BUILDPLATFORM} ${BUILDER_IMAGE:-golang:1.24.4} AS builder
|
||||
FROM --platform=${BUILDPLATFORM} ${BUILDER_IMAGE:-golang:1.24.6} AS builder
|
||||
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
|
||||
25
README.md
25
README.md
@@ -329,13 +329,30 @@ Reloader supports multiple strategies for triggering rolling updates when a watc
|
||||
|------|-------------|
|
||||
| `--resources-to-ignore=configmaps` | Ignore ConfigMaps (only one type can be ignored at a time) |
|
||||
| `--resources-to-ignore=secrets` | Ignore Secrets (cannot combine with configMaps) |
|
||||
| `--ignored-workload-types=jobs,cronjobs` | Ignore specific workload types from reload monitoring |
|
||||
| `--resource-label-selector=key=value` | Only watch ConfigMaps/Secrets with matching labels |
|
||||
|
||||
> **⚠️ Note:**
|
||||
> Only **one** resource type can be ignored at a time.
|
||||
> Trying to ignore **both `configmaps` and `secrets`** will cause an error in Reloader.
|
||||
> **⚠️ Note:**
|
||||
>
|
||||
> Only **one** resource type can be ignored at a time.
|
||||
> Trying to ignore **both `configmaps` and `secrets`** will cause an error in Reloader.
|
||||
> ✅ **Workaround:** Scale the Reloader deployment to `0` replicas if you want to disable it completely.
|
||||
|
||||
**💡 Workload Type Examples:**
|
||||
|
||||
```bash
|
||||
# Ignore only Jobs
|
||||
--ignored-workload-types=jobs
|
||||
|
||||
# Ignore only CronJobs
|
||||
--ignored-workload-types=cronjobs
|
||||
|
||||
# Ignore both (comma-separated)
|
||||
--ignored-workload-types=jobs,cronjobs
|
||||
```
|
||||
|
||||
> **🔧 Use Case:** Ignoring workload types is useful when you don't want certain types of workloads to be automatically reloaded.
|
||||
|
||||
#### 3. 🧩 Namespace Filtering
|
||||
|
||||
| Flag | Description |
|
||||
@@ -420,7 +437,7 @@ To make a GitHub release:
|
||||
1. Code owners run a dispatch mode workflow to automatically generate version and manifests on the release branch
|
||||
1. A PR is created to bump the image version on the release branch, example: [PR-798](https://github.com/stakater/Reloader/pull/798)
|
||||
1. Code owners create a GitHub release with tag `vX.Y.Z` and target branch `release-vX.Y.Z`, which triggers creation of images
|
||||
1. Code owners create a PR to update the Helm chart version, example: [PR-846](https://github.com/stakater/Reloader/pull/846)
|
||||
1. Code owners create a PR with `release/helm-chart` label to update the Helm chart version, example: [PR-846](https://github.com/stakater/Reloader/pull/846)
|
||||
|
||||
_Repository git tagging_: Push to the main branch will create a merge-image and merge-tag named `merge-${{ github.event.number }}`, for example `merge-800` when pull request number 800 is merged.
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ If you have configured helm on your cluster, you can add Reloader to helm from o
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Add stakater helm repoository
|
||||
helm repo add stakater https://stakater.github.io/stakater-charts
|
||||
|
||||
helm repo update
|
||||
@@ -14,6 +15,8 @@ helm install stakater/reloader # For helm3 add --generate-name flag or set the r
|
||||
helm install {{RELEASE_NAME}} stakater/reloader -n {{NAMESPACE}} --set reloader.watchGlobally=false # By default, Reloader watches in all namespaces. To watch in single namespace, set watchGlobally=false
|
||||
|
||||
helm install stakater/reloader --set reloader.watchGlobally=false --namespace test --generate-name # Install Reloader in `test` namespace which will only watch `Deployments`, `Daemonsets` `Statefulsets` and `Rollouts` in `test` namespace.
|
||||
|
||||
helm install stakater/reloader --set reloader.ignoreJobs=true --set reloader.ignoreCronJobs=true --generate-name # Install Reloader ignoring Jobs and CronJobs from reload monitoring
|
||||
```
|
||||
|
||||
## Uninstalling
|
||||
@@ -47,6 +50,8 @@ helm uninstall {{RELEASE_NAME}} -n {{NAMESPACE}}
|
||||
| `reloader.isOpenshift` | Enable OpenShift DeploymentConfigs. Valid value are either `true` or `false` | boolean | `false` |
|
||||
| `reloader.ignoreSecrets` | To ignore secrets. Valid value are either `true` or `false`. Either `ignoreSecrets` or `ignoreConfigMaps` can be ignored, not both at the same time | boolean | `false` |
|
||||
| `reloader.ignoreConfigMaps` | To ignore configmaps. Valid value are either `true` or `false` | boolean | `false` |
|
||||
| `reloader.ignoreJobs` | To ignore jobs from reload monitoring. Valid value are either `true` or `false`. Translates to `--ignored-workload-types=jobs` | boolean | `false` |
|
||||
| `reloader.ignoreCronJobs` | To ignore CronJobs from reload monitoring. Valid value are either `true` or `false`. Translates to `--ignored-workload-types=cronjobs` | boolean | `false` |
|
||||
| `reloader.reloadOnCreate` | Enable reload on create events. Valid value are either `true` or `false` | boolean | `false` |
|
||||
| `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` |
|
||||
@@ -58,7 +63,7 @@ helm uninstall {{RELEASE_NAME}} -n {{NAMESPACE}}
|
||||
| `reloader.watchGlobally` | Allow Reloader to watch in all namespaces (`true`) or just in a single namespace (`false`) | boolean | `true` |
|
||||
| `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` |
|
||||
| `reloader.pprofAddr` | Address to start pprof server on | string | `:6060` |
|
||||
| `reloader.readOnlyRootFileSystem` | Enforce readOnlyRootFilesystem | boolean | `false` |
|
||||
| `reloader.legacy.rbac` | | boolean | `false` |
|
||||
| `reloader.matchLabels` | Pod labels to match | map | `{}` |
|
||||
@@ -115,6 +120,10 @@ helm uninstall {{RELEASE_NAME}} -n {{NAMESPACE}}
|
||||
- Only one of these resources can be ignored at a time:
|
||||
- `ignoreConfigMaps` **or** `ignoreSecrets`
|
||||
- Trying to ignore both will cause Helm template compilation errors
|
||||
- The `ignoreJobs` and `ignoreCronJobs` flags can be used together or individually
|
||||
- When both are enabled, translates to `--ignored-workload-types=jobs,cronjobs`
|
||||
- When used individually, translates to `--ignored-workload-types=jobs` or `--ignored-workload-types=cronjobs`
|
||||
- These flags prevent Reloader from monitoring and reloading the specified workload types
|
||||
|
||||
### Special Integrations
|
||||
- OpenShift (`DeploymentConfig`) and Argo Rollouts support must be **explicitly enabled**
|
||||
|
||||
@@ -155,7 +155,7 @@ spec:
|
||||
|
||||
- name: RELOADER_DEPLOYMENT_NAME
|
||||
value: {{ template "reloader-fullname" . }}
|
||||
|
||||
|
||||
{{- if .Values.reloader.enableHA }}
|
||||
- name: POD_NAME
|
||||
valueFrom:
|
||||
@@ -210,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)}}
|
||||
{{- 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)}}
|
||||
args:
|
||||
{{- if .Values.reloader.logFormat }}
|
||||
- "--log-format={{ .Values.reloader.logFormat }}"
|
||||
@@ -224,6 +224,13 @@ spec:
|
||||
{{- if .Values.reloader.ignoreConfigMaps }}
|
||||
- "--resources-to-ignore=configMaps"
|
||||
{{- end }}
|
||||
{{- if and (.Values.reloader.ignoreJobs) (.Values.reloader.ignoreCronJobs) }}
|
||||
- "--ignored-workload-types=jobs,cronjobs"
|
||||
{{- else if .Values.reloader.ignoreJobs }}
|
||||
- "--ignored-workload-types=jobs"
|
||||
{{- else if .Values.reloader.ignoreCronJobs }}
|
||||
- "--ignored-workload-types=cronjobs"
|
||||
{{- end }}
|
||||
{{- if .Values.reloader.ignoreNamespaces }}
|
||||
- "--namespaces-to-ignore={{ .Values.reloader.ignoreNamespaces }}"
|
||||
{{- end }}
|
||||
|
||||
@@ -61,3 +61,44 @@ tests:
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
|
||||
- it: sets ignored-workload-types argument when ignoreJobs is true
|
||||
set:
|
||||
reloader:
|
||||
ignoreJobs: true
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: "--ignored-workload-types=jobs"
|
||||
|
||||
- it: sets ignored-workload-types argument when ignoreCronJobs is true
|
||||
set:
|
||||
reloader:
|
||||
ignoreCronJobs: true
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: "--ignored-workload-types=cronjobs"
|
||||
|
||||
- it: sets ignored-workload-types argument when both ignoreJobs and ignoreCronJobs are true
|
||||
set:
|
||||
reloader:
|
||||
ignoreJobs: true
|
||||
ignoreCronJobs: true
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: "--ignored-workload-types=jobs,cronjobs"
|
||||
|
||||
- it: does not set ignored-workload-types argument when both ignoreJobs and ignoreCronJobs are false
|
||||
set:
|
||||
reloader:
|
||||
ignoreJobs: false
|
||||
ignoreCronJobs: false
|
||||
asserts:
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: "--ignored-workload-types=jobs"
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: "--ignored-workload-types=cronjobs"
|
||||
|
||||
@@ -27,7 +27,11 @@ reloader:
|
||||
isOpenshift: false
|
||||
ignoreSecrets: false
|
||||
ignoreConfigMaps: false
|
||||
# Set to true to exclude Job workloads from automatic reload monitoring
|
||||
# Useful when you don't want Jobs to be restarted when their referenced ConfigMaps/Secrets change
|
||||
ignoreJobs: false
|
||||
# Set to true to exclude CronJob workloads from automatic reload monitoring
|
||||
# Useful when you don't want CronJobs to be restarted when their referenced ConfigMaps/Secrets change
|
||||
ignoreCronJobs: false
|
||||
reloadOnCreate: false
|
||||
reloadOnDelete: false
|
||||
@@ -84,7 +88,7 @@ reloader:
|
||||
# - key: "node-role.kubernetes.io/infra-worker"
|
||||
# operator: "Exists"
|
||||
affinity: {}
|
||||
|
||||
|
||||
volumeMounts: []
|
||||
volumes: []
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ spec:
|
||||
app: reloader-reloader
|
||||
spec:
|
||||
containers:
|
||||
- image: "ghcr.io/stakater/reloader:v1.1.0"
|
||||
- image: "ghcr.io/stakater/reloader:v1.4.8"
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: reloader-reloader
|
||||
env:
|
||||
|
||||
@@ -141,7 +141,7 @@ spec:
|
||||
fieldPath: metadata.namespace
|
||||
- name: RELOADER_DEPLOYMENT_NAME
|
||||
value: reloader-reloader
|
||||
image: ghcr.io/stakater/reloader:latest
|
||||
image: ghcr.io/stakater/reloader:v1.4.8
|
||||
imagePullPolicy: IfNotPresent
|
||||
livenessProbe:
|
||||
failureThreshold: 5
|
||||
|
||||
2
go.mod
2
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/stakater/Reloader
|
||||
|
||||
go 1.24.4
|
||||
go 1.24.6
|
||||
|
||||
require (
|
||||
github.com/argoproj/argo-rollouts v1.8.2
|
||||
|
||||
@@ -65,6 +65,8 @@ var (
|
||||
WebhookUrl = ""
|
||||
// ResourcesToIgnore is a list of resources to ignore when watching for changes
|
||||
ResourcesToIgnore = []string{}
|
||||
// WorkloadTypesToIgnore is a list of workload types to ignore when watching for changes
|
||||
WorkloadTypesToIgnore = []string{}
|
||||
// NamespacesToIgnore is a list of namespace names to ignore when watching for changes
|
||||
NamespacesToIgnore = []string{}
|
||||
// NamespaceSelectors is a list of namespace selectors to watch for changes
|
||||
|
||||
@@ -83,6 +83,7 @@ func ConfigureReloaderFlags(cmd *cobra.Command) {
|
||||
cmd.PersistentFlags().StringVar(&options.LogLevel, "log-level", "info", "Log level to use (trace, debug, info, warning, error, fatal and panic)")
|
||||
cmd.PersistentFlags().StringVar(&options.WebhookUrl, "webhook-url", "", "webhook to trigger instead of performing a reload")
|
||||
cmd.PersistentFlags().StringSliceVar(&options.ResourcesToIgnore, "resources-to-ignore", options.ResourcesToIgnore, "list of resources to ignore (valid options 'configMaps' or 'secrets')")
|
||||
cmd.PersistentFlags().StringSliceVar(&options.WorkloadTypesToIgnore, "ignored-workload-types", options.WorkloadTypesToIgnore, "list of workload types to ignore (valid options: 'jobs', 'cronjobs', or both)")
|
||||
cmd.PersistentFlags().StringSliceVar(&options.NamespacesToIgnore, "namespaces-to-ignore", options.NamespacesToIgnore, "list of namespaces to ignore")
|
||||
cmd.PersistentFlags().StringSliceVar(&options.NamespaceSelectors, "namespace-selector", options.NamespaceSelectors, "list of key:value labels to filter on for namespaces")
|
||||
cmd.PersistentFlags().StringSliceVar(&options.ResourceSelectors, "resource-label-selector", options.ResourceSelectors, "list of key:value labels to filter on for configmaps and secrets")
|
||||
@@ -112,3 +113,16 @@ func GetIgnoredResourcesList() (List, error) {
|
||||
|
||||
return ignoredResourcesList, nil
|
||||
}
|
||||
|
||||
func GetIgnoredWorkloadTypesList() (List, error) {
|
||||
|
||||
ignoredWorkloadTypesList := options.WorkloadTypesToIgnore
|
||||
|
||||
for _, v := range ignoredWorkloadTypesList {
|
||||
if v != "jobs" && v != "cronjobs" {
|
||||
return nil, fmt.Errorf("'ignored-workload-types' accepts 'jobs', 'cronjobs', or both, not '%s'", v)
|
||||
}
|
||||
}
|
||||
|
||||
return ignoredWorkloadTypesList, nil
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package util
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stakater/Reloader/internal/pkg/options"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
@@ -45,3 +46,141 @@ func TestGetHashFromConfigMap(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetIgnoredWorkloadTypesList(t *testing.T) {
|
||||
// Save original state
|
||||
originalWorkloadTypes := options.WorkloadTypesToIgnore
|
||||
defer func() {
|
||||
options.WorkloadTypesToIgnore = originalWorkloadTypes
|
||||
}()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
workloadTypes []string
|
||||
expectError bool
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "Both jobs and cronjobs",
|
||||
workloadTypes: []string{"jobs", "cronjobs"},
|
||||
expectError: false,
|
||||
expected: []string{"jobs", "cronjobs"},
|
||||
},
|
||||
{
|
||||
name: "Only jobs",
|
||||
workloadTypes: []string{"jobs"},
|
||||
expectError: false,
|
||||
expected: []string{"jobs"},
|
||||
},
|
||||
{
|
||||
name: "Only cronjobs",
|
||||
workloadTypes: []string{"cronjobs"},
|
||||
expectError: false,
|
||||
expected: []string{"cronjobs"},
|
||||
},
|
||||
{
|
||||
name: "Empty list",
|
||||
workloadTypes: []string{},
|
||||
expectError: false,
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "Invalid workload type",
|
||||
workloadTypes: []string{"invalid"},
|
||||
expectError: true,
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "Mixed valid and invalid",
|
||||
workloadTypes: []string{"jobs", "invalid"},
|
||||
expectError: true,
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "Duplicate values",
|
||||
workloadTypes: []string{"jobs", "jobs"},
|
||||
expectError: false,
|
||||
expected: []string{"jobs", "jobs"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Set the global option
|
||||
options.WorkloadTypesToIgnore = tt.workloadTypes
|
||||
|
||||
result, err := GetIgnoredWorkloadTypesList()
|
||||
|
||||
if tt.expectError && err == nil {
|
||||
t.Errorf("Expected error but got none")
|
||||
}
|
||||
|
||||
if !tt.expectError && err != nil {
|
||||
t.Errorf("Expected no error but got: %v", err)
|
||||
}
|
||||
|
||||
if !tt.expectError {
|
||||
if len(result) != len(tt.expected) {
|
||||
t.Errorf("Expected %v, got %v", tt.expected, result)
|
||||
return
|
||||
}
|
||||
|
||||
for i, expected := range tt.expected {
|
||||
if i >= len(result) || result[i] != expected {
|
||||
t.Errorf("Expected %v, got %v", tt.expected, result)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListContains(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
list List
|
||||
item string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "List contains item",
|
||||
list: List{"jobs", "cronjobs"},
|
||||
item: "jobs",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "List does not contain item",
|
||||
list: List{"jobs"},
|
||||
item: "cronjobs",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Empty list",
|
||||
list: List{},
|
||||
item: "jobs",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Case sensitive matching",
|
||||
list: List{"jobs", "cronjobs"},
|
||||
item: "Jobs",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Multiple occurrences",
|
||||
list: List{"jobs", "jobs", "cronjobs"},
|
||||
item: "jobs",
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := tt.list.Contains(tt.item)
|
||||
if result != tt.expected {
|
||||
t.Errorf("Expected %v, got %v", tt.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stakater/Reloader/internal/pkg/constants"
|
||||
"github.com/stakater/Reloader/internal/pkg/options"
|
||||
"github.com/stakater/Reloader/internal/pkg/util"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
@@ -74,6 +75,8 @@ type ReloaderOptions struct {
|
||||
WebhookUrl string `json:"webhookUrl"`
|
||||
// ResourcesToIgnore is a list of resource types to ignore (e.g., "configmaps" or "secrets")
|
||||
ResourcesToIgnore []string `json:"resourcesToIgnore"`
|
||||
// WorkloadTypesToIgnore is a list of workload types to ignore (e.g., "jobs" or "cronjobs")
|
||||
WorkloadTypesToIgnore []string `json:"workloadTypesToIgnore"`
|
||||
// NamespaceSelectors is a list of label selectors to filter namespaces to watch
|
||||
NamespaceSelectors []string `json:"namespaceSelectors"`
|
||||
// ResourceSelectors is a list of label selectors to filter ConfigMaps and Secrets to watch
|
||||
@@ -182,6 +185,32 @@ func GetResourceLabelSelector(slice []string) (string, error) {
|
||||
// ShouldReload checks if a resource should be reloaded based on its annotations and the provided options.
|
||||
func ShouldReload(config Config, resourceType string, annotations Map, podAnnotations Map, options *ReloaderOptions) ReloadCheckResult {
|
||||
|
||||
// Check if this workload type should be ignored
|
||||
if len(options.WorkloadTypesToIgnore) > 0 {
|
||||
ignoredWorkloadTypes, err := util.GetIgnoredWorkloadTypesList()
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to parse ignored workload types: %v", err)
|
||||
} else {
|
||||
// Map Kubernetes resource types to CLI-friendly names for comparison
|
||||
var resourceToCheck string
|
||||
switch resourceType {
|
||||
case "Job":
|
||||
resourceToCheck = "jobs"
|
||||
case "CronJob":
|
||||
resourceToCheck = "cronjobs"
|
||||
default:
|
||||
resourceToCheck = resourceType // For other types, use as-is
|
||||
}
|
||||
|
||||
// Check if current resource type should be ignored
|
||||
if ignoredWorkloadTypes.Contains(resourceToCheck) {
|
||||
return ReloadCheckResult{
|
||||
ShouldReload: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ignoreResourceAnnotatonValue := config.ResourceAnnotations[options.IgnoreResourceAnnotation]
|
||||
if ignoreResourceAnnotatonValue == "true" {
|
||||
return ReloadCheckResult{
|
||||
@@ -304,6 +333,7 @@ func GetCommandLineOptions() *ReloaderOptions {
|
||||
CommandLineOptions.EnableHA = options.EnableHA
|
||||
CommandLineOptions.WebhookUrl = options.WebhookUrl
|
||||
CommandLineOptions.ResourcesToIgnore = options.ResourcesToIgnore
|
||||
CommandLineOptions.WorkloadTypesToIgnore = options.WorkloadTypesToIgnore
|
||||
CommandLineOptions.NamespaceSelectors = options.NamespaceSelectors
|
||||
CommandLineOptions.ResourceSelectors = options.ResourceSelectors
|
||||
CommandLineOptions.NamespacesToIgnore = options.NamespacesToIgnore
|
||||
|
||||
224
pkg/common/common_test.go
Normal file
224
pkg/common/common_test.go
Normal file
@@ -0,0 +1,224 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stakater/Reloader/internal/pkg/options"
|
||||
)
|
||||
|
||||
func TestShouldReload_IgnoredWorkloadTypes(t *testing.T) {
|
||||
// Save original state
|
||||
originalWorkloadTypes := options.WorkloadTypesToIgnore
|
||||
defer func() {
|
||||
options.WorkloadTypesToIgnore = originalWorkloadTypes
|
||||
}()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
ignoredWorkloadTypes []string
|
||||
resourceType string
|
||||
shouldReload bool
|
||||
description string
|
||||
}{
|
||||
{
|
||||
name: "Jobs ignored - Job should not reload",
|
||||
ignoredWorkloadTypes: []string{"jobs"},
|
||||
resourceType: "Job",
|
||||
shouldReload: false,
|
||||
description: "When jobs are ignored, Job resources should not be reloaded",
|
||||
},
|
||||
{
|
||||
name: "Jobs ignored - CronJob should reload",
|
||||
ignoredWorkloadTypes: []string{"jobs"},
|
||||
resourceType: "CronJob",
|
||||
shouldReload: true,
|
||||
description: "When jobs are ignored, CronJob resources should still be processed",
|
||||
},
|
||||
{
|
||||
name: "CronJobs ignored - CronJob should not reload",
|
||||
ignoredWorkloadTypes: []string{"cronjobs"},
|
||||
resourceType: "CronJob",
|
||||
shouldReload: false,
|
||||
description: "When cronjobs are ignored, CronJob resources should not be reloaded",
|
||||
},
|
||||
{
|
||||
name: "CronJobs ignored - Job should reload",
|
||||
ignoredWorkloadTypes: []string{"cronjobs"},
|
||||
resourceType: "Job",
|
||||
shouldReload: true,
|
||||
description: "When cronjobs are ignored, Job resources should still be processed",
|
||||
},
|
||||
{
|
||||
name: "Both ignored - Job should not reload",
|
||||
ignoredWorkloadTypes: []string{"jobs", "cronjobs"},
|
||||
resourceType: "Job",
|
||||
shouldReload: false,
|
||||
description: "When both are ignored, Job resources should not be reloaded",
|
||||
},
|
||||
{
|
||||
name: "Both ignored - CronJob should not reload",
|
||||
ignoredWorkloadTypes: []string{"jobs", "cronjobs"},
|
||||
resourceType: "CronJob",
|
||||
shouldReload: false,
|
||||
description: "When both are ignored, CronJob resources should not be reloaded",
|
||||
},
|
||||
{
|
||||
name: "Both ignored - Deployment should reload",
|
||||
ignoredWorkloadTypes: []string{"jobs", "cronjobs"},
|
||||
resourceType: "Deployment",
|
||||
shouldReload: true,
|
||||
description: "When both are ignored, other workload types should still be processed",
|
||||
},
|
||||
{
|
||||
name: "None ignored - Job should reload",
|
||||
ignoredWorkloadTypes: []string{},
|
||||
resourceType: "Job",
|
||||
shouldReload: true,
|
||||
description: "When nothing is ignored, all workload types should be processed",
|
||||
},
|
||||
{
|
||||
name: "None ignored - CronJob should reload",
|
||||
ignoredWorkloadTypes: []string{},
|
||||
resourceType: "CronJob",
|
||||
shouldReload: true,
|
||||
description: "When nothing is ignored, all workload types should be processed",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Set the ignored workload types
|
||||
options.WorkloadTypesToIgnore = tt.ignoredWorkloadTypes
|
||||
|
||||
// Create minimal test config and options
|
||||
config := Config{
|
||||
ResourceName: "test-resource",
|
||||
Annotation: "configmap.reloader.stakater.com/reload",
|
||||
}
|
||||
|
||||
annotations := Map{
|
||||
"configmap.reloader.stakater.com/reload": "test-config",
|
||||
}
|
||||
|
||||
// Create ReloaderOptions with the ignored workload types
|
||||
opts := &ReloaderOptions{
|
||||
WorkloadTypesToIgnore: tt.ignoredWorkloadTypes,
|
||||
AutoReloadAll: true, // Enable auto-reload to simplify test
|
||||
ReloaderAutoAnnotation: "reloader.stakater.com/auto",
|
||||
}
|
||||
|
||||
// Call ShouldReload
|
||||
result := ShouldReload(config, tt.resourceType, annotations, Map{}, opts)
|
||||
|
||||
// Check the result
|
||||
if result.ShouldReload != tt.shouldReload {
|
||||
t.Errorf("For resource type %s with ignored types %v, expected ShouldReload=%v, got=%v",
|
||||
tt.resourceType, tt.ignoredWorkloadTypes, tt.shouldReload, result.ShouldReload)
|
||||
}
|
||||
|
||||
t.Logf("✓ %s", tt.description)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldReload_IgnoredWorkloadTypes_ValidationError(t *testing.T) {
|
||||
// Save original state
|
||||
originalWorkloadTypes := options.WorkloadTypesToIgnore
|
||||
defer func() {
|
||||
options.WorkloadTypesToIgnore = originalWorkloadTypes
|
||||
}()
|
||||
|
||||
// Test with invalid workload type - should still continue processing
|
||||
options.WorkloadTypesToIgnore = []string{"invalid"}
|
||||
|
||||
config := Config{
|
||||
ResourceName: "test-resource",
|
||||
Annotation: "configmap.reloader.stakater.com/reload",
|
||||
}
|
||||
|
||||
annotations := Map{
|
||||
"configmap.reloader.stakater.com/reload": "test-config",
|
||||
}
|
||||
|
||||
opts := &ReloaderOptions{
|
||||
WorkloadTypesToIgnore: []string{"invalid"},
|
||||
AutoReloadAll: true, // Enable auto-reload to simplify test
|
||||
ReloaderAutoAnnotation: "reloader.stakater.com/auto",
|
||||
}
|
||||
|
||||
// Should not panic and should continue with normal processing
|
||||
result := ShouldReload(config, "Job", annotations, Map{}, opts)
|
||||
|
||||
// Since validation failed, it should continue with normal processing (should reload)
|
||||
if !result.ShouldReload {
|
||||
t.Errorf("Expected ShouldReload=true when validation fails, got=%v", result.ShouldReload)
|
||||
}
|
||||
}
|
||||
|
||||
// Test that validates the fix for issue #996
|
||||
func TestShouldReload_IssueRBACPermissionFixed(t *testing.T) {
|
||||
// Save original state
|
||||
originalWorkloadTypes := options.WorkloadTypesToIgnore
|
||||
defer func() {
|
||||
options.WorkloadTypesToIgnore = originalWorkloadTypes
|
||||
}()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
ignoredWorkloadTypes []string
|
||||
resourceType string
|
||||
description string
|
||||
}{
|
||||
{
|
||||
name: "Issue #996 - ignoreJobs prevents Job processing",
|
||||
ignoredWorkloadTypes: []string{"jobs"},
|
||||
resourceType: "Job",
|
||||
description: "Job resources are skipped entirely, preventing RBAC permission errors",
|
||||
},
|
||||
{
|
||||
name: "Issue #996 - ignoreCronJobs prevents CronJob processing",
|
||||
ignoredWorkloadTypes: []string{"cronjobs"},
|
||||
resourceType: "CronJob",
|
||||
description: "CronJob resources are skipped entirely, preventing RBAC permission errors",
|
||||
},
|
||||
{
|
||||
name: "Issue #996 - both ignored prevent both types",
|
||||
ignoredWorkloadTypes: []string{"jobs", "cronjobs"},
|
||||
resourceType: "Job",
|
||||
description: "Job resources are skipped entirely when both types are ignored",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Set the ignored workload types
|
||||
options.WorkloadTypesToIgnore = tt.ignoredWorkloadTypes
|
||||
|
||||
config := Config{
|
||||
ResourceName: "test-resource",
|
||||
Annotation: "configmap.reloader.stakater.com/reload",
|
||||
}
|
||||
|
||||
annotations := Map{
|
||||
"configmap.reloader.stakater.com/reload": "test-config",
|
||||
}
|
||||
|
||||
opts := &ReloaderOptions{
|
||||
WorkloadTypesToIgnore: tt.ignoredWorkloadTypes,
|
||||
AutoReloadAll: true, // Enable auto-reload to simplify test
|
||||
ReloaderAutoAnnotation: "reloader.stakater.com/auto",
|
||||
}
|
||||
|
||||
// Call ShouldReload
|
||||
result := ShouldReload(config, tt.resourceType, annotations, Map{}, opts)
|
||||
|
||||
// Should not reload when workload type is ignored
|
||||
if result.ShouldReload {
|
||||
t.Errorf("Expected ShouldReload=false for ignored workload type %s, got=%v",
|
||||
tt.resourceType, result.ShouldReload)
|
||||
}
|
||||
|
||||
t.Logf("✓ %s", tt.description)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user