From 82f5472fd699b09b097095a72126837cdaf5ed90 Mon Sep 17 00:00:00 2001 From: Jean-Edouard Babin Date: Thu, 7 Sep 2023 19:43:40 +0200 Subject: [PATCH] Add a label take precedence argument --- cmd/root.go | 39 ++++++++++++++++++--------------- docs/arguments.md | 16 ++++++++++++-- internal/actions/update.go | 4 ++-- internal/actions/update_test.go | 35 ++++++++++++++++++++++++++++- internal/flags/flags.go | 6 +++++ pkg/types/update_params.go | 15 +++++++------ 6 files changed, 85 insertions(+), 30 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index dbb7e89..75a24be 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -28,17 +28,18 @@ import ( ) var ( - client container.Client - scheduleSpec string - cleanup bool - noRestart bool - monitorOnly bool - enableLabel bool - notifier t.Notifier - timeout time.Duration - lifecycleHooks bool - rollingRestart bool - scope string + client container.Client + scheduleSpec string + cleanup bool + noRestart bool + monitorOnly bool + enableLabel bool + notifier t.Notifier + timeout time.Duration + lifecycleHooks bool + rollingRestart bool + scope string + labelPrecedence bool ) var rootCmd = NewRootCommand() @@ -109,6 +110,7 @@ func PreRun(cmd *cobra.Command, _ []string) { lifecycleHooks, _ = f.GetBool("enable-lifecycle-hooks") rollingRestart, _ = f.GetBool("rolling-restart") scope, _ = f.GetString("scope") + labelPrecedence, _ = f.GetBool("label-take-precedence") if scope != "" { log.Debugf(`Using scope %q`, scope) @@ -359,13 +361,14 @@ func runUpgradesOnSchedule(c *cobra.Command, filter t.Filter, filtering string, func runUpdatesWithNotifications(filter t.Filter) *metrics.Metric { notifier.StartNotification() updateParams := t.UpdateParams{ - Filter: filter, - Cleanup: cleanup, - NoRestart: noRestart, - Timeout: timeout, - MonitorOnly: monitorOnly, - LifecycleHooks: lifecycleHooks, - RollingRestart: rollingRestart, + Filter: filter, + Cleanup: cleanup, + NoRestart: noRestart, + Timeout: timeout, + MonitorOnly: monitorOnly, + LifecycleHooks: lifecycleHooks, + RollingRestart: rollingRestart, + LabelPrecedence: labelPrecedence, } result, err := actions.Update(client, updateParams) if err != nil { diff --git a/docs/arguments.md b/docs/arguments.md index f74b102..c1604f4 100644 --- a/docs/arguments.md +++ b/docs/arguments.md @@ -205,7 +205,7 @@ Environment Variable: WATCHTOWER_POLL_INTERVAL ``` ## Filter by enable label -Update containers that have a `com.centurylinklabs.watchtower.enable` label set to true. +Monitor and update containers that have a `com.centurylinklabs.watchtower.enable` label set to true. ```text Argument: --label-enable @@ -215,7 +215,7 @@ Environment Variable: WATCHTOWER_LABEL_ENABLE ``` ## Filter by disable label -__Do not__ update containers that have `com.centurylinklabs.watchtower.enable` label set to false and +__Do not__ Monitor and update containers that have `com.centurylinklabs.watchtower.enable` label set to false and no `--label-enable` argument is passed. Note that only one or the other (targeting by enable label) can be used at the same time to target containers. @@ -238,6 +238,18 @@ Environment Variable: WATCHTOWER_MONITOR_ONLY Note that monitor-only can also be specified on a per-container basis with the `com.centurylinklabs.watchtower.monitor-only` label set on those containers. +## With label taking precedence over environment variables + +By default, environement variables will take precedence over labels. This means that if you set `WATCHTOWER_MONITOR_ONLY` to true, a container with `com.centurylinklabs.watchtower.monitor-only` set to false will not be updated. If you set `WATCHTOWER_LABEL_TAKE_PRECEDENCE` to true, then the container will also be updated + + +```text + Argument: --label-take-precedence +Environment Variable: WATCHTOWER_LABEL_TAKE_PRECEDENCE + Type: Boolean + Default: false +``` + ## Without restarting containers Do not restart containers after updating. This option can be useful when the start of the containers is managed by an external system such as systemd. diff --git a/internal/actions/update.go b/internal/actions/update.go index 9c97f27..436b2d8 100644 --- a/internal/actions/update.go +++ b/internal/actions/update.go @@ -34,7 +34,7 @@ func Update(client container.Client, params types.UpdateParams) (types.Report, e for i, targetContainer := range containers { stale, newestImage, err := client.IsContainerStale(targetContainer) - shouldUpdate := stale && !params.NoRestart && !params.MonitorOnly && !targetContainer.IsMonitorOnly() + shouldUpdate := stale && !params.NoRestart && (( !params.MonitorOnly && !targetContainer.IsMonitorOnly() ) || ( params.LabelPrecedence && !targetContainer.IsMonitorOnly() )) if err == nil && shouldUpdate { // Check to make sure we have all the necessary information for recreating the container err = targetContainer.VerifyConfiguration() @@ -72,7 +72,7 @@ func Update(client container.Client, params types.UpdateParams) (types.Report, e UpdateImplicitRestart(containers) var containersToUpdate []types.Container - if !params.MonitorOnly { + if ( !params.MonitorOnly || params.LabelPrecedence ) { for _, c := range containers { if !c.IsMonitorOnly() { containersToUpdate = append(containersToUpdate, c) diff --git a/internal/actions/update_test.go b/internal/actions/update_test.go index 24534de..467439c 100644 --- a/internal/actions/update_test.go +++ b/internal/actions/update_test.go @@ -182,8 +182,41 @@ var _ = Describe("the update action", func() { Expect(err).NotTo(HaveOccurred()) Expect(client.TestData.TriedToRemoveImageCount).To(Equal(0)) }) - }) + When("watchtower has been instructed to have label take precedence", func() { + It("it should update containers with monitor only set to false", func() { + client := CreateMockClient( + &TestData{ + NameOfContainerToKeep: "test-container-02", + Containers: []types.Container{ + CreateMockContainer( + "test-container-01", + "test-container-01", + "fake-image1:latest", + time.Now()), + CreateMockContainerWithConfig( + "test-container-02", + "test-container-02", + "fake-image2:latest", + false, + false, + time.Now(), + &dockerContainer.Config{ + Labels: map[string]string{ + "com.centurylinklabs.watchtower.monitor-only": "false", + }, + }), + }, + }, + false, + false, + ) + _, err := actions.Update(client, types.UpdateParams{MonitorOnly: true, LabelPrecedence: true}) + Expect(err).To(HaveOccurred()) + Expect(client.TestData.TriedToRemoveImageCount).To(Equal(1)) + }) + }) + }) }) When("watchtower has been instructed to run lifecycle hooks", func() { diff --git a/internal/flags/flags.go b/internal/flags/flags.go index 1195119..f8ee9b6 100644 --- a/internal/flags/flags.go +++ b/internal/flags/flags.go @@ -185,6 +185,12 @@ func RegisterSystemFlags(rootCmd *cobra.Command) { "log-level", viper.GetString("WATCHTOWER_LOG_LEVEL"), "The maximum log level that will be written to STDERR. Possible values: panic, fatal, error, warn, info, debug or trace") + + flags.BoolP( + "label-take-precedence", + "", + viper.GetBool("WATCHTOWER_LABEL_TAKE_PRECEDENCE"), + "Label applied to containers take precedence over environement variable") } // RegisterNotificationFlags that are used by watchtower to send notifications diff --git a/pkg/types/update_params.go b/pkg/types/update_params.go index 611cc70..d049661 100644 --- a/pkg/types/update_params.go +++ b/pkg/types/update_params.go @@ -6,11 +6,12 @@ import ( // UpdateParams contains all different options available to alter the behavior of the Update func type UpdateParams struct { - Filter Filter - Cleanup bool - NoRestart bool - Timeout time.Duration - MonitorOnly bool - LifecycleHooks bool - RollingRestart bool + Filter Filter + Cleanup bool + NoRestart bool + Timeout time.Duration + MonitorOnly bool + LifecycleHooks bool + RollingRestart bool + LabelPrecedence bool }