From b151d92a93cb7157ea1f3c5103dd32b06290bf3b Mon Sep 17 00:00:00 2001 From: Edward Viaene Date: Wed, 18 Sep 2019 10:58:28 +0200 Subject: [PATCH] retries --- provider/ecs/appmesh.go | 113 ++++++++++++++++++++++++++++++++++++++-- provider/ecs/ecs.go | 47 +++++++++++------ service/deploy.go | 1 + terraform/ecs-deploy.tf | 4 ++ 4 files changed, 145 insertions(+), 20 deletions(-) diff --git a/provider/ecs/appmesh.go b/provider/ecs/appmesh.go index 6d4a920..b6aa965 100644 --- a/provider/ecs/appmesh.go +++ b/provider/ecs/appmesh.go @@ -94,11 +94,22 @@ func (a *AppMesh) listVirtualRouters(meshName string) (map[string]string, error) return result, nil } -func (a *AppMesh) createVirtualNodeName(virtualNodeName, virtualNodeDNS, meshName string, servicePort int64, healthcheck AppMeshHealthCheck) error { +func (a *AppMesh) createVirtualNode(virtualNodeName, virtualNodeDNS, meshName string, servicePort int64, healthcheck AppMeshHealthCheck, backends []string) error { + var appmeshBackends []*appmesh.Backend + + for _, backend := range backends { + appmeshBackends = append(appmeshBackends, &appmesh.Backend{ + VirtualService: &appmesh.VirtualServiceBackend{ + VirtualServiceName: aws.String(backend), + }, + }) + } + svc := appmesh.New(session.New()) input := &appmesh.CreateVirtualNodeInput{ MeshName: aws.String(meshName), Spec: &appmesh.VirtualNodeSpec{ + Backends: appmeshBackends, Listeners: []*appmesh.Listener{ { HealthCheck: &appmesh.HealthCheckPolicy{ @@ -133,7 +144,57 @@ func (a *AppMesh) createVirtualNodeName(virtualNodeName, virtualNodeDNS, meshNam return nil } -func (a *AppMesh) createVirtualService(virtualServiceName, virtualNodeName, meshName string) error { +func (a *AppMesh) updateVirtualNode(virtualNodeName, virtualNodeDNS, meshName string, servicePort int64, healthcheck AppMeshHealthCheck, backends []string) error { + var appmeshBackends []*appmesh.Backend + + for _, backend := range backends { + appmeshBackends = append(appmeshBackends, &appmesh.Backend{ + VirtualService: &appmesh.VirtualServiceBackend{ + VirtualServiceName: aws.String(backend), + }, + }) + } + + svc := appmesh.New(session.New()) + input := &appmesh.UpdateVirtualNodeInput{ + MeshName: aws.String(meshName), + Spec: &appmesh.VirtualNodeSpec{ + Backends: appmeshBackends, + Listeners: []*appmesh.Listener{ + { + HealthCheck: &appmesh.HealthCheckPolicy{ + HealthyThreshold: aws.Int64(healthcheck.HealthyThreshold), + IntervalMillis: aws.Int64(healthcheck.IntervalMillis), + Path: aws.String(healthcheck.Path), + Port: aws.Int64(healthcheck.Port), + Protocol: aws.String(healthcheck.Protocol), + TimeoutMillis: aws.Int64(healthcheck.TimeoutMillis), + UnhealthyThreshold: aws.Int64(healthcheck.UnhealthyThreshold), + }, + PortMapping: &appmesh.PortMapping{ + Port: aws.Int64(servicePort), + Protocol: aws.String("http"), + }, + }, + }, + ServiceDiscovery: &appmesh.ServiceDiscovery{ + Dns: &appmesh.DnsServiceDiscovery{ + Hostname: aws.String(virtualNodeDNS), + }, + }, + }, + VirtualNodeName: aws.String(virtualNodeName), + } + + _, err := svc.UpdateVirtualNode(input) + if err != nil { + return err + } + + return nil +} + +func (a *AppMesh) createVirtualServiceWithVirtualNode(virtualServiceName, virtualNodeName, meshName string) error { svc := appmesh.New(session.New()) input := &appmesh.CreateVirtualServiceInput{ MeshName: aws.String(meshName), @@ -155,6 +216,50 @@ func (a *AppMesh) createVirtualService(virtualServiceName, virtualNodeName, mesh return nil } +func (a *AppMesh) createVirtualServiceWithVirtualRouter(virtualServiceName, virtualRouterName, meshName string) error { + svc := appmesh.New(session.New()) + input := &appmesh.CreateVirtualServiceInput{ + MeshName: aws.String(meshName), + Spec: &appmesh.VirtualServiceSpec{ + Provider: &appmesh.VirtualServiceProvider{ + VirtualRouter: &appmesh.VirtualRouterServiceProvider{ + VirtualRouterName: aws.String(virtualRouterName), + }, + }, + }, + VirtualServiceName: aws.String(virtualServiceName), + } + + _, err := svc.CreateVirtualService(input) + if err != nil { + return err + } + + return nil +} + +func (a *AppMesh) updateVirtualServiceWithVirtualRouter(virtualServiceName, virtualRouterName, meshName string) error { + svc := appmesh.New(session.New()) + input := &appmesh.UpdateVirtualServiceInput{ + MeshName: aws.String(meshName), + Spec: &appmesh.VirtualServiceSpec{ + Provider: &appmesh.VirtualServiceProvider{ + VirtualRouter: &appmesh.VirtualRouterServiceProvider{ + VirtualRouterName: aws.String(virtualRouterName), + }, + }, + }, + VirtualServiceName: aws.String(virtualServiceName), + } + + _, err := svc.UpdateVirtualService(input) + if err != nil { + return err + } + + return nil +} + func (a *AppMesh) createVirtualRouter(virtualRouterName string, meshName string, servicePort int64) error { svc := appmesh.New(session.New()) input := &appmesh.CreateVirtualRouterInput{ @@ -192,14 +297,14 @@ func (a *AppMesh) createRoute(routeName, virtualRouterName, virtualNodeName, hos HttpRoute: &appmesh.HttpRoute{ Match: &appmesh.HttpRouteMatch{ Prefix: aws.String("/"), - Headers: []*appmesh.HttpRouteHeader{ + /*Headers: []*appmesh.HttpRouteHeader{ { Name: aws.String("Host"), Match: &appmesh.HeaderMatchMethod{ Exact: aws.String(hostname), }, }, - }, + },*/ }, Action: &appmesh.HttpRouteAction{ WeightedTargets: []*appmesh.WeightedTarget{ diff --git a/provider/ecs/ecs.go b/provider/ecs/ecs.go index cd621f7..bffc8dc 100644 --- a/provider/ecs/ecs.go +++ b/provider/ecs/ecs.go @@ -534,31 +534,29 @@ func (e *ECS) CreateTaskDefinitionInput(d service.Deploy, secrets map[string]str virtualNodeDNS := strings.ToLower(d.ServiceName + "." + d.ServiceRegistry) virtualServiceName := strings.ToLower(d.ServiceName + "." + d.ServiceRegistry) - // create virtual node if it doesn't exist yet + // list virtual nodes and services virtualNodes, err := a.listVirtualNodes(d.AppMesh.Name) if err != nil { return err } + virtualServices, err := a.listVirtualServices(d.AppMesh.Name) + if err != nil { + return err + } + // get healthcheck object + healthCheck, err := e.prepareAppMeshHealthcheck(d.HealthCheck, d.ServicePort, d.ServiceProtocol) + if err != nil { + return err + } + + // create virtual node if it doesn't exist yet if _, ok := virtualNodes[virtualNodeName]; !ok { - // get healthcheck object - healthCheck, err := e.prepareAppMeshHealthcheck(d.HealthCheck, d.ServicePort, d.ServiceProtocol) - if err != nil { - return err - } - if err := a.createVirtualNodeName(virtualNodeName, virtualNodeDNS, d.AppMesh.Name, d.ServicePort, healthCheck); err != nil { + if err := a.createVirtualNode(virtualNodeName, virtualNodeDNS, d.AppMesh.Name, d.ServicePort, healthCheck, d.AppMesh.Backends); err != nil { return err } } else { // update - } - - // create virtual service if it doesn't exist yet - virtualServices, err := a.listVirtualServices(d.AppMesh.Name) - if err != nil { - return err - } - if _, ok := virtualServices[virtualServiceName]; !ok { - if err := a.createVirtualService(virtualServiceName, virtualNodeName, d.AppMesh.Name); err != nil { + if err := a.updateVirtualNode(virtualNodeName, virtualNodeDNS, d.AppMesh.Name, d.ServicePort, healthCheck, d.AppMesh.Backends); err != nil { return err } } @@ -578,6 +576,23 @@ func (e *ECS) CreateTaskDefinitionInput(d service.Deploy, secrets map[string]str return err } } + // create virtual service if it doesn't exist yet, or update existing with new virtualRouter + if _, ok := virtualServices[virtualServiceName]; !ok { + if err := a.createVirtualServiceWithVirtualRouter(virtualServiceName, virtualRouterName, d.AppMesh.Name); err != nil { + return err + } + } else { + if err := a.updateVirtualServiceWithVirtualRouter(virtualServiceName, virtualRouterName, d.AppMesh.Name); err != nil { + return err + } + } + } else { + // create virtual service if it doesn't exist yet + if _, ok := virtualServices[virtualServiceName]; !ok { + if err := a.createVirtualServiceWithVirtualNode(virtualServiceName, virtualNodeName, d.AppMesh.Name); err != nil { + return err + } + } } proxyConfiguration := &ecs.ProxyConfiguration{ diff --git a/service/deploy.go b/service/deploy.go index 258297f..649fb96 100644 --- a/service/deploy.go +++ b/service/deploy.go @@ -255,6 +255,7 @@ type LoadBalancer struct { type DeployAppMesh struct { Name string `json:"name" yaml:"name"` + Backends []string `json:"backends" yaml:"backends"` RetryPolicy DeployAppMeshRetryPolicy `json:"retryPolicy" yaml:"retryPolicy"` } diff --git a/terraform/ecs-deploy.tf b/terraform/ecs-deploy.tf index 64c00c6..9a00d63 100644 --- a/terraform/ecs-deploy.tf +++ b/terraform/ecs-deploy.tf @@ -158,6 +158,10 @@ resource "aws_iam_role_policy" "ecs-deploy-policy" { "appmesh:CreateVirtualService", "appmesh:CreateVirtualRouter", "appmesh:CreateRoute", + "appmesh:UpdateVirtualNode", + "appmesh:UpdateVirtualService", + "appmesh:UpdateVirtualRouter", + "appmesh:UpdateRoute", "appmesh:ListVirtualNodes", "appmesh:ListVirtualServices", "appmesh:ListVirtualNodes",