From 9a6fe86a86bab70f2f051236230cef6662c045c1 Mon Sep 17 00:00:00 2001
From: Nicolas De Loof <nicolas.deloof@gmail.com>
Date: Tue, 5 May 2020 13:50:57 +0200
Subject: [PATCH] Introduce "Validate" phase to check/make app ECS-compliant

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
---
 ecs/README.md                          | 36 ++++++++++++++++----------
 ecs/pkg/amazon/cloudformation.go       |  3 +--
 ecs/pkg/{convert => amazon}/convert.go | 20 +-------------
 ecs/pkg/amazon/up.go                   |  5 ++++
 ecs/pkg/amazon/validate.go             | 20 ++++++++++++++
 5 files changed, 50 insertions(+), 34 deletions(-)
 rename ecs/pkg/{convert => amazon}/convert.go (97%)
 create mode 100644 ecs/pkg/amazon/validate.go

diff --git a/ecs/README.md b/ecs/README.md
index 9ec4ab694..f15fd25f5 100644
--- a/ecs/README.md
+++ b/ecs/README.md
@@ -11,21 +11,31 @@ template, which will create all resources in dependent order and cleanup on
 `down` command or deployment failure.
 
 ```
-  +-----------------------------+
-  | compose.yaml file           |
-  +-----------------------------+
+  +--------------------------------------+
+  | compose.yaml file                    |
+  +--------------------------------------+
 - Load
-  +-----------------------------+
-  | compose-go Model            |
-  +-----------------------------+
+  +--------------------------------------+
+  | compose Model                        |
+  +--------------------------------------+
+- Validate
+  +--------------------------------------+
+  | compose Model suitable for ECS       |
+  +--------------------------------------+
 - Convert
-  +-----------------------------+
-  | CloudFormation Template     |
-  +-----------------------------+
+  +--------------------------------------+
+  | CloudFormation Template              |
+  +--------------------------------------+
 - Apply
-  +---------+      +------------+  
-  | AWS API |  or  | stack file |
-  +---------+      +------------+
+  +--------------+      +----------------+  
+  | AWS API      |  or  | stack file     |
+  +--------------+      +----------------+
 ```
 
-(if this sounds familiar, see [Kompose](https://github.com/kubernetes/kompose/blob/master/docs/architecture.md))
\ No newline at end of file
+* _Load_ phase relies on [compose-go](https://github.com/compose-spec/compose-go). Any generic code we write for this 
+purpose should be proposed upstream.
+* _Validate_ phase is responsible to inject sane ECS defaults into the compose-go model, and validate the `compose.yaml` 
+file do not include unsupported features.
+* _Convert_ produces a CloudFormation template to define all resources required to implement the application model on AWS.
+* _Apply_ phase do apply the CloudFormation template, either by exporting to a stack file or to deploy on AWS.  
+
diff --git a/ecs/pkg/amazon/cloudformation.go b/ecs/pkg/amazon/cloudformation.go
index c805e099c..76aa80887 100644
--- a/ecs/pkg/amazon/cloudformation.go
+++ b/ecs/pkg/amazon/cloudformation.go
@@ -14,7 +14,6 @@ import (
 	"github.com/awslabs/goformation/v4/cloudformation/ecs"
 	"github.com/awslabs/goformation/v4/cloudformation/iam"
 	"github.com/docker/ecs-plugin/pkg/compose"
-	"github.com/docker/ecs-plugin/pkg/convert"
 )
 
 func (c client) Convert(ctx context.Context, project *compose.Project) (*cloudformation.Template, error) {
@@ -56,7 +55,7 @@ func (c client) Convert(ctx context.Context, project *compose.Project) (*cloudfo
 	}
 
 	for _, service := range project.Services {
-		definition, err := convert.Convert(project, service)
+		definition, err := Convert(project, service)
 		if err != nil {
 			return nil, err
 		}
diff --git a/ecs/pkg/convert/convert.go b/ecs/pkg/amazon/convert.go
similarity index 97%
rename from ecs/pkg/convert/convert.go
rename to ecs/pkg/amazon/convert.go
index 8b70a6488..a0bd9e423 100644
--- a/ecs/pkg/convert/convert.go
+++ b/ecs/pkg/amazon/convert.go
@@ -1,4 +1,4 @@
-package convert
+package amazon
 
 import (
 	"strings"
@@ -174,16 +174,6 @@ func toUlimits(ulimits map[string]*types.UlimitsConfig) []ecs.TaskDefinition_Uli
 	return u
 }
 
-func uint32Toint64Ptr(i uint32) *int64 {
-	v := int64(i)
-	return &v
-}
-
-func intToInt64Ptr(i int) *int64 {
-	v := int64(i)
-	return &v
-}
-
 const Mb = 1024 * 1024
 
 func toMemoryLimits(deploy *types.DeployConfig) int {
@@ -265,14 +255,6 @@ func toHealthCheck(check *types.HealthCheckConfig) *ecs.TaskDefinition_HealthChe
 	}
 }
 
-func uint64ToInt64Ptr(i *uint64) *int64 {
-	if i == nil {
-		return nil
-	}
-	v := int64(*i)
-	return &v
-}
-
 func durationToInt(interval *types.Duration) int {
 	if interval == nil {
 		return 0
diff --git a/ecs/pkg/amazon/up.go b/ecs/pkg/amazon/up.go
index 459f95d52..21adf9733 100644
--- a/ecs/pkg/amazon/up.go
+++ b/ecs/pkg/amazon/up.go
@@ -24,6 +24,11 @@ func (c *client) ComposeUp(ctx context.Context, project *compose.Project) error
 		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(ctx, project)
 	if err != nil {
 		return err
diff --git a/ecs/pkg/amazon/validate.go b/ecs/pkg/amazon/validate.go
new file mode 100644
index 000000000..5e61a273d
--- /dev/null
+++ b/ecs/pkg/amazon/validate.go
@@ -0,0 +1,20 @@
+package amazon
+
+import (
+	"github.com/compose-spec/compose-go/types"
+	"github.com/docker/ecs-plugin/pkg/compose"
+)
+
+// 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 {
+	if len(project.Networks) == 0 {
+		// Compose application model implies a default network if none is explicitly set.
+		// FIXME move this to compose-go
+		project.Networks["default"] = types.NetworkConfig{
+			Name: "default",
+		}
+	}
+
+	// Here we can check for incompatible attributes, inject sane defaults, etc
+	return nil
+}