Forráskód Böngészése

introduce ecs-local context

Signed-off-by: Nicolas De Loof <[email protected]>
Nicolas De Loof 5 éve
szülő
commit
fed50d79f2

+ 0 - 4
aci/backend.go

@@ -396,10 +396,6 @@ func (cs *aciComposeService) Up(ctx context.Context, project *types.Project) err
 	return createOrUpdateACIContainers(ctx, cs.ctx, groupDefinition)
 }
 
-func (cs *aciComposeService) Emulate(context.Context, *cli.ProjectOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
 func (cs *aciComposeService) Down(ctx context.Context, project string) error {
 	logrus.Debugf("Down on project with name %q\n", project)
 

+ 2 - 2
cli/cmd/compose/compose.go

@@ -60,7 +60,7 @@ func (o *composeOptions) toProjectOptions() (*cli.ProjectOptions, error) {
 }
 
 // Command returns the compose command with its child commands
-func Command(contextType string) *cobra.Command {
+func Command() *cobra.Command {
 	command := &cobra.Command{
 		Short: "Docker Compose",
 		Use:   "compose",
@@ -70,7 +70,7 @@ func Command(contextType string) *cobra.Command {
 	}
 
 	command.AddCommand(
-		upCommand(contextType),
+		upCommand(),
 		downCommand(),
 		psCommand(),
 		logsCommand(),

+ 3 - 12
cli/cmd/compose/up.go

@@ -24,17 +24,15 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/docker/compose-cli/client"
-	"github.com/docker/compose-cli/context/store"
 	"github.com/docker/compose-cli/progress"
 )
 
-func upCommand(contextType string) *cobra.Command {
+func upCommand() *cobra.Command {
 	opts := composeOptions{}
-	var simulation bool
 	upCmd := &cobra.Command{
 		Use: "up",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return runUp(cmd.Context(), opts, simulation)
+			return runUp(cmd.Context(), opts)
 		},
 	}
 	upCmd.Flags().StringVarP(&opts.Name, "project-name", "p", "", "Project name")
@@ -42,14 +40,10 @@ func upCommand(contextType string) *cobra.Command {
 	upCmd.Flags().StringArrayVarP(&opts.ConfigPaths, "file", "f", []string{}, "Compose configuration files")
 	upCmd.Flags().StringArrayVarP(&opts.Environment, "environment", "e", []string{}, "Environment variables")
 	upCmd.Flags().BoolP("detach", "d", true, " Detached mode: Run containers in the background")
-	if contextType == store.EcsContextType {
-		upCmd.Flags().BoolVar(&simulation, "simulate", false, " Simulation mode: run compose app with ECS local container endpoints")
-	}
-
 	return upCmd
 }
 
-func runUp(ctx context.Context, opts composeOptions, simulation bool) error {
+func runUp(ctx context.Context, opts composeOptions) error {
 	c, err := client.New(ctx)
 	if err != nil {
 		return err
@@ -65,9 +59,6 @@ func runUp(ctx context.Context, opts composeOptions, simulation bool) error {
 			return err
 		}
 
-        if simulation {
-			return c.ComposeService().Emulate(ctx, options)
-		}		
 		return c.ComposeService().Up(ctx, project)
 	})
 }

+ 21 - 1
cli/cmd/context/create_ecs.go

@@ -38,17 +38,22 @@ $ docker context create ecs CONTEXT [flags]
 }
 
 func createEcsCommand() *cobra.Command {
+	var localSimulation bool
 	var opts ecs.ContextParams
 	cmd := &cobra.Command{
 		Use:   "ecs CONTEXT [flags]",
 		Short: "Create a context for Amazon ECS",
 		Args:  cobra.ExactArgs(1),
 		RunE: func(cmd *cobra.Command, args []string) error {
+			if localSimulation {
+				return runCreateLocalSimulation(cmd.Context(), args[0], opts)
+			}
 			return runCreateEcs(cmd.Context(), args[0], opts)
 		},
 	}
 
 	addDescriptionFlag(cmd, &opts.Description)
+	cmd.Flags().BoolVar(&localSimulation, "local-simulation", false, "Create context for ECS local simulation endpoints")
 	cmd.Flags().StringVar(&opts.Profile, "profile", "", "Profile")
 	cmd.Flags().StringVar(&opts.Region, "region", "", "Region")
 	cmd.Flags().StringVar(&opts.AwsID, "key-id", "", "AWS Access Key ID")
@@ -56,6 +61,21 @@ func createEcsCommand() *cobra.Command {
 	return cmd
 }
 
+func runCreateLocalSimulation(ctx context.Context, contextName string, opts ecs.ContextParams) error {
+	if contextExists(ctx, contextName) {
+		return errors.Wrapf(errdefs.ErrAlreadyExists, "context %q", contextName)
+	}
+	cs, err := client.GetCloudService(ctx, store.EcsLocalSimulationContextType)
+	if err != nil {
+		return errors.Wrap(err, "cannot connect to ECS backend")
+	}
+	data, description, err := cs.CreateContextData(ctx, opts)
+	if err != nil {
+		return err
+	}
+	return createDockerContext(ctx, contextName, store.EcsLocalSimulationContextType, description, data)
+}
+
 func runCreateEcs(ctx context.Context, contextName string, opts ecs.ContextParams) error {
 	if contextExists(ctx, contextName) {
 		return errors.Wrapf(errdefs.ErrAlreadyExists, "context %q", contextName)
@@ -71,7 +91,7 @@ func runCreateEcs(ctx context.Context, contextName string, opts ecs.ContextParam
 func getEcsContextData(ctx context.Context, opts ecs.ContextParams) (interface{}, string, error) {
 	cs, err := client.GetCloudService(ctx, store.EcsContextType)
 	if err != nil {
-		return nil, "", errors.Wrap(err, "cannot connect to AWS backend")
+		return nil, "", errors.Wrap(err, "cannot connect to ECS backend")
 	}
 	return cs.CreateContextData(ctx, opts)
 }

+ 4 - 3
cli/main.go

@@ -27,6 +27,8 @@ import (
 	"syscall"
 	"time"
 
+	"github.com/docker/compose-cli/cli/cmd/compose"
+
 	"github.com/docker/compose-cli/cli/cmd/logout"
 
 	"github.com/docker/compose-cli/errdefs"
@@ -38,12 +40,12 @@ import (
 	// Backend registrations
 	_ "github.com/docker/compose-cli/aci"
 	_ "github.com/docker/compose-cli/ecs"
+	_ "github.com/docker/compose-cli/ecs/local"
 	_ "github.com/docker/compose-cli/example"
 	_ "github.com/docker/compose-cli/local"
 	"github.com/docker/compose-cli/metrics"
 
 	"github.com/docker/compose-cli/cli/cmd"
-	"github.com/docker/compose-cli/cli/cmd/compose"
 	contextcmd "github.com/docker/compose-cli/cli/cmd/context"
 	"github.com/docker/compose-cli/cli/cmd/login"
 	"github.com/docker/compose-cli/cli/cmd/run"
@@ -126,6 +128,7 @@ func main() {
 		cmd.VersionCommand(version),
 		cmd.StopCommand(),
 		cmd.SecretCommand(),
+		compose.Command(),
 
 		// Place holders
 		cmd.EcsCommand(),
@@ -183,8 +186,6 @@ func main() {
 $ docker context create %s <name>`, cc.Type(), store.EcsContextType))
 	}
 
-	root.AddCommand(compose.Command(ctype))
-
 	metrics.Track(ctype, os.Args[1:], root.PersistentFlags())
 
 	ctx = apicontext.WithCurrentContext(ctx, currentContext)

+ 0 - 5
client/compose.go

@@ -34,11 +34,6 @@ func (c *composeService) Up(context.Context, *types.Project) error {
 	return errdefs.ErrNotImplemented
 }
 
-// Emulate executes the equivalent to a `compose up` in platform emulation mode
-func (c *composeService) Emulate(context.Context, *cli.ProjectOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
 // Down executes the equivalent to a `compose down`
 func (c *composeService) Down(context.Context, string) error {
 	return errdefs.ErrNotImplemented

+ 0 - 2
compose/api.go

@@ -35,8 +35,6 @@ type Service interface {
 	Ps(ctx context.Context, projectName string) ([]ServiceStatus, error)
 	// Convert translate compose model into backend's native format
 	Convert(ctx context.Context, project *types.Project) ([]byte, error)
-	// Emulate executes the equivalent to a `compose up` in platform emulation mode
-	Emulate(ctx context.Context, options *cli.ProjectOptions) error	
 }
 
 // PortPublisher hold status about published port

+ 5 - 0
context/store/store.go

@@ -44,6 +44,11 @@ const (
 	// EcsContextType is the endpoint key in the context endpoints for an ECS
 	// backend
 	EcsContextType = "ecs"
+
+	// EcsLocalSimulationContextType is the endpoint key in the context endpoints for an ECS backend
+	// running local simulation endpoints
+	EcsLocalSimulationContextType = "ecs-local"
+
 	// AciContextType is the endpoint key in the context endpoints for an ACI
 	// backend
 	AciContextType = "aci"

+ 1 - 2
ecs/backend.go

@@ -22,8 +22,6 @@ import (
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws/session"
 
-	"github.com/docker/compose-cli/secrets"
-
 	"github.com/docker/compose-cli/backend"
 	"github.com/docker/compose-cli/compose"
 	"github.com/docker/compose-cli/containers"
@@ -31,6 +29,7 @@ import (
 	"github.com/docker/compose-cli/context/cloud"
 	"github.com/docker/compose-cli/context/store"
 	"github.com/docker/compose-cli/errdefs"
+	"github.com/docker/compose-cli/secrets"
 )
 
 const backendType = store.EcsContextType

+ 67 - 0
ecs/local/backend.go

@@ -0,0 +1,67 @@
+/*
+   Copyright 2020 Docker, Inc.
+
+   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 local
+
+import (
+	"context"
+
+	"github.com/docker/compose-cli/compose"
+	"github.com/docker/compose-cli/containers"
+	"github.com/docker/compose-cli/secrets"
+	"github.com/docker/docker/client"
+
+	"github.com/docker/compose-cli/backend"
+	"github.com/docker/compose-cli/context/cloud"
+	"github.com/docker/compose-cli/context/store"
+)
+
+const backendType = store.EcsLocalSimulationContextType
+
+func init() {
+	backend.Register(backendType, backendType, service, getCloudService)
+}
+
+type ecsLocalSimulation struct {
+	moby *client.Client
+}
+
+func service(ctx context.Context) (backend.Service, error) {
+	apiClient, err := client.NewClientWithOpts(client.FromEnv)
+	if err != nil {
+		return nil, err
+	}
+
+	return &ecsLocalSimulation{
+		moby: apiClient,
+	}, nil
+}
+
+func getCloudService() (cloud.Service, error) {
+	return ecsLocalSimulation{}, nil
+}
+
+func (e ecsLocalSimulation) ContainerService() containers.Service {
+	return nil
+}
+
+func (e ecsLocalSimulation) SecretsService() secrets.Service {
+	return nil
+}
+
+func (e ecsLocalSimulation) ComposeService() compose.Service {
+	return e
+}

+ 44 - 30
ecs/emulate.go → ecs/local/compose.go

@@ -14,31 +14,59 @@
    limitations under the License.
 */
 
-package ecs
+package local
 
 import (
 	"bufio"
 	"bytes"
 	"context"
 	"fmt"
+	"io"
 	"os"
 	"os/exec"
 	"path/filepath"
 	"strings"
 
+	"github.com/docker/compose-cli/compose"
+	"github.com/docker/compose-cli/errdefs"
+
 	"github.com/aws/aws-sdk-go/aws"
-	"github.com/compose-spec/compose-go/cli"
 	"github.com/compose-spec/compose-go/types"
 	"github.com/pkg/errors"
 	"github.com/sanathkr/go-yaml"
 	"golang.org/x/mod/semver"
 )
 
-func (c *ecsAPIService) Emulate(ctx context.Context, options *cli.ProjectOptions) error {
-	project, err := cli.ProjectFromOptions(options)
+func (e ecsLocalSimulation) Up(ctx context.Context, project *types.Project) 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)
 	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()
+}
+
+func (e ecsLocalSimulation) Convert(ctx context.Context, project *types.Project) ([]byte, error) {
 	project.Networks["credentials_network"] = types.NetworkConfig{
 		Driver: "bridge",
 		Ipam: types.IPAMConfig{
@@ -54,7 +82,7 @@ func (c *ecsAPIService) Emulate(ctx context.Context, options *cli.ProjectOptions
 	// On Windows, this directory can be found at "%UserProfile%\.aws"
 	home, err := os.UserHomeDir()
 	if err != nil {
-		return err
+		return nil, err
 	}
 
 	for i, service := range project.Services {
@@ -62,7 +90,6 @@ func (c *ecsAPIService) Emulate(ctx context.Context, options *cli.ProjectOptions
 			Ipv4Address: fmt.Sprintf("169.254.170.%d", i+3),
 		}
 		service.DependsOn = append(service.DependsOn, "ecs-local-endpoints")
-		service.Environment["AWS_DEFAULT_REGION"] = aws.String(c.ctx.Region)
 		service.Environment["AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"] = aws.String("/creds")
 		service.Environment["ECS_CONTAINER_METADATA_URI"] = aws.String("http://169.254.170.2/v3")
 		project.Services[i] = service
@@ -102,30 +129,17 @@ func (c *ecsAPIService) Emulate(ctx context.Context, options *cli.ProjectOptions
 		"secrets":  project.Secrets,
 		"configs":  project.Configs,
 	}
-	marshal, err := yaml.Marshal(config)
-	if err != nil {
-		return err
-	}
+	return yaml.Marshal(config)
+}
 
-	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)
-	}
+func (e ecsLocalSimulation) Down(ctx context.Context, projectName string) error {
+	return errors.Wrap(errdefs.ErrNotImplemented, "use docker-compose down")
+}
 
-	cmd = exec.Command("docker-compose", "--context", "default", "--project-directory", project.WorkingDir, "--project-name", project.Name, "-f", "-", "up")
-	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, w io.Writer) error {
+	return errors.Wrap(errdefs.ErrNotImplemented, "use docker-compose logs")
+}
+
+func (e ecsLocalSimulation) Ps(ctx context.Context, projectName string) ([]compose.ServiceStatus, error) {
+	return nil, errors.Wrap(errdefs.ErrNotImplemented, "use docker-compose ps")
 }

+ 40 - 0
ecs/local/context.go

@@ -0,0 +1,40 @@
+/*
+   Copyright 2020 Docker, Inc.
+
+   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 local
+
+import (
+	"context"
+
+	"github.com/docker/compose-cli/context/cloud"
+	"github.com/docker/compose-cli/ecs"
+	"github.com/docker/compose-cli/errdefs"
+)
+
+var _ cloud.Service = ecsLocalSimulation{}
+
+func (e ecsLocalSimulation) Login(ctx context.Context, params interface{}) error {
+	return errdefs.ErrNotImplemented
+}
+
+func (e ecsLocalSimulation) Logout(ctx context.Context) error {
+	return errdefs.ErrNotImplemented
+}
+
+func (e ecsLocalSimulation) CreateContextData(ctx context.Context, params interface{}) (contextData interface{}, description string, err error) {
+	opts := params.(ecs.ContextParams)
+	return struct{}{}, opts.Description, nil
+}

+ 0 - 4
example/backend.go

@@ -132,10 +132,6 @@ func (cs *composeService) Down(ctx context.Context, project string) error {
 	return nil
 }
 
-func (cs *composeService) Emulate(context.Context, *cli.ProjectOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
 func (cs *composeService) Ps(ctx context.Context, project string) ([]compose.ServiceStatus, error) {
 	return nil, errdefs.ErrNotImplemented
 }