Reject compose file with unsupported features

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2020-05-18 10:53:07 +02:00
parent 8cd4a6fe9b
commit ae4dc2e0db
No known key found for this signature in database
GPG Key ID: 9858809D6F8F6E7E
6 changed files with 50 additions and 30 deletions

View File

@ -26,6 +26,11 @@ const (
// Convert a compose project into a CloudFormation template // Convert a compose project into a CloudFormation template
func (c client) Convert(project *compose.Project) (*cloudformation.Template, error) { func (c client) Convert(project *compose.Project) (*cloudformation.Template, error) {
err := Validate(project)
if err != nil {
return nil, err
}
template := cloudformation.NewTemplate() template := cloudformation.NewTemplate()
template.Parameters[ParameterClusterName] = cloudformation.Parameter{ template.Parameters[ParameterClusterName] = cloudformation.Parameter{

View File

@ -4,46 +4,42 @@ import (
"fmt" "fmt"
"testing" "testing"
"gotest.tools/assert"
"github.com/docker/ecs-plugin/pkg/compose" "github.com/docker/ecs-plugin/pkg/compose"
"gotest.tools/v3/golden" "gotest.tools/v3/golden"
) )
func TestSimpleConvert(t *testing.T) { func TestSimpleConvert(t *testing.T) {
options := compose.ProjectOptions{ project := load(t, "testdata/input/simple-single-service.yaml")
Name: t.Name(), result := convertResultAsString(t, project, "TestCluster")
ConfigPaths: []string{"testdata/input/simple-single-service.yaml"},
}
result := convertResultAsString(t, options, "TestCluster")
expected := "simple/simple-cloudformation-conversion.golden" expected := "simple/simple-cloudformation-conversion.golden"
golden.Assert(t, result, expected) golden.Assert(t, result, expected)
} }
func TestSimpleWithOverrides(t *testing.T) { func TestSimpleWithOverrides(t *testing.T) {
options := compose.ProjectOptions{ project := load(t, "testdata/input/simple-single-service.yaml", "testdata/input/simple-single-service-with-overrides.yaml")
Name: t.Name(), result := convertResultAsString(t, project, "TestCluster")
ConfigPaths: []string{"testdata/input/simple-single-service.yaml", "testdata/input/simple-single-service-with-overrides.yaml"},
}
result := convertResultAsString(t, options, "TestCluster")
expected := "simple/simple-cloudformation-with-overrides-conversion.golden" expected := "simple/simple-cloudformation-with-overrides-conversion.golden"
golden.Assert(t, result, expected) golden.Assert(t, result, expected)
} }
func convertResultAsString(t *testing.T, options compose.ProjectOptions, clusterName string) string { func convertResultAsString(t *testing.T, project *compose.Project, clusterName string) string {
project, err := compose.ProjectFromOptions(&options)
if err != nil {
t.Error(err)
}
client, err := NewClient("", clusterName, "") client, err := NewClient("", clusterName, "")
if err != nil { assert.NilError(t, err)
t.Error(err)
}
result, err := client.Convert(project) result, err := client.Convert(project)
if err != nil { assert.NilError(t, err)
t.Error(err)
}
resultAsJSON, err := result.JSON() resultAsJSON, err := result.JSON()
if err != nil { assert.NilError(t, err)
t.Error(err)
}
return fmt.Sprintf("%s\n", string(resultAsJSON)) return fmt.Sprintf("%s\n", string(resultAsJSON))
} }
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
}

View File

@ -0,0 +1,5 @@
version: "3"
services:
simple:
image: nginx
network_mode: bridge

View File

@ -27,11 +27,6 @@ func (c *client) ComposeUp(ctx context.Context, project *compose.Project) error
return fmt.Errorf("we do not (yet) support updating an existing CloudFormation stack") return fmt.Errorf("we do not (yet) support updating an existing CloudFormation stack")
} }
err = c.Validate(project)
if err != nil {
return err
}
template, err := c.Convert(project) template, err := c.Convert(project)
if err != nil { if err != nil {
return err return err

View File

@ -1,12 +1,14 @@
package amazon package amazon
import ( import (
"fmt"
"github.com/compose-spec/compose-go/types" "github.com/compose-spec/compose-go/types"
"github.com/docker/ecs-plugin/pkg/compose" "github.com/docker/ecs-plugin/pkg/compose"
) )
// Validate check the compose model do not use unsupported features and inject sane defaults for ECS deployment // Validate check the compose model do not use unsupported features and inject sane defaults for ECS deployment
func (c *client) Validate(project *compose.Project) error { func Validate(project *compose.Project) error {
if len(project.Networks) == 0 { if len(project.Networks) == 0 {
// Compose application model implies a default network if none is explicitly set. // Compose application model implies a default network if none is explicitly set.
// FIXME move this to compose-go // FIXME move this to compose-go
@ -22,6 +24,10 @@ func (c *client) Validate(project *compose.Project) error {
service.Networks = map[string]*types.ServiceNetworkConfig{"default": nil} service.Networks = map[string]*types.ServiceNetworkConfig{"default": nil}
project.Services[i] = service project.Services[i] = service
} }
if service.NetworkMode != "" && service.NetworkMode != "awsvpc" {
return fmt.Errorf("ECS do not support NetworkMode %q", service.NetworkMode)
}
} }
// Here we can check for incompatible attributes, inject sane defaults, etc // Here we can check for incompatible attributes, inject sane defaults, etc

View File

@ -0,0 +1,13 @@
package amazon
import (
"testing"
"gotest.tools/assert"
)
func TestInvalidNetworkMode(t *testing.T) {
project := load(t, "testdata/invalid_network_mode.yaml")
err := Validate(project)
assert.Error(t, err, "ECS do not support NetworkMode \"bridge\"")
}