watchtower/actions/check.go
Simon Aronsson 3fd97f80e1 add tests for check action, resolve wt cleanup bug
add unit tests for the check action to allow for some
refactoring and bug fixing without having to worry about
breaking stuff.

resolve watchtower cleanup bug by adding an initial 1 second sleep
in the check action. without the sleep, the docker client returns an
empty array, which is why we were left with two watchtowers.
2019-04-20 11:15:33 +02:00

84 lines
2.2 KiB
Go

package actions
import (
"errors"
"fmt"
"sort"
"strings"
"time"
"github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus"
log "github.com/sirupsen/logrus"
"github.com/containrrr/watchtower/container"
)
// 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 {
awaitDockerClient()
containers, err := client.ListContainers(container.WatchtowerContainersFilter)
if err != nil {
log.Fatal(err)
return err
}
if len(containers) <= 1 {
log.Debug("There are no additional watchtower containers")
return nil
}
log.Info("Found multiple running watchtower instances. Cleaning up.")
return cleanupExcessWatchtowers(containers, client, cleanup)
}
func cleanupExcessWatchtowers(containers []container.Container, client container.Client, cleanup bool) error {
var cleanupErrors int
var stopErrors int
sort.Sort(container.ByCreated(containers))
allContainersExceptLast := containers[0 : len(containers)-1]
for _, c := range allContainersExceptLast {
if err := client.StopContainer(c, 60); err != nil {
// logging the original here as we're just returning a count
logrus.Error(err)
stopErrors++
continue
}
if cleanup == true {
if err := client.RemoveImage(c); err != nil {
// logging the original here as we're just returning a count
logrus.Error(err)
cleanupErrors++
}
}
}
return createErrorIfAnyHaveOccurred(stopErrors, cleanupErrors)
}
func createErrorIfAnyHaveOccurred(c int, i int) error {
if c == 0 && i == 0 {
return nil
}
var output strings.Builder
if c > 0 {
output.WriteString(fmt.Sprintf("%d errors while stopping containers", c))
}
if i > 0 {
output.WriteString(fmt.Sprintf("%d errors while cleaning up images", c))
}
return errors.New(output.String())
}
func awaitDockerClient() {
log.Debug("Sleeping for a seconds to ensure the docker api client has been properly initialized.")
time.Sleep(1 * time.Second)
}