Browse Source

fix support for ssh key from CLI flags

Signed-off-by: Nicolas De Loof <[email protected]>
Nicolas De Loof 10 months ago
parent
commit
4b70ff0ccd
4 changed files with 114 additions and 42 deletions
  1. 11 10
      cmd/compose/build.go
  2. 6 2
      cmd/compose/create_test.go
  3. 2 0
      pkg/api/api.go
  4. 95 30
      pkg/compose/build_bake.go

+ 11 - 10
cmd/compose/build.go

@@ -68,16 +68,17 @@ func (opts buildOptions) toAPIBuildOptions(services []string) (api.BuildOptions,
 		uiMode = "rawjson"
 	}
 	return api.BuildOptions{
-		Pull:     opts.pull,
-		Push:     opts.push,
-		Progress: uiMode,
-		Args:     types.NewMappingWithEquals(opts.args),
-		NoCache:  opts.noCache,
-		Quiet:    opts.quiet,
-		Services: services,
-		Deps:     opts.deps,
-		SSHs:     SSHKeys,
-		Builder:  builderName,
+		Pull:          opts.pull,
+		Push:          opts.push,
+		Progress:      uiMode,
+		Args:          types.NewMappingWithEquals(opts.args),
+		NoCache:       opts.noCache,
+		Quiet:         opts.quiet,
+		Services:      services,
+		Deps:          opts.deps,
+		SSHs:          SSHKeys,
+		Builder:       builderName,
+		Compatibility: opts.Compatibility,
 	}, nil
 }
 

+ 6 - 2
cmd/compose/create_test.go

@@ -40,7 +40,9 @@ func TestRunCreate(t *testing.T) {
 	)
 
 	createOpts := createOptions{}
-	buildOpts := buildOptions{}
+	buildOpts := buildOptions{
+		ProjectOptions: &ProjectOptions{},
+	}
 	project := sampleProject()
 	err := runCreate(ctx, nil, backend, createOpts, buildOpts, project, nil)
 	require.NoError(t, err)
