forked from awslabs/fargatecli
/
task_run.go
209 lines (175 loc) · 7.47 KB
/
task_run.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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
package cmd
import (
CWL "github.com/jpignata/fargate/cloudwatchlogs"
"github.com/jpignata/fargate/console"
"github.com/jpignata/fargate/docker"
EC2 "github.com/jpignata/fargate/ec2"
ECR "github.com/jpignata/fargate/ecr"
ECS "github.com/jpignata/fargate/ecs"
"github.com/jpignata/fargate/git"
IAM "github.com/jpignata/fargate/iam"
"github.com/spf13/cobra"
)
const typeTask string = "task"
type TaskRunOperation struct {
Cpu string
EnvVars []ECS.EnvVar
Image string
Memory string
Num int64
SecurityGroupIds []string
SubnetIds []string
TaskName string
TaskRole string
}
func (o *TaskRunOperation) Validate() {
err := validateCpuAndMemory(o.Cpu, o.Memory)
if err != nil {
console.ErrorExit(err, "Invalid settings: %s CPU units / %s MiB", o.Cpu, o.Memory)
}
if o.Num < 1 {
console.ErrorExit(err, "Invalid number of tasks: %d, num must be > 1", o.Num)
}
}
func (o *TaskRunOperation) SetEnvVars(inputEnvVars []string) {
o.EnvVars = extractEnvVars(inputEnvVars)
}
var (
flagTaskRunNum int64
flagTaskRunCpu string
flagTaskRunEnvVars []string
flagTaskRunImage string
flagTaskRunMemory string
flagTaskRunSecurityGroupIds []string
flagTaskRunSubnetIds []string
flagTaskRunTaskRole string
)
var taskRunCmd = &cobra.Command{
Use: "run <task name>",
Short: "Run new tasks",
Long: `Run new tasks
You must specify a task group name in order to interact with the task(s) in
subsequent commands to view logs, stop and inspect tasks. Task group names do
not have to be unique -- multiple configurations of task instances can be
started with the same task group.
Multiple instances of a task can be run by specifying a number in the --num
flag. If no number is specified, a single task instance will be run.
CPU and memory settings can be optionally specified as CPU units and mebibytes
respectively using the --cpu and --memory flags. Every 1024 CPU units is
equivilent to a single vCPU. AWS Fargate only supports certain combinations of
CPU and memory configurations:
| CPU (CPU Units) | Memory (MiB) |
| --------------- | ------------------------------------- |
| 256 | 512, 1024, or 2048 |
| 512 | 1024 through 4096 in 1GiB increments |
| 1024 | 2048 through 8192 in 1GiB increments |
| 2048 | 4096 through 16384 in 1GiB increments |
| 4096 | 8192 through 30720 in 1GiB increments |
If not specified, fargate will launch minimally sized tasks at 0.25 vCPU (256
CPU units) and 0.5GB (512 MiB) of memory.
The Docker container image to use in the task can be optionally specified via
the --image flag. If not specified, fargate will build a new Docker container
image from the current working directory and push it to Amazon ECR in a
repository named for the task group. If the current working directory is a git
repository, the container image will be tagged with the short ref of the HEAD
commit. If not, a timestamp in the format of YYYYMMDDHHMMSS will be used.
Environment variables can be specified via the --env flag. Specify --env with a
key=value parameter multiple times to add multiple variables.
Security groups can optionally be specified for the task by passing the
--security-group-id flag with a security group ID. To add multiple security
groups, pass --security-group-id with a security group ID multiple times. If
--security-group-id is omitted, a permissive security group will be applied to
the task.
By default, the task will be created in the default VPC and attached to the
default VPC subnets for each availability zone. You can override this by
specifying explicit subnets by passing the --subnet-id flag with a subnet ID.
A task role can be optionally specified via the --task-role flag by providing
eith a full IAM role ARN or the name of an IAM role. The tasks will be able to
assume this role.`,
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
operation := &TaskRunOperation{
Cpu: flagTaskRunCpu,
Image: flagTaskRunImage,
Memory: flagTaskRunMemory,
Num: flagTaskRunNum,
SecurityGroupIds: flagTaskRunSecurityGroupIds,
SubnetIds: flagTaskRunSubnetIds,
TaskName: args[0],
TaskRole: flagTaskRunTaskRole,
}
operation.SetEnvVars(flagTaskRunEnvVars)
operation.Validate()
runTask(operation)
},
}
func init() {
taskRunCmd.Flags().Int64VarP(&flagTaskRunNum, "num", "n", 1, "Number of task instances to run")
taskRunCmd.Flags().StringSliceVarP(&flagTaskRunEnvVars, "env", "e", []string{}, "Environment variables to set [e.g. KEY=value] (can be specified multiple times)")
taskRunCmd.Flags().StringVarP(&flagTaskRunCpu, "cpu", "c", "256", "Amount of cpu units to allocate for each task")
taskRunCmd.Flags().StringVarP(&flagTaskRunImage, "image", "i", "", "Docker image to run; if omitted Fargate will build an image from the Dockerfile in the current directory")
taskRunCmd.Flags().StringVarP(&flagTaskRunMemory, "memory", "m", "512", "Amount of MiB to allocate for each task")
taskRunCmd.Flags().StringSliceVar(&flagTaskRunSecurityGroupIds, "security-group-id", []string{}, "ID of a security group to apply to the task (can be specified multiple times)")
taskRunCmd.Flags().StringSliceVar(&flagTaskRunSubnetIds, "subnet-id", []string{}, "ID of a subnet in which to place the task (can be specified multiple times)")
taskRunCmd.Flags().StringVarP(&flagTaskRunTaskRole, "task-role", "", "", "Name or ARN of an IAM role that the tasks can assume")
taskCmd.AddCommand(taskRunCmd)
}
func runTask(operation *TaskRunOperation) {
cwl := CWL.New(sess)
ec2 := EC2.New(sess)
ecr := ECR.New(sess)
ecs := ECS.New(sess, clusterName)
iam := IAM.New(sess)
ecsTaskExecutionRoleArn := iam.CreateEcsTaskExecutionRole()
logGroupName := cwl.CreateLogGroup(taskLogGroupFormat, operation.TaskName)
if len(operation.SecurityGroupIds) == 0 {
operation.SecurityGroupIds = []string{ec2.GetDefaultSecurityGroupId()}
}
if len(operation.SubnetIds) == 0 {
operation.SubnetIds = ec2.GetDefaultVpcSubnetIds()
}
if operation.Image == "" {
var repositoryUri, tag string
if ecr.IsRepositoryCreated(operation.TaskName) {
repositoryUri = ecr.GetRepositoryUri(operation.TaskName)
} else {
repositoryUri = ecr.CreateRepository(operation.TaskName)
}
if git.IsCwdGitRepo() {
tag = git.GetShortSha()
} else {
tag = docker.GenerateTag()
}
repository := docker.NewRepository(repositoryUri)
username, password := ecr.GetUsernameAndPassword()
repository.Login(username, password)
repository.Build(tag)
repository.Push(tag)
operation.Image = repository.UriFor(tag)
}
taskDefinitionArn := ecs.CreateTaskDefinition(
&ECS.CreateTaskDefinitionInput{
Cpu: operation.Cpu,
EnvVars: operation.EnvVars,
ExecutionRoleArn: ecsTaskExecutionRoleArn,
Image: operation.Image,
LogGroupName: logGroupName,
LogRegion: region,
Memory: operation.Memory,
Name: operation.TaskName,
Type: typeTask,
TaskRole: operation.TaskRole,
},
)
ecs.RunTask(
&ECS.RunTaskInput{
ClusterName: clusterName,
Count: operation.Num,
TaskName: operation.TaskName,
TaskDefinitionArn: taskDefinitionArn,
SubnetIds: operation.SubnetIds,
SecurityGroupIds: operation.SecurityGroupIds,
},
)
console.Info("Running task %s", operation.TaskName)
}