mirror of
https://github.com/docker/compose.git
synced 2025-07-24 06:04:57 +02:00
a single place for shell-out command setup
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
8faf1eb808
commit
60ee6adcd2
@ -34,7 +34,6 @@ import (
|
||||
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
"github.com/docker/cli/cli-plugins/manager"
|
||||
"github.com/docker/cli/cli-plugins/socket"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/progress"
|
||||
@ -45,8 +44,6 @@ import (
|
||||
"github.com/moby/buildkit/util/progress/progressui"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
@ -294,26 +291,12 @@ func (s *composeService) doBuildBake(ctx context.Context, project *types.Project
|
||||
logrus.Debugf("Executing bake with args: %v", args)
|
||||
|
||||
cmd := exec.CommandContext(ctx, buildx.Path, args...)
|
||||
// Remove DOCKER_CLI_PLUGIN... variable so buildx can detect it run standalone
|
||||
cmd.Env = filter(project.Environment.Values(), manager.ReexecEnvvar)
|
||||
|
||||
// Use docker/cli mechanism to propagate termination signal to child process
|
||||
server, err := socket.NewPluginServer(nil)
|
||||
if err == nil {
|
||||
defer server.Close() //nolint:errcheck
|
||||
cmd.Env = replace(cmd.Env, socket.EnvKey, server.Addr().String())
|
||||
err = s.prepareShellOut(ctx, project, cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cmd.Env = append(cmd.Env,
|
||||
fmt.Sprintf("DOCKER_CONTEXT=%s", s.dockerCli.CurrentContext()),
|
||||
fmt.Sprintf("DOCKER_HOST=%s", s.dockerCli.DockerEndpoint().Host),
|
||||
)
|
||||
|
||||
// propagate opentelemetry context to child process, see https://github.com/open-telemetry/oteps/blob/main/text/0258-env-context-baggage-carriers.md
|
||||
carrier := propagation.MapCarrier{}
|
||||
otel.GetTextMapPropagator().Inject(ctx, &carrier)
|
||||
cmd.Env = append(cmd.Env, types.Mapping(carrier).Values()...)
|
||||
|
||||
cmd.Stdout = s.stdout()
|
||||
cmd.Stdin = bytes.NewBuffer(b)
|
||||
pipe, err := cmd.StderrPipe()
|
||||
@ -443,22 +426,6 @@ func toBakeSecrets(project *types.Project, secrets []types.ServiceSecretConfig)
|
||||
return s
|
||||
}
|
||||
|
||||
func filter(environ []string, variable string) []string {
|
||||
prefix := variable + "="
|
||||
filtered := make([]string, 0, len(environ))
|
||||
for _, val := range environ {
|
||||
if !strings.HasPrefix(val, prefix) {
|
||||
filtered = append(filtered, val)
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
func replace(environ []string, variable, value string) []string {
|
||||
filtered := filter(environ, variable)
|
||||
return append(filtered, fmt.Sprintf("%s=%s", variable, value))
|
||||
}
|
||||
|
||||
func dockerFilePath(ctxName string, dockerfile string) string {
|
||||
if dockerfile == "" {
|
||||
return ""
|
||||
|
@ -21,7 +21,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"slices"
|
||||
"strconv"
|
||||
@ -32,8 +31,6 @@ import (
|
||||
"github.com/docker/cli/cli-plugins/manager"
|
||||
"github.com/docker/compose/v2/pkg/progress"
|
||||
"github.com/spf13/cobra"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
@ -51,7 +48,11 @@ func (s *composeService) ensureModels(ctx context.Context, project *types.Projec
|
||||
}
|
||||
|
||||
cmd := exec.CommandContext(ctx, dockerModel.Path, "ls", "--json")
|
||||
s.setupChildProcess(ctx, cmd)
|
||||
err = s.prepareShellOut(ctx, project, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error checking available models: %w", err)
|
||||
@ -85,23 +86,18 @@ func (s *composeService) ensureModels(ctx context.Context, project *types.Projec
|
||||
eg.Go(func() error {
|
||||
w := progress.ContextWriter(gctx)
|
||||
if !slices.Contains(availableModels, config.Model) {
|
||||
err = s.pullModel(gctx, dockerModel, config, quietPull, w)
|
||||
err = s.pullModel(gctx, dockerModel, project, config, quietPull, w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = s.configureModel(gctx, dockerModel, config, w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.Event(progress.CreatedEvent(config.Name))
|
||||
return nil
|
||||
return s.configureModel(gctx, dockerModel, project, config, w)
|
||||
})
|
||||
}
|
||||
return eg.Wait()
|
||||
}
|
||||
|
||||
func (s *composeService) pullModel(ctx context.Context, dockerModel *manager.Plugin, model types.ModelConfig, quietPull bool, w progress.Writer) error {
|
||||
func (s *composeService) pullModel(ctx context.Context, dockerModel *manager.Plugin, project *types.Project, model types.ModelConfig, quietPull bool, w progress.Writer) error {
|
||||
w.Event(progress.Event{
|
||||
ID: model.Name,
|
||||
Status: progress.Working,
|
||||
@ -109,8 +105,10 @@ func (s *composeService) pullModel(ctx context.Context, dockerModel *manager.Plu
|
||||
})
|
||||
|
||||
cmd := exec.CommandContext(ctx, dockerModel.Path, "pull", model.Model)
|
||||
s.setupChildProcess(ctx, cmd)
|
||||
|
||||
err := s.prepareShellOut(ctx, project, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stream, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -150,7 +148,7 @@ func (s *composeService) pullModel(ctx context.Context, dockerModel *manager.Plu
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *composeService) configureModel(ctx context.Context, dockerModel *manager.Plugin, config types.ModelConfig, w progress.Writer) error {
|
||||
func (s *composeService) configureModel(ctx context.Context, dockerModel *manager.Plugin, project *types.Project, config types.ModelConfig, w progress.Writer) error {
|
||||
w.Event(progress.Event{
|
||||
ID: config.Name,
|
||||
Status: progress.Working,
|
||||
@ -167,13 +165,20 @@ func (s *composeService) configureModel(ctx context.Context, dockerModel *manage
|
||||
args = append(args, config.RuntimeFlags...)
|
||||
}
|
||||
cmd := exec.CommandContext(ctx, dockerModel.Path, args...)
|
||||
s.setupChildProcess(ctx, cmd)
|
||||
err := s.prepareShellOut(ctx, project, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
func (s *composeService) setModelVariables(ctx context.Context, dockerModel *manager.Plugin, project *types.Project) error {
|
||||
cmd := exec.CommandContext(ctx, dockerModel.Path, "status", "--json")
|
||||
s.setupChildProcess(ctx, cmd)
|
||||
err := s.prepareShellOut(ctx, project, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
statusOut, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error checking docker-model status: %w", err)
|
||||
@ -211,19 +216,6 @@ func (s *composeService) setModelVariables(ctx context.Context, dockerModel *man
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *composeService) setupChildProcess(gctx context.Context, cmd *exec.Cmd) {
|
||||
// exec provider command with same environment Compose is running
|
||||
env := types.NewMapping(os.Environ())
|
||||
// but remove DOCKER_CLI_PLUGIN... variable so plugin can detect it run standalone
|
||||
delete(env, manager.ReexecEnvvar)
|
||||
// propagate opentelemetry context to child process, see https://github.com/open-telemetry/oteps/blob/main/text/0258-env-context-baggage-carriers.md
|
||||
carrier := propagation.MapCarrier{}
|
||||
otel.GetTextMapPropagator().Inject(gctx, &carrier)
|
||||
env.Merge(types.Mapping(carrier))
|
||||
env["DOCKER_CONTEXT"] = s.dockerCli.CurrentContext()
|
||||
cmd.Env = env.Values()
|
||||
}
|
||||
|
||||
type Model struct {
|
||||
Id string `json:"id"`
|
||||
Tags []string `json:"tags"`
|
||||
|
@ -29,16 +29,12 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
"github.com/docker/cli/cli-plugins/manager"
|
||||
"github.com/docker/cli/cli/config"
|
||||
"github.com/docker/compose/v2/pkg/progress"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
"github.com/docker/cli/cli-plugins/manager"
|
||||
"github.com/docker/cli/cli-plugins/socket"
|
||||
"github.com/docker/cli/cli/config"
|
||||
)
|
||||
|
||||
type JsonMessage struct {
|
||||
@ -199,29 +195,11 @@ func (s *composeService) setupPluginCommand(ctx context.Context, project *types.
|
||||
args = append(args, service.Name)
|
||||
|
||||
cmd := exec.CommandContext(ctx, path, args...)
|
||||
// exec provider command with same environment Compose is running
|
||||
env := types.NewMapping(os.Environ())
|
||||
// but remove DOCKER_CLI_PLUGIN... variable so plugin can detect it run standalone
|
||||
delete(env, manager.ReexecEnvvar)
|
||||
// and add the explicit environment variables set for service
|
||||
for key, val := range service.Environment.RemoveEmpty().ToMapping() {
|
||||
env[key] = val
|
||||
|
||||
err := s.prepareShellOut(ctx, project, cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cmd.Env = env.Values()
|
||||
|
||||
// Use docker/cli mechanism to propagate termination signal to child process
|
||||
server, err := socket.NewPluginServer(nil)
|
||||
if err == nil {
|
||||
defer server.Close() //nolint:errcheck
|
||||
cmd.Env = replace(cmd.Env, socket.EnvKey, server.Addr().String())
|
||||
}
|
||||
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("DOCKER_CONTEXT=%s", s.dockerCli.CurrentContext()))
|
||||
|
||||
// propagate opentelemetry context to child process, see https://github.com/open-telemetry/oteps/blob/main/text/0258-env-context-baggage-carriers.md
|
||||
carrier := propagation.MapCarrier{}
|
||||
otel.GetTextMapPropagator().Inject(ctx, &carrier)
|
||||
cmd.Env = append(cmd.Env, types.Mapping(carrier).Values()...)
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
|
61
pkg/compose/shellout.go
Normal file
61
pkg/compose/shellout.go
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
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 compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os/exec"
|
||||
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
"github.com/docker/cli/cli-plugins/manager"
|
||||
"github.com/docker/cli/cli/context/docker"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
)
|
||||
|
||||
// prepareShellOut prepare a shell-out command to be ran by Compose
|
||||
func (s *composeService) prepareShellOut(gctx context.Context, project *types.Project, cmd *exec.Cmd) error {
|
||||
// exec command with same environment Compose is running
|
||||
env := types.NewMapping(project.Environment.Values())
|
||||
|
||||
// remove DOCKER_CLI_PLUGIN... variable so a docker-cli plugin will detect it run standalone
|
||||
delete(env, manager.ReexecEnvvar)
|
||||
|
||||
// propagate opentelemetry context to child process, see https://github.com/open-telemetry/oteps/blob/main/text/0258-env-context-baggage-carriers.md
|
||||
carrier := propagation.MapCarrier{}
|
||||
otel.GetTextMapPropagator().Inject(gctx, &carrier)
|
||||
env.Merge(types.Mapping(carrier))
|
||||
|
||||
env["DOCKER_CONTEXT"] = s.dockerCli.CurrentContext()
|
||||
|
||||
metadata, err := s.dockerCli.ContextStore().GetMetadata(s.dockerCli.CurrentContext())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
endpoint, err := docker.EndpointFromContext(metadata)
|
||||
if err != nil {
|
||||
return 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
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user