Browse Source

propagate docker endpoint to bake using DOCKER_* env variables

Signed-off-by: Nicolas De Loof <[email protected]>
Nicolas De Loof 3 months ago
parent
commit
2d482e61ce
3 changed files with 60 additions and 18 deletions
  1. 6 0
      pkg/compose/build_bake.go
  2. 12 1
      pkg/compose/model.go
  3. 42 17
      pkg/compose/shellout.go

+ 6 - 0
pkg/compose/build_bake.go

@@ -335,6 +335,12 @@ func (s *composeService) doBuildBake(ctx context.Context, project *types.Project
 	if err != nil {
 		return nil, err
 	}
+	endpoint, cleanup, err := s.propagateDockerEndpoint()
+	if err != nil {
+		return nil, err
+	}
+	cmd.Env = append(cmd.Env, endpoint...)
+	defer cleanup()
 
 	cmd.Stdout = s.stdout()
 	cmd.Stdin = bytes.NewBuffer(b)

+ 12 - 1
pkg/compose/model.go

@@ -43,6 +43,7 @@ func (s *composeService) ensureModels(ctx context.Context, project *types.Projec
 	if err != nil {
 		return err
 	}
+	defer api.Close()
 	availableModels, err := api.ListModels(ctx)
 
 	eg, ctx := errgroup.WithContext(ctx)
@@ -72,6 +73,7 @@ type modelAPI struct {
 	path    string
 	env     []string
 	prepare func(ctx context.Context, cmd *exec.Cmd) error
+	cleanup func()
 }
 
 func (s *composeService) newModelAPI(project *types.Project) (*modelAPI, error) {
@@ -82,15 +84,24 @@ func (s *composeService) newModelAPI(project *types.Project) (*modelAPI, error)
 		}
 		return nil, err
 	}
+	endpoint, cleanup, err := s.propagateDockerEndpoint()
+	if err != nil {
+		return nil, err
+	}
 	return &modelAPI{
 		path: dockerModel.Path,
 		prepare: func(ctx context.Context, cmd *exec.Cmd) error {
 			return s.prepareShellOut(ctx, project.Environment, cmd)
 		},
-		env: project.Environment.Values(),
+		cleanup: cleanup,
+		env:     append(project.Environment.Values(), endpoint...),
 	}, nil
 }
 
+func (m *modelAPI) Close() {
+	m.cleanup()
+}
+
 func (m *modelAPI) PullModel(ctx context.Context, model types.ModelConfig, quietPull bool, w progress.Writer) error {
 	w.Event(progress.Event{
 		ID:     model.Name,

+ 42 - 17
pkg/compose/shellout.go

@@ -18,12 +18,16 @@ package compose
 
 import (
 	"context"
+	"os"
 	"os/exec"
+	"path/filepath"
 
 	"github.com/compose-spec/compose-go/v2/types"
 	"github.com/docker/cli/cli-plugins/metadata"
-	"github.com/docker/cli/cli/context/docker"
+	"github.com/docker/cli/cli/command"
+	"github.com/docker/cli/cli/flags"
 	"github.com/docker/compose/v2/internal"
+	"github.com/docker/docker/client"
 	"go.opentelemetry.io/otel"
 	"go.opentelemetry.io/otel/propagation"
 )
@@ -39,23 +43,44 @@ func (s *composeService) prepareShellOut(gctx context.Context, env types.Mapping
 	otel.GetTextMapPropagator().Inject(gctx, &carrier)
 	env.Merge(types.Mapping(carrier))
 
-	env["DOCKER_CONTEXT"] = s.dockerCli.CurrentContext()
+	cmd.Env = env.Values()
+	return nil
+}
+
+// propagateDockerEndpoint produces DOCKER_* env vars for a child CLI plugin to target the same docker endpoint
+// `cleanup` func MUST be called after child process completion to enforce removal of cert files
+func (s *composeService) propagateDockerEndpoint() ([]string, func(), error) {
+	cleanup := func() {}
+	env := types.Mapping{}
+	env[command.EnvOverrideContext] = s.dockerCli.CurrentContext()
 	env["USER_AGENT"] = "compose/" + internal.Version
+	endpoint := s.dockerCli.DockerEndpoint()
+	env[client.EnvOverrideHost] = endpoint.Host
+	if endpoint.TLSData != nil {
+		certs, err := os.MkdirTemp("", "compose")
+		if err != nil {
+			return nil, cleanup, err
+		}
+		cleanup = func() {
+			_ = os.RemoveAll(certs)
+		}
+		env[client.EnvOverrideCertPath] = certs
+		if !endpoint.SkipTLSVerify {
+			env[client.EnvTLSVerify] = "1"
+		}
 
-	md, err := s.dockerCli.ContextStore().GetMetadata(s.dockerCli.CurrentContext())
-	if err != nil {
-		return err
-	}
-	endpoint, err := docker.EndpointFromContext(md)
-	if err != nil {
-		return err
+		err = os.WriteFile(filepath.Join(certs, flags.DefaultKeyFile), endpoint.TLSData.Key, 0o600)
+		if err != nil {
+			return nil, cleanup, err
+		}
+		err = os.WriteFile(filepath.Join(certs, flags.DefaultCaFile), endpoint.TLSData.Cert, 0o600)
+		if err != nil {
+			return nil, cleanup, err
+		}
+		err = os.WriteFile(filepath.Join(certs, flags.DefaultCaFile), endpoint.TLSData.CA, 0o600)
+		if err != nil {
+			return nil, cleanup, err
+		}
 	}
-	actualHost := s.dockerCli.DockerEndpoint().Host
-	if endpoint.Host != actualHost {
-		// We are running with `--host` or `DOCKER_HOST` which overrides selected context
-		env["DOCKER_HOST"] = actualHost
-	}
-
-	cmd.Env = env.Values()
-	return nil
+	return env.Values(), cleanup, nil
 }