From db5467ce221e0fdb887bf3f1ce6d23e9e5dd915a Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Tue, 15 Dec 2020 17:21:09 +0100 Subject: [PATCH] Use local compose implementation for local ecs simulation context Signed-off-by: Nicolas De Loof --- cli/cmd/compose/up.go | 2 +- ecs/local/backend.go | 10 ++- ecs/local/compose.go | 144 ++++++++++++++---------------------------- 3 files changed, 54 insertions(+), 102 deletions(-) diff --git a/cli/cmd/compose/up.go b/cli/cmd/compose/up.go index 0be7eb9b1..3b1f104f1 100644 --- a/cli/cmd/compose/up.go +++ b/cli/cmd/compose/up.go @@ -40,7 +40,7 @@ func upCommand(contextType string) *cobra.Command { Short: "Create and start containers", RunE: func(cmd *cobra.Command, args []string) error { switch contextType { - case store.LocalContextType, store.DefaultContextType: + case store.LocalContextType, store.DefaultContextType, store.EcsLocalSimulationContextType: return runCreateStart(cmd.Context(), opts, args) default: return runUp(cmd.Context(), opts, args) diff --git a/ecs/local/backend.go b/ecs/local/backend.go index 934bf0b86..952c48ca0 100644 --- a/ecs/local/backend.go +++ b/ecs/local/backend.go @@ -19,6 +19,8 @@ package local import ( "context" + local_compose "github.com/docker/compose-cli/local/compose" + "github.com/docker/docker/client" "github.com/docker/compose-cli/api/compose" @@ -38,17 +40,19 @@ func init() { } type ecsLocalSimulation struct { - moby *client.Client + moby *client.Client + compose compose.Service } func service(ctx context.Context) (backend.Service, error) { - apiClient, err := client.NewClientWithOpts(client.FromEnv) + apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) if err != nil { return nil, err } return &ecsLocalSimulation{ - moby: apiClient, + moby: apiClient, + compose: local_compose.NewComposeService(apiClient), }, nil } diff --git a/ecs/local/compose.go b/ecs/local/compose.go index abe9812d5..fff413cc1 100644 --- a/ecs/local/compose.go +++ b/ecs/local/compose.go @@ -17,80 +17,76 @@ package local import ( - "bufio" - "bytes" "context" "encoding/json" "fmt" "os" - "os/exec" "path/filepath" - "strings" "github.com/aws/aws-sdk-go/aws" "github.com/compose-spec/compose-go/types" - types2 "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/filters" - "github.com/pkg/errors" - "github.com/sanathkr/go-yaml" - "golang.org/x/mod/semver" - "github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/errdefs" + "github.com/sanathkr/go-yaml" ) func (e ecsLocalSimulation) Build(ctx context.Context, project *types.Project) error { - return errdefs.ErrNotImplemented + return e.compose.Build(ctx, project) } func (e ecsLocalSimulation) Push(ctx context.Context, project *types.Project) error { - return errdefs.ErrNotImplemented + return e.compose.Push(ctx, project) } func (e ecsLocalSimulation) Pull(ctx context.Context, project *types.Project) error { - return errdefs.ErrNotImplemented + return e.compose.Pull(ctx, project) } func (e ecsLocalSimulation) Create(ctx context.Context, project *types.Project) error { - return errdefs.ErrNotImplemented -} - -func (e ecsLocalSimulation) Start(ctx context.Context, project *types.Project, consumer compose.LogConsumer) error { - return errdefs.ErrNotImplemented -} - -func (e ecsLocalSimulation) Up(ctx context.Context, project *types.Project, detach bool) error { - - cmd := exec.Command("docker-compose", "version", "--short") - b := bytes.Buffer{} - b.WriteString("v") - cmd.Stdout = bufio.NewWriter(&b) - err := cmd.Run() - if err != nil { - return errors.Wrap(err, "ECS simulation mode require Docker-compose 1.27") - } - version := semver.MajorMinor(strings.TrimSpace(b.String())) - if version == "" { - return fmt.Errorf("can't parse docker-compose version: %s", b.String()) - } - if semver.Compare(version, "v1.27") < 0 { - return fmt.Errorf("ECS simulation mode require Docker-compose 1.27, found %s", version) - } - - converted, err := e.Convert(ctx, project, "json") + enhanced, err := e.enhanceForLocalSimulation(project) if err != nil { return err } - cmd = exec.Command("docker-compose", "--context", "default", "--project-directory", project.WorkingDir, "--project-name", project.Name, "-f", "-", "up") - cmd.Stdin = strings.NewReader(string(converted)) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - return cmd.Run() + return e.compose.Create(ctx, enhanced) +} + +func (e ecsLocalSimulation) Start(ctx context.Context, project *types.Project, consumer compose.LogConsumer) error { + return e.compose.Start(ctx, project, consumer) +} + +func (e ecsLocalSimulation) Up(ctx context.Context, project *types.Project, detach bool) error { + return errdefs.ErrNotImplemented } func (e ecsLocalSimulation) Convert(ctx context.Context, project *types.Project, format string) ([]byte, error) { + enhanced, err := e.enhanceForLocalSimulation(project) + if err != nil { + return nil, err + } + + delete(enhanced.Networks, "default") + config := map[string]interface{}{ + "services": enhanced.Services, + "networks": enhanced.Networks, + "volumes": enhanced.Volumes, + "secrets": enhanced.Secrets, + "configs": enhanced.Configs, + } + switch format { + case "json": + return json.MarshalIndent(config, "", " ") + case "yaml": + return yaml.Marshal(config) + default: + return nil, fmt.Errorf("unsupported format %q", format) + } + +} + +func (e ecsLocalSimulation) enhanceForLocalSimulation(project *types.Project) (*types.Project, error) { project.Networks["credentials_network"] = types.NetworkConfig{ + Name: "credentials_network", Driver: "bridge", Ipam: types.IPAMConfig{ Config: []*types.IPAMPool{ @@ -148,68 +144,20 @@ func (e ecsLocalSimulation) Convert(ctx context.Context, project *types.Project, }, }, }) - - delete(project.Networks, "default") - config := map[string]interface{}{ - "services": project.Services, - "networks": project.Networks, - "volumes": project.Volumes, - "secrets": project.Secrets, - "configs": project.Configs, - } - switch format { - case "json": - return json.MarshalIndent(config, "", " ") - case "yaml": - return yaml.Marshal(config) - default: - return nil, fmt.Errorf("unsupported format %q", format) - } - + return project, nil } func (e ecsLocalSimulation) Down(ctx context.Context, projectName string) error { - cmd := exec.Command("docker-compose", "--context", "default", "--project-name", projectName, "-f", "-", "down", "--remove-orphans") - cmd.Stdin = strings.NewReader(string(` -services: - ecs-local-endpoints: - image: "amazon/amazon-ecs-local-container-endpoints" -`)) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - return cmd.Run() + return e.compose.Down(ctx, projectName) } -func (e ecsLocalSimulation) Logs(ctx context.Context, projectName string, consumer compose.LogConsumer, options compose.LogOptions) error { - list, err := e.moby.ContainerList(ctx, types2.ContainerListOptions{ - Filters: filters.NewArgs(filters.Arg("label", "com.docker.compose.project="+projectName)), - }) - if err != nil { - return err - } - services := map[string]types.ServiceConfig{} - for _, c := range list { - services[c.Labels["com.docker.compose.service"]] = types.ServiceConfig{ - Image: "unused", - } - } - - marshal, err := yaml.Marshal(map[string]interface{}{ - "services": services, - }) - if err != nil { - return err - } - cmd := exec.Command("docker-compose", "--context", "default", "--project-name", projectName, "-f", "-", "logs", "-f") - cmd.Stdin = strings.NewReader(string(marshal)) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - return cmd.Run() +func (e ecsLocalSimulation) Logs(ctx context.Context, projectName string, consumer compose.LogConsumer, options componse.LogOptions) error { + return e.compose.Logs(ctx, projectName, consumer, options) } func (e ecsLocalSimulation) Ps(ctx context.Context, projectName string) ([]compose.ContainerSummary, error) { - return nil, errors.Wrap(errdefs.ErrNotImplemented, "use docker-compose ps") + return e.compose.Ps(ctx, projectName) } func (e ecsLocalSimulation) List(ctx context.Context, projectName string) ([]compose.Stack, error) { - return nil, errors.Wrap(errdefs.ErrNotImplemented, "use docker-compose ls") + return e.compose.List(ctx, projectName) }