2020-08-25 10:30:51 +02:00
|
|
|
/*
|
2020-09-22 12:13:00 +02:00
|
|
|
Copyright 2020 Docker Compose CLI authors
|
2020-08-25 10:30:51 +02:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2020-08-31 14:26:00 +02:00
|
|
|
package local
|
2020-08-25 10:30:51 +02:00
|
|
|
|
|
|
|
import (
|
2020-08-26 09:12:30 +02:00
|
|
|
"bufio"
|
|
|
|
"bytes"
|
2020-08-25 10:30:51 +02:00
|
|
|
"context"
|
|
|
|
"fmt"
|
2020-08-31 14:26:00 +02:00
|
|
|
"io"
|
2020-08-25 10:30:51 +02:00
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
|
2020-09-01 16:02:06 +02:00
|
|
|
types2 "github.com/docker/docker/api/types"
|
|
|
|
"github.com/docker/docker/api/types/filters"
|
|
|
|
|
2020-09-07 13:22:08 +02:00
|
|
|
"github.com/docker/compose-cli/api/compose"
|
2020-08-31 14:26:00 +02:00
|
|
|
"github.com/docker/compose-cli/errdefs"
|
|
|
|
|
2020-08-25 10:30:51 +02:00
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
|
|
"github.com/compose-spec/compose-go/types"
|
2020-08-26 09:12:30 +02:00
|
|
|
"github.com/pkg/errors"
|
2020-08-25 10:30:51 +02:00
|
|
|
"github.com/sanathkr/go-yaml"
|
2020-08-26 09:12:30 +02:00
|
|
|
"golang.org/x/mod/semver"
|
2020-08-25 10:30:51 +02:00
|
|
|
)
|
|
|
|
|
2020-10-06 10:56:00 +02:00
|
|
|
func (e ecsLocalSimulation) Up(ctx context.Context, project *types.Project, detach bool) error {
|
2020-08-31 14:26:00 +02:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2020-11-05 09:27:14 +01:00
|
|
|
converted, err := e.Convert(ctx, project, "yaml")
|
2020-08-25 10:30:51 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-08-31 14:26:00 +02:00
|
|
|
|
|
|
|
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()
|
|
|
|
}
|
|
|
|
|
2020-11-05 09:27:14 +01:00
|
|
|
func (e ecsLocalSimulation) Convert(ctx context.Context, project *types.Project, format string) ([]byte, error) {
|
2020-08-25 10:30:51 +02:00
|
|
|
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 {
|
2020-08-31 14:26:00 +02:00
|
|
|
return nil, err
|
2020-08-25 10:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for i, service := range project.Services {
|
|
|
|
service.Networks["credentials_network"] = &types.ServiceNetworkConfig{
|
|
|
|
Ipv4Address: fmt.Sprintf("169.254.170.%d", i+3),
|
|
|
|
}
|
2020-09-08 10:50:50 +02:00
|
|
|
if service.DependsOn == nil {
|
|
|
|
service.DependsOn = types.DependsOnConfig{}
|
|
|
|
}
|
2020-09-07 10:52:34 +02:00
|
|
|
service.DependsOn["ecs-local-endpoints"] = types.ServiceDependency{
|
|
|
|
Condition: types.ServiceConditionStarted,
|
|
|
|
}
|
2020-08-25 10:30:51 +02:00
|
|
|
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,
|
|
|
|
}
|
2020-08-31 14:26:00 +02:00
|
|
|
return yaml.Marshal(config)
|
|
|
|
}
|
2020-08-25 10:30:51 +02:00
|
|
|
|
2020-08-31 14:26:00 +02:00
|
|
|
func (e ecsLocalSimulation) Down(ctx context.Context, projectName string) error {
|
2020-09-01 15:35:31 +02:00
|
|
|
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()
|
2020-08-31 14:26:00 +02:00
|
|
|
}
|
2020-08-26 09:12:30 +02:00
|
|
|
|
2020-08-31 14:26:00 +02:00
|
|
|
func (e ecsLocalSimulation) Logs(ctx context.Context, projectName string, w io.Writer) error {
|
2020-09-01 16:02:06 +02:00
|
|
|
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()
|
2020-08-31 14:26:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (e ecsLocalSimulation) Ps(ctx context.Context, projectName string) ([]compose.ServiceStatus, error) {
|
|
|
|
return nil, errors.Wrap(errdefs.ErrNotImplemented, "use docker-compose ps")
|
2020-08-25 10:30:51 +02:00
|
|
|
}
|
2020-09-04 13:20:11 +02:00
|
|
|
func (e ecsLocalSimulation) List(ctx context.Context, projectName string) ([]compose.Stack, error) {
|
|
|
|
return nil, errors.Wrap(errdefs.ErrNotImplemented, "use docker-compose ls")
|
|
|
|
}
|