You've already forked watchtower
							
							
				mirror of
				https://github.com/containrrr/watchtower.git
				synced 2025-10-31 00:17:44 +02:00 
			
		
		
		
	Allow user-configurable DOCKER_HOST
This commit is contained in:
		| @@ -8,9 +8,7 @@ import ( | ||||
|  | ||||
| func watchtowerContainersFilter(c container.Container) bool { return c.IsWatchtower() } | ||||
|  | ||||
| func CheckPrereqs() error { | ||||
| 	client := container.NewClient() | ||||
|  | ||||
| func CheckPrereqs(client container.Client) error { | ||||
| 	containers, err := client.ListContainers(watchtowerContainersFilter) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
|   | ||||
							
								
								
									
										81
									
								
								actions/check_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								actions/check_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| package actions | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/CenturyLinkLabs/watchtower/container" | ||||
| 	"github.com/CenturyLinkLabs/watchtower/container/mockclient" | ||||
| 	"github.com/samalba/dockerclient" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"github.com/stretchr/testify/mock" | ||||
| ) | ||||
|  | ||||
| func TestCheckPrereqs_Success(t *testing.T) { | ||||
| 	cc := &dockerclient.ContainerConfig{ | ||||
| 		Labels: map[string]string{"com.centurylinklabs.watchtower": "true"}, | ||||
| 	} | ||||
| 	c1 := *container.NewContainer( | ||||
| 		&dockerclient.ContainerInfo{ | ||||
| 			Name:    "c1", | ||||
| 			Config:  cc, | ||||
| 			Created: "2015-07-01T12:00:01.000000000Z", | ||||
| 		}, | ||||
| 		nil, | ||||
| 	) | ||||
| 	c2 := *container.NewContainer( | ||||
| 		&dockerclient.ContainerInfo{ | ||||
| 			Name:    "c2", | ||||
| 			Config:  cc, | ||||
| 			Created: "2015-07-01T12:00:00.000000000Z", | ||||
| 		}, | ||||
| 		nil, | ||||
| 	) | ||||
| 	cs := []container.Container{c1, c2} | ||||
|  | ||||
| 	client := &mockclient.MockClient{} | ||||
| 	client.On("ListContainers", mock.AnythingOfType("container.ContainerFilter")).Return(cs, nil) | ||||
| 	client.On("Stop", c2, time.Duration(60)).Return(nil) | ||||
|  | ||||
| 	err := CheckPrereqs(client) | ||||
|  | ||||
| 	assert.NoError(t, err) | ||||
| 	client.AssertExpectations(t) | ||||
| } | ||||
|  | ||||
| func TestCheckPrereqs_OnlyOneContainer(t *testing.T) { | ||||
| 	cc := &dockerclient.ContainerConfig{ | ||||
| 		Labels: map[string]string{"com.centurylinklabs.watchtower": "true"}, | ||||
| 	} | ||||
| 	c1 := *container.NewContainer( | ||||
| 		&dockerclient.ContainerInfo{ | ||||
| 			Name:    "c1", | ||||
| 			Config:  cc, | ||||
| 			Created: "2015-07-01T12:00:01.000000000Z", | ||||
| 		}, | ||||
| 		nil, | ||||
| 	) | ||||
| 	cs := []container.Container{c1} | ||||
|  | ||||
| 	client := &mockclient.MockClient{} | ||||
| 	client.On("ListContainers", mock.AnythingOfType("container.ContainerFilter")).Return(cs, nil) | ||||
|  | ||||
| 	err := CheckPrereqs(client) | ||||
|  | ||||
| 	assert.NoError(t, err) | ||||
| 	client.AssertExpectations(t) | ||||
| } | ||||
|  | ||||
| func TestCheckPrereqs_ListError(t *testing.T) { | ||||
| 	cs := []container.Container{} | ||||
|  | ||||
| 	client := &mockclient.MockClient{} | ||||
| 	client.On("ListContainers", mock.AnythingOfType("container.ContainerFilter")).Return(cs, errors.New("oops")) | ||||
|  | ||||
| 	err := CheckPrereqs(client) | ||||
|  | ||||
| 	assert.Error(t, err) | ||||
| 	assert.EqualError(t, err, "oops") | ||||
| 	client.AssertExpectations(t) | ||||
| } | ||||
| @@ -12,8 +12,7 @@ var ( | ||||
|  | ||||
| func allContainersFilter(container.Container) bool { return true } | ||||
|  | ||||
| func Update() error { | ||||
| 	client := container.NewClient() | ||||
| func Update(client container.Client) error { | ||||
| 	containers, err := client.ListContainers(allContainersFilter) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
|   | ||||
| @@ -5,17 +5,18 @@ import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/CenturyLinkLabs/watchtower/container" | ||||
| 	"github.com/samalba/dockerclient" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestCheckDependencies(t *testing.T) { | ||||
| 	cs := []container.Container{ | ||||
| 		container.NewTestContainer("1", []string{}), | ||||
| 		container.NewTestContainer("2", []string{"1:"}), | ||||
| 		container.NewTestContainer("3", []string{"2:"}), | ||||
| 		container.NewTestContainer("4", []string{"3:"}), | ||||
| 		container.NewTestContainer("5", []string{"4:"}), | ||||
| 		container.NewTestContainer("6", []string{"5:"}), | ||||
| 		newTestContainer("1", []string{}), | ||||
| 		newTestContainer("2", []string{"1:"}), | ||||
| 		newTestContainer("3", []string{"2:"}), | ||||
| 		newTestContainer("4", []string{"3:"}), | ||||
| 		newTestContainer("5", []string{"4:"}), | ||||
| 		newTestContainer("6", []string{"5:"}), | ||||
| 	} | ||||
| 	cs[3].Stale = true | ||||
|  | ||||
| @@ -36,3 +37,15 @@ func TestRandName(t *testing.T) { | ||||
|  | ||||
| 	assert.True(t, validPattern.MatchString(name)) | ||||
| } | ||||
|  | ||||
| func newTestContainer(name string, links []string) container.Container { | ||||
| 	return *container.NewContainer( | ||||
| 		&dockerclient.ContainerInfo{ | ||||
| 			Name: name, | ||||
| 			HostConfig: &dockerclient.HostConfig{ | ||||
| 				Links: links, | ||||
| 			}, | ||||
| 		}, | ||||
| 		nil, | ||||
| 	) | ||||
| } | ||||
|   | ||||
| @@ -32,8 +32,8 @@ type Client interface { | ||||
| 	Rename(Container, string) error | ||||
| } | ||||
|  | ||||
| func NewClient() Client { | ||||
| 	docker, err := dockerclient.NewDockerClient("unix:///var/run/docker.sock", nil) | ||||
| func NewClient(dockerHost string) Client { | ||||
| 	docker, err := dockerclient.NewDockerClient(dockerHost, nil) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("Error instantiating Docker client: %s\n", err) | ||||
|   | ||||
| @@ -7,6 +7,13 @@ import ( | ||||
| 	"github.com/samalba/dockerclient" | ||||
| ) | ||||
|  | ||||
| func NewContainer(containerInfo *dockerclient.ContainerInfo, imageInfo *dockerclient.ImageInfo) *Container { | ||||
| 	return &Container{ | ||||
| 		containerInfo: containerInfo, | ||||
| 		imageInfo:     imageInfo, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type Container struct { | ||||
| 	Stale bool | ||||
|  | ||||
| @@ -95,14 +102,3 @@ func (c Container) hostConfig() *dockerclient.HostConfig { | ||||
|  | ||||
| 	return hostConfig | ||||
| } | ||||
|  | ||||
| func NewTestContainer(name string, links []string) Container { | ||||
| 	return Container{ | ||||
| 		containerInfo: &dockerclient.ContainerInfo{ | ||||
| 			Name: name, | ||||
| 			HostConfig: &dockerclient.HostConfig{ | ||||
| 				Links: links, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										37
									
								
								container/mockclient/mock.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								container/mockclient/mock.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| package mockclient | ||||
|  | ||||
| import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/CenturyLinkLabs/watchtower/container" | ||||
| 	"github.com/stretchr/testify/mock" | ||||
| ) | ||||
|  | ||||
| type MockClient struct { | ||||
| 	mock.Mock | ||||
| } | ||||
|  | ||||
| func (m *MockClient) ListContainers(cf container.ContainerFilter) ([]container.Container, error) { | ||||
| 	args := m.Called(cf) | ||||
| 	return args.Get(0).([]container.Container), args.Error(1) | ||||
| } | ||||
|  | ||||
| func (m *MockClient) RefreshImage(c *container.Container) error { | ||||
| 	args := m.Called(c) | ||||
| 	return args.Error(0) | ||||
| } | ||||
|  | ||||
| func (m *MockClient) Stop(c container.Container, timeout time.Duration) error { | ||||
| 	args := m.Called(c, timeout) | ||||
| 	return args.Error(0) | ||||
| } | ||||
|  | ||||
| func (m *MockClient) Start(c container.Container) error { | ||||
| 	args := m.Called(c) | ||||
| 	return args.Error(0) | ||||
| } | ||||
|  | ||||
| func (m *MockClient) Rename(c container.Container, name string) error { | ||||
| 	args := m.Called(c, name) | ||||
| 	return args.Error(0) | ||||
| } | ||||
							
								
								
									
										17
									
								
								container/mockclient/mock_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								container/mockclient/mock_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| package mockclient | ||||
|  | ||||
| import ( | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/CenturyLinkLabs/watchtower/container" | ||||
| ) | ||||
|  | ||||
| func TestMockInterface(t *testing.T) { | ||||
| 	iface := reflect.TypeOf((*container.Client)(nil)).Elem() | ||||
| 	mock := &MockClient{} | ||||
|  | ||||
| 	if !reflect.TypeOf(mock).Implements(iface) { | ||||
| 		t.Fatalf("Mock does not implement the Client interface") | ||||
| 	} | ||||
| } | ||||
| @@ -32,12 +32,12 @@ func TestByCreated(t *testing.T) { | ||||
| } | ||||
|  | ||||
| func TestSortByDependencies_Success(t *testing.T) { | ||||
| 	c1 := NewTestContainer("1", []string{}) | ||||
| 	c2 := NewTestContainer("2", []string{"1:"}) | ||||
| 	c3 := NewTestContainer("3", []string{"2:"}) | ||||
| 	c4 := NewTestContainer("4", []string{"3:"}) | ||||
| 	c5 := NewTestContainer("5", []string{"4:"}) | ||||
| 	c6 := NewTestContainer("6", []string{"5:", "3:"}) | ||||
| 	c1 := newTestContainer("1", []string{}) | ||||
| 	c2 := newTestContainer("2", []string{"1:"}) | ||||
| 	c3 := newTestContainer("3", []string{"2:"}) | ||||
| 	c4 := newTestContainer("4", []string{"3:"}) | ||||
| 	c5 := newTestContainer("5", []string{"4:"}) | ||||
| 	c6 := newTestContainer("6", []string{"5:", "3:"}) | ||||
| 	containers := []Container{c6, c2, c4, c1, c3, c5} | ||||
|  | ||||
| 	result, err := SortByDependencies(containers) | ||||
| @@ -47,9 +47,9 @@ func TestSortByDependencies_Success(t *testing.T) { | ||||
| } | ||||
|  | ||||
| func TestSortByDependencies_Error(t *testing.T) { | ||||
| 	c1 := NewTestContainer("1", []string{"3:"}) | ||||
| 	c2 := NewTestContainer("2", []string{"1:"}) | ||||
| 	c3 := NewTestContainer("3", []string{"2:"}) | ||||
| 	c1 := newTestContainer("1", []string{"3:"}) | ||||
| 	c2 := newTestContainer("2", []string{"1:"}) | ||||
| 	c3 := newTestContainer("3", []string{"2:"}) | ||||
| 	containers := []Container{c1, c2, c3} | ||||
|  | ||||
| 	_, err := SortByDependencies(containers) | ||||
| @@ -57,3 +57,15 @@ func TestSortByDependencies_Error(t *testing.T) { | ||||
| 	assert.Error(t, err) | ||||
| 	assert.EqualError(t, err, "Circular reference to 1") | ||||
| } | ||||
|  | ||||
| func newTestContainer(name string, links []string) Container { | ||||
| 	return *NewContainer( | ||||
| 		&dockerclient.ContainerInfo{ | ||||
| 			Name: name, | ||||
| 			HostConfig: &dockerclient.HostConfig{ | ||||
| 				Links: links, | ||||
| 			}, | ||||
| 		}, | ||||
| 		nil, | ||||
| 	) | ||||
| } | ||||
|   | ||||
							
								
								
									
										18
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								main.go
									
									
									
									
									
								
							| @@ -9,6 +9,7 @@ import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/CenturyLinkLabs/watchtower/actions" | ||||
| 	"github.com/CenturyLinkLabs/watchtower/container" | ||||
| 	"github.com/codegangsta/cli" | ||||
| ) | ||||
|  | ||||
| @@ -23,6 +24,12 @@ func main() { | ||||
| 	app.Before = before | ||||
| 	app.Action = start | ||||
| 	app.Flags = []cli.Flag{ | ||||
| 		cli.StringFlag{ | ||||
| 			Name:   "host, H", | ||||
| 			Value:  "unix:///var/run/docker.sock", | ||||
| 			Usage:  "Docker daemon socket to connect to", | ||||
| 			EnvVar: "DOCKER_HOST", | ||||
| 		}, | ||||
| 		cli.IntFlag{ | ||||
| 			Name:  "interval, i", | ||||
| 			Value: 300, | ||||
| @@ -48,15 +55,17 @@ func handleSignals() { | ||||
| } | ||||
|  | ||||
| func before(c *cli.Context) error { | ||||
| 	return actions.CheckPrereqs() | ||||
| 	client := newContainerClient(c) | ||||
| 	return actions.CheckPrereqs(client) | ||||
| } | ||||
|  | ||||
| func start(c *cli.Context) { | ||||
| 	client := newContainerClient(c) | ||||
| 	secs := time.Duration(c.Int("interval")) * time.Second | ||||
|  | ||||
| 	for { | ||||
| 		wg.Add(1) | ||||
| 		if err := actions.Update(); err != nil { | ||||
| 		if err := actions.Update(client); err != nil { | ||||
| 			fmt.Println(err) | ||||
| 		} | ||||
| 		wg.Done() | ||||
| @@ -64,3 +73,8 @@ func start(c *cli.Context) { | ||||
| 		time.Sleep(secs) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func newContainerClient(c *cli.Context) container.Client { | ||||
| 	dockerHost := c.GlobalString("host") | ||||
| 	return container.NewClient(dockerHost) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user