@@ -58,7 +60,9 @@ func TestRunCreate_Build(t *testing.T) {
 	createOpts := createOptions{
 		Build: true,
 	}
-	buildOpts := buildOptions{}
+	buildOpts := buildOptions{
+		ProjectOptions: &ProjectOptions{},
+	}
 	project := sampleProject()
 	err := runCreate(ctx, nil, backend, createOpts, buildOpts, project, nil)
 	require.NoError(t, err)

+ 2 - 0
pkg/api/api.go

@@ -155,6 +155,8 @@ type BuildOptions struct {
 	Memory int64
 	// Builder name passed in the command line
 	Builder string
+	// Compatibility let compose run with best backward compatibility
+	Compatibility bool
 }
 
 // Apply mutates project according to build options

+ 95 - 30
pkg/compose/build_bake.go

@@ -26,6 +26,7 @@ import (
 	"os"
 	"os/exec"
 	"path/filepath"
+	"slices"
 	"strconv"
 	"strings"
 
@@ -35,6 +36,7 @@ import (
 	"github.com/docker/cli/cli/command"
 	"github.com/docker/compose/v2/pkg/api"
 	"github.com/docker/compose/v2/pkg/progress"
+	"github.com/docker/docker/api/types/versions"
 	"github.com/docker/docker/builder/remotecontext/urlutil"
 	"github.com/moby/buildkit/client"
 	"github.com/moby/buildkit/util/progress/progressui"
@@ -93,19 +95,25 @@ type bakeGroup struct {
 }
 
 type bakeTarget struct {
-	Context    string            `json:"context,omitempty"`
-	Dockerfile string            `json:"dockerfile,omitempty"`
-	Args       map[string]string `json:"args,omitempty"`
-	Labels     map[string]string `json:"labels,omitempty"`
-	Tags       []string          `json:"tags,omitempty"`
-	CacheFrom  []string          `json:"cache-from,omitempty"`
-	CacheTo    []string          `json:"cache-to,omitempty"`
-	Secrets    []string          `json:"secret,omitempty"`
-	SSH        []string          `json:"ssh,omitempty"`
-	Platforms  []string          `json:"platforms,omitempty"`
-	Target     string            `json:"target,omitempty"`
-	Pull       bool              `json:"pull,omitempty"`
-	NoCache    bool              `json:"no-cache,omitempty"`
+	Context          string            `json:"context,omitempty"`
+	Contexts         map[string]string `json:"contexts,omitempty"`
+	Dockerfile       string            `json:"dockerfile,omitempty"`
+	DockerfileInline string            `json:"dockerfile-inline,omitempty"`
+	Args             map[string]string `json:"args,omitempty"`
+	Labels           map[string]string `json:"labels,omitempty"`
+	Tags             []string          `json:"tags,omitempty"`
+	CacheFrom        []string          `json:"cache-from,omitempty"`
+	CacheTo          []string          `json:"cache-to,omitempty"`
+	Secrets          []string          `json:"secret,omitempty"`
+	SSH              []string          `json:"ssh,omitempty"`
+	Platforms        []string          `json:"platforms,omitempty"`
+	Target           string            `json:"target,omitempty"`
+	Pull             bool              `json:"pull,omitempty"`
+	NoCache          bool              `json:"no-cache,omitempty"`
+	ShmSize          types.UnitBytes   `json:"shm-size,omitempty"`
+	Ulimits          []string          `json:"ulimits,omitempty"`
+	Entitlements     []string          `json:"entitlements,omitempty"`
+	Outputs          []string          `json:"output,omitempty"`
 }
 
 type bakeMetadata map[string]buildStatus
@@ -136,8 +144,9 @@ func (s *composeService) doBuildBake(ctx context.Context, project *types.Project
 		Targets: map[string]bakeTarget{},
 	}
 	var group bakeGroup
+	var privileged bool
 
-	for _, service := range serviceToBeBuild {
+	for serviceName, service := range serviceToBeBuild {
 		if service.Build == nil {
 			continue
 		}
@@ -153,23 +162,43 @@ func (s *composeService) doBuildBake(ctx context.Context, project *types.Project
 
 		image := api.GetImageNameOrDefault(service, project.Name)
 
-		cfg.Targets[image] = bakeTarget{
-			Context:    build.Context,
-			Dockerfile: dockerFilePath(build.Context, build.Dockerfile),
-			Args:       args,
-			Labels:     build.Labels,
-			Tags:       append(build.Tags, image),
+		entitlements := build.Entitlements
+		if slices.Contains(build.Entitlements, "security.insecure") {
+			privileged = true
+		}
+		if build.Privileged {
+			entitlements = append(entitlements, "security.insecure")
+			privileged = true
+		}
+
+		outputs := []string{"type=docker"}
+		if options.Push && service.Image != "" {
+			outputs = append(outputs, "type=image,push=true")
+		}
+
+		cfg.Targets[serviceName] = bakeTarget{
+			Context:          build.Context,
+			Contexts:         additionalContexts(build.AdditionalContexts, service.DependsOn, options.Compatibility),
+			Dockerfile:       dockerFilePath(build.Context, build.Dockerfile),
+			DockerfileInline: build.DockerfileInline,
+			Args:             args,
+			Labels:           build.Labels,
+			Tags:             append(build.Tags, image),
 
 			CacheFrom: build.CacheFrom,
 			// CacheTo:    TODO
-			Platforms: build.Platforms,
-			Target:    build.Target,
-			Secrets:   toBakeSecrets(project, build.Secrets),
-			SSH:       toBakeSSH(build.SSH),
-			Pull:      options.Pull,
-			NoCache:   options.NoCache,
+			Platforms:    build.Platforms,
+			Target:       build.Target,
+			Secrets:      toBakeSecrets(project, build.Secrets),
+			SSH:          toBakeSSH(append(build.SSH, options.SSHs...)),
+			Pull:         options.Pull,
+			NoCache:      options.NoCache,
+			ShmSize:      build.ShmSize,
+			Ulimits:      toBakeUlimits(build.Ulimits),
+			Entitlements: entitlements,
+			Outputs:      outputs,
 		}
-		group.Targets = append(group.Targets, image)
+		group.Targets = append(group.Targets, serviceName)
 	}
 
 	cfg.Groups["default"] = group
@@ -188,7 +217,14 @@ func (s *composeService) doBuildBake(ctx context.Context, project *types.Project
 	if err != nil {
 		return nil, err
 	}
-	cmd := exec.CommandContext(ctx, buildx.Path, "bake", "--file", "-", "--progress", "rawjson", "--metadata-file", metadata.Name())
+
+	args := []string{"bake", "--file", "-", "--progress", "rawjson", "--metadata-file", metadata.Name()}
+	mustAllow := buildx.Version != "" && versions.GreaterThanOrEqualTo(buildx.Version[1:], "0.17.0")
+	if privileged && mustAllow {
+		args = append(args, "--allow", "security.insecure")
+	}
+
+	cmd := exec.CommandContext(ctx, buildx.Path, args...)
 	// Remove DOCKER_CLI_PLUGIN... variable so buildx can detect it run standalone
 	cmd.Env = filter(os.Environ(), manager.ReexecEnvvar)
 
@@ -258,6 +294,31 @@ func (s *composeService) doBuildBake(ctx context.Context, project *types.Project
 	return results, nil
 }
 
+func additionalContexts(contexts types.Mapping, dependencies types.DependsOnConfig, compatibility bool) map[string]string {
+	ac := map[string]string{}
+	if compatibility {
+		for name := range dependencies {
+			ac[name] = "target:" + name
+		}
+	}
+	for k, v := range contexts {
+		ac[k] = v
+	}
+	return ac
+}
+
+func toBakeUlimits(ulimits map[string]*types.UlimitsConfig) []string {
+	s := []string{}
+	for u, l := range ulimits {
+		if l.Single > 0 {
+			s = append(s, fmt.Sprintf("%s=%d", u, l.Single))
+		} else {
+			s = append(s, fmt.Sprintf("%s=%d:%d", u, l.Soft, l.Hard))
+		}
+	}
+	return s
+}
+
 func toBakeSSH(ssh types.SSHConfig) []string {
 	var s []string
 	for _, key := range ssh {
@@ -270,11 +331,15 @@ func toBakeSecrets(project *types.Project, secrets []types.ServiceSecretConfig)
 	var s []string
 	for _, ref := range secrets {
 		def := project.Secrets[ref.Source]
+		target := ref.Target
+		if target == "" {
+			target = ref.Source
+		}
 		switch {
 		case def.Environment != "":
-			s = append(s, fmt.Sprintf("id=%s,type=env,env=%s", ref.Source, def.Environment))
+			s = append(s, fmt.Sprintf("id=%s,type=env,env=%s", target, def.Environment))
 		case def.File != "":
-			s = append(s, fmt.Sprintf("id=%s,type=file,src=%s", ref.Source, def.File))
+			s = append(s, fmt.Sprintf("id=%s,type=file,src=%s", target, def.File))
 		}
 	}
 	return s