Adopt CloudFormation to create ECS app from compose.yaml

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2020-04-21 11:38:52 +02:00
parent 4e72d1892a
commit b70f01d2f4
17 changed files with 314 additions and 361 deletions

View File

@ -2,6 +2,7 @@ package main
import (
"fmt"
"github.com/docker/cli/cli-plugins/manager"
"github.com/docker/cli/cli-plugins/plugin"
"github.com/docker/cli/cli/command"
@ -70,6 +71,7 @@ func ComposeCommand(clusteropts *clusterOptions) *cobra.Command {
opts.AddFlags(cmd.Flags())
cmd.AddCommand(
ConvertCommand(clusteropts, opts),
UpCommand(clusteropts, opts),
DownCommand(clusteropts, opts),
)
@ -87,6 +89,32 @@ func (o upOptions) LoadBalancerArn() *string {
return &o.loadBalancerArn
}
func ConvertCommand(clusteropts *clusterOptions, projectOpts *compose.ProjectOptions) *cobra.Command {
opts := upOptions{}
cmd := &cobra.Command{
Use: "convert",
RunE: compose.WithProject(projectOpts, func(project *compose.Project, args []string) error {
client, err := amazon.NewClient(clusteropts.profile, clusteropts.cluster, clusteropts.region)
if err != nil {
return err
}
template, err := client.Convert(project, opts.LoadBalancerArn())
if err != nil {
return err
}
j, err := template.JSON()
if err != nil {
fmt.Printf("Failed to generate JSON: %s\n", err)
} else {
fmt.Printf("%s\n", string(j))
}
return nil
}),
}
return cmd
}
func UpCommand(clusteropts *clusterOptions, projectOpts *compose.ProjectOptions) *cobra.Command {
opts := upOptions{}
cmd := &cobra.Command{
@ -107,7 +135,6 @@ type downOptions struct {
KeepLoadBalancer bool
}
func DownCommand(clusteropts *clusterOptions, projectOpts *compose.ProjectOptions) *cobra.Command {
opts := downOptions{}
cmd := &cobra.Command{
@ -122,4 +149,4 @@ func DownCommand(clusteropts *clusterOptions, projectOpts *compose.ProjectOption
}
cmd.Flags().BoolVar(&opts.KeepLoadBalancer, "keep-load-balancer", false, "Keep Load Balancer for further use")
return cmd
}
}

View File

@ -6,6 +6,7 @@ require (
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d // indirect
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect
github.com/aws/aws-sdk-go v1.28.9
github.com/awslabs/goformation/v4 v4.8.0
github.com/bitly/go-hostpool v0.1.0 // indirect
github.com/bitly/go-simplejson v0.5.0 // indirect
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect

View File

@ -21,6 +21,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/aws/aws-sdk-go v1.28.9 h1:grIuBQc+p3dTRXerh5+2OxSuWFi0iXuxbFdTSg0jaW0=
github.com/aws/aws-sdk-go v1.28.9/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/awslabs/goformation/v4 v4.8.0 h1:UiUhyokRy3suEqBXTnipvY8klqY3Eyl4GCH17brraEc=
github.com/awslabs/goformation/v4 v4.8.0/go.mod h1:GcJULxCJfloT+3pbqCluXftdEK2AD/UqpS3hkaaBntg=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@ -46,8 +48,6 @@ github.com/cloudflare/cfssl v1.4.1 h1:vScfU2DrIUI9VPHBVeeAQ0q5A+9yshO1Gz+3QoUQiK
github.com/cloudflare/cfssl v1.4.1/go.mod h1:KManx/OJPb5QY+y0+o/898AMcM128sF0bURvoVUSjTo=
github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4=
github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo=
github.com/compose-spec/compose-go v0.0.0-20200131085702-0b38cc2d8e6b h1:VK0c2Hfrg9FHjvJpWfGwiHPP2UeU0QZ6/5/dN0ehbSQ=
github.com/compose-spec/compose-go v0.0.0-20200131085702-0b38cc2d8e6b/go.mod h1:KoJjdV81vERSyYVuQD63nryyt8ZTlqTWe8JuJIMhRo4=
github.com/compose-spec/compose-go v0.0.0-20200409090215-53c0040c9127 h1:mAsQN3s19glh3KBOQjiRYBhqaX1SdzNqhB3/cuqgSbE=
github.com/compose-spec/compose-go v0.0.0-20200409090215-53c0040c9127/go.mod h1:1PUpzRF1O/65VOqXZuwpCuYY7pJxbIq1jbAvAf62FGM=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
@ -139,7 +139,9 @@ github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
@ -180,7 +182,6 @@ github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-shellwords v1.0.9/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mattn/go-shellwords v1.0.10 h1:Y7Xqm8piKOO3v10Thp7Z36h4FYFjt5xB//6XvOrs2Gw=
github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
@ -205,8 +206,12 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P
github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
github.com/onsi/ginkgo v1.5.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.2.0/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@ -244,12 +249,14 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa
github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b h1:jUK33OXuZP/l6babJtnLo1qsGvq6G9so9KMflGAm4YA=
github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b/go.mod h1:8458kAagoME2+LN5//WxE71ysZ3B7r22fdgb7qVmXSY=
github.com/sanathkr/yaml v0.0.0-20170819201035-0056894fa522 h1:fOCp11H0yuyAt2wqlbJtbyPzSgaxHTv8uN1pMpkG1t8=
github.com/sanathkr/yaml v0.0.0-20170819201035-0056894fa522/go.mod h1:tQTYKOQgxoH3v6dEmdHiz4JG+nbxWwM5fgPQUpSZqVQ=
github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
@ -285,9 +292,12 @@ github.com/weppos/publicsuffix-go v0.5.0 h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg
github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
github.com/xeipuuv/gojsonschema v0.0.0-20181112162635-ac52e6811b56/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1 h1:j2hhcujLRHAg872RWAV5yaUrEjHEObwDv3aImCaNLek=
@ -327,6 +337,8 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09 h1:KaQtG+aDELoNmXYas3TVkGNYR
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -385,10 +397,12 @@ gopkg.in/dancannon/gorethink.v3 v3.0.5 h1:/g7PWP7zUS6vSNmHSDbjCHQh1Rqn8Jy6zSMQxA
gopkg.in/dancannon/gorethink.v3 v3.0.5/go.mod h1:GXsi1e3N2OcKhcP6nsYABTiUejbWMFO4GY5a4pEaeEc=
gopkg.in/fatih/pool.v2 v2.0.0 h1:xIFeWtxifuQJGk/IEPKsTduEKcKvPmhoiVDGpC40nKg=
gopkg.in/fatih/pool.v2 v2.0.0/go.mod h1:8xVGeu1/2jr2wm5V9SPuMht2H5AEmf5aFMGSQixtjTY=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/gorethink/gorethink.v3 v3.0.5 h1:e2Uc/Xe+hpcVQFsj6MuHlYog3r0JYpnTzwDj/y2O4MU=
gopkg.in/gorethink/gorethink.v3 v3.0.5/go.mod h1:+3yIIHJUGMBK+wyPH+iN5TP+88ikFDfZdqTlK3Y9q8I=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@ -396,8 +410,6 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.0 h1:d+tVGRu6X0ZBQ+kyAR8JKi6AXhTP2gmQaoIYaGFz634=
gotest.tools/v3 v3.0.0/go.mod h1:TUP+/YtXl/dp++T+SZ5v2zUmLVBHmptSb/ajDLCJ+3c=
gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -18,7 +18,6 @@ import (
"github.com/docker/ecs-plugin/pkg/compose"
)
const (
ProjectTag = "com.docker.compose.project"
)
@ -35,27 +34,27 @@ func NewClient(profile string, cluster string, region string) (compose.API, erro
}
return &client{
Cluster: cluster,
Region: region,
sess: sess,
ECS: ecs.New(sess),
EC2: ec2.New(sess),
ELB: elbv2.New(sess),
CW: cloudwatchlogs.New(sess),
IAM: iam.New(sess),
CF: cloudformation.New(sess),
Region: region,
sess: sess,
ECS: ecs.New(sess),
EC2: ec2.New(sess),
ELB: elbv2.New(sess),
CW: cloudwatchlogs.New(sess),
IAM: iam.New(sess),
CF: cloudformation.New(sess),
}, nil
}
type client struct {
Cluster string
Region string
sess *session.Session
ECS ecsiface.ECSAPI
EC2 ec2iface.EC2API
ELB elbv2iface.ELBV2API
CW cloudwatchlogsiface.CloudWatchLogsAPI
IAM iamiface.IAMAPI
CF cloudformationiface.CloudFormationAPI
Region string
sess *session.Session
ECS ecsiface.ECSAPI
EC2 ec2iface.EC2API
ELB elbv2iface.ELBV2API
CW cloudwatchlogsiface.CloudWatchLogsAPI
IAM iamiface.IAMAPI
CF cloudformationiface.CloudFormationAPI
}
var _ compose.API = &client{}

View File

@ -1 +1,81 @@
package amazon
import (
"fmt"
"strings"
ecsapi "github.com/aws/aws-sdk-go/service/ecs"
"github.com/awslabs/goformation/v4/cloudformation"
"github.com/awslabs/goformation/v4/cloudformation/ec2"
"github.com/awslabs/goformation/v4/cloudformation/ecs"
"github.com/docker/ecs-plugin/pkg/compose"
"github.com/docker/ecs-plugin/pkg/convert"
)
func (c client) Convert(project *compose.Project, loadBalancerArn *string) (*cloudformation.Template, error) {
template := cloudformation.NewTemplate()
vpc, err := c.GetDefaultVPC()
if err != nil {
return nil, err
}
subnets, err := c.GetSubNets(vpc)
if err != nil {
return nil, err
}
var ingresses = []ec2.SecurityGroup_Ingress{}
for _, service := range project.Services {
for _, port := range service.Ports {
ingresses = append(ingresses, ec2.SecurityGroup_Ingress{
CidrIp: "0.0.0.0/0",
Description: fmt.Sprintf("%d/%s", port.Target, port.Protocol),
FromPort: int(port.Target),
IpProtocol: strings.ToUpper(port.Protocol),
ToPort: int(port.Target),
})
}
}
securityGroup := fmt.Sprintf("%s Security Group", project.Name)
template.Resources["SecurityGroup"] = &ec2.SecurityGroup{
GroupDescription: securityGroup,
GroupName: securityGroup,
SecurityGroupIngress: ingresses,
VpcId: *vpc,
}
for _, service := range project.Services {
definition, err := convert.Convert(project, service)
if err != nil {
return nil, err
}
role, err := c.GetEcsTaskExecutionRole(service)
if err != nil {
return nil, err
}
definition.TaskRoleArn = *role
taskDefinition := fmt.Sprintf("%sTaskDefinition", service.Name)
template.Resources[taskDefinition] = definition
template.Resources[service.Name] = &ecs.Service{
Cluster: c.Cluster,
DesiredCount: 1,
LaunchType: ecsapi.LaunchTypeFargate,
NetworkConfiguration: &ecs.Service_NetworkConfiguration{
AwsvpcConfiguration: &ecs.Service_AwsVpcConfiguration{
AssignPublicIp: ecsapi.AssignPublicIpEnabled,
SecurityGroups: []string{cloudformation.Ref("SecurityGroup")},
Subnets: subnets,
},
},
SchedulingStrategy: ecsapi.SchedulingStrategyReplica,
ServiceName: service.Name,
TaskDefinition: cloudformation.Ref(taskDefinition),
}
}
return template, nil
}

View File

@ -1,64 +1,18 @@
package amazon
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ecs"
"github.com/aws/aws-sdk-go/service/cloudformation"
"github.com/docker/ecs-plugin/pkg/compose"
"github.com/sirupsen/logrus"
)
func (c *client) ComposeDown(project *compose.Project, keepLoadBalancer bool) error {
err := c.DeleteLoadBalancer(project, keepLoadBalancer)
if err != nil {
return err
}
services := []*string{}
// FIXME we should be able to retrieve services by tags, so we don't need the initial compose file to run "down"
for _, service := range project.Services {
logrus.Debugf("Deleting service %q\n", service.Name)
out, err := c.ECS.DeleteService(&ecs.DeleteServiceInput{
// Force to true so that we don't have to scale down to 0
// before deleting
Force: aws.Bool(true),
Cluster: aws.String(c.Cluster),
Service: aws.String(service.Name),
})
if err != nil {
return err
}
services = append(services, out.Service.ServiceArn)
}
logrus.Info("Stopping services...")
err = c.ECS.WaitUntilServicesInactive(&ecs.DescribeServicesInput{
Services: services,
_, err := c.CF.DeleteStack(&cloudformation.DeleteStackInput{
StackName: &project.Name,
})
if err != nil {
return err
}
logrus.Info("All services stopped")
logrus.Debug("Deleting security groups")
groups, err := c.EC2.DescribeSecurityGroups(&ec2.DescribeSecurityGroupsInput{
Filters: []*ec2.Filter{
{
Name: aws.String("tag:" + ProjectTag),
Values: aws.StringSlice([]string{project.Name}),
},
},
})
if err != nil {
return err
}
for _, g := range groups.SecurityGroups {
_, err = c.EC2.DeleteSecurityGroup(&ec2.DeleteSecurityGroupInput{
GroupId: g.GroupId,
})
if err != nil {
return err
}
}
// TODO monitor progress
return nil
}

View File

@ -5,7 +5,6 @@ import (
"github.com/sirupsen/logrus"
)
func (c client) RegisterTaskDefinition(task *ecs.RegisterTaskDefinitionInput) (*string, error) {
logrus.Debug("Register Task Definition")
def, err := c.ECS.RegisterTaskDefinition(task)

View File

@ -2,9 +2,10 @@ package amazon
import (
"fmt"
"strings"
"github.com/docker/ecs-plugin/pkg/compose"
"github.com/sirupsen/logrus"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/elbv2"
@ -132,4 +133,4 @@ func (c client) DeleteListeners(loadBalancer *string) error {
}
}
return nil
}
}

View File

@ -2,6 +2,7 @@ package amazon
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
"github.com/docker/ecs-plugin/pkg/compose"

View File

@ -2,12 +2,13 @@ package amazon
import (
"fmt"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/compose-spec/compose-go/types"
"github.com/docker/ecs-plugin/pkg/compose"
"github.com/sirupsen/logrus"
"strings"
)
// GetDefaultVPC retrieve the default VPC for AWS account
@ -30,9 +31,8 @@ func (c client) GetDefaultVPC() (*string, error) {
return vpcs.Vpcs[0].VpcId, nil
}
// GetSubNets retrieve default subnets for a VPC
func (c client) GetSubNets(vpc *string) ([]*string, error) {
func (c client) GetSubNets(vpc *string) ([]string, error) {
logrus.Debug("Retrieve SubNets")
subnets, err := c.EC2.DescribeSubnets(&ec2.DescribeSubnetsInput{
DryRun: nil,
@ -51,9 +51,9 @@ func (c client) GetSubNets(vpc *string) ([]*string, error) {
return nil, err
}
ids := []*string{}
ids := []string{}
for _, subnet := range subnets.Subnets {
ids = append(ids, subnet.SubnetId)
ids = append(ids, *subnet.SubnetId)
}
return ids, nil
}
@ -91,7 +91,6 @@ func (c client) CreateSecurityGroup(project *compose.Project, vpc *string) (*str
return securityGroup.GroupId, nil
}
func (c *client) ExposePort(securityGroup *string, port types.ServicePortConfig) error {
logrus.Debugf("Authorize ingress port %d/%s\n", port.Published, port.Protocol)
_, err := c.EC2.AuthorizeSecurityGroupIngress(&ec2.AuthorizeSecurityGroupIngressInput{
@ -110,4 +109,4 @@ func (c *client) ExposePort(securityGroup *string, port types.ServicePortConfig)
},
})
return err
}
}

View File

@ -2,6 +2,7 @@ package amazon
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/compose-spec/compose-go/types"
@ -13,7 +14,7 @@ const ECSTaskExecutionPolicy = "arn:aws:iam::aws:policy/service-role/AmazonECSTa
var defaultTaskExecutionRole *string
// GetEcsTaskExecutionRole retrieve the role ARN to apply for task execution
func (c client) GetEcsTaskExecutionRole(spec *types.ServiceConfig) (*string, error) {
func (c client) GetEcsTaskExecutionRole(spec types.ServiceConfig) (*string, error) {
if arn, ok := spec.Extras["x-ecs-TaskExecutionRole"]; ok {
s := arn.(string)
return &s, nil

View File

@ -2,128 +2,54 @@ package amazon
import (
"fmt"
"os"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ecs"
"github.com/compose-spec/compose-go/types"
"github.com/aws/aws-sdk-go/service/cloudformation"
"github.com/docker/ecs-plugin/pkg/compose"
"github.com/docker/ecs-plugin/pkg/convert"
"github.com/sirupsen/logrus"
)
func (c *client) ComposeUp(project *compose.Project, loadBalancerArn *string) error {
type mapping struct {
service *types.ServiceConfig
task *ecs.RegisterTaskDefinitionInput
}
mappings := []mapping{}
for _, service := range project.Services {
task, err := convert.Convert(project, service)
if err != nil {
return err
}
mappings = append(mappings, mapping{
service: &service,
task: task,
})
}
vpc, err := c.GetDefaultVPC()
if err != nil {
return err
}
subnets, err := c.GetSubNets(vpc)
template, err := c.Convert(project, loadBalancerArn)
if err != nil {
return err
}
securityGroup, err := c.CreateSecurityGroup(project, vpc)
json, err := template.JSON()
if err != nil {
return err
}
if loadBalancerArn == nil {
loadBalancerArn, err = c.CreateLoadBalancer(project, subnets)
if err != nil {
return err
}
}
logGroup, err := c.GetOrCreateLogGroup(project)
_, err = c.CF.ValidateTemplate(&cloudformation.ValidateTemplateInput{
TemplateBody: aws.String(string(json)),
})
if err != nil {
return err
}
for _, mapping := range mappings {
ingress := []*ecs.LoadBalancer{}
for _, port := range mapping.service.Ports {
name := fmt.Sprintf("%s-%s-%d-%s", project.Name, mapping.service.Name, port.Target, port.Protocol)
targetgroup, err := c.CreateTargetGroup(name, vpc, port)
if err != nil {
return err
}
ingress = append(ingress, &ecs.LoadBalancer{
ContainerName: aws.String(mapping.service.Name),
ContainerPort: aws.Int64(int64(port.Target)),
TargetGroupArn: targetgroup,
})
_, err = c.CF.CreateStack(&cloudformation.CreateStackInput{
OnFailure: aws.String("DELETE"),
StackName: aws.String(project.Name),
TemplateBody: aws.String(string(json)),
TimeoutInMinutes: aws.Int64(10),
})
if err != nil {
return err
}
err = c.CreateListener(port, loadBalancerArn, targetgroup)
if err != nil {
return err
}
}
_, err = c.CreateService(project, mapping.service, mapping.task, securityGroup, subnets, logGroup, ingress)
if err != nil {
return err
events, err := c.CF.DescribeStackEvents(&cloudformation.DescribeStackEventsInput{
StackName: aws.String(project.Name),
})
if err != nil {
return err
}
for _, event := range events.StackEvents {
fmt.Printf("%s %s\n", *event.LogicalResourceId, *event.ResourceStatus)
if *event.ResourceStatus == "CREATE_FAILED" {
fmt.Fprintln(os.Stderr, event.ResourceStatusReason)
}
}
// TODO monitor progress
return nil
}
func (c *client) CreateService(project *compose.Project, service *types.ServiceConfig, task *ecs.RegisterTaskDefinitionInput, securityGroup *string, subnets []*string, logGroup *string, ingress []*ecs.LoadBalancer) (*string, error) {
role, err := c.GetEcsTaskExecutionRole(service)
if err != nil {
return nil, err
}
task.ExecutionRoleArn = role
for _, def := range task.ContainerDefinitions {
def.LogConfiguration.Options["awslogs-group"] = logGroup
def.LogConfiguration.Options["awslogs-stream-prefix"] = aws.String(service.Name)
def.LogConfiguration.Options["awslogs-region"] = aws.String(c.Region)
}
arn, err := c.RegisterTaskDefinition(task)
if err != nil {
return nil, err
}
logrus.Debug("Create Service")
created, err := c.ECS.CreateService(&ecs.CreateServiceInput{
Cluster: aws.String(c.Cluster),
DesiredCount: aws.Int64(1), // FIXME get from deploy options
LaunchType: aws.String(ecs.LaunchTypeFargate), //FIXME use service.Isolation tro select EC2 vs Fargate
NetworkConfiguration: &ecs.NetworkConfiguration{
AwsvpcConfiguration: &ecs.AwsVpcConfiguration{
AssignPublicIp: aws.String(ecs.AssignPublicIpEnabled),
SecurityGroups: []*string{securityGroup},
Subnets: subnets,
},
},
ServiceName: aws.String(service.Name),
SchedulingStrategy: aws.String(ecs.SchedulingStrategyReplica),
TaskDefinition: arn,
LoadBalancers: ingress,
})
for _, port := range service.Ports {
err = c.ExposePort(securityGroup, port)
if err != nil {
return nil, err
}
}
return created.Service.ServiceArn, err
}

View File

@ -1,6 +1,9 @@
package compose
import "github.com/awslabs/goformation/v4/cloudformation"
type API interface {
Convert(project *Project, loadBalancerArn *string) (*cloudformation.Template, error)
ComposeUp(project *Project, loadBalancerArn *string) error
ComposeDown(project *Project, keepLoadBalancer bool) error
}
}

View File

@ -15,7 +15,6 @@ func (o *ProjectOptions) AddFlags(flags *pflag.FlagSet) {
flags.StringVarP(&o.name, "project-name", "n", "", "Specify an alternate project name (default: directory name)")
}
type ProjectFunc func(project *Project, args []string) error
// WithProject wrap a ProjectFunc into a cobra command

View File

@ -2,14 +2,15 @@ package compose
import (
"fmt"
"github.com/compose-spec/compose-go/loader"
"github.com/compose-spec/compose-go/types"
"github.com/sirupsen/logrus"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/compose-spec/compose-go/loader"
"github.com/compose-spec/compose-go/types"
"github.com/sirupsen/logrus"
)
type Project struct {
@ -32,7 +33,6 @@ func NewProject(config types.ConfigDetails, name string) (*Project, error) {
return &p, nil
}
// projectFromOptions load a compose project based on command line options
func projectFromOptions(options *ProjectOptions) (*Project, error) {
configPath, err := getConfigPathFromOptions(options)

View File

@ -1,9 +1,10 @@
package compose
import (
"gotest.tools/v3/assert"
"os"
"testing"
"gotest.tools/v3/assert"
)
func Test_project_name(t *testing.T) {

View File

@ -1,118 +1,87 @@
package convert
import (
"github.com/docker/ecs-plugin/pkg/compose"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ecs"
ecsapi "github.com/aws/aws-sdk-go/service/ecs"
"github.com/awslabs/goformation/v4/cloudformation/ecs"
"github.com/compose-spec/compose-go/types"
"github.com/docker/cli/opts"
"github.com/docker/ecs-plugin/pkg/compose"
)
func Convert(project *compose.Project, service types.ServiceConfig) (*ecs.RegisterTaskDefinitionInput, error) {
func Convert(project *compose.Project, service types.ServiceConfig) (*ecs.TaskDefinition, error) {
_, err := toCPULimits(service)
if err != nil {
return nil, err
}
foo := int64(256)
logDriver := "awslogs" // FIXME could be set by service.Logging, especially to enable use of firelens
return &ecs.RegisterTaskDefinitionInput{
ContainerDefinitions: []*ecs.ContainerDefinition{
return &ecs.TaskDefinition{
ContainerDefinitions: []ecs.TaskDefinition_ContainerDefinition{
// Here we can declare sidecars and init-containers using https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html#container_definition_dependson
{
Command: toStringPtrSlice(service.Command),
Cpu: &foo,
DependsOn: nil,
DisableNetworking: toBoolPtr(service.NetworkMode == "none"),
DnsSearchDomains: toStringPtrSlice(service.DNSSearch),
DnsServers: toStringPtrSlice(service.DNS),
DockerLabels: nil,
DockerSecurityOptions: toStringPtrSlice(service.SecurityOpt),
EntryPoint: toStringPtrSlice(service.Entrypoint),
Environment: toKeyValuePairPtr(service.Environment),
Essential: toBoolPtr(true),
ExtraHosts: toHostEntryPtr(service.ExtraHosts),
FirelensConfiguration: nil,
HealthCheck: toHealthCheck(service.HealthCheck),
Hostname: toStringPtr(service.Hostname),
Image: toStringPtr(service.Image),
Interactive: nil,
Links: nil,
LinuxParameters: toLinuxParameters(service),
LogConfiguration: &ecs.LogConfiguration{
LogDriver: &logDriver,
Options: map[string]*string{},
SecretOptions: nil,
},
Command: service.Command,
Cpu: 256,
DisableNetworking: service.NetworkMode == "none",
DnsSearchDomains: service.DNSSearch,
DnsServers: service.DNS,
DockerLabels: nil,
DockerSecurityOptions: service.SecurityOpt,
EntryPoint: service.Entrypoint,
Environment: toKeyValuePair(service.Environment),
Essential: true,
ExtraHosts: toHostEntryPtr(service.ExtraHosts),
FirelensConfiguration: nil,
HealthCheck: toHealthCheck(service.HealthCheck),
Hostname: service.Hostname,
Image: service.Image,
Interactive: false,
Links: nil,
LinuxParameters: toLinuxParameters(service),
Memory: toMemoryLimits(service.Deploy),
MemoryReservation: toMemoryReservation(service.Deploy),
MountPoints: nil,
Name: toStringPtr(service.Name),
Name: service.Name,
PortMappings: toPortMappings(service.Ports),
Privileged: toBoolPtr(service.Privileged),
PseudoTerminal: toBoolPtr(service.Tty),
ReadonlyRootFilesystem: toBoolPtr(service.ReadOnly),
Privileged: service.Privileged,
PseudoTerminal: service.Tty,
ReadonlyRootFilesystem: service.ReadOnly,
RepositoryCredentials: nil,
ResourceRequirements: nil,
Secrets: nil,
StartTimeout: nil,
StopTimeout: durationToInt64Ptr(service.StopGracePeriod),
StartTimeout: 0,
StopTimeout: durationToInt(service.StopGracePeriod),
SystemControls: nil,
Ulimits: toUlimits(service.Ulimits),
User: toStringPtr(service.User),
User: service.User,
VolumesFrom: nil,
WorkingDirectory: toStringPtr(service.WorkingDir),
WorkingDirectory: service.WorkingDir,
},
},
Cpu: toCPU(service),
ExecutionRoleArn: nil,
Family: toStringPtr(project.Name),
IpcMode: toStringPtr(service.Ipc),
Family: project.Name,
IpcMode: service.Ipc,
Memory: toMemory(service),
NetworkMode: toStringPtr("awsvpc"), // FIXME could be set by service.NetworkMode, Fargate only supports network mode awsvpc.
PidMode: toStringPtr(service.Pid),
NetworkMode: ecsapi.NetworkModeAwsvpc, // FIXME could be set by service.NetworkMode, Fargate only supports network mode awsvpc.
PidMode: service.Pid,
PlacementConstraints: toPlacementConstraints(service.Deploy),
ProxyConfiguration: nil,
RequiresCompatibilities: toRequiresCompatibilities(ecs.LaunchTypeFargate),
RequiresCompatibilities: []string{ecsapi.LaunchTypeFargate},
Tags: nil,
Volumes: []*ecs.Volume{
{
/* ONLY supported when using EC2 launch type
DockerVolumeConfiguration: {
Autoprovision: nil,
Driver: nil,
DriverOpts: nil,
Labels: nil,
Scope: nil,
}, */
/* Beta and ONLY supported when using EC2 launch type
EfsVolumeConfiguration: {
FileSystemId: nil,
RootDirectory: nil,
}, */
/* Bind mount host volume
Host: {
SourcePath:
}, */
Name: aws.String("MyVolume"),
},
},
Volumes: []ecs.TaskDefinition_Volume{},
}, nil
}
func toCPU(service types.ServiceConfig) *string {
func toCPU(service types.ServiceConfig) string {
// FIXME based on service's memory/cpu requirements, select the adequate Fargate CPU
v := "256"
return &v
return "256"
}
func toMemory(service types.ServiceConfig) *string {
func toMemory(service types.ServiceConfig) string {
// FIXME based on service's memory/cpu requirements, select the adequate Fargate CPU
v := "512"
return &v
return "512"
}
func toCPULimits(service types.ServiceConfig) (*int64, error) {
@ -153,45 +122,45 @@ func hasMemoryOrMemoryReservation(service types.ServiceConfig) bool {
return false
}
func toPlacementConstraints(deploy *types.DeployConfig) []*ecs.TaskDefinitionPlacementConstraint {
func toPlacementConstraints(deploy *types.DeployConfig) []ecs.TaskDefinition_TaskDefinitionPlacementConstraint {
if deploy == nil || deploy.Placement.Constraints == nil || len(deploy.Placement.Constraints) == 0 {
return nil
}
pl := []*ecs.TaskDefinitionPlacementConstraint{}
pl := []ecs.TaskDefinition_TaskDefinitionPlacementConstraint{}
for _, c := range deploy.Placement.Constraints {
pl = append(pl, &ecs.TaskDefinitionPlacementConstraint{
Expression: toStringPtr(c),
Type: nil,
pl = append(pl, ecs.TaskDefinition_TaskDefinitionPlacementConstraint{
Expression: c,
Type: "",
})
}
return pl
}
func toPortMappings(ports []types.ServicePortConfig) []*ecs.PortMapping {
func toPortMappings(ports []types.ServicePortConfig) []ecs.TaskDefinition_PortMapping {
if len(ports) == 0 {
return nil
}
m := []*ecs.PortMapping{}
m := []ecs.TaskDefinition_PortMapping{}
for _, p := range ports {
m = append(m, &ecs.PortMapping{
ContainerPort: uint32Toint64Ptr(p.Target),
HostPort: uint32Toint64Ptr(p.Published),
Protocol: toStringPtr(p.Protocol),
m = append(m, ecs.TaskDefinition_PortMapping{
ContainerPort: int(p.Target),
HostPort: int(p.Published),
Protocol: p.Protocol,
})
}
return m
}
func toUlimits(ulimits map[string]*types.UlimitsConfig) []*ecs.Ulimit {
func toUlimits(ulimits map[string]*types.UlimitsConfig) []ecs.TaskDefinition_Ulimit {
if len(ulimits) == 0 {
return nil
}
u := []*ecs.Ulimit{}
u := []ecs.TaskDefinition_Ulimit{}
for k, v := range ulimits {
u = append(u, &ecs.Ulimit{
Name: toStringPtr(k),
SoftLimit: intToInt64Ptr(v.Soft),
HardLimit: intToInt64Ptr(v.Hard),
u = append(u, ecs.TaskDefinition_Ulimit{
Name: k,
SoftLimit: v.Soft,
HardLimit: v.Hard,
})
}
return u
@ -209,79 +178,82 @@ func intToInt64Ptr(i int) *int64 {
const Mb = 1024 * 1024
func toMemoryLimits(deploy *types.DeployConfig) *int64 {
func toMemoryLimits(deploy *types.DeployConfig) int {
if deploy == nil {
return nil
return 0
}
res := deploy.Resources.Limits
if res == nil {
return nil
return 0
}
v := int64(res.MemoryBytes) / Mb
return &v
v := int(res.MemoryBytes) / Mb
return v
}
func toMemoryReservation(deploy *types.DeployConfig) *int64 {
func toMemoryReservation(deploy *types.DeployConfig) int {
if deploy == nil {
return nil
return 0
}
res := deploy.Resources.Reservations
if res == nil {
return nil
return 0
}
v := int64(res.MemoryBytes) / Mb
return &v
v := int(res.MemoryBytes) / Mb
return v
}
func toLinuxParameters(service types.ServiceConfig) *ecs.LinuxParameters {
return &ecs.LinuxParameters{
func toLinuxParameters(service types.ServiceConfig) *ecs.TaskDefinition_LinuxParameters {
return &ecs.TaskDefinition_LinuxParameters{
Capabilities: toKernelCapabilities(service.CapAdd, service.CapDrop),
Devices: nil,
InitProcessEnabled: service.Init,
MaxSwap: nil,
InitProcessEnabled: service.Init != nil && *service.Init,
MaxSwap: 0,
// FIXME SharedMemorySize: service.ShmSize,
Swappiness: nil,
Swappiness: 0,
Tmpfs: toTmpfs(service.Tmpfs),
}
}
func toTmpfs(tmpfs types.StringList) []*ecs.Tmpfs {
func toTmpfs(tmpfs types.StringList) []ecs.TaskDefinition_Tmpfs {
if tmpfs == nil || len(tmpfs) == 0 {
return nil
}
o := []*ecs.Tmpfs{}
for _, t := range tmpfs {
path := t
o = append(o, &ecs.Tmpfs{
ContainerPath: &path,
o := []ecs.TaskDefinition_Tmpfs{}
for _, path := range tmpfs {
o = append(o, ecs.TaskDefinition_Tmpfs{
ContainerPath: path,
MountOptions: nil,
Size: nil,
Size: 0,
})
}
return o
}
func toKernelCapabilities(add []string, drop []string) *ecs.KernelCapabilities {
func toKernelCapabilities(add []string, drop []string) *ecs.TaskDefinition_KernelCapabilities {
if len(add) == 0 && len(drop) == 0 {
return nil
}
return &ecs.KernelCapabilities{
Add: toStringPtrSlice(add),
Drop: toStringPtrSlice(drop),
return &ecs.TaskDefinition_KernelCapabilities{
Add: add,
Drop: drop,
}
}
func toHealthCheck(check *types.HealthCheckConfig) *ecs.HealthCheck {
func toHealthCheck(check *types.HealthCheckConfig) *ecs.TaskDefinition_HealthCheck {
if check == nil {
return nil
}
return &ecs.HealthCheck{
Command: toStringPtrSlice(check.Test),
Interval: durationToInt64Ptr(check.Interval),
Retries: uint64ToInt64Ptr(check.Retries),
StartPeriod: durationToInt64Ptr(check.StartPeriod),
Timeout: durationToInt64Ptr(check.Timeout),
retries := 0
if check.Retries != nil {
retries = int(*check.Retries)
}
return &ecs.TaskDefinition_HealthCheck{
Command: check.Test,
Interval: durationToInt(check.Interval),
Retries: retries,
StartPeriod: durationToInt(check.StartPeriod),
Timeout: durationToInt(check.Timeout),
}
}
@ -293,66 +265,44 @@ func uint64ToInt64Ptr(i *uint64) *int64 {
return &v
}
func durationToInt64Ptr(interval *types.Duration) *int64 {
func durationToInt(interval *types.Duration) int {
if interval == nil {
return nil
return 0
}
v := int64(time.Duration(*interval).Seconds())
return &v
v := int(time.Duration(*interval).Seconds())
return v
}
func toHostEntryPtr(hosts types.HostsList) []*ecs.HostEntry {
func toHostEntryPtr(hosts types.HostsList) []ecs.TaskDefinition_HostEntry {
if hosts == nil || len(hosts) == 0 {
return nil
}
e := []*ecs.HostEntry{}
e := []ecs.TaskDefinition_HostEntry{}
for _, h := range hosts {
host := h
e = append(e, &ecs.HostEntry{
Hostname: &host,
parts := strings.SplitN(h, ":", 2) // FIXME this should be handled by compose-go
e = append(e, ecs.TaskDefinition_HostEntry{
Hostname: parts[0],
IpAddress: parts[1],
})
}
return e
}
func toKeyValuePairPtr(environment types.MappingWithEquals) []*ecs.KeyValuePair {
func toKeyValuePair(environment types.MappingWithEquals) []ecs.TaskDefinition_KeyValuePair {
if environment == nil || len(environment) == 0 {
return nil
}
pairs := []*ecs.KeyValuePair{}
pairs := []ecs.TaskDefinition_KeyValuePair{}
for k, v := range environment {
name := k
value := v
pairs = append(pairs, &ecs.KeyValuePair{
Name: &name,
var value string
if v != nil {
value = *v
}
pairs = append(pairs, ecs.TaskDefinition_KeyValuePair{
Name: name,
Value: value,
})
}
return pairs
}
func toStringPtr(s string) *string {
if s == "" {
return nil
}
return &s
}
func toStringPtrSlice(s []string) []*string {
if len(s) == 0 {
return nil
}
v := []*string{}
for _, x := range s {
value := x
v = append(v, &value)
}
return v
}
func toBoolPtr(b bool) *bool {
if !b {
return nil
}
return &b
}