Introduce ECS emulation mode

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2020-08-25 10:30:51 +02:00
parent ed1776fec0
commit 7f8bb030e6
No known key found for this signature in database
GPG Key ID: 9858809D6F8F6E7E
10 changed files with 146 additions and 9 deletions

View File

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

View File

@ -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(),

View File

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

View File

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

View File

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

View File

@ -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
ecs/emulate.go Normal file
View File

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

View File

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

3
go.mod
View File

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

4
go.sum
View File

@ -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=