Skip to content

Instantly share code, notes, and snippets.

@lox
Created November 25, 2015 05:39
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save lox/a8f77c7afcec6cbabf25 to your computer and use it in GitHub Desktop.
Save lox/a8f77c7afcec6cbabf25 to your computer and use it in GitHub Desktop.
Convert from docker-compose.yml to ecs task definition in golang
package transform
import (
"errors"
"fmt"
"strconv"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ecs"
"github.com/docker/libcompose/docker"
"github.com/docker/libcompose/project"
)
func TransformComposeFile(composeFile string, projectName string) (ecs.TaskDefinition, error) {
task := ecs.TaskDefinition{
ContainerDefinitions: []*ecs.ContainerDefinition{},
Volumes: []*ecs.Volume{},
}
project, err := docker.NewProject(&docker.Context{
Context: project.Context{
ComposeFile: composeFile,
ProjectName: projectName,
}})
if err != nil {
return task, err
}
for name, config := range project.Configs {
var def = ecs.ContainerDefinition{}
if config.Name != "" {
def.Name = aws.String(config.Name)
}
if config.Image != "" {
def.Image = aws.String(config.Image)
}
if config.Hostname != "" {
def.Hostname = aws.String(config.Hostname)
}
if config.WorkingDir != "" {
def.WorkingDirectory = aws.String(config.WorkingDir)
}
if config.CPUShares > 0 {
def.Cpu = aws.Int64(config.CPUShares)
}
if config.MemLimit > 0 {
def.Memory = aws.Int64(config.MemLimit)
}
if config.Privileged {
def.Privileged = aws.Bool(config.Privileged)
}
if slice := config.DNS.Slice(); len(slice) > 0 {
for _, dns := range slice {
def.DnsServers = append(def.DnsServers, aws.String(dns))
}
}
if slice := config.DNSSearch.Slice(); len(slice) > 0 {
for _, item := range slice {
def.DnsSearchDomains = append(def.DnsSearchDomains, aws.String(item))
}
}
if cmds := config.Command.Slice(); len(cmds) > 0 {
def.Command = []*string{}
for _, command := range cmds {
def.Command = append(def.Command, aws.String(command))
}
}
if cmds := config.Entrypoint.Slice(); len(cmds) > 0 {
def.EntryPoint = []*string{}
for _, command := range cmds {
def.EntryPoint = append(def.EntryPoint, aws.String(command))
}
}
if slice := config.Environment.Slice(); len(slice) > 0 {
def.Environment = []*ecs.KeyValuePair{}
for _, val := range slice {
parts := strings.SplitN(val, "=", 2)
def.Environment = append(def.Environment, &ecs.KeyValuePair{
Name: aws.String(parts[0]),
Value: aws.String(parts[1]),
})
}
}
if ports := config.Ports; len(ports) > 0 {
def.PortMappings = []*ecs.PortMapping{}
for _, val := range ports {
parts := strings.Split(val, ":")
mapping := &ecs.PortMapping{}
// TODO: support host to map to
if len(parts) > 0 {
portInt, err := strconv.ParseInt(parts[0], 10, 64)
if err != nil {
return task, err
}
mapping.ContainerPort = aws.Int64(portInt)
}
if len(parts) > 1 {
hostParts := strings.Split(parts[1], "/")
portInt, err := strconv.ParseInt(hostParts[0], 10, 64)
if err != nil {
return task, err
}
mapping.HostPort = aws.Int64(portInt)
// handle the protocol at the end of the mapping
if len(hostParts) > 1 {
mapping.Protocol = aws.String(hostParts[1])
}
}
if len(parts) == 0 || len(parts) > 2 {
return task, errors.New("Unsupported port mapping " + val)
}
def.PortMappings = append(def.PortMappings, mapping)
}
}
if links := config.Links.Slice(); len(links) > 0 {
def.Links = []*string{}
for _, link := range links {
def.Links = append(def.Links, aws.String(link))
}
}
if vols := config.Volumes; len(vols) > 0 {
def.MountPoints = []*ecs.MountPoint{}
for idx, vol := range vols {
parts := strings.Split(vol, ":")
volumeName := fmt.Sprintf("%s-vol%d", name, idx)
volume := ecs.Volume{
Host: &ecs.HostVolumeProperties{
SourcePath: aws.String(parts[0]),
},
Name: aws.String(volumeName),
}
mount := ecs.MountPoint{
SourceVolume: aws.String(volumeName),
ContainerPath: aws.String(parts[1]),
}
if len(parts) == 3 && parts[2] == "ro" {
mount.ReadOnly = aws.Bool(true)
}
task.Volumes = append(task.Volumes, &volume)
def.MountPoints = append(def.MountPoints, &mount)
}
}
if volsFrom := config.VolumesFrom; len(volsFrom) > 0 {
def.VolumesFrom = []*ecs.VolumeFrom{}
for _, container := range volsFrom {
def.VolumesFrom = append(def.VolumesFrom, &ecs.VolumeFrom{
SourceContainer: aws.String(container),
})
}
}
if config.Build != "" {
return task, errors.New("Build directive not supported")
}
if config.Dockerfile != "" {
return task, errors.New("Dockerfile directive not supported")
}
if config.DomainName != "" {
return task, errors.New("DomainName directive not supported")
}
if config.VolumeDriver != "" {
return task, errors.New("VolumeDriver directive not supported")
}
task.ContainerDefinitions = append(task.ContainerDefinitions, &def)
// Not Implemented
// CapAdd:[]string(nil),
// CapDrop:[]string(nil),
// CPUSet:"",
// ContainerName:"",
// Devices:[]string(nil),
// EnvFile:project.Stringorslice{parts:[]string(nil)},
// Labels:project.SliceorMap{parts:map[string]string(nil)},
// LogDriver:"",
// MemSwapLimit:0,
// Net:"",
// Pid:"",
// Uts:"",
// Ipc:"",
// Restart:"",
// ReadOnly:false,
// StdinOpen:false,
// SecurityOpt:[]string(nil),
// Tty:false,
// User:"",
// Expose:[]string(nil),
// ExternalLinks:[]string(nil),
// LogOpt:map[string]string(nil),
// ExtraHosts:[]string(nil)}
}
return task, nil
}
@james-nesbitt
Copy link

james-nesbitt commented Feb 28, 2017

Was it really necessary to use aws and require the entire aws sdk for dict type enforcement?

edit: nvr mind, I hadn't realized that your return target was an aws task, not a swarm task. My bad.

@niedbalski
Copy link

Was it really necessary to use aws and require the entire aws sdk for dict type enforcement?

edit: nvr mind, I hadn't realized that your return target was an aws task, not a swarm task. My bad.

That moment when you realize you are shooting to the wrong duck.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment