diff --git a/lib/deploy.go b/lib/deploy.go index f6ce141..3463e08 100644 --- a/lib/deploy.go +++ b/lib/deploy.go @@ -108,7 +108,7 @@ func deployService(ctx log.Interface, cluster, imageTag string, imageTags []stri RequiresCompatibilities: taskDefinition.Compatibilities, TaskRoleArn: taskDefinition.TaskRoleArn, Volumes: taskDefinition.Volumes, - Tags: describeTaskResult.Tags, + Tags: nilIfEmpty(describeTaskResult.Tags), }) if err != nil { ctx.WithError(err).Error("Can't register task definition") diff --git a/lib/run.go b/lib/run.go index aafc05c..feb3741 100644 --- a/lib/run.go +++ b/lib/run.go @@ -11,14 +11,14 @@ import ( // RunTask runs the specified one-off task in the cluster using the task definition func RunTask(profile, cluster, service, taskDefinitionName, imageTag string, imageTags []string, workDir, containerName, awslogGroup, launchType string, args []string) (exitCode int, err error) { ctx := log.WithFields(log.Fields{ - "task_definition": taskDefinitionName, - "launch_type": launchType, - }) + "task_definition": taskDefinitionName, + "launch_type": launchType, + }) err = makeSession(profile) if err != nil { return 1, err } - + svc := ecs.New(localSession) describeResult, err := svc.DescribeTaskDefinition(&ecs.DescribeTaskDefinitionInput{ @@ -68,7 +68,7 @@ func RunTask(profile, cluster, service, taskDefinitionName, imageTag string, ima RequiresCompatibilities: taskDefinition.Compatibilities, TaskRoleArn: taskDefinition.TaskRoleArn, Volumes: taskDefinition.Volumes, - Tags: describeResult.Tags, + Tags: nilIfEmpty(describeResult.Tags), }) if err != nil { ctx.WithError(err).Error("Can't register task definition") diff --git a/lib/runFargate.go b/lib/runFargate.go index 4c9b6ea..2d8a6d4 100644 --- a/lib/runFargate.go +++ b/lib/runFargate.go @@ -112,7 +112,7 @@ func RunFargate(profile, cluster, service, taskDefinitionName, imageTag string, RequiresCompatibilities: taskDefinition.Compatibilities, TaskRoleArn: taskDefinition.TaskRoleArn, Volumes: taskDefinition.Volumes, - Tags: describeResult.Tags, + Tags: nilIfEmpty(describeResult.Tags), }) if err != nil { ctx.WithError(err).Error("Can't register task definition") diff --git a/lib/util.go b/lib/util.go index b480667..5356fc2 100644 --- a/lib/util.go +++ b/lib/util.go @@ -179,3 +179,13 @@ func fetchSecurityGroupsByName(svc *ec2.EC2, securityGroupFilter string) ([]*str // Return the filtered list of security group IDs return securityGroups, nil } + +// nilIfEmpty returns nil when tags is empty so AWS doesn't reject the call with +// "Tags can not be empty" — the AWS API rejects an empty Tags list at the wire level; +// passing nil omits the field entirely. +func nilIfEmpty(tags []*ecs.Tag) []*ecs.Tag { + if len(tags) == 0 { + return nil + } + return tags +} diff --git a/lib/util_test.go b/lib/util_test.go index 68e4c22..d0b7ab6 100644 --- a/lib/util_test.go +++ b/lib/util_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ecs" ) var testdata = map[string]string{ @@ -11,6 +12,20 @@ var testdata = map[string]string{ "arn:aws:ecs:ap-southeast-2:208168611618:task/0c5027c6-7bbd-476b-a534-adaf56760ca9": "0c5027c6-7bbd-476b-a534-adaf56760ca9", // old format } +func TestNilIfEmpty(t *testing.T) { + if nilIfEmpty(nil) != nil { + t.Fatal("nil input should return nil") + } + if nilIfEmpty([]*ecs.Tag{}) != nil { + t.Fatal("empty slice should return nil") + } + tags := []*ecs.Tag{{Key: aws.String("env"), Value: aws.String("prod")}} + result := nilIfEmpty(tags) + if len(result) != 1 || aws.StringValue(result[0].Key) != "env" || aws.StringValue(result[0].Value) != "prod" { + t.Fatalf("non-empty slice should be returned unchanged, got %v", result) + } +} + func TestParseTaskUUID(t *testing.T) { for testArn, uuid := range testdata { if parsedUUID, err := parseTaskUUID(aws.String(testArn)); err != nil {