1
0
mirror of https://github.com/containrrr/watchtower.git synced 2025-10-31 00:17:44 +02:00

refactor: extract types and pkgs to new files

This commit is contained in:
Simon Aronsson
2019-07-21 19:58:19 +02:00
parent 4a92a03f31
commit e109a7a6ce
15 changed files with 71 additions and 57 deletions

View File

@@ -10,6 +10,7 @@ import (
"github.com/containrrr/watchtower/container/mocks" "github.com/containrrr/watchtower/container/mocks"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
t "github.com/containrrr/watchtower/pkg/types"
cli "github.com/docker/docker/client" cli "github.com/docker/docker/client"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
@@ -149,7 +150,7 @@ type TestData struct {
Containers []container.Container Containers []container.Container
} }
func (client mockClient) ListContainers(f container.Filter) ([]container.Container, error) { func (client mockClient) ListContainers(f t.Filter) ([]container.Container, error) {
return client.TestData.Containers, nil return client.TestData.Containers, nil
} }

View File

@@ -5,6 +5,7 @@ import (
"time" "time"
"github.com/containrrr/watchtower/container" "github.com/containrrr/watchtower/container"
t "github.com/containrrr/watchtower/pkg/types"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@@ -14,7 +15,7 @@ var (
// UpdateParams contains all different options available to alter the behavior of the Update func // UpdateParams contains all different options available to alter the behavior of the Update func
type UpdateParams struct { type UpdateParams struct {
Filter container.Filter Filter t.Filter
Cleanup bool Cleanup bool
NoRestart bool NoRestart bool
Timeout time.Duration Timeout time.Duration

View File

@@ -11,6 +11,7 @@ import (
"github.com/containrrr/watchtower/container" "github.com/containrrr/watchtower/container"
"github.com/containrrr/watchtower/internal/flags" "github.com/containrrr/watchtower/internal/flags"
"github.com/containrrr/watchtower/notifications" "github.com/containrrr/watchtower/notifications"
t "github.com/containrrr/watchtower/pkg/types"
"github.com/robfig/cron" "github.com/robfig/cron"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@@ -123,7 +124,7 @@ func Run(c *cobra.Command, names []string) {
os.Exit(1) os.Exit(1)
} }
func runUpgradesOnSchedule(filter container.Filter) error { func runUpgradesOnSchedule(filter t.Filter) error {
tryLockSem := make(chan bool, 1) tryLockSem := make(chan bool, 1)
tryLockSem <- true tryLockSem <- true
@@ -164,7 +165,7 @@ func runUpgradesOnSchedule(filter container.Filter) error {
return nil return nil
} }
func runUpdatesWithNotifications(filter container.Filter) { func runUpdatesWithNotifications(filter t.Filter) {
notifier.StartNotification() notifier.StartNotification()
updateParams := actions.UpdateParams{ updateParams := actions.UpdateParams{
Filter: filter, Filter: filter,

View File

@@ -5,10 +5,10 @@ import (
"io/ioutil" "io/ioutil"
"time" "time"
t "github.com/containrrr/watchtower/pkg/types"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/network"
dockerclient "github.com/docker/docker/client" dockerclient "github.com/docker/docker/client"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@@ -22,7 +22,7 @@ const (
// A Client is the interface through which watchtower interacts with the // A Client is the interface through which watchtower interacts with the
// Docker API. // Docker API.
type Client interface { type Client interface {
ListContainers(Filter) ([]Container, error) ListContainers(t.Filter) ([]Container, error)
StopContainer(Container, time.Duration) error StopContainer(Container, time.Duration) error
StartContainer(Container) error StartContainer(Container) error
RenameContainer(Container, string) error RenameContainer(Container, string) error
@@ -58,7 +58,7 @@ type dockerClient struct {
includeStopped bool includeStopped bool
} }
func (client dockerClient) ListContainers(fn Filter) ([]Container, error) { func (client dockerClient) ListContainers(fn t.Filter) ([]Container, error) {
cs := []Container{} cs := []Container{}
bg := context.Background() bg := context.Background()

View File

@@ -2,6 +2,7 @@ package container
import ( import (
"fmt" "fmt"
"github.com/containrrr/watchtower/internal/util"
"strconv" "strconv"
"strings" "strings"
@@ -146,19 +147,19 @@ func (c Container) runtimeConfig() *dockercontainer.Config {
config.User = "" config.User = ""
} }
if sliceEqual(config.Cmd, imageConfig.Cmd) { if util.SliceEqual(config.Cmd, imageConfig.Cmd) {
config.Cmd = nil config.Cmd = nil
} }
if sliceEqual(config.Entrypoint, imageConfig.Entrypoint) { if util.SliceEqual(config.Entrypoint, imageConfig.Entrypoint) {
config.Entrypoint = nil config.Entrypoint = nil
} }
config.Env = sliceSubtract(config.Env, imageConfig.Env) config.Env = util.SliceSubtract(config.Env, imageConfig.Env)
config.Labels = stringMapSubtract(config.Labels, imageConfig.Labels) config.Labels = util.StringMapSubtract(config.Labels, imageConfig.Labels)
config.Volumes = structMapSubtract(config.Volumes, imageConfig.Volumes) config.Volumes = util.StructMapSubtract(config.Volumes, imageConfig.Volumes)
// subtract ports exposed in image from container // subtract ports exposed in image from container
for k := range config.ExposedPorts { for k := range config.ExposedPorts {

View File

@@ -1,30 +1,20 @@
package container package container
// A Filter is a prototype for a function that can be used to filter the import t "github.com/containrrr/watchtower/pkg/types"
// results from a call to the ListContainers() method on the Client.
type Filter func(FilterableContainer) bool
// A FilterableContainer is the interface which is used to filter
// containers.
type FilterableContainer interface {
Name() string
IsWatchtower() bool
Enabled() (bool, bool)
}
// WatchtowerContainersFilter filters only watchtower containers // WatchtowerContainersFilter filters only watchtower containers
func WatchtowerContainersFilter(c FilterableContainer) bool { return c.IsWatchtower() } func WatchtowerContainersFilter(c t.FilterableContainer) bool { return c.IsWatchtower() }
// Filter no containers and returns all // Filter no containers and returns all
func noFilter(FilterableContainer) bool { return true } func noFilter(t.FilterableContainer) bool { return true }
// Filters containers which don't have a specified name // Filters containers which don't have a specified name
func filterByNames(names []string, baseFilter Filter) Filter { func filterByNames(names []string, baseFilter t.Filter) t.Filter {
if len(names) == 0 { if len(names) == 0 {
return baseFilter return baseFilter
} }
return func(c FilterableContainer) bool { return func(c t.FilterableContainer) bool {
for _, name := range names { for _, name := range names {
if (name == c.Name()) || (name == c.Name()[1:]) { if (name == c.Name()) || (name == c.Name()[1:]) {
return baseFilter(c) return baseFilter(c)
@@ -35,8 +25,8 @@ func filterByNames(names []string, baseFilter Filter) Filter {
} }
// Filters out containers that don't have the 'enableLabel' // Filters out containers that don't have the 'enableLabel'
func filterByEnableLabel(baseFilter Filter) Filter { func filterByEnableLabel(baseFilter t.Filter) t.Filter {
return func(c FilterableContainer) bool { return func(c t.FilterableContainer) bool {
// If label filtering is enabled, containers should only be considered // If label filtering is enabled, containers should only be considered
// if the label is specifically set. // if the label is specifically set.
_, ok := c.Enabled() _, ok := c.Enabled()
@@ -49,8 +39,8 @@ func filterByEnableLabel(baseFilter Filter) Filter {
} }
// Filters out containers that have a 'enableLabel' and is set to disable. // Filters out containers that have a 'enableLabel' and is set to disable.
func filterByDisabledLabel(baseFilter Filter) Filter { func filterByDisabledLabel(baseFilter t.Filter) t.Filter {
return func(c FilterableContainer) bool { return func(c t.FilterableContainer) bool {
enabledLabel, ok := c.Enabled() enabledLabel, ok := c.Enabled()
if ok && !enabledLabel { if ok && !enabledLabel {
// If the label has been set and it demands a disable // If the label has been set and it demands a disable
@@ -62,7 +52,7 @@ func filterByDisabledLabel(baseFilter Filter) Filter {
} }
// BuildFilter creates the needed filter of containers // BuildFilter creates the needed filter of containers
func BuildFilter(names []string, enableLabel bool) Filter { func BuildFilter(names []string, enableLabel bool) t.Filter {
filter := noFilter filter := noFilter
filter = filterByNames(names, filter) filter = filterByNames(names, filter)
if enableLabel { if enableLabel {

View File

@@ -1,6 +1,6 @@
package container package util
func sliceEqual(s1, s2 []string) bool { func SliceEqual(s1, s2 []string) bool {
if len(s1) != len(s2) { if len(s1) != len(s2) {
return false return false
} }
@@ -14,7 +14,7 @@ func sliceEqual(s1, s2 []string) bool {
return true return true
} }
func sliceSubtract(a1, a2 []string) []string { func SliceSubtract(a1, a2 []string) []string {
a := []string{} a := []string{}
for _, e1 := range a1 { for _, e1 := range a1 {
@@ -35,7 +35,7 @@ func sliceSubtract(a1, a2 []string) []string {
return a return a
} }
func stringMapSubtract(m1, m2 map[string]string) map[string]string { func StringMapSubtract(m1, m2 map[string]string) map[string]string {
m := map[string]string{} m := map[string]string{}
for k1, v1 := range m1 { for k1, v1 := range m1 {
@@ -51,7 +51,7 @@ func stringMapSubtract(m1, m2 map[string]string) map[string]string {
return m return m
} }
func structMapSubtract(m1, m2 map[string]struct{}) map[string]struct{} { func StructMapSubtract(m1, m2 map[string]struct{}) map[string]struct{} {
m := map[string]struct{}{} m := map[string]struct{}{}
for k1, v1 := range m1 { for k1, v1 := range m1 {

View File

@@ -1,8 +1,8 @@
package container package util
import ( import (
"testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"testing"
) )
@@ -11,7 +11,7 @@ func TestSliceEqual_True(t *testing.T) {
s1 := []string{"a", "b", "c"} s1 := []string{"a", "b", "c"}
s2 := []string{"a", "b", "c"} s2 := []string{"a", "b", "c"}
result := sliceEqual(s1, s2) result := SliceEqual(s1, s2)
assert.True(t, result) assert.True(t, result)
} }
@@ -20,7 +20,7 @@ func TestSliceEqual_DifferentLengths(t *testing.T) {
s1 := []string{"a", "b", "c"} s1 := []string{"a", "b", "c"}
s2 := []string{"a", "b", "c", "d"} s2 := []string{"a", "b", "c", "d"}
result := sliceEqual(s1, s2) result := SliceEqual(s1, s2)
assert.False(t, result) assert.False(t, result)
} }
@@ -29,7 +29,7 @@ func TestSliceEqual_DifferentContents(t *testing.T) {
s1 := []string{"a", "b", "c"} s1 := []string{"a", "b", "c"}
s2 := []string{"a", "b", "d"} s2 := []string{"a", "b", "d"}
result := sliceEqual(s1, s2) result := SliceEqual(s1, s2)
assert.False(t, result) assert.False(t, result)
} }
@@ -38,7 +38,7 @@ func TestSliceSubtract(t *testing.T) {
a1 := []string{"a", "b", "c"} a1 := []string{"a", "b", "c"}
a2 := []string{"a", "c"} a2 := []string{"a", "c"}
result := sliceSubtract(a1, a2) result := SliceSubtract(a1, a2)
assert.Equal(t, []string{"b"}, result) assert.Equal(t, []string{"b"}, result)
assert.Equal(t, []string{"a", "b", "c"}, a1) assert.Equal(t, []string{"a", "b", "c"}, a1)
assert.Equal(t, []string{"a", "c"}, a2) assert.Equal(t, []string{"a", "c"}, a2)
@@ -48,7 +48,7 @@ func TestStringMapSubtract(t *testing.T) {
m1 := map[string]string{"a": "a", "b": "b", "c": "sea"} m1 := map[string]string{"a": "a", "b": "b", "c": "sea"}
m2 := map[string]string{"a": "a", "c": "c"} m2 := map[string]string{"a": "a", "c": "c"}
result := stringMapSubtract(m1, m2) result := StringMapSubtract(m1, m2)
assert.Equal(t, map[string]string{"b": "b", "c": "sea"}, result) assert.Equal(t, map[string]string{"b": "b", "c": "sea"}, result)
assert.Equal(t, map[string]string{"a": "a", "b": "b", "c": "sea"}, m1) assert.Equal(t, map[string]string{"a": "a", "b": "b", "c": "sea"}, m1)
assert.Equal(t, map[string]string{"a": "a", "c": "c"}, m2) assert.Equal(t, map[string]string{"a": "a", "c": "c"}, m2)
@@ -59,7 +59,7 @@ func TestStructMapSubtract(t *testing.T) {
m1 := map[string]struct{}{"a": x, "b": x, "c": x} m1 := map[string]struct{}{"a": x, "b": x, "c": x}
m2 := map[string]struct{}{"a": x, "c": x} m2 := map[string]struct{}{"a": x, "c": x}
result := structMapSubtract(m1, m2) result := StructMapSubtract(m1, m2)
assert.Equal(t, map[string]struct{}{"b": x}, result) assert.Equal(t, map[string]struct{}{"b": x}, result)
assert.Equal(t, map[string]struct{}{"a": x, "b": x, "c": x}, m1) assert.Equal(t, map[string]struct{}{"a": x, "b": x, "c": x}, m1)
assert.Equal(t, map[string]struct{}{"a": x, "c": x}, m2) assert.Equal(t, map[string]struct{}{"a": x, "c": x}, m2)

View File

@@ -9,7 +9,7 @@ import (
"time" "time"
"strconv" "strconv"
t "github.com/containrrr/watchtower/pkg/types"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@@ -17,7 +17,7 @@ const (
emailType = "email" emailType = "email"
) )
// Implements typeNotifier, logrus.Hook // Implements Notifier, logrus.Hook
// The default logrus email integration would have several issues: // The default logrus email integration would have several issues:
// - It would send one email per log output // - It would send one email per log output
// - It would only send errors // - It would only send errors
@@ -31,7 +31,7 @@ type emailTypeNotifier struct {
logLevels []log.Level logLevels []log.Level
} }
func newEmailNotifier(c *cobra.Command, acceptedLogLevels []log.Level) typeNotifier { func newEmailNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.Notifier {
flags := c.PersistentFlags() flags := c.PersistentFlags()
from, _ := flags.GetString("notification-email-from") from, _ := flags.GetString("notification-email-from")

View File

@@ -7,6 +7,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"net/http" "net/http"
t "github.com/containrrr/watchtower/pkg/types"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"io/ioutil" "io/ioutil"
) )
@@ -21,7 +22,7 @@ type msTeamsTypeNotifier struct {
data bool data bool
} }
func newMsTeamsNotifier(cmd *cobra.Command, acceptedLogLevels []log.Level) typeNotifier { func newMsTeamsNotifier(cmd *cobra.Command, acceptedLogLevels []log.Level) t.Notifier {
flags := cmd.PersistentFlags() flags := cmd.PersistentFlags()

View File

@@ -1,19 +1,17 @@
package notifications package notifications
import ( import (
ty "github.com/containrrr/watchtower/pkg/types"
"github.com/johntdyer/slackrus" "github.com/johntdyer/slackrus"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
type typeNotifier interface {
StartNotification()
SendNotification()
}
// Notifier can send log output as notification to admins, with optional batching. // Notifier can send log output as notification to admins, with optional batching.
type Notifier struct { type Notifier struct {
types []typeNotifier types []ty.Notifier
} }
// NewNotifier creates and returns a new Notifier, using global configuration. // NewNotifier creates and returns a new Notifier, using global configuration.
@@ -34,7 +32,7 @@ func NewNotifier(c *cobra.Command) *Notifier {
types, _ := f.GetStringSlice("notifications") types, _ := f.GetStringSlice("notifications")
for _, t := range types { for _, t := range types {
var tn typeNotifier var tn ty.Notifier
switch t { switch t {
case emailType: case emailType:
tn = newEmailNotifier(c, acceptedLogLevels) tn = newEmailNotifier(c, acceptedLogLevels)

View File

@@ -4,6 +4,7 @@ import (
"github.com/johntdyer/slackrus" "github.com/johntdyer/slackrus"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
t "github.com/containrrr/watchtower/pkg/types"
) )
const ( const (
@@ -14,7 +15,7 @@ type slackTypeNotifier struct {
slackrus.SlackrusHook slackrus.SlackrusHook
} }
func newSlackNotifier(c *cobra.Command, acceptedLogLevels []log.Level) typeNotifier { func newSlackNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.Notifier {
flags := c.PersistentFlags() flags := c.PersistentFlags()
hookURL, _ := flags.GetString("notification-slack-hook-url") hookURL, _ := flags.GetString("notification-slack-hook-url")

5
pkg/types/filter.go Normal file
View File

@@ -0,0 +1,5 @@
package types
// A Filter is a prototype for a function that can be used to filter the
// results from a call to the ListContainers() method on the Client.
type Filter func(FilterableContainer) bool

View File

@@ -0,0 +1,9 @@
package types
// A FilterableContainer is the interface which is used to filter
// containers.
type FilterableContainer interface {
Name() string
IsWatchtower() bool
Enabled() (bool, bool)
}

6
pkg/types/notifier.go Normal file
View File

@@ -0,0 +1,6 @@
package types
type Notifier interface {
StartNotification()
SendNotification()
}