diff --git a/pkg/api/dryrunclient.go b/pkg/api/dryrunclient.go index e418726f0..a7a6c8262 100644 --- a/pkg/api/dryrunclient.go +++ b/pkg/api/dryrunclient.go @@ -23,7 +23,9 @@ import ( "net" "net/http" "strings" + "sync" + "github.com/distribution/distribution/v3/uuid" moby "github.com/docker/docker/api/types" containerType "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/events" @@ -35,6 +37,7 @@ import ( "github.com/docker/docker/api/types/volume" "github.com/docker/docker/client" specs "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" ) const ( @@ -48,12 +51,19 @@ type DryRunKey struct{} // DryRunClient implements APIClient by delegating to implementation functions. This allows lazy init and per-method overrides type DryRunClient struct { apiClient client.APIClient + execs sync.Map +} + +type execDetails struct { + container string + command []string } // NewDryRunClient produces a DryRunClient func NewDryRunClient(apiClient client.APIClient) *DryRunClient { return &DryRunClient{ apiClient: apiClient, + execs: sync.Map{}, } } @@ -155,6 +165,27 @@ func (d *DryRunClient) VolumeRemove(ctx context.Context, volumeID string, force return ErrNotImplemented } +func (d *DryRunClient) ContainerExecCreate(ctx context.Context, container string, config moby.ExecConfig) (moby.IDResponse, error) { + id := uuid.Generate().String() + d.execs.Store(id, execDetails{ + container: container, + command: config.Cmd, + }) + return moby.IDResponse{ + ID: id, + }, nil +} + +func (d *DryRunClient) ContainerExecStart(ctx context.Context, execID string, config moby.ExecStartCheck) error { + v, ok := d.execs.LoadAndDelete(execID) + if !ok { + return fmt.Errorf("invalid exec ID %q", execID) + } + details := v.(execDetails) + fmt.Printf("%sExecuting command %q in %s (detached mode)\n", DRYRUN_PREFIX, details.command, details.container) + return nil +} + // Functions delegated to original APIClient (not used by Compose or not modifying the Compose stack func (d *DryRunClient) ConfigList(ctx context.Context, options moby.ConfigListOptions) ([]swarm.Config, error) { @@ -186,11 +217,7 @@ func (d *DryRunClient) ContainerDiff(ctx context.Context, container string) ([]c } func (d *DryRunClient) ContainerExecAttach(ctx context.Context, execID string, config moby.ExecStartCheck) (moby.HijackedResponse, error) { - return d.apiClient.ContainerExecAttach(ctx, execID, config) -} - -func (d *DryRunClient) ContainerExecCreate(ctx context.Context, container string, config moby.ExecConfig) (moby.IDResponse, error) { - return d.apiClient.ContainerExecCreate(ctx, container, config) + return moby.HijackedResponse{}, errors.New("interactive exec is not supported in dry-run mode") } func (d *DryRunClient) ContainerExecInspect(ctx context.Context, execID string) (moby.ContainerExecInspect, error) { @@ -201,10 +228,6 @@ func (d *DryRunClient) ContainerExecResize(ctx context.Context, execID string, o return d.apiClient.ContainerExecResize(ctx, execID, options) } -func (d *DryRunClient) ContainerExecStart(ctx context.Context, execID string, config moby.ExecStartCheck) error { - return d.apiClient.ContainerExecStart(ctx, execID, config) -} - func (d *DryRunClient) ContainerExport(ctx context.Context, container string) (io.ReadCloser, error) { return d.apiClient.ContainerExport(ctx, container) }