|
|
@@ -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)
|
|
|
}
|