-
Notifications
You must be signed in to change notification settings - Fork 4
/
deploy.go
150 lines (123 loc) · 3.99 KB
/
deploy.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package cmd
import (
"fmt"
"log"
"os"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ecs"
"github.com/lox/ecsy/api"
"github.com/lox/ecsy/compose"
"gopkg.in/alecthomas/kingpin.v2"
)
func ConfigureDeploy(app *kingpin.Application, svc api.Services) {
var cluster, projectName, imageTags string
var composeFiles []string
cmd := app.Command("deploy", "Deploy updated task definitions to ECS")
cmd.Flag("cluster", "The ECS cluster to deploy to").
Required().
StringVar(&cluster)
cmd.Flag("project-name", "The name of the project").
Short('p').
Default(currentDirName()).
StringVar(&projectName)
cmd.Flag("file", "The docker-compose file to use").
Short('f').
Default("docker-compose.yml").
ExistingFilesVar(&composeFiles)
cmd.Arg("imagetags", "Tags in the form image=tag to apply to the task").
StringVar(&imageTags)
cmd.Action(func(c *kingpin.ParseContext) error {
images, err := parseImageMap(imageTags)
if err != nil {
return err
}
log.Printf("Generating task definition from %#v", composeFiles)
t := compose.Transformer{
ComposeFiles: composeFiles,
ProjectName: projectName,
}
taskDefinitionInput, err := t.Transform()
if err != nil {
return err
}
clusterStack, err := api.FindClusterStack(svc.Cloudformation, cluster)
if err != nil {
return err
} else if clusterStack == nil {
return fmt.Errorf("No cluster exists for %q. Use `create-cluster`",
cluster)
}
if logGroup, exists := api.GetStackOutputByKey(clusterStack, "LogGroupName"); exists {
log.Printf("Setting tasks to use log group %s", logGroup)
for _, def := range taskDefinitionInput.ContainerDefinitions {
if def.LogConfiguration == nil {
def.LogConfiguration = &ecs.LogConfiguration{
LogDriver: aws.String("awslogs"),
Options: map[string]*string{
"awslogs-group": aws.String(logGroup),
"awslogs-region": aws.String(os.Getenv("AWS_REGION")),
"awslogs-stream-prefix": aws.String(projectName),
},
}
}
}
}
log.Printf("Updating task definition for task %s", *taskDefinitionInput.Family)
err = api.UpdateContainerImages(taskDefinitionInput.ContainerDefinitions, images)
if err != nil {
return err
}
resp, err := svc.ECS.RegisterTaskDefinition(taskDefinitionInput)
if err != nil {
return err
}
log.Printf("Registered task definition %s:%d", *resp.TaskDefinition.Family, *resp.TaskDefinition.Revision)
serviceStack, err := api.FindServiceStack(svc.Cloudformation, cluster, projectName)
if err != nil {
return err
}
log.Printf("Found service stack %s", *serviceStack.StackName)
outputs := api.StackOutputMap(serviceStack)
timer := time.Now()
log.Printf("Updating service %s with new task definition", *serviceStack.StackName)
_, err = svc.ECS.UpdateService(&ecs.UpdateServiceInput{
Service: aws.String(outputs["ECSService"]),
Cluster: aws.String(outputs["ECSCluster"]),
TaskDefinition: aws.String(*resp.TaskDefinition.TaskDefinitionArn),
})
if err != nil {
return err
}
var printer = func(e *ecs.ServiceEvent) {
log.Println(*e.Message)
}
log.Printf("Waiting for service to reach a steady state.")
err = api.PollUntilTaskDeployed(svc.ECS, outputs["ECSCluster"], outputs["ECSService"], *resp.TaskDefinition.TaskDefinitionArn, printer)
if err != nil {
return err
}
// ui.Printf("Waiting for service to stabilize")
// if err = apient.WaitUntilServicesStable(input.ClusterName, serviceOutputs["ECSService"]); err != nil {
// ui.Fatal(err)
// }
log.Printf("Deployed in %s", time.Now().Sub(timer).String())
return nil
})
}
func parseImageMap(s string) (map[string]string, error) {
m := map[string]string{}
if s == "" {
return m, nil
}
for _, token := range strings.Split(s, ",") {
pieces := strings.SplitN(token, "=", 2)
if len(pieces) != 2 {
return nil, fmt.Errorf("Failed to parse image tag %q", s)
}
m[pieces[0]] = pieces[1]
}
log.Printf("Parsed %s to %#v", s, m)
return m, nil
}