diff --git a/asg.go b/asg.go index 5020e98..9a3e9b7 100644 --- a/asg.go +++ b/asg.go @@ -8,7 +8,7 @@ import ( "github.com/aws/aws-sdk-go/service/autoscaling/autoscalingiface" "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ecs" - "github.com/cenkalti/backoff" + "github.com/cenkalti/backoff/v3" "log" "strings" "sync" diff --git a/asg_test.go b/asg_test.go index 9f6f330..c74b772 100644 --- a/asg_test.go +++ b/asg_test.go @@ -11,38 +11,38 @@ type mockAutoScalingClient struct { } func (m *mockAutoScalingClient) DescribeAutoScalingGroups(input *autoscaling.DescribeAutoScalingGroupsInput) (*autoscaling.DescribeAutoScalingGroupsOutput, error) { - name := "" + name := "" return &autoscaling.DescribeAutoScalingGroupsOutput{ - AutoScalingGroups: []*autoscaling.Group{ - &autoscaling.Group{ - Instances: []*autoscaling.Instance{ - // TODO - }, - LaunchConfigurationName: &name, - }, - }, - }, nil + AutoScalingGroups: []*autoscaling.Group{ + &autoscaling.Group{ + Instances: []*autoscaling.Instance{ + // TODO + }, + LaunchConfigurationName: &name, + }, + }, + }, nil } func TestListASGInstaces(t *testing.T) { instances, name, err := listASGInstaces(&mockAutoScalingClient{}, "") - if len(instances) != 0 { - t.Errorf("unexpected") - } - if *name != "" { - t.Errorf("unexpected") - } - if err != nil { - t.Errorf("unexpected") - } + if len(instances) != 0 { + t.Errorf("unexpected") + } + if *name != "" { + t.Errorf("unexpected") + } + if err != nil { + t.Errorf("unexpected") + } } func TestNeedReplacement(t *testing.T) { - name := "" + name := "" replace := needReplacement("", autoscaling.Instance{LaunchConfigurationName: &name}) - if replace { - t.Errorf("unexpected") - } + if replace { + t.Errorf("unexpected") + } } func TestFilterInstancesToReplace(t *testing.T) { diff --git a/cmd/enforce-aws-ecs-asg-launchconfig/main.go b/cmd/enforce-aws-ecs-asg-launchconfig/main.go index 4c873b8..62c78c2 100644 --- a/cmd/enforce-aws-ecs-asg-launchconfig/main.go +++ b/cmd/enforce-aws-ecs-asg-launchconfig/main.go @@ -8,7 +8,7 @@ import ( "github.com/aws/aws-sdk-go/service/autoscaling" "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ecs" - "github.com/cenkalti/backoff" + "github.com/cenkalti/backoff/v3" "log" ) diff --git a/cmd/update-aws-ecs-service/main.go b/cmd/update-aws-ecs-service/main.go index ff24797..dcab611 100644 --- a/cmd/update-aws-ecs-service/main.go +++ b/cmd/update-aws-ecs-service/main.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/ecs" - "github.com/cenkalti/backoff" + "github.com/cenkalti/backoff/v3" "log" "os" "strings" diff --git a/ecs-alter-service.go b/ecs-alter-service.go index 20a41b9..c5f3cf8 100644 --- a/ecs-alter-service.go +++ b/ecs-alter-service.go @@ -2,8 +2,9 @@ package awsecs import ( "errors" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ecs" - "github.com/cenkalti/backoff" + "github.com/cenkalti/backoff/v3" "log" ) @@ -26,7 +27,7 @@ func alterServiceOrValidatedRollBack(api ecs.ECS, cluster, service string, image return ErrPermanentNothingToRollback } log.Printf("attempt rollback %v", alterSvcErr) - rollback, err := api.UpdateService(&ecs.UpdateServiceInput{Cluster: oldsvc.ClusterArn, Service: oldsvc.ServiceName, TaskDefinition: oldsvc.TaskDefinition, DesiredCount: oldsvc.DesiredCount}) + rollback, err := api.UpdateService(&ecs.UpdateServiceInput{Cluster: oldsvc.ClusterArn, Service: oldsvc.ServiceName, TaskDefinition: oldsvc.TaskDefinition, DesiredCount: oldsvc.DesiredCount, ForceNewDeployment: aws.Bool(true)}) if err != nil { return err } diff --git a/ecs.go b/ecs.go index 95e4793..154e35b 100644 --- a/ecs.go +++ b/ecs.go @@ -1,11 +1,13 @@ package awsecs import ( + "encoding/json" "errors" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ecs" - "github.com/cenkalti/backoff" + "github.com/cenkalti/backoff/v3" "log" + "reflect" ) var ( @@ -27,56 +29,95 @@ var ( errNoPrimaryDeployment = backoff.Permanent(errors.New("no PRIMARY deployment")) ) -func copy(input ecs.TaskDefinition) ecs.RegisterTaskDefinitionInput { +func copyTd(input ecs.TaskDefinition, tags []*ecs.Tag) ecs.RegisterTaskDefinitionInput { + obj, err := json.Marshal(input) + if err != nil { + panic(err) + } + inputClone := ecs.TaskDefinition{} + err = json.Unmarshal(obj, &inputClone) + if err != nil { + panic(err) + } output := ecs.RegisterTaskDefinitionInput{} - output.ContainerDefinitions = input.ContainerDefinitions - output.Cpu = input.Cpu - output.ExecutionRoleArn = input.ExecutionRoleArn - output.Family = input.Family - output.IpcMode = input.IpcMode - output.Memory = input.Memory - output.NetworkMode = input.NetworkMode - output.PidMode = input.PidMode - output.PlacementConstraints = input.PlacementConstraints - output.RequiresCompatibilities = input.RequiresCompatibilities - output.TaskRoleArn = input.TaskRoleArn - output.Volumes = input.Volumes + output.ContainerDefinitions = inputClone.ContainerDefinitions + output.Cpu = inputClone.Cpu + output.ExecutionRoleArn = inputClone.ExecutionRoleArn + output.Family = inputClone.Family + // output.InferenceAccelerators // not supported by the current version of the SDK + output.IpcMode = inputClone.IpcMode + output.Memory = inputClone.Memory + output.NetworkMode = inputClone.NetworkMode + output.PidMode = inputClone.PidMode + output.PlacementConstraints = inputClone.PlacementConstraints + output.ProxyConfiguration = inputClone.ProxyConfiguration + output.RequiresCompatibilities = inputClone.RequiresCompatibilities + output.Tags = tags + output.TaskRoleArn = inputClone.TaskRoleArn + output.Volumes = inputClone.Volumes return output } func alterImages(copy ecs.RegisterTaskDefinitionInput, imageMap map[string]string) ecs.RegisterTaskDefinitionInput { + obj, err := json.Marshal(copy) + if err != nil { + panic(err) + } + copyClone := ecs.RegisterTaskDefinitionInput{} + err = json.Unmarshal(obj, ©Clone) + if err != nil { + panic(err) + } for name, image := range imageMap { - for _, containerDefinition := range copy.ContainerDefinitions { + for _, containerDefinition := range copyClone.ContainerDefinitions { if *containerDefinition.Name == name { containerDefinition.Image = aws.String(image) } } } - return copy + return copyClone } func alterEnvironments(copy ecs.RegisterTaskDefinitionInput, envMaps map[string]map[string]string) ecs.RegisterTaskDefinitionInput { + obj, err := json.Marshal(copy) + if err != nil { + panic(err) + } + copyClone := ecs.RegisterTaskDefinitionInput{} + err = json.Unmarshal(obj, ©Clone) + if err != nil { + panic(err) + } for name, envMap := range envMaps { - for i, containerDefinition := range copy.ContainerDefinitions { + for i, containerDefinition := range copyClone.ContainerDefinitions { if *containerDefinition.Name == name { - new := alterEnvironment(*containerDefinition, envMap) - copy.ContainerDefinitions[i] = &new + altered := alterEnvironment(*containerDefinition, envMap) + copyClone.ContainerDefinitions[i] = &altered } } } - return copy + return copyClone } func alterSecrets(copy ecs.RegisterTaskDefinitionInput, secretMaps map[string]map[string]string) ecs.RegisterTaskDefinitionInput { + obj, err := json.Marshal(copy) + if err != nil { + panic(err) + } + copyClone := ecs.RegisterTaskDefinitionInput{} + err = json.Unmarshal(obj, ©Clone) + if err != nil { + panic(err) + } for name, secretMap := range secretMaps { - for i, containerDefinition := range copy.ContainerDefinitions { + for i, containerDefinition := range copyClone.ContainerDefinitions { if *containerDefinition.Name == name { - new := alterSecret(*containerDefinition, secretMap) - copy.ContainerDefinitions[i] = &new + altered := alterSecret(*containerDefinition, secretMap) + copyClone.ContainerDefinitions[i] = &altered } } } - return copy + return copyClone } func alterEnvironment(copy ecs.ContainerDefinition, envMap map[string]string) ecs.ContainerDefinition { @@ -130,13 +171,28 @@ func copyTaskDef(api ecs.ECS, taskdef string, imageMap map[string]string, envMap if err != nil { return "", err } - copy := alterSecrets(alterEnvironments(alterImages(copy(*output.TaskDefinition), imageMap), envMaps), secretMaps) - new, err := api.RegisterTaskDefinition(©) - if err != nil { - return "", err + + asRegisterTaskDefinitionInput := copyTd(*output.TaskDefinition, output.Tags) + tdCopy := alterSecrets(alterEnvironments(alterImages(asRegisterTaskDefinitionInput, imageMap), envMaps), secretMaps) + + // if os.Getenv("DEBUG") == "YES" { + // out, _ := json.Marshal(asRegisterTaskDefinitionInput) + // fmt.Println(string(out)) + // out, _ = json.Marshal(tdCopy) + // fmt.Println(string(out)) + // panic("something") + // } + + if reflect.DeepEqual(asRegisterTaskDefinitionInput, tdCopy) { + return *output.TaskDefinition.TaskDefinitionArn, nil + } else { + tdNew, err := api.RegisterTaskDefinition(&tdCopy) + if err != nil { + return "", err + } + arn := tdNew.TaskDefinition.TaskDefinitionArn + return *arn, nil } - arn := new.TaskDefinition.TaskDefinitionArn - return *arn, nil } func alterService(api ecs.ECS, cluster, service string, imageMap map[string]string, envMaps map[string]map[string]string, secretMaps map[string]map[string]string, desiredCount *int64, taskdef string) (ecs.Service, ecs.Service, error) { @@ -156,7 +212,7 @@ func alterService(api ecs.ECS, cluster, service string, imageMap map[string]stri if desiredCount == nil { desiredCount = svc.DesiredCount } - updated, err := api.UpdateService(&ecs.UpdateServiceInput{Cluster: aws.String(cluster), Service: aws.String(service), TaskDefinition: aws.String(newTd), DesiredCount: desiredCount}) + updated, err := api.UpdateService(&ecs.UpdateServiceInput{Cluster: aws.String(cluster), Service: aws.String(service), TaskDefinition: aws.String(newTd), DesiredCount: desiredCount, ForceNewDeployment: aws.Bool(true)}) if err != nil { return *svc, ecs.Service{}, err } diff --git a/go.mod b/go.mod index ce2da22..7d5d7f4 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/Autodesk/go-awsecs -go 1.12 +go 1.13 require ( - github.com/aws/aws-sdk-go v1.19.24 - github.com/cenkalti/backoff v0.0.0-20190506075156-2146c9339422 + github.com/aws/aws-sdk-go v1.19.49 + github.com/cenkalti/backoff/v3 v3.0.0 ) diff --git a/go.sum b/go.sum index 5f2845a..737e31d 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,6 @@ -github.com/aws/aws-sdk-go v1.19.24 h1:qOIYaFxcFg07Vdn799ERpGiuUUIEi5MQ2vYib3CNMp4= -github.com/aws/aws-sdk-go v1.19.24/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/cenkalti/backoff v0.0.0-20190506075156-2146c9339422 h1:+FKjzBIdfBHYDvxCv+djmDJdes/AoDtg8gpcxowBlF8= -github.com/cenkalti/backoff v0.0.0-20190506075156-2146c9339422/go.mod h1:b6Nc7NRH5C4aCISLry0tLnTjcuTEvoiqcWDdsU0sOGM= +github.com/aws/aws-sdk-go v1.19.49 h1:GUlenK625g5iKrIiRcqRS/CvPMLc8kZRtMxXuXBhFx4= +github.com/aws/aws-sdk-go v1.19.49/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= +github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=