Use `Project` from compose-go

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2020-06-17 14:48:42 +02:00
parent dcf84f2499
commit c5895fe09a
No known key found for this signature in database
GPG Key ID: 9858809D6F8F6E7E
25 changed files with 178 additions and 686 deletions

View File

@ -7,9 +7,10 @@ import (
"os"
"strings"
"github.com/compose-spec/compose-go/cli"
"github.com/compose-spec/compose-go/types"
"github.com/docker/cli/cli/command"
amazon "github.com/docker/ecs-plugin/pkg/amazon/backend"
"github.com/docker/ecs-plugin/pkg/compose"
"github.com/docker/ecs-plugin/pkg/docker"
"github.com/spf13/cobra"
)
@ -18,8 +19,8 @@ func ComposeCommand(dockerCli command.Cli) *cobra.Command {
cmd := &cobra.Command{
Use: "compose",
}
opts := &compose.ProjectOptions{}
opts.AddFlags(cmd.Flags())
opts := &cli.ProjectOptions{}
AddFlags(opts, cmd.Flags())
cmd.AddCommand(
ConvertCommand(dockerCli, opts),
@ -42,10 +43,10 @@ func (o upOptions) LoadBalancerArn() *string {
return &o.loadBalancerArn
}
func ConvertCommand(dockerCli command.Cli, projectOpts *compose.ProjectOptions) *cobra.Command {
func ConvertCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "convert",
RunE: compose.WithProject(projectOpts, func(project *compose.Project, args []string) error {
RunE: WithProject(projectOpts, func(project *types.Project, args []string) error {
clusteropts, err := docker.GetAwsContext(dockerCli)
if err != nil {
return err
@ -71,7 +72,7 @@ func ConvertCommand(dockerCli command.Cli, projectOpts *compose.ProjectOptions)
return cmd
}
func UpCommand(dockerCli command.Cli, projectOpts *compose.ProjectOptions) *cobra.Command {
func UpCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cobra.Command {
opts := upOptions{}
cmd := &cobra.Command{
Use: "up",
@ -87,11 +88,11 @@ func UpCommand(dockerCli command.Cli, projectOpts *compose.ProjectOptions) *cobr
return cmd
}
func PsCommand(dockerCli command.Cli, projectOpts *compose.ProjectOptions) *cobra.Command {
func PsCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cobra.Command {
opts := upOptions{}
cmd := &cobra.Command{
Use: "ps",
RunE: compose.WithProject(projectOpts, func(project *compose.Project, args []string) error {
RunE: WithProject(projectOpts, func(project *types.Project, args []string) error {
clusteropts, err := docker.GetAwsContext(dockerCli)
if err != nil {
return err
@ -120,7 +121,7 @@ type downOptions struct {
DeleteCluster bool
}
func DownCommand(dockerCli command.Cli, projectOpts *compose.ProjectOptions) *cobra.Command {
func DownCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cobra.Command {
opts := downOptions{}
cmd := &cobra.Command{
Use: "down",
@ -136,7 +137,7 @@ func DownCommand(dockerCli command.Cli, projectOpts *compose.ProjectOptions) *co
return cmd
}
func LogsCommand(dockerCli command.Cli, projectOpts *compose.ProjectOptions) *cobra.Command {
func LogsCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "logs [PROJECT NAME]",
RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, args []string) error {
@ -147,7 +148,7 @@ func LogsCommand(dockerCli command.Cli, projectOpts *compose.ProjectOptions) *co
var name string
if len(args) == 0 {
project, err := compose.ProjectFromOptions(projectOpts)
project, err := cli.ProjectFromOptions(projectOpts)
if err != nil {
return err
}

View File

@ -1,26 +1,23 @@
package compose
package commands
import (
"github.com/compose-spec/compose-go/cli"
"github.com/compose-spec/compose-go/types"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
type ProjectOptions struct {
ConfigPaths []string
Name string
}
func (o *ProjectOptions) AddFlags(flags *pflag.FlagSet) {
func AddFlags(o *cli.ProjectOptions, flags *pflag.FlagSet) {
flags.StringArrayVarP(&o.ConfigPaths, "file", "f", nil, "Specify an alternate compose file")
flags.StringVarP(&o.Name, "project-name", "n", "", "Specify an alternate project name (default: directory name)")
}
type ProjectFunc func(project *Project, args []string) error
type ProjectFunc func(project *types.Project, args []string) error
// WithProject wrap a ProjectFunc into a cobra command
func WithProject(options *ProjectOptions, f ProjectFunc) func(cmd *cobra.Command, args []string) error {
func WithProject(options *cli.ProjectOptions, f ProjectFunc) func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error {
project, err := ProjectFromOptions(options)
project, err := cli.ProjectFromOptions(options)
if err != nil {
return err
}

View File

@ -11,7 +11,7 @@ import (
"github.com/docker/cli/cli/command"
amazon "github.com/docker/ecs-plugin/pkg/amazon/backend"
"github.com/docker/ecs-plugin/pkg/amazon/types"
"github.com/docker/ecs-plugin/pkg/compose"
"github.com/docker/ecs-plugin/pkg/docker"
"github.com/spf13/cobra"
)
@ -57,7 +57,7 @@ func CreateSecret(dockerCli command.Cli) *cobra.Command {
}
name := args[0]
secret := types.NewSecret(name, opts.Username, opts.Password, opts.Description)
secret := compose.NewSecret(name, opts.Username, opts.Password, opts.Description)
id, err := backend.CreateSecret(context.Background(), secret)
fmt.Println(id)
return err
@ -140,7 +140,7 @@ func DeleteSecret(dockerCli command.Cli) *cobra.Command {
return cmd
}
func printList(out io.Writer, secrets []types.Secret) {
func printList(out io.Writer, secrets []compose.Secret) {
printSection(out, len(secrets), func(w io.Writer) {
for _, secret := range secrets {
fmt.Fprintf(w, "%s\t%s\t%s\n", secret.ID, secret.Name, secret.Description)

View File

@ -14,7 +14,7 @@ require (
github.com/bugsnag/panicwrap v1.2.0 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/cloudflare/cfssl v1.4.1 // indirect
github.com/compose-spec/compose-go v0.0.0-20200409090215-53c0040c9127
github.com/compose-spec/compose-go v0.0.0-20200622094647-0bb9a6c7d89a
github.com/containerd/containerd v1.3.2 // indirect
github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb // indirect
github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492
@ -35,11 +35,11 @@ require (
github.com/manifoldco/promptui v0.7.0
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
github.com/miekg/pkcs11 v1.0.3 // indirect
github.com/mitchellh/mapstructure v1.2.2
github.com/mitchellh/mapstructure v1.3.2
github.com/morikuni/aec v1.0.0 // indirect
github.com/onsi/ginkgo v1.11.0 // indirect
github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/sirupsen/logrus v1.5.0
github.com/sirupsen/logrus v1.6.0
github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/spf13/cobra v0.0.5
github.com/spf13/pflag v1.0.5
@ -52,7 +52,6 @@ require (
gopkg.in/fatih/pool.v2 v2.0.0 // indirect
gopkg.in/gorethink/gorethink.v3 v3.0.5 // indirect
gopkg.in/ini.v1 v1.55.0
gotest.tools v2.2.0+incompatible
gotest.tools/v3 v3.0.2
vbom.ml/util v0.0.0-20180919145318-efcd4e0f9787 // indirect
)

View File

@ -54,8 +54,12 @@ 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-20200409090215-53c0040c9127 h1:mAsQN3s19glh3KBOQjiRYBhqaX1SdzNqhB3/cuqgSbE=
github.com/compose-spec/compose-go v0.0.0-20200409090215-53c0040c9127/go.mod h1:1PUpzRF1O/65VOqXZuwpCuYY7pJxbIq1jbAvAf62FGM=
github.com/compose-spec/compose-go v0.0.0-20200616184722-5b8dc203fd7f h1:XE6hHZdPjxN8uGaRlvdCB8YwXbz1PXnQ0CboNygdL2o=
github.com/compose-spec/compose-go v0.0.0-20200616184722-5b8dc203fd7f/go.mod h1:d3Vb4tH01Pr4YKD3RvfwguRcezDBUYJTVYgpCSRYSVg=
github.com/compose-spec/compose-go v0.0.0-20200617133919-fca3bb55c5cc h1:jZfF+HzxW+c8Em308MvcK7j5+ZqIAWqFjN1RZnVFzck=
github.com/compose-spec/compose-go v0.0.0-20200617133919-fca3bb55c5cc/go.mod h1:d3Vb4tH01Pr4YKD3RvfwguRcezDBUYJTVYgpCSRYSVg=
github.com/compose-spec/compose-go v0.0.0-20200622094647-0bb9a6c7d89a h1:FmEuebUePUA0Kd/NSiCmdPG/n6eKdZdBtIbfejVtRS8=
github.com/compose-spec/compose-go v0.0.0-20200622094647-0bb9a6c7d89a/go.mod h1:ih9anT8po+49hrb+1j3ldIJ/YRAaBH52ErlQLTKE2Yo=
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=
github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
@ -134,9 +138,12 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE=
github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@ -151,6 +158,7 @@ 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 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
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=
@ -183,6 +191,8 @@ github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49/go.mod h1:yyMNCy
github.com/kisom/goutils v1.1.0/go.mod h1:+UBTfd78habUYWFbNWTJNG+jNG/i/lGURakr4A/yNRw=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@ -218,8 +228,8 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg=
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
@ -282,8 +292,8 @@ github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvH
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.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
@ -330,6 +340,7 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2
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 h1:yhqBHs09SmmUoNOHc9jgK4a60T3XFRtPAkYxVnqgY50=
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=
@ -450,6 +461,8 @@ 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=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/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.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E=

View File

@ -5,14 +5,9 @@ import (
"regexp"
"strings"
"github.com/compose-spec/compose-go/types"
"github.com/sirupsen/logrus"
ecsapi "github.com/aws/aws-sdk-go/service/ecs"
"github.com/aws/aws-sdk-go/service/elbv2"
cloudmapapi "github.com/aws/aws-sdk-go/service/servicediscovery"
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"
@ -21,10 +16,11 @@ import (
"github.com/awslabs/goformation/v4/cloudformation/logs"
cloudmap "github.com/awslabs/goformation/v4/cloudformation/servicediscovery"
"github.com/awslabs/goformation/v4/cloudformation/tags"
"github.com/docker/ecs-plugin/pkg/amazon/compatibility"
"github.com/compose-spec/compose-go/compatibility"
"github.com/compose-spec/compose-go/types"
sdk "github.com/docker/ecs-plugin/pkg/amazon/sdk"
btypes "github.com/docker/ecs-plugin/pkg/amazon/types"
"github.com/docker/ecs-plugin/pkg/compose"
"github.com/sirupsen/logrus"
)
const (
@ -35,11 +31,38 @@ const (
ParameterLoadBalancerARN = "ParameterLoadBalancerARN"
)
type FargateCompatibilityChecker struct {
*compatibility.AllowList
}
// Convert a compose project into a CloudFormation template
func (b Backend) Convert(project *compose.Project) (*cloudformation.Template, error) {
warnings := compatibility.Check(project)
for _, w := range warnings {
logrus.Warn(w)
func (b Backend) Convert(project *types.Project) (*cloudformation.Template, error) {
var checker compatibility.Checker = FargateCompatibilityChecker{
&compatibility.AllowList{
Supported: []string{
"services.command",
"services.container_name",
"services.depends_on",
"services.entrypoint",
"services.environment",
"services.healthcheck",
"services.healthcheck.interval",
"services.healthcheck.start_period",
"services.healthcheck.test",
"services.healthcheck.timeout",
"services.networks",
"services.ports",
"services.ports.mode",
"services.ports.target",
"services.ports.protocol",
"services.user",
"services.working_dir",
},
},
}
compatibility.Check(project, checker)
for _, err := range checker.Errors() {
logrus.Warn(err.Error())
}
template := cloudformation.NewTemplate()
@ -188,7 +211,7 @@ func (b Backend) Convert(project *compose.Project) (*cloudformation.Template, er
return template, nil
}
func getLoadBalancerType(project *compose.Project) string {
func getLoadBalancerType(project *types.Project) string {
for _, service := range project.Services {
for _, port := range service.Ports {
if port.Published != 80 && port.Published != 443 {
@ -199,7 +222,7 @@ func getLoadBalancerType(project *compose.Project) string {
return elbv2.LoadBalancerTypeEnumApplication
}
func getLoadBalancerSecurityGroups(project *compose.Project, template *cloudformation.Template) []string {
func getLoadBalancerSecurityGroups(project *types.Project, template *cloudformation.Template) []string {
securityGroups := []string{}
for _, network := range project.Networks {
if !network.Internal {
@ -210,7 +233,7 @@ func getLoadBalancerSecurityGroups(project *compose.Project, template *cloudform
return uniqueStrings(securityGroups)
}
func createLoadBalancer(project *compose.Project, template *cloudformation.Template) string {
func createLoadBalancer(project *types.Project, template *cloudformation.Template) string {
loadBalancerName := fmt.Sprintf("%sLoadBalancer", strings.Title(project.Name))
// Create LoadBalancer if `ParameterLoadBalancerName` is not set
template.Conditions["CreateLoadBalancer"] = cloudformation.Equals("", cloudformation.Ref(ParameterLoadBalancerARN))
@ -270,7 +293,7 @@ func createListener(service types.ServiceConfig, port types.ServicePortConfig, t
return listenerName
}
func createTargetGroup(project *compose.Project, service types.ServiceConfig, port types.ServicePortConfig, template *cloudformation.Template, protocol string) string {
func createTargetGroup(project *types.Project, service types.ServiceConfig, port types.ServicePortConfig, template *cloudformation.Template, protocol string) string {
targetGroupName := fmt.Sprintf(
"%s%s%dTargetGroup",
normalizeResourceName(service.Name),
@ -345,7 +368,7 @@ func createTaskExecutionRole(service types.ServiceConfig, err error, definition
return taskExecutionRole, nil
}
func createCluster(project *compose.Project, template *cloudformation.Template) string {
func createCluster(project *types.Project, template *cloudformation.Template) string {
template.Resources["Cluster"] = &ecs.Cluster{
ClusterName: project.Name,
Tags: []tags.Tag{
@ -360,7 +383,7 @@ func createCluster(project *compose.Project, template *cloudformation.Template)
return cluster
}
func createCloudMap(project *compose.Project, template *cloudformation.Template) {
func createCloudMap(project *types.Project, template *cloudformation.Template) {
template.Resources["CloudMap"] = &cloudmap.PrivateDnsNamespace{
Description: fmt.Sprintf("Service Map for Docker Compose project %s", project.Name),
Name: fmt.Sprintf("%s.local", project.Name),
@ -368,8 +391,8 @@ func createCloudMap(project *compose.Project, template *cloudformation.Template)
}
}
func convertNetwork(project *compose.Project, net types.NetworkConfig, vpc string, template *cloudformation.Template) string {
if sg, ok := net.Extras[btypes.ExtensionSecurityGroup]; ok {
func convertNetwork(project *types.Project, net types.NetworkConfig, vpc string, template *cloudformation.Template) string {
if sg, ok := net.Extensions[compose.ExtensionSecurityGroup]; ok {
logrus.Debugf("Security Group for network %q set by user to %q", net.Name, sg)
return sg.(string)
}
@ -420,7 +443,7 @@ func convertNetwork(project *compose.Project, net types.NetworkConfig, vpc strin
return cloudformation.Ref(securityGroup)
}
func networkResourceName(project *compose.Project, network string) string {
func networkResourceName(project *types.Project, network string) string {
return fmt.Sprintf("%s%sNetwork", normalizeResourceName(project.Name), normalizeResourceName(network))
}

View File

@ -7,13 +7,11 @@ import (
"github.com/aws/aws-sdk-go/service/elbv2"
"github.com/awslabs/goformation/v4/cloudformation"
"github.com/awslabs/goformation/v4/cloudformation/ec2"
"github.com/awslabs/goformation/v4/cloudformation/iam"
"github.com/awslabs/goformation/v4/cloudformation/elasticloadbalancingv2"
"github.com/awslabs/goformation/v4/cloudformation/iam"
"github.com/compose-spec/compose-go/cli"
"github.com/compose-spec/compose-go/loader"
"github.com/compose-spec/compose-go/types"
"github.com/docker/ecs-plugin/pkg/compose"
"gotest.tools/v3/assert"
"gotest.tools/v3/golden"
)
@ -58,6 +56,10 @@ version: "3"
services:
test:
image: hello_world
networks:
- front-tier
- back-tier
networks:
front-tier:
name: public
@ -103,7 +105,7 @@ services:
assert.Check(t, lb.Type == elbv2.LoadBalancerTypeEnumNetwork)
}
func convertResultAsString(t *testing.T, project *compose.Project, clusterName string) string {
func convertResultAsString(t *testing.T, project *types.Project, clusterName string) string {
client, err := NewBackend("", clusterName, "")
assert.NilError(t, err)
result, err := client.Convert(project)
@ -113,12 +115,12 @@ func convertResultAsString(t *testing.T, project *compose.Project, clusterName s
return fmt.Sprintf("%s\n", string(resultAsJSON))
}
func load(t *testing.T, paths ...string) *compose.Project {
options := compose.ProjectOptions{
func load(t *testing.T, paths ...string) *types.Project {
options := cli.ProjectOptions{
Name: t.Name(),
ConfigPaths: paths,
}
project, err := compose.ProjectFromOptions(&options)
project, err := cli.ProjectFromOptions(&options)
assert.NilError(t, err)
return project
}
@ -130,14 +132,11 @@ func convertYaml(t *testing.T, yaml string) *cloudformation.Template {
ConfigFiles: []types.ConfigFile{
{Config: dict},
},
}, func(options *loader.Options) {
options.Name = "Test"
})
assert.NilError(t, err)
err = compose.Normalize(model)
assert.NilError(t, err)
template, err := Backend{}.Convert(&compose.Project{
Config: *model,
Name: "test",
})
template, err := Backend{}.Convert(model)
assert.NilError(t, err)
return template
}

View File

@ -3,14 +3,14 @@ package backend
import (
"context"
"github.com/docker/ecs-plugin/pkg/amazon/types"
"github.com/compose-spec/compose-go/cli"
"github.com/docker/ecs-plugin/pkg/compose"
)
func (b *Backend) Down(ctx context.Context, options compose.ProjectOptions) error {
func (b *Backend) Down(ctx context.Context, options cli.ProjectOptions) error {
name := options.Name
if name == "" {
project, err := compose.ProjectFromOptions(&options)
project, err := cli.ProjectFromOptions(&options)
if err != nil {
return err
}
@ -22,7 +22,7 @@ func (b *Backend) Down(ctx context.Context, options compose.ProjectOptions) erro
return err
}
err = b.WaitStackCompletion(ctx, name, types.StackDelete)
err = b.WaitStackCompletion(ctx, name, compose.StackDelete)
if err != nil {
return err
}

View File

@ -4,8 +4,8 @@ import (
"context"
"testing"
"github.com/compose-spec/compose-go/cli"
"github.com/docker/ecs-plugin/pkg/amazon/sdk"
btypes "github.com/docker/ecs-plugin/pkg/amazon/types"
"github.com/docker/ecs-plugin/pkg/compose"
"github.com/golang/mock/gomock"
)
@ -23,10 +23,10 @@ func TestDown(t *testing.T) {
recorder := m.EXPECT()
recorder.DeleteStack(ctx, "test_project").Return(nil)
recorder.GetStackID(ctx, "test_project").Return("stack-123", nil)
recorder.WaitStackComplete(ctx, "stack-123", btypes.StackDelete).Return(nil)
recorder.WaitStackComplete(ctx, "stack-123", compose.StackDelete).Return(nil)
recorder.DescribeStackEvents(ctx, "stack-123").Return(nil, nil)
c.Down(ctx, compose.ProjectOptions{
c.Down(ctx, cli.ProjectOptions{
ConfigPaths: []string{},
Name: "test_project",
})

View File

@ -6,11 +6,11 @@ import (
"sort"
"strings"
"github.com/docker/ecs-plugin/pkg/amazon/types"
"github.com/compose-spec/compose-go/types"
"github.com/docker/ecs-plugin/pkg/compose"
)
func (b *Backend) Ps(ctx context.Context, project *compose.Project) ([]types.TaskStatus, error) {
func (b *Backend) Ps(ctx context.Context, project *types.Project) ([]compose.TaskStatus, error) {
cluster := b.Cluster
if cluster == "" {
cluster = project.Name
@ -19,17 +19,17 @@ func (b *Backend) Ps(ctx context.Context, project *compose.Project) ([]types.Tas
for _, service := range project.Services {
tasks, err := b.api.ListTasks(ctx, cluster, service.Name)
if err != nil {
return []types.TaskStatus{}, err
return []compose.TaskStatus{}, err
}
arns = append(arns, tasks...)
}
if len(arns) == 0 {
return []types.TaskStatus{}, nil
return []compose.TaskStatus{}, nil
}
tasks, err := b.api.DescribeTasks(ctx, cluster, arns...)
if err != nil {
return []types.TaskStatus{}, err
return []compose.TaskStatus{}, err
}
networkInterfaces := []string{}
@ -40,21 +40,21 @@ func (b *Backend) Ps(ctx context.Context, project *compose.Project) ([]types.Tas
}
publicIps, err := b.api.GetPublicIPs(ctx, networkInterfaces...)
if err != nil {
return []types.TaskStatus{}, err
return []compose.TaskStatus{}, err
}
sort.Slice(tasks, func(i, j int) bool {
return strings.Compare(tasks[i].Service, tasks[j].Service) < 0
})
for i, t := range tasks {
for i, task := range tasks {
ports := []string{}
s, err := project.GetService(t.Service)
s, err := project.GetService(task.Service)
if err != nil {
return []types.TaskStatus{}, err
return []compose.TaskStatus{}, err
}
for _, p := range s.Ports {
ports = append(ports, fmt.Sprintf("%s:%d->%d/%s", publicIps[t.NetworkInterface], p.Published, p.Target, p.Protocol))
ports = append(ports, fmt.Sprintf("%s:%d->%d/%s", publicIps[task.NetworkInterface], p.Published, p.Target, p.Protocol))
}
tasks[i].Name = s.Name
tasks[i].Ports = ports

View File

@ -3,18 +3,18 @@ package backend
import (
"context"
"github.com/docker/ecs-plugin/pkg/amazon/types"
"github.com/docker/ecs-plugin/pkg/compose"
)
func (b Backend) CreateSecret(ctx context.Context, secret types.Secret) (string, error) {
func (b Backend) CreateSecret(ctx context.Context, secret compose.Secret) (string, error) {
return b.api.CreateSecret(ctx, secret)
}
func (b Backend) InspectSecret(ctx context.Context, id string) (types.Secret, error) {
func (b Backend) InspectSecret(ctx context.Context, id string) (compose.Secret, error) {
return b.api.InspectSecret(ctx, id)
}
func (b Backend) ListSecrets(ctx context.Context) ([]types.Secret, error) {
func (b Backend) ListSecrets(ctx context.Context) ([]compose.Secret, error) {
return b.api.ListSecrets(ctx)
}

View File

@ -4,12 +4,13 @@ import (
"context"
"fmt"
"github.com/docker/ecs-plugin/pkg/amazon/types"
"github.com/compose-spec/compose-go/cli"
"github.com/compose-spec/compose-go/types"
"github.com/docker/ecs-plugin/pkg/compose"
)
func (b *Backend) Up(ctx context.Context, options compose.ProjectOptions) error {
project, err := compose.ProjectFromOptions(&options)
func (b *Backend) Up(ctx context.Context, options cli.ProjectOptions) error {
project, err := cli.ProjectFromOptions(&options)
if err != nil {
return err
}
@ -66,12 +67,12 @@ func (b *Backend) Up(ctx context.Context, options compose.ProjectOptions) error
}
fmt.Println()
return b.WaitStackCompletion(ctx, project.Name, types.StackCreate)
return b.WaitStackCompletion(ctx, project.Name, compose.StackCreate)
}
func (b Backend) GetVPC(ctx context.Context, project *compose.Project) (string, error) {
func (b Backend) GetVPC(ctx context.Context, project *types.Project) (string, error) {
//check compose file for custom VPC selected
if vpc, ok := project.Extras[types.ExtensionVPC]; ok {
if vpc, ok := project.Extensions[compose.ExtensionVPC]; ok {
vpcID := vpc.(string)
ok, err := b.api.VpcExists(ctx, vpcID)
if err != nil {
@ -88,9 +89,9 @@ func (b Backend) GetVPC(ctx context.Context, project *compose.Project) (string,
return defaultVPC, nil
}
func (b Backend) GetLoadBalancer(ctx context.Context, project *compose.Project) (string, error) {
func (b Backend) GetLoadBalancer(ctx context.Context, project *types.Project) (string, error) {
//check compose file for custom VPC selected
if lb, ok := project.Extras[types.ExtensionLB]; ok {
if lb, ok := project.Extensions[compose.ExtensionLB]; ok {
lbName := lb.(string)
ok, err := b.api.LoadBalancerExists(ctx, lbName)
if err != nil {

View File

@ -1,41 +0,0 @@
package compatibility
import (
"github.com/compose-spec/compose-go/types"
"github.com/docker/ecs-plugin/pkg/compose"
)
type Warning string
type Warnings []string
type Checker interface {
CheckService(service *types.ServiceConfig)
CheckCapAdd(service *types.ServiceConfig)
CheckDNS(service *types.ServiceConfig)
CheckDNSOpts(service *types.ServiceConfig)
CheckDNSSearch(service *types.ServiceConfig)
CheckDomainName(service *types.ServiceConfig)
CheckExtraHosts(service *types.ServiceConfig)
CheckHostname(service *types.ServiceConfig)
CheckIpc(service *types.ServiceConfig)
CheckLabels(service *types.ServiceConfig)
CheckLinks(service *types.ServiceConfig)
CheckLogging(service *types.ServiceConfig)
CheckMacAddress(service *types.ServiceConfig)
CheckNetworkMode(service *types.ServiceConfig)
CheckPid(service *types.ServiceConfig)
CheckSysctls(service *types.ServiceConfig)
CheckTmpfs(service *types.ServiceConfig)
CheckUserNSMode(service *types.ServiceConfig)
Errors() []error
}
// Check the compose model do not use unsupported features and inject sane defaults for ECS deployment
func Check(project *compose.Project) []error {
c := FargateCompatibilityChecker{}
for i, service := range project.Services {
c.CheckService(&service)
project.Services[i] = service
}
return c.errors
}

View File

@ -1,23 +0,0 @@
package compatibility
import (
"testing"
"github.com/docker/ecs-plugin/pkg/compose"
"gotest.tools/v3/assert"
)
func load(t *testing.T, paths ...string) *compose.Project {
options := compose.ProjectOptions{
Name: t.Name(),
ConfigPaths: paths,
}
project, err := compose.ProjectFromOptions(&options)
assert.NilError(t, err)
return project
}
func TestInvalidNetworkMode(t *testing.T) {
project := load(t, "../backend/testdata/invalid_network_mode.yaml")
err := Check(project)
assert.Error(t, err[0], "'network_mode' \"bridge\" is not supported")
}

View File

@ -1,171 +0,0 @@
package compatibility
import (
"fmt"
"github.com/aws/aws-sdk-go/service/ecs"
"github.com/compose-spec/compose-go/types"
)
type FargateCompatibilityChecker struct {
errors []error
}
func (c *FargateCompatibilityChecker) error(message string, args ...interface{}) {
c.errors = append(c.errors, fmt.Errorf(message, args...))
}
func (c *FargateCompatibilityChecker) Errors() []error {
return c.errors
}
func (c *FargateCompatibilityChecker) CheckService(service *types.ServiceConfig) {
c.CheckCapAdd(service)
c.CheckDNS(service)
c.CheckDNSOpts(service)
c.CheckDNSSearch(service)
c.CheckDomainName(service)
c.CheckExtraHosts(service)
c.CheckHostname(service)
c.CheckIpc(service)
c.CheckLabels(service)
c.CheckLinks(service)
c.CheckLogging(service)
c.CheckMacAddress(service)
c.CheckNetworkMode(service)
c.CheckPid(service)
c.CheckSysctls(service)
c.CheckTmpfs(service)
c.CheckUserNSMode(service)
}
func (c *FargateCompatibilityChecker) CheckNetworkMode(service *types.ServiceConfig) {
if service.NetworkMode != "" && service.NetworkMode != ecs.NetworkModeAwsvpc {
c.error("'network_mode' %q is not supported", service.NetworkMode)
}
service.NetworkMode = ecs.NetworkModeAwsvpc
}
func (c *FargateCompatibilityChecker) CheckLinks(service *types.ServiceConfig) {
if len(service.Links) != 0 {
c.error("'links' is not supported")
service.Links = nil
}
}
func (c *FargateCompatibilityChecker) CheckLogging(service *types.ServiceConfig) {
c.CheckLoggingDriver(service)
}
func (c *FargateCompatibilityChecker) CheckLoggingDriver(service *types.ServiceConfig) {
if service.LogDriver != "" && service.LogDriver != ecs.LogDriverAwslogs {
c.error("'log_driver' %q is not supported", service.LogDriver)
service.LogDriver = ecs.LogDriverAwslogs
}
}
func (c *FargateCompatibilityChecker) CheckPid(service *types.ServiceConfig) {
if service.Pid != "" {
c.error("'pid' is not supported")
service.Pid = ""
}
}
func (c *FargateCompatibilityChecker) CheckUserNSMode(service *types.ServiceConfig) {
if service.UserNSMode != "" {
c.error("'userns_mode' is not supported")
service.UserNSMode = ""
}
}
func (c *FargateCompatibilityChecker) CheckIpc(service *types.ServiceConfig) {
if service.Ipc != "" {
c.error("'ipc' is not supported")
service.Ipc = ""
}
}
func (c *FargateCompatibilityChecker) CheckMacAddress(service *types.ServiceConfig) {
if service.MacAddress != "" {
c.error("'mac_address' is not supported")
service.MacAddress = ""
}
}
func (c *FargateCompatibilityChecker) CheckHostname(service *types.ServiceConfig) {
if service.Hostname != "" {
c.error("'hostname' is not supported")
service.Hostname = ""
}
}
func (c *FargateCompatibilityChecker) CheckDomainName(service *types.ServiceConfig) {
if service.DomainName != "" {
c.error("'domainname' is not supported")
service.DomainName = ""
}
}
func (c *FargateCompatibilityChecker) CheckDNSSearch(service *types.ServiceConfig) {
if len(service.DNSSearch) > 0 {
c.error("'dns_search' is not supported")
service.DNSSearch = nil
}
}
func (c *FargateCompatibilityChecker) CheckDNS(service *types.ServiceConfig) {
if len(service.DNS) > 0 {
c.error("'dns' is not supported")
service.DNS = nil
}
}
func (c *FargateCompatibilityChecker) CheckDNSOpts(service *types.ServiceConfig) {
if len(service.DNSOpts) > 0 {
c.error("'dns_opt' is not supported")
service.DNSOpts = nil
}
}
func (c *FargateCompatibilityChecker) CheckExtraHosts(service *types.ServiceConfig) {
if len(service.ExtraHosts) > 0 {
c.error("'extra_hosts' is not supported")
service.ExtraHosts = nil
}
}
func (c *FargateCompatibilityChecker) CheckCapAdd(service *types.ServiceConfig) {
for i, v := range service.CapAdd {
if v != "SYS_PTRACE" {
c.error("'cap_add' %s is not supported", v)
l := len(service.CapAdd)
service.CapAdd[i] = service.CapAdd[l-1]
service.CapAdd = service.CapAdd[:l-1]
}
}
}
func (c *FargateCompatibilityChecker) CheckTmpfs(service *types.ServiceConfig) {
if len(service.Tmpfs) > 0 {
c.error("'tmpfs' is not supported")
service.Tmpfs = nil
}
}
func (c *FargateCompatibilityChecker) CheckSysctls(service *types.ServiceConfig) {
if len(service.Sysctls) > 0 {
c.error("'sysctls' is not supported")
service.Sysctls = nil
}
}
func (c *FargateCompatibilityChecker) CheckLabels(service *types.ServiceConfig) {
for k, v := range service.Labels {
if v == "" {
c.error("'labels' with an empty value is not supported")
delete(service.Labels, k)
}
}
}
var _ Checker = &FargateCompatibilityChecker{}

View File

@ -5,7 +5,7 @@ import (
cf "github.com/aws/aws-sdk-go/service/cloudformation"
"github.com/awslabs/goformation/v4/cloudformation"
"github.com/docker/ecs-plugin/pkg/amazon/types"
"github.com/docker/ecs-plugin/pkg/compose"
)
//go:generate mockgen -destination=./api_mock.go -self_package "github.com/docker/ecs-plugin/pkg/amazon" -package=amazon . API
@ -38,19 +38,19 @@ type downAPI interface {
}
type logsAPI interface {
GetLogs(ctx context.Context, name string, consumer types.LogConsumer) error
GetLogs(ctx context.Context, name string, consumer compose.LogConsumer) error
}
type secretsAPI interface {
CreateSecret(ctx context.Context, secret types.Secret) (string, error)
InspectSecret(ctx context.Context, id string) (types.Secret, error)
ListSecrets(ctx context.Context) ([]types.Secret, error)
CreateSecret(ctx context.Context, secret compose.Secret) (string, error)
InspectSecret(ctx context.Context, id string) (compose.Secret, error)
ListSecrets(ctx context.Context) ([]compose.Secret, error)
DeleteSecret(ctx context.Context, id string, recover bool) error
}
type listAPI interface {
ListTasks(ctx context.Context, cluster string, name string) ([]string, error)
DescribeTasks(ctx context.Context, cluster string, arns ...string) ([]types.TaskStatus, error)
DescribeTasks(ctx context.Context, cluster string, arns ...string) ([]compose.TaskStatus, error)
GetPublicIPs(ctx context.Context, interfaces ...string) (map[string]string, error)
}

View File

@ -8,9 +8,10 @@ import (
context "context"
reflect "reflect"
"github.com/docker/ecs-plugin/pkg/compose"
cloudformation "github.com/aws/aws-sdk-go/service/cloudformation"
cloudformation0 "github.com/awslabs/goformation/v4/cloudformation"
btypes "github.com/docker/ecs-plugin/pkg/amazon/types"
gomock "github.com/golang/mock/gomock"
)
@ -53,7 +54,7 @@ func (mr *MockAPIMockRecorder) ClusterExists(arg0, arg1 interface{}) *gomock.Cal
}
// CreateSecret mocks base method
func (m *MockAPI) CreateSecret(arg0 context.Context, arg1 btypes.Secret) (string, error) {
func (m *MockAPI) CreateSecret(arg0 context.Context, arg1 compose.Secret) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CreateSecret", arg0, arg1)
ret0, _ := ret[0].(string)
@ -139,14 +140,14 @@ func (mr *MockAPIMockRecorder) DescribeStackEvents(arg0, arg1 interface{}) *gomo
}
// DescribeTasks mocks base method
func (m *MockAPI) DescribeTasks(arg0 context.Context, arg1 string, arg2 ...string) ([]btypes.TaskStatus, error) {
func (m *MockAPI) DescribeTasks(arg0 context.Context, arg1 string, arg2 ...string) ([]compose.TaskStatus, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "DescribeTasks", varargs...)
ret0, _ := ret[0].([]btypes.TaskStatus)
ret0, _ := ret[0].([]compose.TaskStatus)
ret1, _ := ret[1].(error)
return ret0, ret1
}
@ -174,7 +175,7 @@ func (mr *MockAPIMockRecorder) GetDefaultVPC(arg0 interface{}) *gomock.Call {
}
// GetLogs mocks base method
func (m *MockAPI) GetLogs(arg0 context.Context, arg1 string, arg2 btypes.LogConsumer) error {
func (m *MockAPI) GetLogs(arg0 context.Context, arg1 string, arg2 compose.LogConsumer) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetLogs", arg0, arg1, arg2)
ret0, _ := ret[0].(error)
@ -238,10 +239,10 @@ func (mr *MockAPIMockRecorder) GetSubNets(arg0, arg1 interface{}) *gomock.Call {
}
// InspectSecret mocks base method
func (m *MockAPI) InspectSecret(arg0 context.Context, arg1 string) (btypes.Secret, error) {
func (m *MockAPI) InspectSecret(arg0 context.Context, arg1 string) (compose.Secret, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "InspectSecret", arg0, arg1)
ret0, _ := ret[0].(btypes.Secret)
ret0, _ := ret[0].(compose.Secret)
ret1, _ := ret[1].(error)
return ret0, ret1
}
@ -253,10 +254,10 @@ func (mr *MockAPIMockRecorder) InspectSecret(arg0, arg1 interface{}) *gomock.Cal
}
// ListSecrets mocks base method
func (m *MockAPI) ListSecrets(arg0 context.Context) ([]btypes.Secret, error) {
func (m *MockAPI) ListSecrets(arg0 context.Context) ([]compose.Secret, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListSecrets", arg0)
ret0, _ := ret[0].([]btypes.Secret)
ret0, _ := ret[0].([]compose.Secret)
ret1, _ := ret[1].(error)
return ret0, ret1
}

View File

@ -13,11 +13,10 @@ import (
"github.com/awslabs/goformation/v4/cloudformation/tags"
"github.com/compose-spec/compose-go/types"
"github.com/docker/cli/opts"
t "github.com/docker/ecs-plugin/pkg/amazon/types"
"github.com/docker/ecs-plugin/pkg/compose"
)
func Convert(project *compose.Project, service types.ServiceConfig) (*ecs.TaskDefinition, error) {
func Convert(project *types.Project, service types.ServiceConfig) (*ecs.TaskDefinition, error) {
cpu, mem, err := toLimits(service)
if err != nil {
return nil, err
@ -318,8 +317,8 @@ func getImage(image string) string {
func getRepoCredentials(service types.ServiceConfig) *ecs.TaskDefinition_RepositoryCredentials {
// extract registry and namespace string from image name
for key, value := range service.Extras {
if key == t.ExtensionPullCredentials {
for key, value := range service.Extensions {
if key == compose.ExtensionPullCredentials {
return &ecs.TaskDefinition_RepositoryCredentials{CredentialsParameter: value.(string)}
}
}

View File

@ -23,10 +23,8 @@ import (
"github.com/aws/aws-sdk-go/service/secretsmanager"
"github.com/aws/aws-sdk-go/service/secretsmanager/secretsmanageriface"
cf "github.com/awslabs/goformation/v4/cloudformation"
"github.com/docker/ecs-plugin/pkg/compose"
"github.com/sirupsen/logrus"
"github.com/docker/ecs-plugin/pkg/amazon/types"
t "github.com/docker/ecs-plugin/pkg/amazon/types"
)
type sdk struct {
@ -189,9 +187,9 @@ func (s sdk) WaitStackComplete(ctx context.Context, name string, operation int)
StackName: aws.String(name),
}
switch operation {
case t.StackCreate:
case compose.StackCreate:
return s.CF.WaitUntilStackCreateCompleteWithContext(ctx, input)
case t.StackDelete:
case compose.StackDelete:
return s.CF.WaitUntilStackDeleteCompleteWithContext(ctx, input)
default:
return fmt.Errorf("internal error: unexpected stack operation %d", operation)
@ -236,7 +234,7 @@ func (s sdk) DeleteStack(ctx context.Context, name string) error {
return err
}
func (s sdk) CreateSecret(ctx context.Context, secret t.Secret) (string, error) {
func (s sdk) CreateSecret(ctx context.Context, secret compose.Secret) (string, error) {
logrus.Debug("Create secret " + secret.Name)
secretStr, err := secret.GetCredString()
if err != nil {
@ -254,17 +252,17 @@ func (s sdk) CreateSecret(ctx context.Context, secret t.Secret) (string, error)
return *response.ARN, nil
}
func (s sdk) InspectSecret(ctx context.Context, id string) (t.Secret, error) {
func (s sdk) InspectSecret(ctx context.Context, id string) (compose.Secret, error) {
logrus.Debug("Inspect secret " + id)
response, err := s.SM.DescribeSecret(&secretsmanager.DescribeSecretInput{SecretId: &id})
if err != nil {
return t.Secret{}, err
return compose.Secret{}, err
}
labels := map[string]string{}
for _, tag := range response.Tags {
labels[*tag.Key] = *tag.Value
}
secret := t.Secret{
secret := compose.Secret{
ID: *response.ARN,
Name: *response.Name,
Labels: labels,
@ -275,14 +273,14 @@ func (s sdk) InspectSecret(ctx context.Context, id string) (t.Secret, error) {
return secret, nil
}
func (s sdk) ListSecrets(ctx context.Context) ([]t.Secret, error) {
func (s sdk) ListSecrets(ctx context.Context) ([]compose.Secret, error) {
logrus.Debug("List secrets ...")
response, err := s.SM.ListSecrets(&secretsmanager.ListSecretsInput{})
if err != nil {
return []t.Secret{}, err
return []compose.Secret{}, err
}
var secrets []t.Secret
var secrets []compose.Secret
for _, sec := range response.SecretList {
@ -294,7 +292,7 @@ func (s sdk) ListSecrets(ctx context.Context) ([]t.Secret, error) {
if sec.Description != nil {
description = *sec.Description
}
secrets = append(secrets, t.Secret{
secrets = append(secrets, compose.Secret{
ID: *sec.ARN,
Name: *sec.Name,
Labels: labels,
@ -311,7 +309,7 @@ func (s sdk) DeleteSecret(ctx context.Context, id string, recover bool) error {
return err
}
func (s sdk) GetLogs(ctx context.Context, name string, consumer types.LogConsumer) error {
func (s sdk) GetLogs(ctx context.Context, name string, consumer compose.LogConsumer) error {
logGroup := fmt.Sprintf("/docker-compose/%s", name)
var startTime int64
for {
@ -357,7 +355,7 @@ func (s sdk) ListTasks(ctx context.Context, cluster string, service string) ([]s
return arns, nil
}
func (s sdk) DescribeTasks(ctx context.Context, cluster string, arns ...string) ([]t.TaskStatus, error) {
func (s sdk) DescribeTasks(ctx context.Context, cluster string, arns ...string) ([]compose.TaskStatus, error) {
tasks, err := s.ECS.DescribeTasksWithContext(ctx, &ecs.DescribeTasksInput{
Cluster: aws.String(cluster),
Tasks: aws.StringSlice(arns),
@ -365,7 +363,7 @@ func (s sdk) DescribeTasks(ctx context.Context, cluster string, arns ...string)
if err != nil {
return nil, err
}
result := []t.TaskStatus{}
result := []compose.TaskStatus{}
for _, task := range tasks.Tasks {
var networkInterface string
for _, attachement := range task.Attachments {
@ -377,7 +375,7 @@ func (s sdk) DescribeTasks(ctx context.Context, cluster string, arns ...string)
}
}
}
result = append(result, t.TaskStatus{
result = append(result, compose.TaskStatus{
State: *task.LastStatus,
Service: strings.Replace(*task.Group, "service:", "", 1),
NetworkInterface: networkInterface,

View File

@ -4,19 +4,20 @@ import (
"context"
"github.com/awslabs/goformation/v4/cloudformation"
"github.com/docker/ecs-plugin/pkg/amazon/types"
"github.com/compose-spec/compose-go/cli"
"github.com/compose-spec/compose-go/types"
)
type API interface {
Up(ctx context.Context, options ProjectOptions) error
Down(ctx context.Context, options ProjectOptions) error
Up(ctx context.Context, options cli.ProjectOptions) error
Down(ctx context.Context, options cli.ProjectOptions) error
Convert(project *Project) (*cloudformation.Template, error)
Convert(project *types.Project) (*cloudformation.Template, error)
Logs(ctx context.Context, projectName string) error
Ps(background context.Context, project *Project) ([]types.TaskStatus, error)
Ps(background context.Context, project *types.Project) ([]TaskStatus, error)
CreateSecret(ctx context.Context, secret types.Secret) (string, error)
InspectSecret(ctx context.Context, id string) (types.Secret, error)
ListSecrets(ctx context.Context) ([]types.Secret, error)
CreateSecret(ctx context.Context, secret Secret) (string, error)
InspectSecret(ctx context.Context, id string) (Secret, error)
ListSecrets(ctx context.Context) ([]Secret, error)
DeleteSecret(ctx context.Context, id string, recover bool) error
}

View File

@ -1,89 +0,0 @@
package compose
import (
"fmt"
"github.com/compose-spec/compose-go/types"
"github.com/sirupsen/logrus"
)
// Normalize a compose-go model to move deprecated attributes to canonical position, and introduce implicit defaults
// FIXME move this to compose-go
func Normalize(model *types.Config) error {
if len(model.Networks) == 0 {
// Compose application model implies a default network if none is explicitly set.
model.Networks["default"] = types.NetworkConfig{
Name: "default",
}
}
for i, s := range model.Services {
if len(s.Networks) == 0 {
// Service without explicit network attachment are implicitly exposed on default network
s.Networks = map[string]*types.ServiceNetworkConfig{"default": nil}
}
for i, p := range s.Ports {
if p.Published == 0 {
p.Published = p.Target
s.Ports[i] = p
}
}
if s.LogDriver != "" {
logrus.Warn("`log_driver` is deprecated. Use the `logging` attribute")
if s.Logging == nil {
s.Logging = &types.LoggingConfig{}
}
if s.Logging.Driver == "" {
s.Logging.Driver = s.LogDriver
} else {
return fmt.Errorf("can't use both 'log_driver' (deprecated) and 'logging.driver'")
}
}
if len(s.LogOpt) != 0 {
logrus.Warn("`log_opts` is deprecated. Use the `logging` attribute")
if s.Logging == nil {
s.Logging = &types.LoggingConfig{}
}
for k, v := range s.LogOpt {
if _, ok := s.Logging.Options[k]; !ok {
s.Logging.Options[k] = v
} else {
return fmt.Errorf("can't use both 'log_opt' (deprecated) and 'logging.options'")
}
}
}
model.Services[i] = s
}
for i, n := range model.Networks {
if n.Name == "" {
n.Name = i
model.Networks[i] = n
}
}
for i, v := range model.Volumes {
if v.Name == "" {
v.Name = i
model.Volumes[i] = v
}
}
for i, c := range model.Configs {
if c.Name == "" {
c.Name = i
model.Configs[i] = c
}
}
for i, s := range model.Secrets {
if s.Name == "" {
s.Name = i
model.Secrets[i] = s
}
}
return nil
}

View File

@ -1,170 +0,0 @@
package compose
import (
"fmt"
"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 {
types.Config
projectDir string
Name string `yaml:"-" json:"-"`
}
func NewProject(config types.ConfigDetails, name string) (*Project, error) {
model, err := loader.Load(config)
if err != nil {
return nil, err
}
err = Normalize(model)
if err != nil {
return nil, err
}
p := Project{
Config: *model,
projectDir: config.WorkingDir,
Name: name,
}
return &p, nil
}
// projectFromOptions load a compose project based on command line options
func ProjectFromOptions(options *ProjectOptions) (*Project, error) {
configPath, err := getConfigPathFromOptions(options)
if err != nil {
return nil, err
}
name := options.Name
if name == "" {
name = os.Getenv("COMPOSE_PROJECT_NAME")
}
workingDir := filepath.Dir(configPath[0])
if name == "" {
r := regexp.MustCompile(`[^a-z0-9\\-_]+`)
name = r.ReplaceAllString(strings.ToLower(filepath.Base(workingDir)), "")
}
configs, err := parseConfigs(configPath)
if err != nil {
return nil, err
}
return NewProject(types.ConfigDetails{
WorkingDir: workingDir,
ConfigFiles: configs,
Environment: environment(),
}, name)
}
func getConfigPathFromOptions(options *ProjectOptions) ([]string, error) {
paths := []string{}
pwd, err := os.Getwd()
if err != nil {
return nil, err
}
if len(options.ConfigPaths) != 0 {
for _, f := range options.ConfigPaths {
if f == "-" {
paths = append(paths, f)
continue
}
if !filepath.IsAbs(f) {
f = filepath.Join(pwd, f)
}
if _, err := os.Stat(f); err != nil {
return nil, err
}
paths = append(paths, f)
}
return paths, nil
}
sep := os.Getenv("COMPOSE_FILE_SEPARATOR")
if sep == "" {
sep = string(os.PathListSeparator)
}
f := os.Getenv("COMPOSE_FILE")
if f != "" {
return strings.Split(f, sep), nil
}
for {
candidates := []string{}
for _, n := range SupportedFilenames {
f := filepath.Join(pwd, n)
if _, err := os.Stat(f); err == nil {
candidates = append(candidates, f)
}
}
if len(candidates) > 0 {
winner := candidates[0]
if len(candidates) > 1 {
logrus.Warnf("Found multiple config files with supported names: %s", strings.Join(candidates, ", "))
logrus.Warnf("Using %s\n", winner)
}
return []string{winner}, nil
}
parent := filepath.Dir(pwd)
if parent == pwd {
return nil, fmt.Errorf("Can't find a suitable configuration file in this directory or any parent. Are you in the right directory?")
}
pwd = parent
}
}
var SupportedFilenames = []string{"compose.yaml", "compose.yml", "docker-compose.yml", "docker-compose.yaml"}
func parseConfigs(configPaths []string) ([]types.ConfigFile, error) {
files := []types.ConfigFile{}
for _, f := range configPaths {
var (
b []byte
err error
)
if f == "-" {
b, err = ioutil.ReadAll(os.Stdin)
} else {
if _, err := os.Stat(f); err != nil {
return nil, err
}
b, err = ioutil.ReadFile(f)
}
if err != nil {
return nil, err
}
config, err := loader.ParseYAML(b)
if err != nil {
return nil, err
}
files = append(files, types.ConfigFile{Filename: f, Config: config})
}
return files, nil
}
func environment() map[string]string {
return getAsEqualsMap(os.Environ())
}
// getAsEqualsMap split key=value formatted strings into a key : value map
func getAsEqualsMap(em []string) map[string]string {
m := make(map[string]string)
for _, v := range em {
kv := strings.SplitN(v, "=", 2)
m[kv[0]] = kv[1]
}
return m
}

View File

@ -1,46 +0,0 @@
package compose
import (
"os"
"testing"
"gotest.tools/v3/assert"
)
func Test_project_name(t *testing.T) {
p, err := ProjectFromOptions(&ProjectOptions{
Name: "my_project",
ConfigPaths: []string{"testdata/simple/compose.yaml"},
})
assert.NilError(t, err)
assert.Equal(t, p.Name, "my_project")
p, err = ProjectFromOptions(&ProjectOptions{
Name: "",
ConfigPaths: []string{"testdata/simple/compose.yaml"},
})
assert.NilError(t, err)
assert.Equal(t, p.Name, "simple")
os.Setenv("COMPOSE_PROJECT_NAME", "my_project_from_env")
p, err = ProjectFromOptions(&ProjectOptions{
Name: "",
ConfigPaths: []string{"testdata/simple/compose.yaml"},
})
assert.NilError(t, err)
assert.Equal(t, p.Name, "my_project_from_env")
}
func Test_project_from_set_of_files(t *testing.T) {
p, err := ProjectFromOptions(&ProjectOptions{
Name: "my_project",
ConfigPaths: []string{
"testdata/simple/compose.yaml",
"testdata/simple/compose-with-overrides.yaml",
},
})
assert.NilError(t, err)
service, err := p.GetService("simple")
assert.NilError(t, err)
assert.Equal(t, service.Image, "haproxy")
}

View File

@ -1,4 +1,4 @@
package types
package compose
import "encoding/json"

View File

@ -1,4 +1,4 @@
package types
package compose
const (
ExtensionSecurityGroup = "x-aws-securitygroup"