From 9a5fa05ad6f8c00071b67afa00c24d315ce780ce Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Fri, 6 Jun 2025 09:45:09 +0200 Subject: [PATCH] add (temporary) support for use_api_socket Signed-off-by: Nicolas De Loof --- pkg/compose/apiSocket.go | 90 ++++++++++++++++++++++++++++++++++++++++ pkg/compose/create.go | 7 ++++ pkg/compose/run.go | 8 +++- 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 pkg/compose/apiSocket.go diff --git a/pkg/compose/apiSocket.go b/pkg/compose/apiSocket.go new file mode 100644 index 000000000..52e702a50 --- /dev/null +++ b/pkg/compose/apiSocket.go @@ -0,0 +1,90 @@ +/* + 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 ( + "bytes" + "fmt" + "strings" + + "github.com/compose-spec/compose-go/v2/types" + "github.com/docker/cli/cli/config/configfile" +) + +// --use-api-socket is not actually supported by the Docker Engine +// but is a client-side hack (see https://github.com/docker/cli/blob/master/cli/command/container/create.go#L246) +// we replicate here by transforming the project model + +func (s *composeService) useAPISocket(project *types.Project) (*types.Project, error) { + useAPISocket := false + for _, service := range project.Services { + if service.UseAPISocket { + useAPISocket = true + break + } + } + if !useAPISocket { + return project, nil + } + + socket := s.dockerCli.DockerEndpoint().Host + if !strings.HasPrefix(socket, "unix://") { + return nil, fmt.Errorf("use_api_socket can only be used with unix sockets: docker endpoint %s is incompatible", socket) + } + socket = strings.TrimPrefix(socket, "unix://") // should we confirm absolute path? + + creds, err := s.dockerCli.ConfigFile().GetAllCredentials() + if err != nil { + return nil, fmt.Errorf("resolving credentials failed: %w", err) + } + newConfig := &configfile.ConfigFile{ + AuthConfigs: creds, + } + var configBuf bytes.Buffer + if err := newConfig.SaveToWriter(&configBuf); err != nil { + return nil, fmt.Errorf("saving creds for API socket: %w", err) + } + + project.Configs["#apisocket"] = types.ConfigObjConfig{ + Content: configBuf.String(), + } + + for name, service := range project.Services { + service.Volumes = append(service.Volumes, types.ServiceVolumeConfig{ + Type: types.VolumeTypeBind, + Source: socket, + Target: "/var/run/docker.sock", + }) + + _, envvarPresent := service.Environment["DOCKER_CONFIG"] + + // If the DOCKER_CONFIG env var is already present, we assume the client knows + // what they're doing and don't inject the creds. + if !envvarPresent { + // Set our special little location for the config file. + path := "/run/secrets/docker" + service.Environment["DOCKER_CONFIG"] = &path + } + + service.Configs = append(service.Configs, types.ServiceConfigObjConfig{ + Source: "#apisocket", + Target: "/run/secrets/docker/config.json", + }) + project.Services[name] = service + } + return project, nil +} diff --git a/pkg/compose/create.go b/pkg/compose/create.go index 01e8ca6ea..bee76f7c5 100644 --- a/pkg/compose/create.go +++ b/pkg/compose/create.go @@ -114,6 +114,13 @@ func (s *composeService) create(ctx context.Context, project *types.Project, opt "--remove-orphans flag to clean it up.", orphans.names()) } } + + // Temporary implementation of use_api_socket until we get actual support inside docker engine + project, err = s.useAPISocket(project) + if err != nil { + return err + } + return newConvergence(options.Services, observedState, networks, volumes, s).apply(ctx, project, options) } diff --git a/pkg/compose/run.go b/pkg/compose/run.go index 7b4f5678f..db8ed34de 100644 --- a/pkg/compose/run.go +++ b/pkg/compose/run.go @@ -59,6 +59,12 @@ func (s *composeService) RunOneOffContainer(ctx context.Context, project *types. } func (s *composeService) prepareRun(ctx context.Context, project *types.Project, opts api.RunOptions) (string, error) { + // Temporary implementation of use_api_socket until we get actual support inside docker engine + project, err := s.useAPISocket(project) + if err != nil { + return "", err + } + err = progress.Run(ctx, func(ctx context.Context) error { return s.startDependencies(ctx, project, opts) }, s.stdinfo()) @@ -171,7 +177,7 @@ func applyRunOptions(project *types.Project, service *types.ServiceConfig, opts func (s *composeService) startDependencies(ctx context.Context, project *types.Project, options api.RunOptions) error { var dependencies []string - for name, _ := range project.Services { + for name := range project.Services { if name != options.Service { dependencies = append(dependencies, name) }