mirror of
https://github.com/containrrr/watchtower.git
synced 2026-02-18 13:18:08 +01:00
Merge master and fix conflicts
This commit is contained in:
commit
18c5bc3f0f
35 changed files with 1021 additions and 132 deletions
|
|
@ -46,7 +46,7 @@ var _ = Describe("the actions package", func() {
|
|||
When("given an empty array", func() {
|
||||
It("should not do anything", func() {
|
||||
client.TestData.Containers = []container.Container{}
|
||||
err := actions.CheckForMultipleWatchtowerInstances(client, false)
|
||||
err := actions.CheckForMultipleWatchtowerInstances(client, false, "")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
|
@ -60,7 +60,7 @@ var _ = Describe("the actions package", func() {
|
|||
time.Now(),
|
||||
make([]string,0)),
|
||||
}
|
||||
err := actions.CheckForMultipleWatchtowerInstances(client, false)
|
||||
err := actions.CheckForMultipleWatchtowerInstances(client, false, "")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
|
@ -93,7 +93,7 @@ var _ = Describe("the actions package", func() {
|
|||
})
|
||||
|
||||
It("should stop all but the latest one", func() {
|
||||
err := actions.CheckForMultipleWatchtowerInstances(client, false)
|
||||
err := actions.CheckForMultipleWatchtowerInstances(client, false, "")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
|
@ -125,12 +125,12 @@ var _ = Describe("the actions package", func() {
|
|||
)
|
||||
})
|
||||
It("should try to delete the image if the cleanup flag is true", func() {
|
||||
err := actions.CheckForMultipleWatchtowerInstances(client, true)
|
||||
err := actions.CheckForMultipleWatchtowerInstances(client, true, "")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(client.TestData.TriedToRemoveImage()).To(BeTrue())
|
||||
})
|
||||
It("should not try to delete the image if the cleanup flag is false", func() {
|
||||
err := actions.CheckForMultipleWatchtowerInstances(client, false)
|
||||
err := actions.CheckForMultipleWatchtowerInstances(client, false, "")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(client.TestData.TriedToRemoveImage()).To(BeFalse())
|
||||
})
|
||||
|
|
|
|||
|
|
@ -19,10 +19,11 @@ import (
|
|||
|
||||
// CheckForMultipleWatchtowerInstances will ensure that there are not multiple instances of the
|
||||
// watchtower running simultaneously. If multiple watchtower containers are detected, this function
|
||||
// will stop and remove all but the most recently started container.
|
||||
func CheckForMultipleWatchtowerInstances(client container.Client, cleanup bool) error {
|
||||
// will stop and remove all but the most recently started container. This behaviour can be bypassed
|
||||
// if a scope UID is defined.
|
||||
func CheckForMultipleWatchtowerInstances(client container.Client, cleanup bool, scope string) error {
|
||||
awaitDockerClient()
|
||||
containers, err := client.ListContainers(filters.WatchtowerContainersFilter)
|
||||
containers, err := client.ListContainers(filters.FilterByScope(scope, filters.WatchtowerContainersFilter))
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
|
|
|||
|
|
@ -36,3 +36,22 @@ func CreateMockContainer(id string, name string, image string, created time.Time
|
|||
},
|
||||
)
|
||||
}
|
||||
|
||||
// CreateMockContainerWithConfig creates a container substitute valid for testing
|
||||
func CreateMockContainerWithConfig(id string, name string, image string, created time.Time, config *container2.Config) container.Container {
|
||||
content := types.ContainerJSON{
|
||||
ContainerJSONBase: &types.ContainerJSONBase{
|
||||
ID: id,
|
||||
Image: image,
|
||||
Name: name,
|
||||
Created: created.String(),
|
||||
},
|
||||
Config: config,
|
||||
}
|
||||
return *container.NewContainer(
|
||||
&content,
|
||||
&types.ImageInspect{
|
||||
ID: image,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package actions
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/containrrr/watchtower/internal/util"
|
||||
"github.com/containrrr/watchtower/pkg/container"
|
||||
"github.com/containrrr/watchtower/pkg/lifecycle"
|
||||
|
|
@ -41,11 +42,13 @@ func PrepareContainerList(client container.Client, params types.UpdateParams) ([
|
|||
return nil, err
|
||||
}
|
||||
|
||||
for i, container := range containers {
|
||||
stale, err := client.IsContainerStale(container)
|
||||
for i, targetContainer := range containers {
|
||||
stale, err := client.IsContainerStale(targetContainer)
|
||||
if stale && !params.NoRestart && !params.MonitorOnly && !targetContainer.IsMonitorOnly() && !targetContainer.HasImageInfo() {
|
||||
err = errors.New("no available image info")
|
||||
}
|
||||
if err != nil {
|
||||
log.Infof("Unable to update container %s. Proceeding to next.", containers[i].Name())
|
||||
log.Debug(err)
|
||||
log.Infof("Unable to update container %q: %v. Proceeding to next.", containers[i].Name(), err)
|
||||
stale = false
|
||||
}
|
||||
containers[i].Stale = stale
|
||||
|
|
@ -76,11 +79,13 @@ func Update(client container.Client, params types.UpdateParams) error {
|
|||
lifecycle.ExecutePreChecks(client, params)
|
||||
}
|
||||
|
||||
if params.MonitorOnly {
|
||||
if params.LifecycleHooks {
|
||||
lifecycle.ExecutePostChecks(client, params)
|
||||
containersToUpdate := []container.Container{}
|
||||
if !params.MonitorOnly {
|
||||
for i := len(containers) - 1; i >= 0; i-- {
|
||||
if !containers[i].IsMonitorOnly() {
|
||||
containersToUpdate = append(containersToUpdate, containers[i])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//shared map for independent and linked update
|
||||
|
|
@ -113,6 +118,21 @@ func Update(client container.Client, params types.UpdateParams) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func performRollingRestart(containers []container.Container, client container.Client, params types.UpdateParams) {
|
||||
cleanupImageIDs := make(map[string]bool)
|
||||
|
||||
for i := len(containers) - 1; i >= 0; i-- {
|
||||
if containers[i].Stale {
|
||||
stopStaleContainer(containers[i], client, params)
|
||||
restartStaleContainer(containers[i], client, params)
|
||||
}
|
||||
}
|
||||
|
||||
if params.Cleanup {
|
||||
cleanupImages(client, cleanupImageIDs)
|
||||
}
|
||||
}
|
||||
|
||||
func stopContainersInReversedOrder(containers []container.Container, client container.Client, params types.UpdateParams) {
|
||||
for i := len(containers) - 1; i >= 0; i-- {
|
||||
stopStaleContainer(containers[i], client, params)
|
||||
|
|
@ -146,8 +166,8 @@ func restartContainersInSortedOrder(containers []container.Container, client con
|
|||
if !container.Stale {
|
||||
continue
|
||||
}
|
||||
restartStaleContainer(container, client, params)
|
||||
imageIDs[container.ImageID()] = true
|
||||
restartStaleContainer(staleContainer, client, params)
|
||||
imageIDs[staleContainer.ImageID()] = true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"github.com/containrrr/watchtower/pkg/container"
|
||||
"github.com/containrrr/watchtower/pkg/container/mocks"
|
||||
"github.com/containrrr/watchtower/pkg/types"
|
||||
container2 "github.com/docker/docker/api/types/container"
|
||||
cli "github.com/docker/docker/client"
|
||||
"time"
|
||||
|
||||
|
|
@ -228,4 +229,73 @@ var _ = Describe("the update action", func() {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("watchtower has been instructed to monitor only", func() {
|
||||
When("certain containers are set to monitor only", func() {
|
||||
BeforeEach(func() {
|
||||
client = CreateMockClient(
|
||||
&TestData{
|
||||
NameOfContainerToKeep: "test-container-02",
|
||||
Containers: []container.Container{
|
||||
CreateMockContainer(
|
||||
"test-container-01",
|
||||
"test-container-01",
|
||||
"fake-image1:latest",
|
||||
time.Now()),
|
||||
CreateMockContainerWithConfig(
|
||||
"test-container-02",
|
||||
"test-container-02",
|
||||
"fake-image2:latest",
|
||||
time.Now(),
|
||||
&container2.Config{
|
||||
Labels: map[string]string{
|
||||
"com.centurylinklabs.watchtower.monitor-only": "true",
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
dockerClient,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
})
|
||||
|
||||
It("should not update those containers", func() {
|
||||
err := actions.Update(client, types.UpdateParams{Cleanup: true})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(client.TestData.TriedToRemoveImageCount).To(Equal(1))
|
||||
})
|
||||
})
|
||||
|
||||
When("monitor only is set globally", func() {
|
||||
BeforeEach(func() {
|
||||
client = CreateMockClient(
|
||||
&TestData{
|
||||
Containers: []container.Container{
|
||||
CreateMockContainer(
|
||||
"test-container-01",
|
||||
"test-container-01",
|
||||
"fake-image:latest",
|
||||
time.Now()),
|
||||
CreateMockContainer(
|
||||
"test-container-02",
|
||||
"test-container-02",
|
||||
"fake-image:latest",
|
||||
time.Now()),
|
||||
},
|
||||
},
|
||||
dockerClient,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
})
|
||||
|
||||
It("should not update any containers", func() {
|
||||
err := actions.Update(client, types.UpdateParams{MonitorOnly: true})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(client.TestData.TriedToRemoveImageCount).To(Equal(0))
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -123,6 +123,12 @@ func RegisterSystemFlags(rootCmd *cobra.Command) {
|
|||
viper.GetBool("WATCHTOWER_LIFECYCLE_HOOKS"),
|
||||
"Enable the execution of commands triggered by pre- and post-update lifecycle hooks")
|
||||
|
||||
flags.BoolP(
|
||||
"rolling-restart",
|
||||
"",
|
||||
viper.GetBool("WATCHTOWER_ROLLING_RESTART"),
|
||||
"Restart containers one at a time")
|
||||
|
||||
flags.BoolP(
|
||||
"http-api",
|
||||
"",
|
||||
|
|
@ -134,6 +140,17 @@ func RegisterSystemFlags(rootCmd *cobra.Command) {
|
|||
"",
|
||||
viper.GetString("WATCHTOWER_HTTP_API_TOKEN"),
|
||||
"Sets an authentication token to HTTP API requests.")
|
||||
// https://no-color.org/
|
||||
flags.BoolP(
|
||||
"no-color",
|
||||
"",
|
||||
viper.IsSet("NO_COLOR"),
|
||||
"Disable ANSI color escape codes in log output")
|
||||
flags.StringP(
|
||||
"scope",
|
||||
"",
|
||||
viper.GetString("WATCHTOWER_SCOPE"),
|
||||
"Defines a monitoring scope for the Watchtower instance.")
|
||||
}
|
||||
|
||||
// RegisterNotificationFlags that are used by watchtower to send notifications
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue