diff --git a/README.md b/README.md index 78333945..222fc23f 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,10 @@ not. We can also specify a specific configmap or secret which would trigger rolling upgrade only upon change in our specified configmap or secret, this way, it will not trigger rolling upgrade upon changes in all configmaps or secrets used in a `deploymentconfig`, `deployment`, `daemonset`, `statefulset` or `rollout`. To do this either set the auto annotation to `"false"` (`reloader.stakater.com/auto: "false"`) or remove it altogether, and use annotations for [Configmap](.#Configmap) or [Secret](.#Secret). +It's also possible to enable auto reloading for all resources, by setting the `--auto-reload-all` flag. +In this case, all resources that do not have the auto annotation set to `"false"`, will be reloaded automatically when their ConfigMaps or Secrets are updated. +Notice that setting the auto annotation to an undefined value counts as false as-well. + ### Configmap To perform rolling upgrade when change happens only on specific configmaps use below annotation. diff --git a/deployments/kubernetes/chart/reloader/templates/deployment.yaml b/deployments/kubernetes/chart/reloader/templates/deployment.yaml index e9d91e14..3860f1d5 100644 --- a/deployments/kubernetes/chart/reloader/templates/deployment.yaml +++ b/deployments/kubernetes/chart/reloader/templates/deployment.yaml @@ -165,7 +165,7 @@ spec: - mountPath: /tmp/ name: tmp-volume {{- end }} - {{- if or (.Values.reloader.logFormat) (.Values.reloader.ignoreSecrets) (.Values.reloader.ignoreNamespaces) (.Values.reloader.namespaceSelector) (.Values.reloader.resourceLabelSelector) (.Values.reloader.ignoreConfigMaps) (.Values.reloader.custom_annotations) (eq .Values.reloader.isArgoRollouts true) (eq .Values.reloader.reloadOnCreate true) (ne .Values.reloader.reloadStrategy "default") (.Values.reloader.enableHA)}} + {{- if or (.Values.reloader.logFormat) (.Values.reloader.ignoreSecrets) (.Values.reloader.ignoreNamespaces) (.Values.reloader.namespaceSelector) (.Values.reloader.resourceLabelSelector) (.Values.reloader.ignoreConfigMaps) (.Values.reloader.custom_annotations) (eq .Values.reloader.isArgoRollouts true) (eq .Values.reloader.reloadOnCreate true) (ne .Values.reloader.reloadStrategy "default") (.Values.reloader.enableHA) (.Values.reloader.autoReloadAll)}} args: {{- if .Values.reloader.logFormat }} - "--log-format={{ .Values.reloader.logFormat }}" @@ -222,6 +222,9 @@ spec: {{- if or (gt (int .Values.reloader.deployment.replicas) 1) (.Values.reloader.enableHA) }} - "--enable-ha=true" {{- end}} + {{- if eq .Values.reloader.autoReloadAll true }} + - "--auto-reload-all=true" + {{- end -}} {{- end }} {{- if .Values.reloader.deployment.resources }} resources: diff --git a/deployments/kubernetes/chart/reloader/values.yaml b/deployments/kubernetes/chart/reloader/values.yaml index c41fbede..a749935c 100644 --- a/deployments/kubernetes/chart/reloader/values.yaml +++ b/deployments/kubernetes/chart/reloader/values.yaml @@ -12,6 +12,7 @@ nameOverride: "" fullnameOverride: "" reloader: + autoReloadAll: false isArgoRollouts: false isOpenshift: false ignoreSecrets: false diff --git a/internal/pkg/cmd/reloader.go b/internal/pkg/cmd/reloader.go index 874e776b..4e1e844e 100644 --- a/internal/pkg/cmd/reloader.go +++ b/internal/pkg/cmd/reloader.go @@ -32,6 +32,7 @@ func NewReloaderCommand() *cobra.Command { } // options + cmd.PersistentFlags().BoolVar(&options.AutoReloadAll, "auto-reload-all", false, "Auto reload all resources") cmd.PersistentFlags().StringVar(&options.ConfigmapUpdateOnChangeAnnotation, "configmap-annotation", "configmap.reloader.stakater.com/reload", "annotation to detect changes in configmaps, specified by name") cmd.PersistentFlags().StringVar(&options.SecretUpdateOnChangeAnnotation, "secret-annotation", "secret.reloader.stakater.com/reload", "annotation to detect changes in secrets, specified by name") cmd.PersistentFlags().StringVar(&options.ReloaderAutoAnnotation, "auto-annotation", "reloader.stakater.com/auto", "annotation to detect changes in secrets") diff --git a/internal/pkg/handler/upgrade.go b/internal/pkg/handler/upgrade.go index af06a9f5..bc2a04a4 100644 --- a/internal/pkg/handler/upgrade.go +++ b/internal/pkg/handler/upgrade.go @@ -153,8 +153,8 @@ func PerformRollingUpgrade(clients kube.Clients, config util.Config, upgradeFunc reloaderEnabledValue = annotations[options.ReloaderAutoAnnotation] } result := constants.NotUpdated - reloaderEnabled, err := strconv.ParseBool(reloaderEnabledValue) - if err == nil && reloaderEnabled { + reloaderEnabled, _ := strconv.ParseBool(reloaderEnabledValue) + if reloaderEnabled || reloaderEnabledValue == "" && options.AutoReloadAll { result = invokeReloadStrategy(upgradeFuncs, i, config, true) } diff --git a/internal/pkg/handler/upgrade_test.go b/internal/pkg/handler/upgrade_test.go index c0f5a539..88f11584 100644 --- a/internal/pkg/handler/upgrade_test.go +++ b/internal/pkg/handler/upgrade_test.go @@ -43,6 +43,7 @@ var ( arsConfigmapWithPodAnnotations = "testconfigmapPodAnnotations-handler-" + testutil.RandSeq(5) arsConfigmapWithBothAnnotations = "testconfigmapBothAnnotations-handler-" + testutil.RandSeq(5) arsConfigmapAnnotated = "testconfigmapAnnotated-handler-" + testutil.RandSeq(5) + arsConfigMapWithNonAnnotatedDeployment = "testconfigmapNonAnnotatedDeployment-handler-" + testutil.RandSeq(5) ersNamespace = "test-handler-" + testutil.RandSeq(5) ersConfigmapName = "testconfigmap-handler-" + testutil.RandSeq(5) @@ -173,6 +174,11 @@ func setupArs() { logrus.Errorf("Error in configmap creation: %v", err) } + _, err = testutil.CreateConfigMap(clients.KubernetesClient, arsNamespace, arsConfigMapWithNonAnnotatedDeployment, "www.google.com") + if err != nil { + logrus.Errorf("Error in configmap creation: %v", err) + } + // Creating Deployment with configmap _, err = testutil.CreateDeployment(clients.KubernetesClient, arsConfigmapName, arsNamespace, true) if err != nil { @@ -268,6 +274,12 @@ func setupArs() { logrus.Errorf("Error in Deployment with secret configmap as envFrom source creation: %v", err) } + // Creating Deployment with configmap and without annotations + _, err = testutil.CreateDeploymentWithEnvVarSourceAndAnnotations(clients.KubernetesClient, arsConfigMapWithNonAnnotatedDeployment, arsNamespace, map[string]string{}) + if err != nil { + logrus.Errorf("Error in Deployment with configmap and without annotation creation: %v", err) + } + // Creating DaemonSet with configmap _, err = testutil.CreateDaemonSet(clients.KubernetesClient, arsConfigmapName, arsNamespace, true) if err != nil { @@ -348,6 +360,7 @@ func setupArs() { // Creating Deployment with both annotations _, err = testutil.CreateDeploymentWithPodAnnotations(clients.KubernetesClient, arsConfigmapWithBothAnnotations, arsNamespace, true) + if err != nil { logrus.Errorf("Error in Deployment with both annotations: %v", err) } @@ -1205,6 +1218,58 @@ func TestRollingUpgradeForDeploymentWithConfigmapUsingArs(t *testing.T) { } } +func TestRollingUpgradeForDeploymentWithConfigmapWithoutReloadAnnotationAndWithoutAutoReloadAllNoTriggersUsingArs(t *testing.T) { + options.ReloadStrategy = constants.AnnotationsReloadStrategy + + shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, arsNamespace, arsConfigMapWithNonAnnotatedDeployment, "www.stakater.com") + config := getConfigWithAnnotations(constants.ConfigmapEnvVarPostfix, arsConfigMapWithNonAnnotatedDeployment, shaData, options.ConfigmapUpdateOnChangeAnnotation) + deploymentFuncs := GetDeploymentRollingUpgradeFuncs() + collectors := getCollectors() + + err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil) + time.Sleep(5 * time.Second) + if err != nil { + t.Errorf("Rolling upgrade failed for Deployment with Configmap") + } + + logrus.Infof("Verifying deployment update") + updated := testutil.VerifyResourceAnnotationUpdate(clients, config, deploymentFuncs) + if updated { + t.Errorf("Deployment was updated") + } + + if promtestutil.ToFloat64(collectors.Reloaded.With(labelSucceeded)) > 0 { + t.Errorf("Counter was increased") + } +} + +func TestRollingUpgradeForDeploymentWithConfigmapWithoutReloadAnnotationButWithAutoReloadAllUsingArs(t *testing.T) { + options.ReloadStrategy = constants.AnnotationsReloadStrategy + options.AutoReloadAll = true + defer func() { options.AutoReloadAll = false }() + + shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, arsNamespace, arsConfigMapWithNonAnnotatedDeployment, "www.stakater.com") + config := getConfigWithAnnotations(constants.ConfigmapEnvVarPostfix, arsConfigMapWithNonAnnotatedDeployment, shaData, "") + deploymentFuncs := GetDeploymentRollingUpgradeFuncs() + collectors := getCollectors() + + err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil) + time.Sleep(5 * time.Second) + if err != nil { + t.Errorf("Rolling upgrade failed for Deployment with Configmap") + } + + logrus.Infof("Verifying deployment update") + updated := testutil.VerifyResourceAnnotationUpdate(clients, config, deploymentFuncs) + if !updated { + t.Errorf("Deployment was not updated") + } + + if promtestutil.ToFloat64(collectors.Reloaded.With(labelSucceeded)) != 1 { + t.Errorf("Counter was not increased") + } +} + func TestRollingUpgradeForDeploymentWithConfigmapInProjectedVolumeUsingArs(t *testing.T) { options.ReloadStrategy = constants.AnnotationsReloadStrategy diff --git a/internal/pkg/options/flags.go b/internal/pkg/options/flags.go index 54c75dad..0faa6d22 100644 --- a/internal/pkg/options/flags.go +++ b/internal/pkg/options/flags.go @@ -3,6 +3,8 @@ package options import "github.com/stakater/Reloader/internal/pkg/constants" var ( + // Auto reload all resources when their corresponding configmaps/secrets are updated + AutoReloadAll = false // ConfigmapUpdateOnChangeAnnotation is an annotation to detect changes in // configmaps specified by name ConfigmapUpdateOnChangeAnnotation = "configmap.reloader.stakater.com/reload" diff --git a/internal/pkg/testutil/kube.go b/internal/pkg/testutil/kube.go index 9d45c2b3..765a04a2 100644 --- a/internal/pkg/testutil/kube.go +++ b/internal/pkg/testutil/kube.go @@ -902,9 +902,9 @@ func VerifyResourceAnnotationUpdate(clients kube.Clients, config util.Config, up annotationValue := annotations[config.Annotation] searchAnnotationValue := annotations[options.AutoSearchAnnotation] reloaderEnabledValue := annotations[options.ReloaderAutoAnnotation] - reloaderEnabled, err := strconv.ParseBool(reloaderEnabledValue) + reloaderEnabled, _ := strconv.ParseBool(reloaderEnabledValue) matches := false - if err == nil && reloaderEnabled { + if reloaderEnabled || reloaderEnabledValue == "" && options.AutoReloadAll { matches = true } else if annotationValue != "" { values := strings.Split(annotationValue, ",")