From 235734823ec1f81e43b1619fcc1cfcd9e0984717 Mon Sep 17 00:00:00 2001 From: Laura Brehm Date: Tue, 23 Aug 2022 16:23:21 +0200 Subject: [PATCH] Pull image regardless of whether it exists locally if `tag=latest` ... and pull policy is `missing` or `if_not_present` Signed-off-by: Laura Brehm --- pkg/compose/pull.go | 15 +++- pkg/e2e/compose_test.go | 55 ------------- .../image-present-locally/docker-compose.yaml | 4 + pkg/e2e/pull_test.go | 81 +++++++++++++++++++ 4 files changed, 99 insertions(+), 56 deletions(-) create mode 100644 pkg/e2e/pull_test.go diff --git a/pkg/compose/pull.go b/pkg/compose/pull.go index a545e8e31..fbeacacec 100644 --- a/pkg/compose/pull.go +++ b/pkg/compose/pull.go @@ -88,7 +88,7 @@ func (s *composeService) pull(ctx context.Context, project *types.Project, opts }) continue case types.PullPolicyMissing, types.PullPolicyIfNotPresent: - if _, ok := images[service.Image]; ok { + if imageAlreadyPresent(service.Image, images) { w.Event(progress.Event{ ID: service.Name, Status: progress.Done, @@ -133,6 +133,19 @@ func (s *composeService) pull(ctx context.Context, project *types.Project, opts return err } +func imageAlreadyPresent(serviceImage string, localImages map[string]string) bool { + normalizedImage, err := reference.ParseDockerRef(serviceImage) + if err != nil { + return false + } + tagged, ok := normalizedImage.(reference.NamedTagged) + if !ok { + return false + } + _, ok = localImages[serviceImage] + return ok && tagged.Tag() != "latest" +} + func (s *composeService) pullServiceImage(ctx context.Context, service types.ServiceConfig, info moby.Info, configFile driver.Auth, w progress.Writer, quietPull bool) (string, error) { w.Event(progress.Event{ ID: service.Name, diff --git a/pkg/e2e/compose_test.go b/pkg/e2e/compose_test.go index 127076a65..668bb7747 100644 --- a/pkg/e2e/compose_test.go +++ b/pkg/e2e/compose_test.go @@ -119,61 +119,6 @@ func TestLocalComposeUp(t *testing.T) { }) } -func TestComposePull(t *testing.T) { - c := NewParallelCLI(t) - - t.Run("Verify image pulled", func(t *testing.T) { - // cleanup existing images - c.RunDockerComposeCmd(t, "--project-directory", "fixtures/compose-pull/simple", "down", "--rmi", "all") - - res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/compose-pull/simple", "pull") - output := res.Combined() - - assert.Assert(t, strings.Contains(output, "simple Pulled")) - assert.Assert(t, strings.Contains(output, "another Pulled")) - - // verify default policy is 'always' for pull command - res = c.RunDockerComposeCmd(t, "--project-directory", "fixtures/compose-pull/simple", "pull") - output = res.Combined() - - assert.Assert(t, strings.Contains(output, "simple Pulled")) - assert.Assert(t, strings.Contains(output, "another Pulled")) - }) - - t.Run("Verify a image is pulled once", func(t *testing.T) { - // cleanup existing images - c.RunDockerComposeCmd(t, "--project-directory", "fixtures/compose-pull/duplicate-images", "down", "--rmi", "all") - - res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/compose-pull/duplicate-images", "pull") - output := res.Combined() - - if strings.Contains(output, "another Pulled") { - assert.Assert(t, strings.Contains(output, "another Pulled")) - assert.Assert(t, strings.Contains(output, "Skipped - Image is already being pulled by another")) - } else { - assert.Assert(t, strings.Contains(output, "simple Pulled")) - assert.Assert(t, strings.Contains(output, "Skipped - Image is already being pulled by simple")) - } - }) - - t.Run("Verify skipped pull if image is already present locally", func(t *testing.T) { - // make sure the required image is present - c.RunDockerComposeCmd(t, "--project-directory", "fixtures/compose-pull/image-present-locally", "pull") - - res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/compose-pull/image-present-locally", "pull") - output := res.Combined() - - assert.Assert(t, strings.Contains(output, "Skipped - Image is already present locally")) - }) - - t.Run("Verify skipped no image to be pulled", func(t *testing.T) { - res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/compose-pull/no-image-name-given", "pull") - output := res.Combined() - - assert.Assert(t, strings.Contains(output, "Skipped - No image to be pulled")) - }) -} - func TestDownComposefileInParentFolder(t *testing.T) { c := NewParallelCLI(t) diff --git a/pkg/e2e/fixtures/compose-pull/image-present-locally/docker-compose.yaml b/pkg/e2e/fixtures/compose-pull/image-present-locally/docker-compose.yaml index 922077799..a23cf5857 100644 --- a/pkg/e2e/fixtures/compose-pull/image-present-locally/docker-compose.yaml +++ b/pkg/e2e/fixtures/compose-pull/image-present-locally/docker-compose.yaml @@ -3,3 +3,7 @@ services: image: alpine:3.13.12 pull_policy: missing command: top + latest: + image: alpine:latest + pull_policy: missing + command: top diff --git a/pkg/e2e/pull_test.go b/pkg/e2e/pull_test.go new file mode 100644 index 000000000..6d7637351 --- /dev/null +++ b/pkg/e2e/pull_test.go @@ -0,0 +1,81 @@ +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package e2e + +import ( + "strings" + "testing" + + "gotest.tools/v3/assert" +) + +func TestComposePull(t *testing.T) { + c := NewParallelCLI(t) + + t.Run("Verify image pulled", func(t *testing.T) { + // cleanup existing images + c.RunDockerComposeCmd(t, "--project-directory", "fixtures/compose-pull/simple", "down", "--rmi", "all") + + res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/compose-pull/simple", "pull") + output := res.Combined() + + assert.Assert(t, strings.Contains(output, "simple Pulled")) + assert.Assert(t, strings.Contains(output, "another Pulled")) + + // verify default policy is 'always' for pull command + res = c.RunDockerComposeCmd(t, "--project-directory", "fixtures/compose-pull/simple", "pull") + output = res.Combined() + + assert.Assert(t, strings.Contains(output, "simple Pulled")) + assert.Assert(t, strings.Contains(output, "another Pulled")) + }) + + t.Run("Verify a image is pulled once", func(t *testing.T) { + // cleanup existing images + c.RunDockerComposeCmd(t, "--project-directory", "fixtures/compose-pull/duplicate-images", "down", "--rmi", "all") + + res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/compose-pull/duplicate-images", "pull") + output := res.Combined() + + if strings.Contains(output, "another Pulled") { + assert.Assert(t, strings.Contains(output, "another Pulled")) + assert.Assert(t, strings.Contains(output, "Skipped - Image is already being pulled by another")) + } else { + assert.Assert(t, strings.Contains(output, "simple Pulled")) + assert.Assert(t, strings.Contains(output, "Skipped - Image is already being pulled by simple")) + } + }) + + t.Run("Verify skipped pull if image is already present locally", func(t *testing.T) { + // make sure the required image is present + c.RunDockerComposeCmd(t, "--project-directory", "fixtures/compose-pull/image-present-locally", "pull") + + res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/compose-pull/image-present-locally", "pull") + output := res.Combined() + + assert.Assert(t, strings.Contains(output, "simple Skipped - Image is already present locally")) + // image with :latest tag gets pulled regardless if pull_policy: missing or if_not_present + assert.Assert(t, strings.Contains(output, "latest Pulled")) + }) + + t.Run("Verify skipped no image to be pulled", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/compose-pull/no-image-name-given", "pull") + output := res.Combined() + + assert.Assert(t, strings.Contains(output, "Skipped - No image to be pulled")) + }) +}