diff --git a/cmd/tink-worker/worker/container_manager_test.go b/cmd/tink-worker/worker/container_manager_test.go index 9a0a7dfc7..ab85b5a89 100644 --- a/cmd/tink-worker/worker/container_manager_test.go +++ b/cmd/tink-worker/worker/container_manager_test.go @@ -26,10 +26,19 @@ type fakeDockerClient struct { statusCode int err error waitErr error + imageInspectErr error } -func newFakeDockerClient(containerID, imagePullContent string, delay time.Duration, statusCode int, err, waitErr error) *fakeDockerClient { - return &fakeDockerClient{ +type dockerClientOpt func(*fakeDockerClient) + +func withImageInspectErr(err error) dockerClientOpt { + return func(c *fakeDockerClient) { + c.imageInspectErr = err + } +} + +func newFakeDockerClient(containerID, imagePullContent string, delay time.Duration, statusCode int, err, waitErr error, opts ...dockerClientOpt) *fakeDockerClient { + f := &fakeDockerClient{ containerID: containerID, imagePullContent: imagePullContent, delay: delay, @@ -37,6 +46,12 @@ func newFakeDockerClient(containerID, imagePullContent string, delay time.Durati err: err, waitErr: waitErr, } + + for _, opt := range opts { + opt(f) + } + + return f } func (c *fakeDockerClient) ContainerCreate( diff --git a/cmd/tink-worker/worker/registry.go b/cmd/tink-worker/worker/registry.go index 144d3714f..9b4b06dbb 100644 --- a/cmd/tink-worker/worker/registry.go +++ b/cmd/tink-worker/worker/registry.go @@ -31,6 +31,7 @@ type ImagePullStatus struct { } // PullImage outputs to stdout the contents of the requested image (relative to the registry). +// If a pull fails but the image already exists then we will return a nil error. func (m *containerManager) PullImage(ctx context.Context, img string) error { l := m.getLogger(ctx) authConfig := registry.AuthConfig{ @@ -46,6 +47,9 @@ func (m *containerManager) PullImage(ctx context.Context, img string) error { out, err := m.cli.ImagePull(ctx, path.Join(m.registryDetails.Registry, img), image.PullOptions{RegistryAuth: authStr}) if err != nil { + if _, _, err := m.cli.ImageInspectWithRaw(ctx, path.Join(m.registryDetails.Registry, img)); err == nil { + return nil + } return errors.Wrap(err, "DOCKER PULL") } defer func() { diff --git a/cmd/tink-worker/worker/registry_test.go b/cmd/tink-worker/worker/registry_test.go index fcc5a40ad..f3989bc7f 100644 --- a/cmd/tink-worker/worker/registry_test.go +++ b/cmd/tink-worker/worker/registry_test.go @@ -7,6 +7,7 @@ import ( "strings" "testing" + "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/image" "github.com/go-logr/zapr" "go.uber.org/zap" @@ -19,6 +20,10 @@ func (c *fakeDockerClient) ImagePull(context.Context, string, image.PullOptions) return io.NopCloser(strings.NewReader(c.imagePullContent)), nil } +func (c *fakeDockerClient) ImageInspectWithRaw(context.Context, string) (types.ImageInspect, []byte, error) { + return types.ImageInspect{}, nil, c.imageInspectErr +} + func TestContainerManagerPullImage(t *testing.T) { cases := []struct { name string @@ -27,6 +32,7 @@ func TestContainerManagerPullImage(t *testing.T) { registry RegistryConnDetails clientErr error wantErr error + imageInspectErr error }{ { name: "Happy Path", @@ -39,19 +45,27 @@ func TestContainerManagerPullImage(t *testing.T) { responseContent: "{", clientErr: errors.New("You missed the shot"), wantErr: errors.New("DOCKER PULL: You missed the shot"), + imageInspectErr: errors.New("Image not in local cache"), }, { name: "pull error", image: "yav.in/4/deathstar:nomedalforchewie", responseContent: `{"error": "You missed the shot"}`, wantErr: errors.New("DOCKER PULL: You missed the shot"), + imageInspectErr: errors.New("Image not in local cache"), + }, + { + name: "image already exists, no error", + image: "yav.in/4/deathstar:nomedalforchewie", + clientErr: errors.New("You missed the shot"), + wantErr: nil, }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { logger := zapr.NewLogger(zap.Must(zap.NewDevelopment())) - mgr := NewContainerManager(logger, newFakeDockerClient("", tc.responseContent, 0, 0, tc.clientErr, nil), tc.registry) + mgr := NewContainerManager(logger, newFakeDockerClient("", tc.responseContent, 0, 0, tc.clientErr, nil, withImageInspectErr(tc.imageInspectErr)), tc.registry) ctx := context.Background() gotErr := mgr.PullImage(ctx, tc.image)