diff --git a/docs/arguments.md b/docs/arguments.md index 58e7e7b61..d0e46ae15 100644 --- a/docs/arguments.md +++ b/docs/arguments.md @@ -234,6 +234,9 @@ Environment Variable: WATCHTOWER_NO_PULL Default: false ``` +Note that no-pull can also be specified on a per-container basis with the +`com.centurylinklabs.watchtower.no-pull` label set on those containers. + ## Without sending a startup message Do not send a message after watchtower started. Otherwise there will be an info-level notification. diff --git a/pkg/container/client.go b/pkg/container/client.go index 7447828b1..7f133e1e5 100644 --- a/pkg/container/client.go +++ b/pkg/container/client.go @@ -280,7 +280,7 @@ func (client dockerClient) RenameContainer(c Container, newName string) error { func (client dockerClient) IsContainerStale(container Container) (stale bool, latestImage t.ImageID, err error) { ctx := context.Background() - if !client.PullImages { + if !client.PullImages || container.IsNoPull() { log.Debugf("Skipping image pull.") } else if err := client.PullImage(ctx, container); err != nil { return false, container.SafeImageID(), err diff --git a/pkg/container/container.go b/pkg/container/container.go index 0bbea16ea..36abe8c6b 100644 --- a/pkg/container/container.go +++ b/pkg/container/container.go @@ -125,6 +125,22 @@ func (c Container) IsMonitorOnly() bool { return parsedBool } +// IsNoPull returns the value of the no-pull label. If the label is not set +// then false is returned. +func (c Container) IsNoPull() bool { + rawBool, ok := c.getLabelValue(noPullLabel) + if !ok { + return false + } + + parsedBool, err := strconv.ParseBool(rawBool) + if err != nil { + return false + } + + return parsedBool +} + // Scope returns the value of the scope UID label and if the label // was set. func (c Container) Scope() (string, bool) { diff --git a/pkg/container/container_test.go b/pkg/container/container_test.go index e75871b91..46cf65842 100644 --- a/pkg/container/container_test.go +++ b/pkg/container/container_test.go @@ -207,6 +207,39 @@ var _ = Describe("the container", func() { }) }) + When("checking no-pull label", func() { + When("no-pull label is true", func() { + c := MockContainer(WithLabels(map[string]string{ + "com.centurylinklabs.watchtower.no-pull": "true", + })) + It("should return true", func() { + Expect(c.IsNoPull()).To(Equal(true)) + }) + }) + When("no-pull label is false", func() { + c := MockContainer(WithLabels(map[string]string{ + "com.centurylinklabs.watchtower.no-pull": "false", + })) + It("should return false", func() { + Expect(c.IsNoPull()).To(Equal(false)) + }) + }) + When("no-pull label is set to an invalid value", func() { + c := MockContainer(WithLabels(map[string]string{ + "com.centurylinklabs.watchtower.no-pull": "maybe", + })) + It("should return false", func() { + Expect(c.IsNoPull()).To(Equal(false)) + }) + }) + When("no-pull label is unset", func() { + c = MockContainer(WithLabels(map[string]string{})) + It("should return false", func() { + Expect(c.IsNoPull()).To(Equal(false)) + }) + }) + }) + When("there is a pre or post update timeout", func() { It("should return minute values", func() { c = MockContainer(WithLabels(map[string]string{ diff --git a/pkg/container/metadata.go b/pkg/container/metadata.go index ee9fddfd6..74a04cbc5 100644 --- a/pkg/container/metadata.go +++ b/pkg/container/metadata.go @@ -1,18 +1,19 @@ package container const ( - watchtowerLabel = "com.centurylinklabs.watchtower" - signalLabel = "com.centurylinklabs.watchtower.stop-signal" - enableLabel = "com.centurylinklabs.watchtower.enable" - monitorOnlyLabel = "com.centurylinklabs.watchtower.monitor-only" - dependsOnLabel = "com.centurylinklabs.watchtower.depends-on" - zodiacLabel = "com.centurylinklabs.zodiac.original-image" - scope = "com.centurylinklabs.watchtower.scope" - preCheckLabel = "com.centurylinklabs.watchtower.lifecycle.pre-check" - postCheckLabel = "com.centurylinklabs.watchtower.lifecycle.post-check" - preUpdateLabel = "com.centurylinklabs.watchtower.lifecycle.pre-update" - postUpdateLabel = "com.centurylinklabs.watchtower.lifecycle.post-update" - preUpdateTimeoutLabel = "com.centurylinklabs.watchtower.lifecycle.pre-update-timeout" + watchtowerLabel = "com.centurylinklabs.watchtower" + signalLabel = "com.centurylinklabs.watchtower.stop-signal" + enableLabel = "com.centurylinklabs.watchtower.enable" + monitorOnlyLabel = "com.centurylinklabs.watchtower.monitor-only" + noPullLabel = "com.centurylinklabs.watchtower.no-pull" + dependsOnLabel = "com.centurylinklabs.watchtower.depends-on" + zodiacLabel = "com.centurylinklabs.zodiac.original-image" + scope = "com.centurylinklabs.watchtower.scope" + preCheckLabel = "com.centurylinklabs.watchtower.lifecycle.pre-check" + postCheckLabel = "com.centurylinklabs.watchtower.lifecycle.post-check" + preUpdateLabel = "com.centurylinklabs.watchtower.lifecycle.pre-update" + postUpdateLabel = "com.centurylinklabs.watchtower.lifecycle.post-update" + preUpdateTimeoutLabel = "com.centurylinklabs.watchtower.lifecycle.pre-update-timeout" postUpdateTimeoutLabel = "com.centurylinklabs.watchtower.lifecycle.post-update-timeout" )