Sfoglia il codice sorgente

Introduce ECS emulation mode

Signed-off-by: Nicolas De Loof <[email protected]>
Nicolas De Loof 5 anni fa
parent
commit
7f8bb030e6
10 ha cambiato i file con 146 aggiunte e 9 eliminazioni
  1. 4 0
      aci/backend.go
  2. 2 2
      cli/cmd/compose/compose.go
  3. 11 3
      cli/cmd/compose/up.go
  4. 2 1
      cli/main.go
  5. 5 0
      client/compose.go
  6. 2 0
      compose/api.go
  7. 112 0
      ecs/emulate.go
  8. 4 0
      example/backend.go
  9. 2 1
      go.mod
  10. 2 2
      go.sum

+ 4 - 0
aci/backend.go

@@ -396,6 +396,10 @@ 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() *cobra.Command {
+func Command(contextType string) *cobra.Command {
 	command := &cobra.Command{
 		Short: "Docker Compose",
 		Use:   "compose",
@@ -70,7 +70,7 @@ func Command() *cobra.Command {
 	}
 
 	command.AddCommand(
-		upCommand(),
+		upCommand(contextType),
 		downCommand(),
 		psCommand(),
 		logsCommand(),

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

@@ -24,15 +24,17 @@ 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() *cobra.Command {
+func upCommand(contextType string) *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)
+			return runUp(cmd.Context(), opts, simulation)
 		},
 	}
 	upCmd.Flags().StringVarP(&opts.Name, "project-name", "p", "", "Project name")
@@ -40,11 +42,14 @@ func upCommand() *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) error {
+func runUp(ctx context.Context, opts composeOptions, simulation bool) error {
 	c, err := client.New(ctx)
 	if err != nil {
 		return err
@@ -60,6 +65,9 @@ func runUp(ctx context.Context, opts composeOptions) error {
 			return err
 		}
 
+        if simulation {
+			return c.ComposeService().Emulate(ctx, options)
+		}		
 		return c.ComposeService().Up(ctx, project)
 	})
 }

+ 2 - 1
cli/main.go

@@ -121,7 +121,6 @@ func main() {
 		cmd.RmCommand(),
 		cmd.StartCommand(),
 		cmd.InspectCommand(),
-		compose.Command(),
 		login.Command(),
 		logout.Command(),
 		cmd.VersionCommand(version),
@@ -184,6 +183,8 @@ 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)

+ 5 - 0
client/compose.go

@@ -34,6 +34,11 @@ 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

+ 2 - 0
compose/api.go

@@ -35,6 +35,8 @@ 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

+ 112 - 0
ecs/emulate.go

@@ -0,0 +1,112 @@
+/*
+   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 ecs
+
+import (
+	"context"
+	"fmt"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/compose-spec/compose-go/types"
+	"github.com/sanathkr/go-yaml"
+
+	"github.com/compose-spec/compose-go/cli"
+)
+
+func (c *ecsAPIService) Emulate(ctx context.Context, options *cli.ProjectOptions) error {
+	project, err := cli.ProjectFromOptions(options)
+	if err != nil {
+		return err
+	}
+	project.Networks["credentials_network"] = types.NetworkConfig{
+		Driver: "bridge",
+		Ipam: types.IPAMConfig{
+			Config: []*types.IPAMPool{
+				{
+					Subnet:  "169.254.170.0/24",
+					Gateway: "169.254.170.1",
+				},
+			},
+		},
+	}
+
+	// On Windows, this directory can be found at "%UserProfile%\.aws"
+	home, err := os.UserHomeDir()
+	if err != nil {
+		return err
+	}
+
+	for i, service := range project.Services {
+		service.Networks["credentials_network"] = &types.ServiceNetworkConfig{
+			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
+	}
+
+	project.Services = append(project.Services, types.ServiceConfig{
+		Name:  "ecs-local-endpoints",
+		Image: "amazon/amazon-ecs-local-container-endpoints",
+		Volumes: []types.ServiceVolumeConfig{
+			{
+				Type:   types.VolumeTypeBind,
+				Source: "/var/run",
+				Target: "/var/run",
+			},
+			{
+				Type:   types.VolumeTypeBind,
+				Source: filepath.Join(home, ".aws"),
+				Target: "/home/.aws",
+			},
+		},
+		Environment: map[string]*string{
+			"HOME":        aws.String("/home"),
+			"AWS_PROFILE": aws.String("default"),
+		},
+		Networks: map[string]*types.ServiceNetworkConfig{
+			"credentials_network": {
+				Ipv4Address: "169.254.170.2",
+			},
+		},
+	})
+
+	delete(project.Networks, "default")
+	config := map[string]interface{}{
+		"services": project.Services,
+		"networks": project.Networks,
+		"volumes":  project.Volumes,
+		"secrets":  project.Secrets,
+		"configs":  project.Configs,
+	}
+	marshal, err := yaml.Marshal(config)
+	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(marshal))
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	return cmd.Run()
+}

+ 4 - 0
example/backend.go

@@ -132,6 +132,10 @@ 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
 }

+ 2 - 1
go.mod

@@ -22,7 +22,7 @@ require (
 	github.com/aws/aws-sdk-go v1.34.8
 	github.com/awslabs/goformation/v4 v4.14.0
 	github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129
-	github.com/compose-spec/compose-go v0.0.0-20200818070525-eb1188aae4a2
+	github.com/compose-spec/compose-go v0.0.0-20200824075806-a70cd5945c25
 	github.com/containerd/console v1.0.0
 	github.com/containerd/containerd v1.3.5 // indirect
 	github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8
@@ -46,6 +46,7 @@ require (
 	github.com/opencontainers/go-digest v1.0.0
 	github.com/opencontainers/runc v0.1.1 // indirect
 	github.com/pkg/errors v0.9.1
+	github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b
 	github.com/sirupsen/logrus v1.6.0
 	github.com/smartystreets/goconvey v1.6.4 // indirect
 	github.com/spf13/cobra v1.0.0

+ 2 - 2
go.sum

@@ -87,8 +87,8 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/compose-spec/compose-go v0.0.0-20200818070525-eb1188aae4a2 h1:b3JmHJVJt8zXy112yGtRq74G32sPQ8XLJxfHKaP/DOg=
-github.com/compose-spec/compose-go v0.0.0-20200818070525-eb1188aae4a2/go.mod h1:P7PZ0svgjrZ8nv/XvxObbl8o0DCIE9ZbL8pllg6uL4w=
+github.com/compose-spec/compose-go v0.0.0-20200824075806-a70cd5945c25 h1:mVlGrHJuNGPJNEvCCIrDIZX5FYtNTwFd++y+fJaGTXM=
+github.com/compose-spec/compose-go v0.0.0-20200824075806-a70cd5945c25/go.mod h1:P7PZ0svgjrZ8nv/XvxObbl8o0DCIE9ZbL8pllg6uL4w=
 github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s=
 github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
 github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=