Explorar o código

Merge pull request #1733 from ndeloof/pull_digested

stop using buildkit hack to pull images
Nicolas De loof %!s(int64=4) %!d(string=hai) anos
pai
achega
165686838e
Modificáronse 3 ficheiros con 67 adicións e 32 borrados
  1. 16 24
      local/compose/build.go
  2. 46 3
      local/compose/pull.go
  3. 5 5
      local/e2e/compose/metrics_test.go

+ 16 - 24
local/compose/build.go

@@ -20,7 +20,6 @@ import (
 	"context"
 	"fmt"
 	"os"
-	"strings"
 
 	"github.com/compose-spec/compose-go/types"
 	"github.com/containerd/containerd/platforms"
@@ -93,7 +92,18 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
 }
 
 func (s *composeService) ensureImagesExists(ctx context.Context, project *types.Project, observedState Containers, quietPull bool) error {
-	images, err := s.getImageDigests(ctx, project)
+	for _, service := range project.Services {
+		if service.Image == "" && service.Build == nil {
+			return fmt.Errorf("invalid service %q. Must specify either image or build", service.Name)
+		}
+	}
+
+	images, err := s.getLocalImagesDigests(ctx, project)
+	if err != nil {
+		return err
+	}
+
+	err = s.pullRequiredImages(ctx, project, images, quietPull)
 	if err != nil {
 		return err
 	}
@@ -128,9 +138,6 @@ func (s *composeService) ensureImagesExists(ctx context.Context, project *types.
 }
 
 func (s *composeService) getBuildOptions(project *types.Project, images map[string]string) (map[string]build.Options, []string, error) {
-	session := []session.Attachable{
-		authprovider.NewDockerAuthProvider(os.Stderr),
-	}
 	opts := map[string]build.Options{}
 	imagesToBuild := []string{}
 	for _, service := range project.Services {
@@ -152,30 +159,12 @@ func (s *composeService) getBuildOptions(project *types.Project, images map[stri
 			opts[imageName] = opt
 			continue
 		}
-		if service.Image != "" {
-			if localImagePresent {
-				continue
-			}
-		}
-		// Buildx has no command to "just pull", see
-		// so we bake a temporary dockerfile that will just pull and export pulled image
-		opts[service.Name] = build.Options{
-			Inputs: build.Inputs{
-				ContextPath:    ".",
-				DockerfilePath: "-",
-				InStream:       strings.NewReader("FROM " + service.Image),
-			},
-			Tags:    []string{service.Image}, // Used to retrieve image to pull in case of windows engine
-			Pull:    true,
-			Session: session,
-		}
-
 	}
 	return opts, imagesToBuild, nil
 
 }
 
-func (s *composeService) getImageDigests(ctx context.Context, project *types.Project) (map[string]string, error) {
+func (s *composeService) getLocalImagesDigests(ctx context.Context, project *types.Project) (map[string]string, error) {
 	imageNames := []string{}
 	for _, s := range project.Services {
 		imgName := getImageName(s, project.Name)
@@ -295,6 +284,9 @@ func (s *composeService) toBuildOptions(project *types.Project, service types.Se
 		Exports:   []bclient.ExportEntry{{Type: "image", Attrs: map[string]string{}}},
 		Platforms: plats,
 		Labels:    service.Build.Labels,
+		Session: []session.Attachable{
+			authprovider.NewDockerAuthProvider(os.Stderr),
+		},
 	}, nil
 }
 

+ 46 - 3
local/compose/pull.go

@@ -70,7 +70,7 @@ func (s *composeService) pull(ctx context.Context, project *types.Project, opts
 			continue
 		}
 		eg.Go(func() error {
-			err := s.pullServiceImage(ctx, service, info, s.configFile, w)
+			err := s.pullServiceImage(ctx, service, info, s.configFile, w, false)
 			if err != nil {
 				if !opts.IgnoreFailures {
 					return err
@@ -84,7 +84,7 @@ func (s *composeService) pull(ctx context.Context, project *types.Project, opts
 	return eg.Wait()
 }
 
-func (s *composeService) pullServiceImage(ctx context.Context, service types.ServiceConfig, info moby.Info, configFile driver.Auth, w progress.Writer) error {
+func (s *composeService) pullServiceImage(ctx context.Context, service types.ServiceConfig, info moby.Info, configFile driver.Auth, w progress.Writer, quietPull bool) error {
 	w.Event(progress.Event{
 		ID:     service.Name,
 		Status: progress.Working,
@@ -140,7 +140,9 @@ func (s *composeService) pullServiceImage(ctx context.Context, service types.Ser
 		if jm.Error != nil {
 			return metrics.WrapCategorisedComposeError(errors.New(jm.Error.Message), metrics.PullFailure)
 		}
-		toPullProgressEvent(service.Name, jm, w)
+		if !quietPull {
+			toPullProgressEvent(service.Name, jm, w)
+		}
 	}
 	w.Event(progress.Event{
 		ID:     service.Name,
@@ -150,6 +152,47 @@ func (s *composeService) pullServiceImage(ctx context.Context, service types.Ser
 	return nil
 }
 
+func (s *composeService) pullRequiredImages(ctx context.Context, project *types.Project, images map[string]string, quietPull bool) error {
+	info, err := s.apiClient.Info(ctx)
+	if err != nil {
+		return err
+	}
+
+	if info.IndexServerAddress == "" {
+		info.IndexServerAddress = registry.IndexServer
+	}
+
+	return progress.Run(ctx, func(ctx context.Context) error {
+		w := progress.ContextWriter(ctx)
+		eg, ctx := errgroup.WithContext(ctx)
+		for _, service := range project.Services {
+			if service.Image == "" {
+				continue
+			}
+			switch service.PullPolicy {
+			case types.PullPolicyMissing, types.PullPolicyIfNotPresent:
+				if _, ok := images[service.Image]; ok {
+					continue
+				}
+			case types.PullPolicyNever, types.PullPolicyBuild:
+				continue
+			case types.PullPolicyAlways:
+				// force pull
+			}
+			service := service
+			eg.Go(func() error {
+				err := s.pullServiceImage(ctx, service, info, s.configFile, w, quietPull)
+				if err != nil && service.Build != nil {
+					// image can be built, so we can ignore pull failure
+					return nil
+				}
+				return err
+			})
+		}
+		return eg.Wait()
+	})
+}
+
 func toPullProgressEvent(parent string, jm jsonmessage.JSONMessage, w progress.Writer) {
 	if jm.ID == "" || jm.Progress == nil {
 		return

+ 5 - 5
local/e2e/compose/metrics_test.go

@@ -65,14 +65,14 @@ func TestComposeMetrics(t *testing.T) {
 		res.Assert(t, icmd.Expected{ExitCode: 16, Err: "unknown flag: --file"})
 		res = c.RunDockerOrExitError("compose", "donw", "--file", "../compose/fixtures/wrong-composefile/compose.yml")
 		res.Assert(t, icmd.Expected{ExitCode: 16, Err: `unknown docker command: "compose donw"`})
-		res = c.RunDockerOrExitError("compose", "--file", "../compose/fixtures/wrong-composefile/unknown-image.yml", "pull")
-		res.Assert(t, icmd.Expected{ExitCode: 18, Err: `pull access denied for unknownimage, repository does not exist or may require 'docker login'`})
 		res = c.RunDockerOrExitError("compose", "--file", "../compose/fixtures/wrong-composefile/build-error.yml", "build")
 		res.Assert(t, icmd.Expected{ExitCode: 17, Err: `line 17: unknown instruction: WRONG`})
 		res = c.RunDockerOrExitError("compose", "--file", "../compose/fixtures/wrong-composefile/build-error.yml", "up")
 		res.Assert(t, icmd.Expected{ExitCode: 17, Err: `line 17: unknown instruction: WRONG`})
+		res = c.RunDockerOrExitError("compose", "--file", "../compose/fixtures/wrong-composefile/unknown-image.yml", "pull")
+		res.Assert(t, icmd.Expected{ExitCode: 18, Err: `pull access denied for unknownimage, repository does not exist or may require 'docker login'`})
 		res = c.RunDockerOrExitError("compose", "--file", "../compose/fixtures/wrong-composefile/unknown-image.yml", "up")
-		res.Assert(t, icmd.Expected{ExitCode: 17, Err: `pull access denied, repository does not exist or may require authorization`})
+		res.Assert(t, icmd.Expected{ExitCode: 18, Err: `pull access denied for unknownimage, repository does not exist or may require 'docker login'`})
 
 		usage := s.GetUsage()
 		assert.DeepEqual(t, []string{
@@ -82,10 +82,10 @@ func TestComposeMetrics(t *testing.T) {
 			`{"command":"compose up","context":"moby","source":"cli","status":"failure-cmd-syntax"}`,
 			`{"command":"compose up","context":"moby","source":"cli","status":"failure-cmd-syntax"}`,
 			`{"command":"compose","context":"moby","source":"cli","status":"failure-cmd-syntax"}`,
-			`{"command":"compose pull","context":"moby","source":"cli","status":"failure-pull"}`,
 			`{"command":"compose build","context":"moby","source":"cli","status":"failure-build"}`,
 			`{"command":"compose up","context":"moby","source":"cli","status":"failure-build"}`,
-			`{"command":"compose up","context":"moby","source":"cli","status":"failure-build"}`,
+			`{"command":"compose pull","context":"moby","source":"cli","status":"failure-pull"}`,
+			`{"command":"compose up","context":"moby","source":"cli","status":"failure-pull"}`,
 		}, usage)
 	})
 }