Skip to content

Commit 75e8909

Browse files
authored
Adds "--image_tags" flag to have better control over (#24)
container definition image tags rewrites. Fixes #23
1 parent 7e1eb87 commit 75e8909

File tree

6 files changed

+52
-38
lines changed

6 files changed

+52
-38
lines changed

cmd/deploy.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ If deployment failed, then rolls back to the previous stack definition.`,
4141
viper.GetString("profile"),
4242
viper.GetString("cluster"),
4343
viper.GetString("image_tag"),
44+
viper.GetStringSlice("image_tags"),
4445
viper.GetStringSlice("deploy.services"),
4546
)
4647
if err != nil {

cmd/root.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ func init() {
4848
rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "Show debug output")
4949
rootCmd.PersistentFlags().StringP("cluster", "c", "", "name of cluster (required)")
5050
rootCmd.PersistentFlags().StringP("profile", "p", "", "name of AWS profile to use, which is set in ~/.aws/config")
51-
rootCmd.PersistentFlags().StringP("image_tag", "", "", "Overrides the docker image tag")
51+
rootCmd.PersistentFlags().StringP("image_tag", "", "", "Overrides the docker image tag in all container definitions. Overrides \"--image-tags\" flag.")
52+
rootCmd.PersistentFlags().StringSliceP("image_tags", "", []string{}, "Modifies the docker image tags in container definitions. Can be specified several times, one for each container definition. Also takes comma-separated values in one tag. I.e. if there are 2 containers and --image-tags is set once to \"new\", then the image tag of the first container will be modified, leaving the second one untouched. Gets overridden by \"--image-tag\". If you have 3 container definitions and want to modify tags for the 1st and the 3rd, but leave the 2nd unchanged, specify it as \"--image_tags first_tag,,last_tag\".")
5253

5354
viper.BindPFlag("profile", rootCmd.PersistentFlags().Lookup("profile"))
5455
viper.BindPFlag("cluster", rootCmd.PersistentFlags().Lookup("cluster"))
5556
viper.BindPFlag("image_tag", rootCmd.PersistentFlags().Lookup("image_tag"))
57+
viper.BindPFlag("image_tags", rootCmd.PersistentFlags().Lookup("image_tags"))
5658

5759
}
5860

cmd/run.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ It can modify the container command.
3434
viper.GetString("run.service"),
3535
viper.GetString("task_definition"),
3636
viper.GetString("image_tag"),
37+
viper.GetStringSlice("image_tags"),
3738
containerName,
3839
viper.GetString("log_group"),
3940
viper.GetString("run.launch_type"),

lib/deploy.go

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package lib
22

33
import (
44
"fmt"
5-
"strings"
65
"sync"
76
"time"
87

@@ -12,7 +11,7 @@ import (
1211
)
1312

1413
// DeployServices deploys specified services in parallel
15-
func DeployServices(profile, cluster, imageTag string, services []string) (exitCode int, err error) {
14+
func DeployServices(profile, cluster, imageTag string, imageTags, services []string) (exitCode int, err error) {
1615
ctx := log.WithFields(log.Fields{
1716
"cluster": cluster,
1817
"image_tag": imageTag,
@@ -31,7 +30,7 @@ func DeployServices(profile, cluster, imageTag string, services []string) (exitC
3130
wg.Add(1)
3231
go func() {
3332
defer wg.Done()
34-
deployService(ctx, cluster, imageTag, service, exits, rollback, &wg)
33+
deployService(ctx, cluster, imageTag, imageTags, service, exits, rollback, &wg)
3534
}()
3635
}
3736

@@ -53,7 +52,7 @@ func DeployServices(profile, cluster, imageTag string, services []string) (exitC
5352
return
5453
}
5554

56-
func deployService(ctx log.Interface, cluster, imageTag string, service string, exitChan chan int, rollback chan bool, wg *sync.WaitGroup) {
55+
func deployService(ctx log.Interface, cluster, imageTag string, imageTags []string, service string, exitChan chan int, rollback chan bool, wg *sync.WaitGroup) {
5756
ctx = ctx.WithFields(log.Fields{
5857
"service": service,
5958
})
@@ -91,22 +90,9 @@ func deployService(ctx log.Interface, cluster, imageTag string, service string,
9190

9291
taskDefinition := describeTaskResult.TaskDefinition
9392
// replace the image tag if there is any
94-
for n, containerDefinition := range taskDefinition.ContainerDefinitions {
95-
if imageTag != "" {
96-
imageWithTag := strings.SplitN(aws.StringValue(containerDefinition.Image), ":", 2)
97-
if len(imageWithTag) == 2 { // successfully split into 2 parts: repo and tag
98-
image := strings.Join([]string{
99-
imageWithTag[0],
100-
imageTag,
101-
}, ":")
102-
taskDefinition.ContainerDefinitions[n].Image = aws.String(image)
103-
ctx.WithFields(log.Fields{
104-
"container_name": aws.StringValue(containerDefinition.Name),
105-
"image": image,
106-
"old_image_tag": imageWithTag[1],
107-
}).Info("Image tag changed")
108-
}
109-
}
93+
if err := modifyContainerDefinitionImages(imageTag, imageTags, taskDefinition.ContainerDefinitions, ctx); err != nil {
94+
ctx.WithError(err).Error("Can't modify container definition images")
95+
exitChan <- 1
11096
}
11197

11298
// now, register the new task

lib/run.go

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@ package lib
22

33
import (
44
"fmt"
5-
"strings"
65

76
"github.com/apex/log"
87
"github.com/aws/aws-sdk-go/aws"
98
"github.com/aws/aws-sdk-go/service/ecs"
109
)
1110

1211
// RunTask runs the specified one-off task in the cluster using the task definition
13-
func RunTask(profile, cluster, service, taskDefinitionName, imageTag, containerName, awslogGroup, launchType string, args []string) (exitCode int, err error) {
12+
func RunTask(profile, cluster, service, taskDefinitionName, imageTag string, imageTags []string, containerName, awslogGroup, launchType string, args []string) (exitCode int, err error) {
1413
err = makeSession(profile)
1514
if err != nil {
1615
return 1, err
@@ -27,23 +26,12 @@ func RunTask(profile, cluster, service, taskDefinitionName, imageTag, containerN
2726
return 1, err
2827
}
2928
taskDefinition := describeResult.TaskDefinition
30-
//var containerNumber int
29+
3130
var foundContainerName bool
31+
if err := modifyContainerDefinitionImages(imageTag, imageTags, taskDefinition.ContainerDefinitions, ctx); err != nil {
32+
return 1, err
33+
}
3234
for n, containerDefinition := range taskDefinition.ContainerDefinitions {
33-
if imageTag != "" {
34-
imageWithTag := strings.SplitN(aws.StringValue(containerDefinition.Image), ":", 2)
35-
if len(imageWithTag) == 2 { // successfully split into 2 parts: repo and tag
36-
image := strings.Join([]string{
37-
imageWithTag[0],
38-
imageTag,
39-
}, ":")
40-
taskDefinition.ContainerDefinitions[n].Image = aws.String(image)
41-
ctx.WithFields(log.Fields{
42-
"container_name": aws.StringValue(containerDefinition.Name),
43-
"image": image,
44-
}).Debug("Image tag changed")
45-
}
46-
}
4735
if aws.StringValue(containerDefinition.Name) == containerName {
4836
foundContainerName = true
4937
taskDefinition.ContainerDefinitions[n].Command = aws.StringSlice(args)

lib/util.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/aws/aws-sdk-go/aws/arn"
1010
"github.com/aws/aws-sdk-go/aws/session"
1111
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
12+
"github.com/aws/aws-sdk-go/service/ecs"
1213
)
1314

1415
var localSession *session.Session
@@ -92,3 +93,38 @@ func fetchCloudWatchLog(cluster, containerName, awslogGroup, taskUUID string, de
9293
}()
9394
return printCloudWatchLogs(awslogGroup, streamName)
9495
}
96+
97+
func modifyContainerDefinitionImages(imageTag string, imageTags []string, containerDefinitions []*ecs.ContainerDefinition, ctx log.Interface) error {
98+
99+
for n, containerDefinition := range containerDefinitions {
100+
ctx := ctx.WithField("container_name", aws.StringValue(containerDefinition.Name))
101+
imageWithTag := strings.SplitN(aws.StringValue(containerDefinition.Image), ":", 2)
102+
103+
if len(imageWithTag) == 2 { // successfully split into 2 parts: repo and tag
104+
var newTag string // if set we'll change the definition
105+
if imageTag != "" {
106+
newTag = imageTag // this takes precedence
107+
} else if len(imageTags) > n && imageTags[n] != "" { // the expression below will make this obsolete, as if the tag is "", then it won't be used anyway. But just adding this condition here to be explicit, just in case we want to do something in here later.
108+
newTag = imageTags[n]
109+
}
110+
111+
if newTag != "" {
112+
image := strings.Join([]string{
113+
imageWithTag[0],
114+
newTag,
115+
}, ":")
116+
containerDefinitions[n].Image = aws.String(image)
117+
ctx.WithFields(log.Fields{
118+
"image": image,
119+
"new_tag": newTag,
120+
"old_tag": imageWithTag[1],
121+
}).Debug("Image tag changed")
122+
}
123+
124+
} else {
125+
ctx.Debug("Container doesn't seem to have a tag in the image. It's safer to not do anything.")
126+
}
127+
128+
}
129+
return nil
130+
}

0 commit comments

Comments
 (0)