Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aws
GitHub Repository: aws/aws-cli
Path: blob/develop/tests/functional/ecs/test_deploy.py
1567 views
1
# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
#
3
# Licensed under the Apache License, Version 2.0 (the "License"). You
4
# may not use this file except in compliance with the License. A copy of
5
# the License is located at
6
#
7
# http://aws.amazon.com/apache2.0/
8
#
9
# or in the "license" file accompanying this file. This file is
10
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
# ANY KIND, either express or implied. See the License for the specific
12
# language governing permissions and limitations under the License.
13
14
import json
15
16
from awscli.testutils import BaseAWSCommandParamsTest, FileCreator
17
from awscli.customizations.ecs.deploy import (CodeDeployer,
18
MAX_WAIT_MIN,
19
TIMEOUT_BUFFER_MIN)
20
from awscli.customizations.ecs.filehelpers import (get_app_name,
21
get_deploy_group_name)
22
23
24
class TestDeployCommand(BaseAWSCommandParamsTest):
25
26
PREFIX = 'ecs deploy '
27
28
TASK_DEFINITION_JSON = {
29
"family": "test",
30
"containerDefinitions": [],
31
"cpu": "256",
32
"memory": '512'
33
}
34
35
JSON_APPSPEC = """
36
{
37
"version": 0.0,
38
"resources": [{
39
"TestService": {
40
"type": "AWS::ECS::Service",
41
"properties": {
42
"taskDefinition": "arn:aws:ecs::123:task-definition:1",
43
"loadBalancerInfo": {
44
"containerName": "web",
45
"containerPort": 80
46
}
47
}
48
}
49
}]
50
}
51
"""
52
53
BAD_APPSPEC = """
54
version: 0.0
55
resources:
56
- TestService:
57
type: AWS::Lambda::Function
58
properties:
59
name: myFunction
60
"""
61
62
YAML_APPSPEC = """
63
version: 0.0
64
resources:
65
- TestService:
66
type: AWS::ECS::Service
67
properties:
68
taskDefinition: arn:aws:ecs::123:task-definition:1
69
loadBalancerInfo:
70
containerName: web
71
containerPort: 80
72
"""
73
74
APPSPEC_DICT = {
75
"version": 0.0,
76
"resources": [{
77
"TestService": {
78
"type": "AWS::ECS::Service",
79
"properties": {
80
"taskDefinition": "arn:aws:ecs::123:task-definition:1",
81
"loadBalancerInfo": {
82
"containerName": "web",
83
"containerPort": 80
84
}
85
}
86
}
87
}]
88
}
89
90
def setUp(self):
91
super(TestDeployCommand, self).setUp()
92
# setup required values
93
files = FileCreator()
94
self.task_def_file = files.create_file(
95
'taskDef.json', json.dumps(self.TASK_DEFINITION_JSON), mode='w')
96
self.appspec_file = files.create_file(
97
'appspec.yaml', self.YAML_APPSPEC, mode='w')
98
self.appspec_file_json = files.create_file(
99
'appspec.json', self.JSON_APPSPEC, mode='w')
100
self.service_name = 'serviceTest'
101
self.service_arn = 'arn:aws:ecs:::service/serviceTest'
102
# setup default optional values
103
self.cluster_name = 'default'
104
self.cluster_arn = 'arn:aws:ecs:::cluster/default'
105
self.application_name = get_app_name(
106
self.service_name, self.cluster_name, None)
107
self.deployment_group_name = get_deploy_group_name(
108
self.service_name, self.cluster_name, None)
109
# setup test response resources
110
self.missing_properties_appspec = files.create_file(
111
'appspec_bad.yaml', self.BAD_APPSPEC, mode='w')
112
self.task_definition_arn = \
113
'arn:aws:ecs::1234567890:task-definition\\test:2'
114
self.deployment_id = 'd-1234567XX'
115
self.mock_deployer = CodeDeployer(None, self.APPSPEC_DICT)
116
self.mock_deployer.update_task_def_arn(self.task_definition_arn)
117
self.expected_stdout = ("Successfully registered new ECS task "
118
"definition " + self.task_definition_arn + "\n"
119
"Successfully created deployment " +
120
self.deployment_id + "\n"
121
"Waiting for " + self.deployment_id +
122
" to succeed (will wait up to 30 minutes)..."
123
"\nSuccessfully deployed "
124
+ self.task_definition_arn + " to service '"
125
+ self.service_name + "'\n")
126
127
def tearDown(self):
128
super(TestDeployCommand, self).tearDown()
129
130
def test_deploy_with_defaults(self):
131
cmdline = self.PREFIX
132
cmdline += '--service ' + self.service_name
133
cmdline += ' --task-definition ' + self.task_def_file
134
cmdline += ' --codedeploy-appspec ' + self.appspec_file
135
136
expected_create_deployment_params = \
137
self.mock_deployer._get_create_deploy_request(
138
self.application_name, self.deployment_group_name)
139
140
self.parsed_responses = self._get_parsed_responses(
141
self.cluster_name,
142
self.application_name,
143
self.deployment_group_name)
144
145
expected_params = self._get_expected_params(
146
self.service_name,
147
self.cluster_name,
148
self.application_name,
149
self.deployment_group_name,
150
expected_create_deployment_params)
151
152
stdout, _, _ = self.assert_params_list_for_cmd(
153
cmdline, expected_params, None)
154
155
self.assertEqual(stdout, self.expected_stdout)
156
157
def test_deploy_with_default_arns(self):
158
cmdline = self.PREFIX
159
cmdline += '--service ' + self.service_arn
160
cmdline += ' --cluster ' + self.cluster_arn
161
cmdline += ' --task-definition ' + self.task_def_file
162
cmdline += ' --codedeploy-appspec ' + self.appspec_file
163
164
expected_create_deployment_params = \
165
self.mock_deployer._get_create_deploy_request(
166
self.application_name, self.deployment_group_name)
167
168
self.parsed_responses = self._get_parsed_responses(
169
self.cluster_name,
170
self.application_name,
171
self.deployment_group_name)
172
173
expected_params = self._get_expected_params(
174
self.service_arn,
175
self.cluster_arn,
176
self.application_name,
177
self.deployment_group_name,
178
expected_create_deployment_params)
179
180
stdout, _, _ = self.assert_params_list_for_cmd(
181
cmdline, expected_params, None)
182
183
self.assertEqual(stdout, self.expected_stdout)
184
185
def test_deploy_with_json_appspec(self):
186
cmdline = self.PREFIX
187
cmdline += '--service ' + self.service_name
188
cmdline += ' --task-definition ' + self.task_def_file
189
cmdline += ' --codedeploy-appspec ' + self.appspec_file_json
190
191
expected_create_deployment_params = \
192
self.mock_deployer._get_create_deploy_request(
193
self.application_name, self.deployment_group_name)
194
195
self.parsed_responses = self._get_parsed_responses(
196
self.cluster_name,
197
self.application_name,
198
self.deployment_group_name)
199
200
expected_params = self._get_expected_params(
201
self.service_name,
202
self.cluster_name,
203
self.application_name,
204
self.deployment_group_name,
205
expected_create_deployment_params)
206
207
stdout, _, _ = self.assert_params_list_for_cmd(
208
cmdline, expected_params, None)
209
210
self.assertEqual(stdout, self.expected_stdout)
211
212
def test_deploy_with_custom_timeout(self):
213
cmdline = self.PREFIX
214
cmdline += '--service ' + self.service_name
215
cmdline += ' --task-definition ' + self.task_def_file
216
cmdline += ' --codedeploy-appspec ' + self.appspec_file
217
218
expected_create_deployment_params = \
219
self.mock_deployer._get_create_deploy_request(
220
self.application_name, self.deployment_group_name)
221
222
custom_deployment_grp_response = {
223
'deploymentGroupInfo': {
224
'applicationName': self.application_name,
225
'deploymentGroupName': self.deployment_group_name,
226
'computePlatform': 'ECS',
227
'blueGreenDeploymentConfiguration': {
228
'deploymentReadyOption': {
229
'waitTimeInMinutes': 5
230
},
231
'terminateBlueInstancesOnDeploymentSuccess': {
232
'terminationWaitTimeInMinutes': 60
233
}
234
},
235
'ecsServices': [{
236
'serviceName': self.service_name,
237
'clusterName': self.cluster_name
238
}]
239
}
240
}
241
custom_timeout = str(60 + 5 + TIMEOUT_BUFFER_MIN)
242
243
self.parsed_responses = self._get_parsed_responses(
244
self.cluster_name,
245
self.application_name,
246
self.deployment_group_name)
247
248
self.parsed_responses[2] = custom_deployment_grp_response
249
250
expected_params = self._get_expected_params(
251
self.service_name,
252
self.cluster_name,
253
self.application_name,
254
self.deployment_group_name,
255
expected_create_deployment_params)
256
257
expected_stdout = ("Successfully registered new ECS task "
258
"definition " + self.task_definition_arn + "\n"
259
"Successfully created deployment " +
260
self.deployment_id + "\n"
261
"Waiting for " + self.deployment_id +
262
" to succeed (will wait up to " + custom_timeout
263
+ " minutes)...\nSuccessfully deployed "
264
+ self.task_definition_arn + " to service '"
265
+ self.service_name + "'\n")
266
267
stdout, _, _ = self.assert_params_list_for_cmd(
268
cmdline, expected_params, None)
269
270
self.assertEqual(stdout, expected_stdout)
271
272
def test_deploy_with_max_timeout(self):
273
cmdline = self.PREFIX
274
cmdline += '--service ' + self.service_name
275
cmdline += ' --task-definition ' + self.task_def_file
276
cmdline += ' --codedeploy-appspec ' + self.appspec_file
277
278
expected_create_deployment_params = \
279
self.mock_deployer._get_create_deploy_request(
280
self.application_name, self.deployment_group_name)
281
282
custom_deployment_grp_response = {
283
'deploymentGroupInfo': {
284
'applicationName': self.application_name,
285
'deploymentGroupName': self.deployment_group_name,
286
'computePlatform': 'ECS',
287
'blueGreenDeploymentConfiguration': {
288
'deploymentReadyOption': {
289
'waitTimeInMinutes': 90
290
},
291
'terminateBlueInstancesOnDeploymentSuccess': {
292
'terminationWaitTimeInMinutes': 300
293
}
294
},
295
'ecsServices': [{
296
'serviceName': self.service_name,
297
'clusterName': self.cluster_name
298
}]
299
}
300
}
301
max_timeout = str(MAX_WAIT_MIN)
302
303
self.parsed_responses = self._get_parsed_responses(
304
self.cluster_name,
305
self.application_name,
306
self.deployment_group_name)
307
308
self.parsed_responses[2] = custom_deployment_grp_response
309
310
expected_params = self._get_expected_params(
311
self.service_name,
312
self.cluster_name,
313
self.application_name,
314
self.deployment_group_name,
315
expected_create_deployment_params)
316
317
expected_stdout = ("Successfully registered new ECS task "
318
"definition " + self.task_definition_arn + "\n"
319
"Successfully created deployment " +
320
self.deployment_id + "\n"
321
"Waiting for " + self.deployment_id +
322
" to succeed (will wait up to " + max_timeout
323
+ " minutes)...\nSuccessfully deployed "
324
+ self.task_definition_arn + " to service '"
325
+ self.service_name + "'\n")
326
327
stdout, _, _ = self.assert_params_list_for_cmd(
328
cmdline, expected_params, None)
329
330
self.assertEqual(stdout, expected_stdout)
331
332
def test_deploy_with_optional_values(self):
333
custom_app = 'myOtherApp'
334
custom_dgp = 'myOtherDgp'
335
custom_cluster = 'myOtherCluster'
336
337
cmdline = self.PREFIX
338
cmdline += '--service ' + self.service_name
339
cmdline += ' --task-definition ' + self.task_def_file
340
cmdline += ' --codedeploy-appspec ' + self.appspec_file
341
cmdline += ' --cluster ' + self.cluster_name
342
cmdline += ' --codedeploy-application ' + custom_app
343
cmdline += ' --codedeploy-deployment-group ' + custom_dgp
344
cmdline += ' --cluster ' + custom_cluster
345
346
expected_create_deployment_params = \
347
self.mock_deployer._get_create_deploy_request(
348
custom_app, custom_dgp)
349
350
self.parsed_responses = self._get_parsed_responses(
351
custom_cluster, custom_app, custom_dgp)
352
353
expected_params = self._get_expected_params(
354
self.service_name, custom_cluster, custom_app,
355
custom_dgp, expected_create_deployment_params)
356
357
stdout, _, _ = self.assert_params_list_for_cmd(
358
cmdline, expected_params, None)
359
360
self.assertEqual(stdout, self.expected_stdout)
361
362
def test_deploy_error_missing_appspec_property(self):
363
cmdline = self.PREFIX
364
cmdline += '--service ' + self.service_name
365
cmdline += ' --task-definition ' + self.task_def_file
366
cmdline += ' --codedeploy-appspec ' + self.missing_properties_appspec
367
368
self.parsed_responses = [
369
{
370
'services': [{
371
'serviceArn': self.service_arn,
372
'serviceName': self.service_name,
373
'clusterArn': 'arn:aws:ecs:::cluster/' + self.cluster_name
374
}]
375
},
376
{
377
'application': {
378
'applicationId': '876uyh6-45tdfg',
379
'applicationName': self.application_name,
380
'computePlatform': 'ECS'
381
}
382
},
383
{
384
'deploymentGroupInfo': {
385
'applicationName': self.application_name,
386
'deploymentGroupName': self.deployment_group_name,
387
'computePlatform': 'ECS',
388
'blueGreenDeploymentConfiguration': {
389
'deploymentReadyOption': {
390
'waitTimeInMinutes': 5
391
},
392
'terminateBlueInstancesOnDeploymentSuccess': {
393
'terminationWaitTimeInMinutes': 10
394
}
395
},
396
'ecsServices': [{
397
'serviceName': self.service_name,
398
'clusterName': self.cluster_name
399
}]
400
}
401
},
402
{
403
'taskDefinition': {
404
'taskDefinitionArn': self.task_definition_arn,
405
'family': 'test',
406
'containerDefinitions': []
407
}
408
}
409
]
410
411
expected_params = [
412
{
413
'operation': 'DescribeServices',
414
'params': {
415
'cluster': self.cluster_name,
416
'services': [self.service_name]
417
}
418
},
419
{
420
'operation': 'GetApplication',
421
'params': {'applicationName': self.application_name}
422
},
423
{
424
'operation': 'GetDeploymentGroup',
425
'params': {
426
'applicationName': self.application_name,
427
'deploymentGroupName': self.deployment_group_name
428
}
429
},
430
{
431
'operation': 'RegisterTaskDefinition',
432
'params': self.TASK_DEFINITION_JSON
433
}
434
]
435
436
expected_stdout = ("Successfully registered new ECS task "
437
"definition " + self.task_definition_arn + "\n")
438
439
expected_stderr = ("\nError: Resource 'properties' must "
440
"include property 'taskDefinition'\n")
441
442
stdout, stderr, _ = self.assert_params_list_for_cmd(
443
cmdline, expected_params, 255)
444
445
self.assertEqual(stdout, expected_stdout)
446
self.assertEqual(stderr, expected_stderr)
447
448
def test_deploy_error_invalid_platform(self):
449
cmdline = self.PREFIX
450
cmdline += '--service ' + self.service_name
451
cmdline += ' --task-definition ' + self.task_def_file
452
cmdline += ' --codedeploy-appspec ' + self.missing_properties_appspec
453
454
self.parsed_responses = [
455
{
456
'services': [{
457
'serviceArn': self.service_arn,
458
'serviceName': self.service_name,
459
'clusterArn': 'arn:aws:ecs:::cluster/' + self.cluster_name
460
}]
461
},
462
{
463
'application': {
464
'applicationId': '876uyh6-45tdfg',
465
'applicationName': self.application_name,
466
'computePlatform': 'Server'
467
}
468
},
469
{
470
'deploymentGroupInfo': {
471
'applicationName': self.application_name,
472
'deploymentGroupName': self.deployment_group_name,
473
'computePlatform': 'ECS',
474
'ecsServices': [{
475
'serviceName': self.service_name,
476
'clusterName': self.cluster_name
477
}]
478
}
479
}
480
]
481
482
expected_params = [
483
{
484
'operation': 'DescribeServices',
485
'params': {
486
'cluster': self.cluster_name,
487
'services': [self.service_name]
488
}
489
},
490
{
491
'operation': 'GetApplication',
492
'params': {'applicationName': self.application_name}
493
},
494
{
495
'operation': 'GetDeploymentGroup',
496
'params': {
497
'applicationName': self.application_name,
498
'deploymentGroupName': self.deployment_group_name
499
}
500
}
501
]
502
503
expected_stderr = ("\nError: Application '" + self.application_name +
504
"' must support 'ECS' compute platform\n")
505
506
stdout, stderr, _ = self.assert_params_list_for_cmd(
507
cmdline, expected_params, 255)
508
509
self.assertEqual('', stdout)
510
self.assertEqual(expected_stderr, stderr)
511
512
def assert_params_list_for_cmd(self, cmd, params, expected_rc=0,
513
stderr_contains=None):
514
stdout, stderr, rc = self.run_cmd(cmd, expected_rc)
515
if stderr_contains is not None:
516
self.assertIn(stderr_contains, stderr)
517
518
self.assertEqual(len(self.operations_called), len(params))
519
for i, param in enumerate(params):
520
self.assertEqual(
521
self.operations_called[i][0].name, param['operation'])
522
self.assertEqual(
523
self.operations_called[i][1], param['params'])
524
525
return stdout, stderr, rc
526
527
def _get_expected_params(self, service_name, cluster_name, app_name,
528
dgp_name, create_deployment_params):
529
return [
530
{
531
'operation': 'DescribeServices',
532
'params': {
533
'cluster': cluster_name,
534
'services': [service_name]
535
}
536
},
537
{
538
'operation': 'GetApplication',
539
'params': {'applicationName': app_name}
540
},
541
{
542
'operation': 'GetDeploymentGroup',
543
'params': {
544
'applicationName': app_name,
545
'deploymentGroupName': dgp_name
546
}
547
},
548
{
549
'operation': 'RegisterTaskDefinition',
550
'params': self.TASK_DEFINITION_JSON
551
},
552
{
553
'operation': 'CreateDeployment',
554
'params': create_deployment_params
555
},
556
{
557
'operation': 'GetDeployment',
558
'params': {
559
'deploymentId': self.deployment_id
560
}
561
}
562
]
563
564
def _get_parsed_responses(self, cluster_name, app_name, dgp_name):
565
return [
566
{
567
'services': [{
568
'serviceArn': self.service_arn,
569
'serviceName': self.service_name,
570
'clusterArn': 'arn:aws:ecs:::cluster/' + cluster_name
571
}]
572
},
573
{
574
'application': {
575
'applicationId': '876uyh6-45tdfg',
576
'applicationName': app_name,
577
'computePlatform': 'ECS'
578
}
579
},
580
{
581
'deploymentGroupInfo': {
582
'applicationName': app_name,
583
'deploymentGroupName': dgp_name,
584
'computePlatform': 'ECS',
585
'blueGreenDeploymentConfiguration': {
586
'deploymentReadyOption': {
587
'waitTimeInMinutes': 5
588
},
589
'terminateBlueInstancesOnDeploymentSuccess': {
590
'terminationWaitTimeInMinutes': 10
591
}
592
},
593
'ecsServices': [{
594
'serviceName': self.service_name,
595
'clusterName': cluster_name
596
}]
597
}
598
},
599
{
600
'taskDefinition': {
601
'taskDefinitionArn': self.task_definition_arn,
602
'family': 'test',
603
'containerDefinitions': []
604
}
605
},
606
{
607
'deploymentId': self.deployment_id
608
},
609
{
610
'deploymentInfo': {
611
'applicationName': app_name,
612
'status': 'Succeeded'
613
}
614
}
615
]
616
617