1from datetime import datetime 2 3from botocore.exceptions import ClientError 4import boto3 5import mock 6import sure # noqa # pylint: disable=unused-import 7import json 8import os 9 10from moto.core import ACCOUNT_ID 11from moto.ec2 import utils as ec2_utils 12from uuid import UUID 13 14from moto import mock_ecs, mock_ec2, settings 15from moto.ecs.exceptions import ( 16 ClusterNotFoundException, 17 ServiceNotFoundException, 18 InvalidParameterException, 19 TaskDefinitionNotFoundException, 20 RevisionNotFoundException, 21) 22import pytest 23from tests import EXAMPLE_AMI_ID 24from unittest import SkipTest 25 26 27@mock_ecs 28def test_create_cluster(): 29 client = boto3.client("ecs", region_name="us-east-1") 30 response = client.create_cluster(clusterName="test_ecs_cluster") 31 response["cluster"]["clusterName"].should.equal("test_ecs_cluster") 32 response["cluster"]["clusterArn"].should.equal( 33 "arn:aws:ecs:us-east-1:{}:cluster/test_ecs_cluster".format(ACCOUNT_ID) 34 ) 35 response["cluster"]["status"].should.equal("ACTIVE") 36 response["cluster"]["registeredContainerInstancesCount"].should.equal(0) 37 response["cluster"]["runningTasksCount"].should.equal(0) 38 response["cluster"]["pendingTasksCount"].should.equal(0) 39 response["cluster"]["activeServicesCount"].should.equal(0) 40 41 42@mock_ecs 43def test_list_clusters(): 44 client = boto3.client("ecs", region_name="us-east-2") 45 _ = client.create_cluster(clusterName="test_cluster0") 46 _ = client.create_cluster(clusterName="test_cluster1") 47 response = client.list_clusters() 48 response["clusterArns"].should.contain( 49 "arn:aws:ecs:us-east-2:{}:cluster/test_cluster0".format(ACCOUNT_ID) 50 ) 51 response["clusterArns"].should.contain( 52 "arn:aws:ecs:us-east-2:{}:cluster/test_cluster1".format(ACCOUNT_ID) 53 ) 54 55 56@mock_ecs 57def test_describe_clusters(): 58 client = boto3.client("ecs", region_name="us-east-1") 59 response = client.describe_clusters(clusters=["some-cluster"]) 60 response["failures"].should.contain( 61 { 62 "arn": "arn:aws:ecs:us-east-1:{}:cluster/some-cluster".format(ACCOUNT_ID), 63 "reason": "MISSING", 64 } 65 ) 66 67 68@mock_ecs 69def test_delete_cluster(): 70 client = boto3.client("ecs", region_name="us-east-1") 71 _ = client.create_cluster(clusterName="test_ecs_cluster") 72 response = client.delete_cluster(cluster="test_ecs_cluster") 73 response["cluster"]["clusterName"].should.equal("test_ecs_cluster") 74 response["cluster"]["clusterArn"].should.equal( 75 "arn:aws:ecs:us-east-1:{}:cluster/test_ecs_cluster".format(ACCOUNT_ID) 76 ) 77 response["cluster"]["status"].should.equal("ACTIVE") 78 response["cluster"]["registeredContainerInstancesCount"].should.equal(0) 79 response["cluster"]["runningTasksCount"].should.equal(0) 80 response["cluster"]["pendingTasksCount"].should.equal(0) 81 response["cluster"]["activeServicesCount"].should.equal(0) 82 83 response = client.list_clusters() 84 len(response["clusterArns"]).should.equal(0) 85 86 87@mock_ecs 88def test_delete_cluster_exceptions(): 89 client = boto3.client("ecs", region_name="us-east-1") 90 client.delete_cluster.when.called_with(cluster="not_a_cluster").should.throw( 91 ClientError, ClusterNotFoundException().message 92 ) 93 94 95@mock_ecs 96def test_register_task_definition(): 97 client = boto3.client("ecs", region_name="us-east-1") 98 # Registering with minimal definition 99 definition = dict( 100 family="test_ecs_task", 101 containerDefinitions=[ 102 {"name": "hello_world", "image": "hello-world:latest", "memory": 400,} 103 ], 104 ) 105 106 response = client.register_task_definition(**definition) 107 108 response["taskDefinition"] = response["taskDefinition"] 109 response["taskDefinition"]["family"].should.equal("test_ecs_task") 110 response["taskDefinition"]["revision"].should.equal(1) 111 response["taskDefinition"]["taskDefinitionArn"].should.equal( 112 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:1".format(ACCOUNT_ID) 113 ) 114 response["taskDefinition"]["networkMode"].should.equal("bridge") 115 response["taskDefinition"]["volumes"].should.equal([]) 116 response["taskDefinition"]["placementConstraints"].should.equal([]) 117 response["taskDefinition"]["compatibilities"].should.equal(["EC2"]) 118 response["taskDefinition"].shouldnt.have.key("requiresCompatibilities") 119 response["taskDefinition"].shouldnt.have.key("cpu") 120 response["taskDefinition"].shouldnt.have.key("memory") 121 122 response["taskDefinition"]["containerDefinitions"][0]["name"].should.equal( 123 "hello_world" 124 ) 125 response["taskDefinition"]["containerDefinitions"][0]["image"].should.equal( 126 "hello-world:latest" 127 ) 128 response["taskDefinition"]["containerDefinitions"][0]["cpu"].should.equal(0) 129 response["taskDefinition"]["containerDefinitions"][0]["portMappings"].should.equal( 130 [] 131 ) 132 response["taskDefinition"]["containerDefinitions"][0]["essential"].should.equal( 133 True 134 ) 135 response["taskDefinition"]["containerDefinitions"][0]["environment"].should.equal( 136 [] 137 ) 138 response["taskDefinition"]["containerDefinitions"][0]["mountPoints"].should.equal( 139 [] 140 ) 141 response["taskDefinition"]["containerDefinitions"][0]["volumesFrom"].should.equal( 142 [] 143 ) 144 145 # Registering again increments the revision 146 response = client.register_task_definition(**definition) 147 148 response["taskDefinition"]["revision"].should.equal(2) 149 response["taskDefinition"]["taskDefinitionArn"].should.equal( 150 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:2".format(ACCOUNT_ID) 151 ) 152 153 # Registering with optional top-level params 154 definition["requiresCompatibilities"] = ["FARGATE"] 155 definition["taskRoleArn"] = "my-custom-task-role-arn" 156 definition["executionRoleArn"] = "my-custom-execution-role-arn" 157 response = client.register_task_definition(**definition) 158 response["taskDefinition"]["requiresCompatibilities"].should.equal(["FARGATE"]) 159 response["taskDefinition"]["compatibilities"].should.equal(["EC2", "FARGATE"]) 160 response["taskDefinition"]["networkMode"].should.equal("awsvpc") 161 response["taskDefinition"]["taskRoleArn"].should.equal("my-custom-task-role-arn") 162 response["taskDefinition"]["executionRoleArn"].should.equal( 163 "my-custom-execution-role-arn" 164 ) 165 166 definition["requiresCompatibilities"] = ["EC2", "FARGATE"] 167 response = client.register_task_definition(**definition) 168 response["taskDefinition"]["requiresCompatibilities"].should.equal( 169 ["EC2", "FARGATE"] 170 ) 171 response["taskDefinition"]["compatibilities"].should.equal(["EC2", "FARGATE"]) 172 response["taskDefinition"]["networkMode"].should.equal("awsvpc") 173 174 definition["cpu"] = "512" 175 response = client.register_task_definition(**definition) 176 response["taskDefinition"]["cpu"].should.equal("512") 177 178 definition.update({"memory": "512"}) 179 response = client.register_task_definition(**definition) 180 response["taskDefinition"]["memory"].should.equal("512") 181 182 # Registering with optional container params 183 definition["containerDefinitions"][0]["cpu"] = 512 184 response = client.register_task_definition(**definition) 185 response["taskDefinition"]["containerDefinitions"][0]["cpu"].should.equal(512) 186 187 definition["containerDefinitions"][0]["essential"] = False 188 response = client.register_task_definition(**definition) 189 response["taskDefinition"]["containerDefinitions"][0]["essential"].should.equal( 190 False 191 ) 192 193 definition["containerDefinitions"][0]["environment"] = [ 194 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 195 ] 196 response = client.register_task_definition(**definition) 197 response["taskDefinition"]["containerDefinitions"][0]["environment"][0][ 198 "name" 199 ].should.equal("AWS_ACCESS_KEY_ID") 200 response["taskDefinition"]["containerDefinitions"][0]["environment"][0][ 201 "value" 202 ].should.equal("SOME_ACCESS_KEY") 203 204 definition["containerDefinitions"][0]["logConfiguration"] = { 205 "logDriver": "json-file" 206 } 207 response = client.register_task_definition(**definition) 208 response["taskDefinition"]["containerDefinitions"][0]["logConfiguration"][ 209 "logDriver" 210 ].should.equal("json-file") 211 212 213@mock_ecs 214def test_list_task_definitions(): 215 client = boto3.client("ecs", region_name="us-east-1") 216 _ = client.register_task_definition( 217 family="test_ecs_task", 218 containerDefinitions=[ 219 { 220 "name": "hello_world", 221 "image": "docker/hello-world:latest", 222 "cpu": 1024, 223 "memory": 400, 224 "essential": True, 225 "environment": [ 226 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 227 ], 228 "logConfiguration": {"logDriver": "json-file"}, 229 } 230 ], 231 ) 232 _ = client.register_task_definition( 233 family="test_ecs_task", 234 containerDefinitions=[ 235 { 236 "name": "hello_world2", 237 "image": "docker/hello-world2:latest", 238 "cpu": 1024, 239 "memory": 400, 240 "essential": True, 241 "environment": [ 242 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY2"} 243 ], 244 "logConfiguration": {"logDriver": "json-file"}, 245 } 246 ], 247 ) 248 response = client.list_task_definitions() 249 len(response["taskDefinitionArns"]).should.equal(2) 250 response["taskDefinitionArns"][0].should.equal( 251 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:1".format(ACCOUNT_ID) 252 ) 253 response["taskDefinitionArns"][1].should.equal( 254 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:2".format(ACCOUNT_ID) 255 ) 256 257 258@mock_ecs 259def test_list_task_definitions_with_family_prefix(): 260 client = boto3.client("ecs", region_name="us-east-1") 261 _ = client.register_task_definition( 262 family="test_ecs_task_a", 263 containerDefinitions=[ 264 { 265 "name": "hello_world", 266 "image": "docker/hello-world:latest", 267 "cpu": 1024, 268 "memory": 400, 269 "essential": True, 270 "environment": [ 271 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 272 ], 273 "logConfiguration": {"logDriver": "json-file"}, 274 } 275 ], 276 ) 277 _ = client.register_task_definition( 278 family="test_ecs_task_a", 279 containerDefinitions=[ 280 { 281 "name": "hello_world", 282 "image": "docker/hello-world:latest", 283 "cpu": 1024, 284 "memory": 400, 285 "essential": True, 286 "environment": [ 287 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 288 ], 289 "logConfiguration": {"logDriver": "json-file"}, 290 } 291 ], 292 ) 293 _ = client.register_task_definition( 294 family="test_ecs_task_b", 295 containerDefinitions=[ 296 { 297 "name": "hello_world2", 298 "image": "docker/hello-world2:latest", 299 "cpu": 1024, 300 "memory": 400, 301 "essential": True, 302 "environment": [ 303 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY2"} 304 ], 305 "logConfiguration": {"logDriver": "json-file"}, 306 } 307 ], 308 ) 309 empty_response = client.list_task_definitions(familyPrefix="test_ecs_task") 310 len(empty_response["taskDefinitionArns"]).should.equal(0) 311 filtered_response = client.list_task_definitions(familyPrefix="test_ecs_task_a") 312 len(filtered_response["taskDefinitionArns"]).should.equal(2) 313 filtered_response["taskDefinitionArns"][0].should.equal( 314 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task_a:1".format(ACCOUNT_ID) 315 ) 316 filtered_response["taskDefinitionArns"][1].should.equal( 317 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task_a:2".format(ACCOUNT_ID) 318 ) 319 320 321@mock_ecs 322def test_describe_task_definitions(): 323 client = boto3.client("ecs", region_name="us-east-1") 324 _ = client.register_task_definition( 325 family="test_ecs_task", 326 containerDefinitions=[ 327 { 328 "name": "hello_world", 329 "image": "docker/hello-world:latest", 330 "cpu": 1024, 331 "memory": 400, 332 "essential": True, 333 "environment": [ 334 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 335 ], 336 "logConfiguration": {"logDriver": "json-file"}, 337 } 338 ], 339 tags=[{"key": "Name", "value": "test_ecs_task"}], 340 ) 341 _ = client.register_task_definition( 342 family="test_ecs_task", 343 taskRoleArn="my-task-role-arn", 344 executionRoleArn="my-execution-role-arn", 345 containerDefinitions=[ 346 { 347 "name": "hello_world2", 348 "image": "docker/hello-world2:latest", 349 "cpu": 1024, 350 "memory": 400, 351 "essential": True, 352 "environment": [ 353 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY2"} 354 ], 355 "logConfiguration": {"logDriver": "json-file"}, 356 } 357 ], 358 ) 359 _ = client.register_task_definition( 360 family="test_ecs_task", 361 containerDefinitions=[ 362 { 363 "name": "hello_world3", 364 "image": "docker/hello-world3:latest", 365 "cpu": 1024, 366 "memory": 400, 367 "essential": True, 368 "environment": [ 369 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY3"} 370 ], 371 "logConfiguration": {"logDriver": "json-file"}, 372 } 373 ], 374 ) 375 response = client.describe_task_definition(taskDefinition="test_ecs_task") 376 response["taskDefinition"]["taskDefinitionArn"].should.equal( 377 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:3".format(ACCOUNT_ID) 378 ) 379 380 response = client.describe_task_definition(taskDefinition="test_ecs_task:2") 381 response["taskDefinition"]["taskDefinitionArn"].should.equal( 382 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:2".format(ACCOUNT_ID) 383 ) 384 response["taskDefinition"]["taskRoleArn"].should.equal("my-task-role-arn") 385 response["taskDefinition"]["executionRoleArn"].should.equal("my-execution-role-arn") 386 387 response = client.describe_task_definition( 388 taskDefinition="test_ecs_task:1", include=["TAGS"] 389 ) 390 response["tags"].should.equal([{"key": "Name", "value": "test_ecs_task"}]) 391 392 393@mock_ecs 394def test_deregister_task_definition_1(): 395 client = boto3.client("ecs", region_name="us-east-1") 396 _ = client.register_task_definition( 397 family="test_ecs_task", 398 containerDefinitions=[ 399 { 400 "name": "hello_world", 401 "image": "docker/hello-world:latest", 402 "cpu": 1024, 403 "memory": 400, 404 "essential": True, 405 "environment": [ 406 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 407 ], 408 "logConfiguration": {"logDriver": "json-file"}, 409 } 410 ], 411 ) 412 response = client.deregister_task_definition(taskDefinition="test_ecs_task:1") 413 type(response["taskDefinition"]).should.be(dict) 414 response["taskDefinition"]["status"].should.equal("INACTIVE") 415 response["taskDefinition"]["taskDefinitionArn"].should.equal( 416 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:1".format(ACCOUNT_ID) 417 ) 418 response["taskDefinition"]["containerDefinitions"][0]["name"].should.equal( 419 "hello_world" 420 ) 421 response["taskDefinition"]["containerDefinitions"][0]["image"].should.equal( 422 "docker/hello-world:latest" 423 ) 424 response["taskDefinition"]["containerDefinitions"][0]["cpu"].should.equal(1024) 425 response["taskDefinition"]["containerDefinitions"][0]["memory"].should.equal(400) 426 response["taskDefinition"]["containerDefinitions"][0]["essential"].should.equal( 427 True 428 ) 429 response["taskDefinition"]["containerDefinitions"][0]["environment"][0][ 430 "name" 431 ].should.equal("AWS_ACCESS_KEY_ID") 432 response["taskDefinition"]["containerDefinitions"][0]["environment"][0][ 433 "value" 434 ].should.equal("SOME_ACCESS_KEY") 435 response["taskDefinition"]["containerDefinitions"][0]["logConfiguration"][ 436 "logDriver" 437 ].should.equal("json-file") 438 439 440@mock_ecs 441def test_deregister_task_definition_2(): 442 client = boto3.client("ecs", region_name="us-east-1") 443 client.deregister_task_definition.when.called_with( 444 taskDefinition="fake_task" 445 ).should.throw(ClientError, RevisionNotFoundException().message) 446 client.deregister_task_definition.when.called_with( 447 taskDefinition="fake_task:foo" 448 ).should.throw( 449 ClientError, 450 InvalidParameterException("Invalid revision number. Number: foo").message, 451 ) 452 client.deregister_task_definition.when.called_with( 453 taskDefinition="fake_task:1" 454 ).should.throw(ClientError, TaskDefinitionNotFoundException().message) 455 456 457@mock_ecs 458def test_create_service(): 459 client = boto3.client("ecs", region_name="us-east-1") 460 _ = client.create_cluster(clusterName="test_ecs_cluster") 461 _ = client.register_task_definition( 462 family="test_ecs_task", 463 containerDefinitions=[ 464 { 465 "name": "hello_world", 466 "image": "docker/hello-world:latest", 467 "cpu": 1024, 468 "memory": 400, 469 "essential": True, 470 "environment": [ 471 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 472 ], 473 "logConfiguration": {"logDriver": "json-file"}, 474 } 475 ], 476 ) 477 response = client.create_service( 478 cluster="test_ecs_cluster", 479 serviceName="test_ecs_service", 480 taskDefinition="test_ecs_task", 481 desiredCount=2, 482 ) 483 response["service"]["clusterArn"].should.equal( 484 "arn:aws:ecs:us-east-1:{}:cluster/test_ecs_cluster".format(ACCOUNT_ID) 485 ) 486 response["service"]["desiredCount"].should.equal(2) 487 len(response["service"]["events"]).should.equal(0) 488 len(response["service"]["loadBalancers"]).should.equal(0) 489 response["service"]["pendingCount"].should.equal(0) 490 response["service"]["runningCount"].should.equal(0) 491 response["service"]["serviceArn"].should.equal( 492 "arn:aws:ecs:us-east-1:{}:service/test_ecs_service".format(ACCOUNT_ID) 493 ) 494 response["service"]["serviceName"].should.equal("test_ecs_service") 495 response["service"]["status"].should.equal("ACTIVE") 496 response["service"]["taskDefinition"].should.equal( 497 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:1".format(ACCOUNT_ID) 498 ) 499 response["service"]["schedulingStrategy"].should.equal("REPLICA") 500 response["service"]["launchType"].should.equal("EC2") 501 502 503@mock_ecs 504def test_create_service_errors(): 505 # given 506 client = boto3.client("ecs", region_name="us-east-1") 507 _ = client.create_cluster(clusterName="test_ecs_cluster") 508 _ = client.register_task_definition( 509 family="test_ecs_task", 510 containerDefinitions=[ 511 { 512 "name": "hello_world", 513 "image": "docker/hello-world:latest", 514 "cpu": 1024, 515 "memory": 400, 516 "essential": True, 517 "environment": [ 518 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 519 ], 520 "logConfiguration": {"logDriver": "json-file"}, 521 } 522 ], 523 ) 524 525 # not existing launch type 526 # when 527 with pytest.raises(ClientError) as e: 528 client.create_service( 529 cluster="test_ecs_cluster", 530 serviceName="test_ecs_service", 531 taskDefinition="test_ecs_task", 532 desiredCount=2, 533 launchType="SOMETHING", 534 ) 535 536 # then 537 ex = e.value 538 ex.operation_name.should.equal("CreateService") 539 ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) 540 ex.response["Error"]["Code"].should.contain("ClientException") 541 ex.response["Error"]["Message"].should.equal( 542 "launch type should be one of [EC2,FARGATE]" 543 ) 544 545 546@mock_ecs 547def test_create_service_scheduling_strategy(): 548 client = boto3.client("ecs", region_name="us-east-1") 549 _ = client.create_cluster(clusterName="test_ecs_cluster") 550 _ = client.register_task_definition( 551 family="test_ecs_task", 552 containerDefinitions=[ 553 { 554 "name": "hello_world", 555 "image": "docker/hello-world:latest", 556 "cpu": 1024, 557 "memory": 400, 558 "essential": True, 559 "environment": [ 560 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 561 ], 562 "logConfiguration": {"logDriver": "json-file"}, 563 } 564 ], 565 ) 566 response = client.create_service( 567 cluster="test_ecs_cluster", 568 serviceName="test_ecs_service", 569 taskDefinition="test_ecs_task", 570 desiredCount=2, 571 schedulingStrategy="DAEMON", 572 ) 573 response["service"]["clusterArn"].should.equal( 574 "arn:aws:ecs:us-east-1:{}:cluster/test_ecs_cluster".format(ACCOUNT_ID) 575 ) 576 response["service"]["desiredCount"].should.equal(2) 577 len(response["service"]["events"]).should.equal(0) 578 len(response["service"]["loadBalancers"]).should.equal(0) 579 response["service"]["pendingCount"].should.equal(0) 580 response["service"]["runningCount"].should.equal(0) 581 response["service"]["serviceArn"].should.equal( 582 "arn:aws:ecs:us-east-1:{}:service/test_ecs_service".format(ACCOUNT_ID) 583 ) 584 response["service"]["serviceName"].should.equal("test_ecs_service") 585 response["service"]["status"].should.equal("ACTIVE") 586 response["service"]["taskDefinition"].should.equal( 587 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:1".format(ACCOUNT_ID) 588 ) 589 response["service"]["schedulingStrategy"].should.equal("DAEMON") 590 591 592@mock_ecs 593def test_list_services(): 594 client = boto3.client("ecs", region_name="us-east-1") 595 _ = client.create_cluster(clusterName="test_ecs_cluster") 596 _ = client.register_task_definition( 597 family="test_ecs_task", 598 containerDefinitions=[ 599 { 600 "name": "hello_world", 601 "image": "docker/hello-world:latest", 602 "cpu": 1024, 603 "memory": 400, 604 "essential": True, 605 "environment": [ 606 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 607 ], 608 "logConfiguration": {"logDriver": "json-file"}, 609 } 610 ], 611 ) 612 _ = client.create_service( 613 cluster="test_ecs_cluster", 614 serviceName="test_ecs_service1", 615 taskDefinition="test_ecs_task", 616 schedulingStrategy="REPLICA", 617 desiredCount=2, 618 ) 619 _ = client.create_service( 620 cluster="test_ecs_cluster", 621 serviceName="test_ecs_service2", 622 taskDefinition="test_ecs_task", 623 schedulingStrategy="DAEMON", 624 desiredCount=2, 625 ) 626 unfiltered_response = client.list_services(cluster="test_ecs_cluster") 627 len(unfiltered_response["serviceArns"]).should.equal(2) 628 unfiltered_response["serviceArns"][0].should.equal( 629 "arn:aws:ecs:us-east-1:{}:service/test_ecs_service1".format(ACCOUNT_ID) 630 ) 631 unfiltered_response["serviceArns"][1].should.equal( 632 "arn:aws:ecs:us-east-1:{}:service/test_ecs_service2".format(ACCOUNT_ID) 633 ) 634 635 filtered_response = client.list_services( 636 cluster="test_ecs_cluster", schedulingStrategy="REPLICA" 637 ) 638 len(filtered_response["serviceArns"]).should.equal(1) 639 filtered_response["serviceArns"][0].should.equal( 640 "arn:aws:ecs:us-east-1:{}:service/test_ecs_service1".format(ACCOUNT_ID) 641 ) 642 643 644@mock_ecs 645def test_describe_services(): 646 client = boto3.client("ecs", region_name="us-east-1") 647 _ = client.create_cluster(clusterName="test_ecs_cluster") 648 _ = client.register_task_definition( 649 family="test_ecs_task", 650 containerDefinitions=[ 651 { 652 "name": "hello_world", 653 "image": "docker/hello-world:latest", 654 "cpu": 1024, 655 "memory": 400, 656 "essential": True, 657 "environment": [ 658 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 659 ], 660 "logConfiguration": {"logDriver": "json-file"}, 661 } 662 ], 663 ) 664 _ = client.create_service( 665 cluster="test_ecs_cluster", 666 serviceName="test_ecs_service1", 667 taskDefinition="test_ecs_task", 668 desiredCount=2, 669 tags=[{"key": "Name", "value": "test_ecs_service1"}], 670 ) 671 _ = client.create_service( 672 cluster="test_ecs_cluster", 673 serviceName="test_ecs_service2", 674 taskDefinition="test_ecs_task", 675 desiredCount=2, 676 ) 677 _ = client.create_service( 678 cluster="test_ecs_cluster", 679 serviceName="test_ecs_service3", 680 taskDefinition="test_ecs_task", 681 desiredCount=2, 682 ) 683 response = client.describe_services( 684 cluster="test_ecs_cluster", 685 services=[ 686 "test_ecs_service1", 687 "arn:aws:ecs:us-east-1:{}:service/test_ecs_service2".format(ACCOUNT_ID), 688 ], 689 ) 690 len(response["services"]).should.equal(2) 691 response["services"][0]["serviceArn"].should.equal( 692 "arn:aws:ecs:us-east-1:{}:service/test_ecs_service1".format(ACCOUNT_ID) 693 ) 694 response["services"][0]["serviceName"].should.equal("test_ecs_service1") 695 response["services"][1]["serviceArn"].should.equal( 696 "arn:aws:ecs:us-east-1:{}:service/test_ecs_service2".format(ACCOUNT_ID) 697 ) 698 response["services"][1]["serviceName"].should.equal("test_ecs_service2") 699 700 response["services"][0]["deployments"][0]["desiredCount"].should.equal(2) 701 response["services"][0]["deployments"][0]["pendingCount"].should.equal(2) 702 response["services"][0]["deployments"][0]["runningCount"].should.equal(0) 703 response["services"][0]["deployments"][0]["status"].should.equal("PRIMARY") 704 response["services"][0]["deployments"][0]["launchType"].should.equal("EC2") 705 ( 706 datetime.now() 707 - response["services"][0]["deployments"][0]["createdAt"].replace(tzinfo=None) 708 ).seconds.should.be.within(0, 10) 709 ( 710 datetime.now() 711 - response["services"][0]["deployments"][0]["updatedAt"].replace(tzinfo=None) 712 ).seconds.should.be.within(0, 10) 713 response = client.describe_services( 714 cluster="test_ecs_cluster", 715 services=[ 716 "test_ecs_service1", 717 "arn:aws:ecs:us-east-1:{}:service/test_ecs_service2".format(ACCOUNT_ID), 718 ], 719 include=["TAGS"], 720 ) 721 response["services"][0]["tags"].should.equal( 722 [{"key": "Name", "value": "test_ecs_service1"}] 723 ) 724 response["services"][1]["tags"].should.equal([]) 725 response["services"][0]["launchType"].should.equal("EC2") 726 response["services"][1]["launchType"].should.equal("EC2") 727 728 729@mock_ecs 730@mock.patch.dict(os.environ, {"MOTO_ECS_NEW_ARN": "TrUe"}) 731def test_describe_services_new_arn(): 732 if settings.TEST_SERVER_MODE: 733 raise SkipTest("Cant set environment variables in server mode") 734 client = boto3.client("ecs", region_name="us-east-1") 735 _ = client.create_cluster(clusterName="test_ecs_cluster") 736 _ = client.register_task_definition( 737 family="test_ecs_task", 738 containerDefinitions=[ 739 {"name": "hello_world", "image": "docker/hello-world:latest",} 740 ], 741 ) 742 _ = client.create_service( 743 cluster="test_ecs_cluster", 744 serviceName="test_ecs_service1", 745 taskDefinition="test_ecs_task", 746 desiredCount=2, 747 tags=[{"key": "Name", "value": "test_ecs_service1"}], 748 ) 749 response = client.describe_services( 750 cluster="test_ecs_cluster", services=["test_ecs_service1"] 751 ) 752 response["services"][0]["serviceArn"].should.equal( 753 "arn:aws:ecs:us-east-1:{}:service/test_ecs_cluster/test_ecs_service1".format( 754 ACCOUNT_ID 755 ) 756 ) 757 758 759@mock_ecs 760def test_describe_services_scheduling_strategy(): 761 client = boto3.client("ecs", region_name="us-east-1") 762 _ = client.create_cluster(clusterName="test_ecs_cluster") 763 _ = client.register_task_definition( 764 family="test_ecs_task", 765 containerDefinitions=[ 766 { 767 "name": "hello_world", 768 "image": "docker/hello-world:latest", 769 "cpu": 1024, 770 "memory": 400, 771 "essential": True, 772 "environment": [ 773 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 774 ], 775 "logConfiguration": {"logDriver": "json-file"}, 776 } 777 ], 778 ) 779 _ = client.create_service( 780 cluster="test_ecs_cluster", 781 serviceName="test_ecs_service1", 782 taskDefinition="test_ecs_task", 783 desiredCount=2, 784 ) 785 _ = client.create_service( 786 cluster="test_ecs_cluster", 787 serviceName="test_ecs_service2", 788 taskDefinition="test_ecs_task", 789 desiredCount=2, 790 schedulingStrategy="DAEMON", 791 ) 792 _ = client.create_service( 793 cluster="test_ecs_cluster", 794 serviceName="test_ecs_service3", 795 taskDefinition="test_ecs_task", 796 desiredCount=2, 797 ) 798 response = client.describe_services( 799 cluster="test_ecs_cluster", 800 services=[ 801 "test_ecs_service1", 802 "arn:aws:ecs:us-east-1:{}:service/test_ecs_service2".format(ACCOUNT_ID), 803 "test_ecs_service3", 804 ], 805 ) 806 len(response["services"]).should.equal(3) 807 response["services"][0]["serviceArn"].should.equal( 808 "arn:aws:ecs:us-east-1:{}:service/test_ecs_service1".format(ACCOUNT_ID) 809 ) 810 response["services"][0]["serviceName"].should.equal("test_ecs_service1") 811 response["services"][1]["serviceArn"].should.equal( 812 "arn:aws:ecs:us-east-1:{}:service/test_ecs_service2".format(ACCOUNT_ID) 813 ) 814 response["services"][1]["serviceName"].should.equal("test_ecs_service2") 815 816 response["services"][0]["deployments"][0]["desiredCount"].should.equal(2) 817 response["services"][0]["deployments"][0]["pendingCount"].should.equal(2) 818 response["services"][0]["deployments"][0]["runningCount"].should.equal(0) 819 response["services"][0]["deployments"][0]["status"].should.equal("PRIMARY") 820 821 response["services"][0]["schedulingStrategy"].should.equal("REPLICA") 822 response["services"][1]["schedulingStrategy"].should.equal("DAEMON") 823 response["services"][2]["schedulingStrategy"].should.equal("REPLICA") 824 825 826@mock_ecs 827def test_describe_services_error_unknown_cluster(): 828 # given 829 client = boto3.client("ecs", region_name="eu-central-1") 830 cluster_name = "unknown" 831 832 # when 833 with pytest.raises(ClientError) as e: 834 client.describe_services( 835 cluster=cluster_name, services=["test"], 836 ) 837 838 # then 839 ex = e.value 840 ex.operation_name.should.equal("DescribeServices") 841 ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) 842 ex.response["Error"]["Code"].should.contain("ClusterNotFoundException") 843 ex.response["Error"]["Message"].should.equal("Cluster not found.") 844 845 846@mock_ecs 847def test_describe_services_with_known_unknown_services(): 848 # given 849 client = boto3.client("ecs", region_name="eu-central-1") 850 cluster_name = "test_cluster" 851 task_name = "test_task" 852 service_name = "test_service" 853 client.create_cluster(clusterName=cluster_name) 854 client.register_task_definition( 855 family=task_name, 856 containerDefinitions=[ 857 { 858 "name": "hello_world", 859 "image": "docker/hello-world:latest", 860 "cpu": 256, 861 "memory": 512, 862 "essential": True, 863 } 864 ], 865 ) 866 service_arn = client.create_service( 867 cluster=cluster_name, 868 serviceName=service_name, 869 taskDefinition=task_name, 870 desiredCount=1, 871 )["service"]["serviceArn"] 872 873 # when 874 response = client.describe_services( 875 cluster=cluster_name, 876 services=[ 877 service_name, 878 "unknown", 879 service_arn, 880 "arn:aws:ecs:eu-central-1:{}:service/unknown-2".format(ACCOUNT_ID), 881 ], 882 ) 883 884 # then 885 services = response["services"] 886 services.should.have.length_of(2) 887 [service["serviceArn"] for service in services].should.equal( 888 [service_arn, service_arn] 889 ) 890 891 failures = response["failures"] 892 failures.should.have.length_of(2) 893 sorted(failures, key=lambda item: item["arn"]).should.equal( 894 [ 895 { 896 "arn": "arn:aws:ecs:eu-central-1:{}:service/unknown".format(ACCOUNT_ID), 897 "reason": "MISSING", 898 }, 899 { 900 "arn": "arn:aws:ecs:eu-central-1:{}:service/unknown-2".format( 901 ACCOUNT_ID 902 ), 903 "reason": "MISSING", 904 }, 905 ] 906 ) 907 908 909@mock_ecs 910def test_update_service(): 911 client = boto3.client("ecs", region_name="us-east-1") 912 _ = client.create_cluster(clusterName="test_ecs_cluster") 913 _ = client.register_task_definition( 914 family="test_ecs_task", 915 containerDefinitions=[ 916 { 917 "name": "hello_world", 918 "image": "docker/hello-world:latest", 919 "cpu": 1024, 920 "memory": 400, 921 "essential": True, 922 "environment": [ 923 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 924 ], 925 "logConfiguration": {"logDriver": "json-file"}, 926 } 927 ], 928 ) 929 response = client.create_service( 930 cluster="test_ecs_cluster", 931 serviceName="test_ecs_service", 932 taskDefinition="test_ecs_task", 933 desiredCount=2, 934 ) 935 response["service"]["desiredCount"].should.equal(2) 936 937 response = client.update_service( 938 cluster="test_ecs_cluster", 939 service="test_ecs_service", 940 taskDefinition="test_ecs_task", 941 desiredCount=0, 942 ) 943 response["service"]["desiredCount"].should.equal(0) 944 response["service"]["schedulingStrategy"].should.equal("REPLICA") 945 946 # Verify we can pass the ARNs of the cluster and service 947 response = client.update_service( 948 cluster=response["service"]["clusterArn"], 949 service=response["service"]["serviceArn"], 950 taskDefinition="test_ecs_task", 951 desiredCount=1, 952 ) 953 response["service"]["desiredCount"].should.equal(1) 954 955 956@mock_ecs 957def test_update_missing_service(): 958 client = boto3.client("ecs", region_name="us-east-1") 959 _ = client.create_cluster(clusterName="test_ecs_cluster") 960 961 client.update_service.when.called_with( 962 cluster="test_ecs_cluster", 963 service="test_ecs_service", 964 taskDefinition="test_ecs_task", 965 desiredCount=0, 966 ).should.throw(ClientError) 967 968 969@mock_ecs 970def test_delete_service(): 971 client = boto3.client("ecs", region_name="us-east-1") 972 _ = client.create_cluster(clusterName="test_ecs_cluster") 973 _ = client.register_task_definition( 974 family="test_ecs_task", 975 containerDefinitions=[ 976 { 977 "name": "hello_world", 978 "image": "docker/hello-world:latest", 979 "cpu": 1024, 980 "memory": 400, 981 "essential": True, 982 "environment": [ 983 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 984 ], 985 "logConfiguration": {"logDriver": "json-file"}, 986 } 987 ], 988 ) 989 _ = client.create_service( 990 cluster="test_ecs_cluster", 991 serviceName="test_ecs_service", 992 taskDefinition="test_ecs_task", 993 desiredCount=2, 994 ) 995 _ = client.update_service( 996 cluster="test_ecs_cluster", service="test_ecs_service", desiredCount=0 997 ) 998 response = client.delete_service( 999 cluster="test_ecs_cluster", service="test_ecs_service" 1000 ) 1001 response["service"]["clusterArn"].should.equal( 1002 "arn:aws:ecs:us-east-1:{}:cluster/test_ecs_cluster".format(ACCOUNT_ID) 1003 ) 1004 response["service"]["desiredCount"].should.equal(0) 1005 len(response["service"]["events"]).should.equal(0) 1006 len(response["service"]["loadBalancers"]).should.equal(0) 1007 response["service"]["pendingCount"].should.equal(0) 1008 response["service"]["runningCount"].should.equal(0) 1009 response["service"]["serviceArn"].should.equal( 1010 "arn:aws:ecs:us-east-1:{}:service/test_ecs_service".format(ACCOUNT_ID) 1011 ) 1012 response["service"]["serviceName"].should.equal("test_ecs_service") 1013 response["service"]["status"].should.equal("ACTIVE") 1014 response["service"]["schedulingStrategy"].should.equal("REPLICA") 1015 response["service"]["taskDefinition"].should.equal( 1016 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:1".format(ACCOUNT_ID) 1017 ) 1018 1019 1020@mock_ecs 1021def test_delete_service_force(): 1022 client = boto3.client("ecs", region_name="us-east-1") 1023 _ = client.create_cluster(clusterName="test_ecs_cluster") 1024 _ = client.register_task_definition( 1025 family="test_ecs_task", 1026 containerDefinitions=[ 1027 { 1028 "name": "hello_world", 1029 "image": "docker/hello-world:latest", 1030 "cpu": 1024, 1031 "memory": 400, 1032 "essential": True, 1033 "environment": [ 1034 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 1035 ], 1036 "logConfiguration": {"logDriver": "json-file"}, 1037 } 1038 ], 1039 ) 1040 _ = client.create_service( 1041 cluster="test_ecs_cluster", 1042 serviceName="test_ecs_service", 1043 taskDefinition="test_ecs_task", 1044 desiredCount=2, 1045 ) 1046 response = client.delete_service( 1047 cluster="test_ecs_cluster", service="test_ecs_service", force=True 1048 ) 1049 response["service"]["clusterArn"].should.equal( 1050 "arn:aws:ecs:us-east-1:{}:cluster/test_ecs_cluster".format(ACCOUNT_ID) 1051 ) 1052 len(response["service"]["events"]).should.equal(0) 1053 len(response["service"]["loadBalancers"]).should.equal(0) 1054 response["service"]["pendingCount"].should.equal(0) 1055 response["service"]["runningCount"].should.equal(0) 1056 response["service"]["serviceArn"].should.equal( 1057 "arn:aws:ecs:us-east-1:{}:service/test_ecs_service".format(ACCOUNT_ID) 1058 ) 1059 response["service"]["serviceName"].should.equal("test_ecs_service") 1060 response["service"]["status"].should.equal("ACTIVE") 1061 response["service"]["schedulingStrategy"].should.equal("REPLICA") 1062 response["service"]["taskDefinition"].should.equal( 1063 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:1".format(ACCOUNT_ID) 1064 ) 1065 1066 1067@mock_ecs 1068def test_delete_service_exceptions(): 1069 client = boto3.client("ecs", region_name="us-east-1") 1070 1071 # Raises ClusterNotFoundException because "default" is not a cluster 1072 client.delete_service.when.called_with(service="not_as_service").should.throw( 1073 ClientError, ClusterNotFoundException().message 1074 ) 1075 1076 _ = client.create_cluster() 1077 client.delete_service.when.called_with(service="not_as_service").should.throw( 1078 ClientError, ServiceNotFoundException().message 1079 ) 1080 1081 _ = client.register_task_definition( 1082 family="test_ecs_task", 1083 containerDefinitions=[ 1084 { 1085 "name": "hello_world", 1086 "image": "docker/hello-world:latest", 1087 "cpu": 1024, 1088 "memory": 400, 1089 } 1090 ], 1091 ) 1092 1093 _ = client.create_service( 1094 serviceName="test_ecs_service", taskDefinition="test_ecs_task", desiredCount=1, 1095 ) 1096 1097 client.delete_service.when.called_with(service="test_ecs_service").should.throw( 1098 ClientError, 1099 InvalidParameterException( 1100 "The service cannot be stopped while it is scaled above 0." 1101 ).message, 1102 ) 1103 1104 1105@mock_ecs 1106def test_update_service_exceptions(): 1107 client = boto3.client("ecs", region_name="us-east-1") 1108 1109 client.update_service.when.called_with( 1110 service="not_a_service", desiredCount=0 1111 ).should.throw(ClientError, ClusterNotFoundException().message) 1112 1113 _ = client.create_cluster() 1114 1115 client.update_service.when.called_with( 1116 service="not_a_service", desiredCount=0 1117 ).should.throw(ClientError, ServiceNotFoundException().message) 1118 1119 1120@mock_ec2 1121@mock_ecs 1122def test_register_container_instance(): 1123 ecs_client = boto3.client("ecs", region_name="us-east-1") 1124 ec2 = boto3.resource("ec2", region_name="us-east-1") 1125 1126 test_cluster_name = "test_ecs_cluster" 1127 1128 _ = ecs_client.create_cluster(clusterName=test_cluster_name) 1129 1130 test_instance = ec2.create_instances( 1131 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 1132 )[0] 1133 1134 instance_id_document = json.dumps( 1135 ec2_utils.generate_instance_identity_document(test_instance) 1136 ) 1137 1138 response = ecs_client.register_container_instance( 1139 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 1140 ) 1141 1142 response["containerInstance"]["ec2InstanceId"].should.equal(test_instance.id) 1143 full_arn = response["containerInstance"]["containerInstanceArn"] 1144 arn_part = full_arn.split("/") 1145 arn_part[0].should.equal( 1146 "arn:aws:ecs:us-east-1:{}:container-instance".format(ACCOUNT_ID) 1147 ) 1148 arn_part[1].should.equal(str(UUID(arn_part[1]))) 1149 response["containerInstance"]["status"].should.equal("ACTIVE") 1150 len(response["containerInstance"]["registeredResources"]).should.equal(4) 1151 len(response["containerInstance"]["remainingResources"]).should.equal(4) 1152 response["containerInstance"]["agentConnected"].should.equal(True) 1153 response["containerInstance"]["versionInfo"]["agentVersion"].should.equal("1.0.0") 1154 response["containerInstance"]["versionInfo"]["agentHash"].should.equal("4023248") 1155 response["containerInstance"]["versionInfo"]["dockerVersion"].should.equal( 1156 "DockerVersion: 1.5.0" 1157 ) 1158 1159 1160@mock_ec2 1161@mock_ecs 1162@mock.patch.dict(os.environ, {"MOTO_ECS_NEW_ARN": "TrUe"}) 1163def test_register_container_instance_new_arn_format(): 1164 if settings.TEST_SERVER_MODE: 1165 raise SkipTest("Cant set environment variables in server mode") 1166 ecs_client = boto3.client("ecs", region_name="us-east-1") 1167 ec2 = boto3.resource("ec2", region_name="us-east-1") 1168 1169 test_cluster_name = "test_ecs_cluster" 1170 1171 ecs_client.create_cluster(clusterName=test_cluster_name) 1172 1173 test_instance = ec2.create_instances( 1174 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 1175 )[0] 1176 1177 instance_id_document = json.dumps( 1178 ec2_utils.generate_instance_identity_document(test_instance) 1179 ) 1180 1181 response = ecs_client.register_container_instance( 1182 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 1183 ) 1184 1185 full_arn = response["containerInstance"]["containerInstanceArn"] 1186 full_arn.should.match( 1187 f"arn:aws:ecs:us-east-1:{ACCOUNT_ID}:container-instance/{test_cluster_name}/[a-z0-9-]+$" 1188 ) 1189 1190 1191@mock_ec2 1192@mock_ecs 1193def test_deregister_container_instance(): 1194 ecs_client = boto3.client("ecs", region_name="us-east-1") 1195 ec2 = boto3.resource("ec2", region_name="us-east-1") 1196 1197 test_cluster_name = "test_ecs_cluster" 1198 1199 _ = ecs_client.create_cluster(clusterName=test_cluster_name) 1200 1201 test_instance = ec2.create_instances( 1202 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 1203 )[0] 1204 1205 instance_id_document = json.dumps( 1206 ec2_utils.generate_instance_identity_document(test_instance) 1207 ) 1208 1209 response = ecs_client.register_container_instance( 1210 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 1211 ) 1212 container_instance_id = response["containerInstance"]["containerInstanceArn"] 1213 response = ecs_client.deregister_container_instance( 1214 cluster=test_cluster_name, containerInstance=container_instance_id 1215 ) 1216 container_instances_response = ecs_client.list_container_instances( 1217 cluster=test_cluster_name 1218 ) 1219 len(container_instances_response["containerInstanceArns"]).should.equal(0) 1220 1221 response = ecs_client.register_container_instance( 1222 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 1223 ) 1224 container_instance_id = response["containerInstance"]["containerInstanceArn"] 1225 _ = ecs_client.register_task_definition( 1226 family="test_ecs_task", 1227 containerDefinitions=[ 1228 { 1229 "name": "hello_world", 1230 "image": "docker/hello-world:latest", 1231 "cpu": 1024, 1232 "memory": 400, 1233 "essential": True, 1234 "environment": [ 1235 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 1236 ], 1237 "logConfiguration": {"logDriver": "json-file"}, 1238 } 1239 ], 1240 ) 1241 1242 ecs_client.start_task( 1243 cluster="test_ecs_cluster", 1244 taskDefinition="test_ecs_task", 1245 overrides={}, 1246 containerInstances=[container_instance_id], 1247 startedBy="moto", 1248 ) 1249 with pytest.raises(Exception): 1250 ecs_client.deregister_container_instance( 1251 cluster=test_cluster_name, containerInstance=container_instance_id 1252 ) 1253 # TODO: Return correct error format 1254 # should.contain("Found running tasks on the instance") 1255 1256 container_instances_response = ecs_client.list_container_instances( 1257 cluster=test_cluster_name 1258 ) 1259 len(container_instances_response["containerInstanceArns"]).should.equal(1) 1260 ecs_client.deregister_container_instance( 1261 cluster=test_cluster_name, containerInstance=container_instance_id, force=True 1262 ) 1263 container_instances_response = ecs_client.list_container_instances( 1264 cluster=test_cluster_name 1265 ) 1266 len(container_instances_response["containerInstanceArns"]).should.equal(0) 1267 1268 1269@mock_ec2 1270@mock_ecs 1271def test_list_container_instances(): 1272 ecs_client = boto3.client("ecs", region_name="us-east-1") 1273 ec2 = boto3.resource("ec2", region_name="us-east-1") 1274 1275 test_cluster_name = "test_ecs_cluster" 1276 _ = ecs_client.create_cluster(clusterName=test_cluster_name) 1277 1278 instance_to_create = 3 1279 test_instance_arns = [] 1280 for _ in range(0, instance_to_create): 1281 test_instance = ec2.create_instances( 1282 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 1283 )[0] 1284 1285 instance_id_document = json.dumps( 1286 ec2_utils.generate_instance_identity_document(test_instance) 1287 ) 1288 1289 response = ecs_client.register_container_instance( 1290 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 1291 ) 1292 1293 test_instance_arns.append(response["containerInstance"]["containerInstanceArn"]) 1294 1295 response = ecs_client.list_container_instances(cluster=test_cluster_name) 1296 1297 len(response["containerInstanceArns"]).should.equal(instance_to_create) 1298 for arn in test_instance_arns: 1299 response["containerInstanceArns"].should.contain(arn) 1300 1301 1302@mock_ec2 1303@mock_ecs 1304def test_describe_container_instances(): 1305 ecs_client = boto3.client("ecs", region_name="us-east-1") 1306 ec2 = boto3.resource("ec2", region_name="us-east-1") 1307 1308 test_cluster_name = "test_ecs_cluster" 1309 _ = ecs_client.create_cluster(clusterName=test_cluster_name) 1310 1311 instance_to_create = 3 1312 test_instance_arns = [] 1313 for _ in range(0, instance_to_create): 1314 test_instance = ec2.create_instances( 1315 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 1316 )[0] 1317 1318 instance_id_document = json.dumps( 1319 ec2_utils.generate_instance_identity_document(test_instance) 1320 ) 1321 1322 response = ecs_client.register_container_instance( 1323 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 1324 ) 1325 1326 test_instance_arns.append(response["containerInstance"]["containerInstanceArn"]) 1327 1328 test_instance_ids = list(map((lambda x: x.split("/")[1]), test_instance_arns)) 1329 response = ecs_client.describe_container_instances( 1330 cluster=test_cluster_name, containerInstances=test_instance_ids 1331 ) 1332 len(response["failures"]).should.equal(0) 1333 len(response["containerInstances"]).should.equal(instance_to_create) 1334 response_arns = [ 1335 ci["containerInstanceArn"] for ci in response["containerInstances"] 1336 ] 1337 for arn in test_instance_arns: 1338 response_arns.should.contain(arn) 1339 for instance in response["containerInstances"]: 1340 instance.keys().should.contain("runningTasksCount") 1341 instance.keys().should.contain("pendingTasksCount") 1342 instance["registeredAt"].should.be.a("datetime.datetime") 1343 1344 with pytest.raises(ClientError) as e: 1345 ecs_client.describe_container_instances( 1346 cluster=test_cluster_name, containerInstances=[] 1347 ) 1348 err = e.value.response["Error"] 1349 err["Code"].should.equal("ClientException") 1350 err["Message"].should.equal("Container Instances cannot be empty.") 1351 1352 1353@mock_ecs 1354def test_describe_container_instances_exceptions(): 1355 client = boto3.client("ecs", region_name="us-east-1") 1356 1357 client.describe_container_instances.when.called_with( 1358 containerInstances=[] 1359 ).should.throw(ClientError, ClusterNotFoundException().message) 1360 1361 _ = client.create_cluster() 1362 client.describe_container_instances.when.called_with( 1363 containerInstances=[] 1364 ).should.throw( 1365 ClientError, 1366 InvalidParameterException("Container Instances cannot be empty.").message, 1367 ) 1368 1369 1370@mock_ec2 1371@mock_ecs 1372def test_update_container_instances_state(): 1373 ecs_client = boto3.client("ecs", region_name="us-east-1") 1374 ec2 = boto3.resource("ec2", region_name="us-east-1") 1375 1376 test_cluster_name = "test_ecs_cluster" 1377 _ = ecs_client.create_cluster(clusterName=test_cluster_name) 1378 1379 instance_to_create = 3 1380 test_instance_arns = [] 1381 for _ in range(0, instance_to_create): 1382 test_instance = ec2.create_instances( 1383 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 1384 )[0] 1385 1386 instance_id_document = json.dumps( 1387 ec2_utils.generate_instance_identity_document(test_instance) 1388 ) 1389 1390 response = ecs_client.register_container_instance( 1391 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 1392 ) 1393 1394 test_instance_arns.append(response["containerInstance"]["containerInstanceArn"]) 1395 1396 test_instance_ids = list(map((lambda x: x.split("/")[1]), test_instance_arns)) 1397 response = ecs_client.update_container_instances_state( 1398 cluster=test_cluster_name, 1399 containerInstances=test_instance_ids, 1400 status="DRAINING", 1401 ) 1402 len(response["failures"]).should.equal(0) 1403 len(response["containerInstances"]).should.equal(instance_to_create) 1404 response_statuses = [ci["status"] for ci in response["containerInstances"]] 1405 for status in response_statuses: 1406 status.should.equal("DRAINING") 1407 response = ecs_client.update_container_instances_state( 1408 cluster=test_cluster_name, 1409 containerInstances=test_instance_ids, 1410 status="DRAINING", 1411 ) 1412 len(response["failures"]).should.equal(0) 1413 len(response["containerInstances"]).should.equal(instance_to_create) 1414 response_statuses = [ci["status"] for ci in response["containerInstances"]] 1415 for status in response_statuses: 1416 status.should.equal("DRAINING") 1417 response = ecs_client.update_container_instances_state( 1418 cluster=test_cluster_name, containerInstances=test_instance_ids, status="ACTIVE" 1419 ) 1420 len(response["failures"]).should.equal(0) 1421 len(response["containerInstances"]).should.equal(instance_to_create) 1422 response_statuses = [ci["status"] for ci in response["containerInstances"]] 1423 for status in response_statuses: 1424 status.should.equal("ACTIVE") 1425 ecs_client.update_container_instances_state.when.called_with( 1426 cluster=test_cluster_name, 1427 containerInstances=test_instance_ids, 1428 status="test_status", 1429 ).should.throw(Exception) 1430 1431 1432@mock_ec2 1433@mock_ecs 1434def test_update_container_instances_state_by_arn(): 1435 ecs_client = boto3.client("ecs", region_name="us-east-1") 1436 ec2 = boto3.resource("ec2", region_name="us-east-1") 1437 1438 test_cluster_name = "test_ecs_cluster" 1439 _ = ecs_client.create_cluster(clusterName=test_cluster_name) 1440 1441 instance_to_create = 3 1442 test_instance_arns = [] 1443 for _ in range(0, instance_to_create): 1444 test_instance = ec2.create_instances( 1445 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 1446 )[0] 1447 1448 instance_id_document = json.dumps( 1449 ec2_utils.generate_instance_identity_document(test_instance) 1450 ) 1451 1452 response = ecs_client.register_container_instance( 1453 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 1454 ) 1455 1456 test_instance_arns.append(response["containerInstance"]["containerInstanceArn"]) 1457 1458 response = ecs_client.update_container_instances_state( 1459 cluster=test_cluster_name, 1460 containerInstances=test_instance_arns, 1461 status="DRAINING", 1462 ) 1463 len(response["failures"]).should.equal(0) 1464 len(response["containerInstances"]).should.equal(instance_to_create) 1465 response_statuses = [ci["status"] for ci in response["containerInstances"]] 1466 for status in response_statuses: 1467 status.should.equal("DRAINING") 1468 response = ecs_client.update_container_instances_state( 1469 cluster=test_cluster_name, 1470 containerInstances=test_instance_arns, 1471 status="DRAINING", 1472 ) 1473 len(response["failures"]).should.equal(0) 1474 len(response["containerInstances"]).should.equal(instance_to_create) 1475 response_statuses = [ci["status"] for ci in response["containerInstances"]] 1476 for status in response_statuses: 1477 status.should.equal("DRAINING") 1478 response = ecs_client.update_container_instances_state( 1479 cluster=test_cluster_name, 1480 containerInstances=test_instance_arns, 1481 status="ACTIVE", 1482 ) 1483 len(response["failures"]).should.equal(0) 1484 len(response["containerInstances"]).should.equal(instance_to_create) 1485 response_statuses = [ci["status"] for ci in response["containerInstances"]] 1486 for status in response_statuses: 1487 status.should.equal("ACTIVE") 1488 ecs_client.update_container_instances_state.when.called_with( 1489 cluster=test_cluster_name, 1490 containerInstances=test_instance_arns, 1491 status="test_status", 1492 ).should.throw(Exception) 1493 1494 1495@mock_ec2 1496@mock_ecs 1497def test_run_task(): 1498 client = boto3.client("ecs", region_name="us-east-1") 1499 ec2 = boto3.resource("ec2", region_name="us-east-1") 1500 1501 test_cluster_name = "test_ecs_cluster" 1502 1503 _ = client.create_cluster(clusterName=test_cluster_name) 1504 1505 test_instance = ec2.create_instances( 1506 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 1507 )[0] 1508 1509 instance_id_document = json.dumps( 1510 ec2_utils.generate_instance_identity_document(test_instance) 1511 ) 1512 1513 response = client.register_container_instance( 1514 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 1515 ) 1516 1517 _ = client.register_task_definition( 1518 family="test_ecs_task", 1519 containerDefinitions=[ 1520 { 1521 "name": "hello_world", 1522 "image": "docker/hello-world:latest", 1523 "cpu": 1024, 1524 "memory": 400, 1525 "essential": True, 1526 "environment": [ 1527 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 1528 ], 1529 "logConfiguration": {"logDriver": "json-file"}, 1530 } 1531 ], 1532 ) 1533 response = client.run_task( 1534 cluster="test_ecs_cluster", 1535 overrides={}, 1536 taskDefinition="test_ecs_task", 1537 count=2, 1538 startedBy="moto", 1539 tags=[ 1540 {"key": "tagKey0", "value": "tagValue0"}, 1541 {"key": "tagKey1", "value": "tagValue1"}, 1542 ], 1543 ) 1544 len(response["tasks"]).should.equal(2) 1545 response["tasks"][0]["taskArn"].should.contain( 1546 "arn:aws:ecs:us-east-1:{}:task/".format(ACCOUNT_ID) 1547 ) 1548 response["tasks"][0]["clusterArn"].should.equal( 1549 "arn:aws:ecs:us-east-1:{}:cluster/test_ecs_cluster".format(ACCOUNT_ID) 1550 ) 1551 response["tasks"][0]["taskDefinitionArn"].should.equal( 1552 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:1".format(ACCOUNT_ID) 1553 ) 1554 response["tasks"][0]["containerInstanceArn"].should.contain( 1555 "arn:aws:ecs:us-east-1:{}:container-instance/".format(ACCOUNT_ID) 1556 ) 1557 response["tasks"][0]["overrides"].should.equal({}) 1558 response["tasks"][0]["lastStatus"].should.equal("RUNNING") 1559 response["tasks"][0]["desiredStatus"].should.equal("RUNNING") 1560 response["tasks"][0]["startedBy"].should.equal("moto") 1561 response["tasks"][0]["stoppedReason"].should.equal("") 1562 response["tasks"][0]["tags"][0].get("value").should.equal("tagValue0") 1563 1564 1565@mock_ec2 1566@mock_ecs 1567def test_run_task_default_cluster(): 1568 client = boto3.client("ecs", region_name="us-east-1") 1569 ec2 = boto3.resource("ec2", region_name="us-east-1") 1570 1571 test_cluster_name = "default" 1572 1573 _ = client.create_cluster(clusterName=test_cluster_name) 1574 1575 test_instance = ec2.create_instances( 1576 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 1577 )[0] 1578 1579 instance_id_document = json.dumps( 1580 ec2_utils.generate_instance_identity_document(test_instance) 1581 ) 1582 1583 response = client.register_container_instance( 1584 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 1585 ) 1586 1587 _ = client.register_task_definition( 1588 family="test_ecs_task", 1589 containerDefinitions=[ 1590 { 1591 "name": "hello_world", 1592 "image": "docker/hello-world:latest", 1593 "cpu": 1024, 1594 "memory": 400, 1595 "essential": True, 1596 "environment": [ 1597 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 1598 ], 1599 "logConfiguration": {"logDriver": "json-file"}, 1600 } 1601 ], 1602 ) 1603 response = client.run_task( 1604 launchType="FARGATE", 1605 overrides={}, 1606 taskDefinition="test_ecs_task", 1607 count=2, 1608 startedBy="moto", 1609 ) 1610 len(response["tasks"]).should.equal(2) 1611 response["tasks"][0]["taskArn"].should.match( 1612 "arn:aws:ecs:us-east-1:{}:task/[a-z0-9-]+$".format(ACCOUNT_ID) 1613 ) 1614 response["tasks"][0]["clusterArn"].should.equal( 1615 "arn:aws:ecs:us-east-1:{}:cluster/default".format(ACCOUNT_ID) 1616 ) 1617 response["tasks"][0]["taskDefinitionArn"].should.equal( 1618 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:1".format(ACCOUNT_ID) 1619 ) 1620 response["tasks"][0]["containerInstanceArn"].should.contain( 1621 "arn:aws:ecs:us-east-1:{}:container-instance/".format(ACCOUNT_ID) 1622 ) 1623 response["tasks"][0]["overrides"].should.equal({}) 1624 response["tasks"][0]["lastStatus"].should.equal("RUNNING") 1625 response["tasks"][0]["desiredStatus"].should.equal("RUNNING") 1626 response["tasks"][0]["startedBy"].should.equal("moto") 1627 response["tasks"][0]["stoppedReason"].should.equal("") 1628 1629 1630@mock_ec2 1631@mock_ecs 1632@mock.patch.dict(os.environ, {"MOTO_ECS_NEW_ARN": "TrUe"}) 1633def test_run_task_default_cluster_new_arn_format(): 1634 if settings.TEST_SERVER_MODE: 1635 raise SkipTest("Cant set environment variables in server mode") 1636 client = boto3.client("ecs", region_name="us-east-1") 1637 ec2 = boto3.resource("ec2", region_name="us-east-1") 1638 1639 test_cluster_name = "default" 1640 1641 client.create_cluster(clusterName=test_cluster_name) 1642 1643 test_instance = ec2.create_instances( 1644 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 1645 )[0] 1646 1647 instance_id_document = json.dumps( 1648 ec2_utils.generate_instance_identity_document(test_instance) 1649 ) 1650 1651 client.register_container_instance( 1652 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 1653 ) 1654 1655 client.register_task_definition( 1656 family="test_ecs_task", 1657 containerDefinitions=[ 1658 { 1659 "name": "hello_world", 1660 "image": "docker/hello-world:latest", 1661 "cpu": 1024, 1662 "memory": 400, 1663 } 1664 ], 1665 ) 1666 response = client.run_task( 1667 launchType="FARGATE", 1668 overrides={}, 1669 taskDefinition="test_ecs_task", 1670 count=1, 1671 startedBy="moto", 1672 ) 1673 response["tasks"][0]["taskArn"].should.match( 1674 f"arn:aws:ecs:us-east-1:{ACCOUNT_ID}:task/{test_cluster_name}/[a-z0-9-]+$" 1675 ) 1676 1677 1678@mock_ecs 1679def test_run_task_exceptions(): 1680 client = boto3.client("ecs", region_name="us-east-1") 1681 _ = client.register_task_definition( 1682 family="test_ecs_task", 1683 containerDefinitions=[ 1684 { 1685 "name": "hello_world", 1686 "image": "docker/hello-world:latest", 1687 "cpu": 1024, 1688 "memory": 400, 1689 } 1690 ], 1691 ) 1692 1693 client.run_task.when.called_with( 1694 cluster="not_a_cluster", taskDefinition="test_ecs_task" 1695 ).should.throw(ClientError, ClusterNotFoundException().message) 1696 1697 1698@mock_ec2 1699@mock_ecs 1700def test_start_task(): 1701 client = boto3.client("ecs", region_name="us-east-1") 1702 ec2 = boto3.resource("ec2", region_name="us-east-1") 1703 1704 test_cluster_name = "test_ecs_cluster" 1705 1706 _ = client.create_cluster(clusterName=test_cluster_name) 1707 1708 test_instance = ec2.create_instances( 1709 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 1710 )[0] 1711 1712 instance_id_document = json.dumps( 1713 ec2_utils.generate_instance_identity_document(test_instance) 1714 ) 1715 1716 response = client.register_container_instance( 1717 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 1718 ) 1719 1720 container_instances = client.list_container_instances(cluster=test_cluster_name) 1721 container_instance_id = container_instances["containerInstanceArns"][0].split("/")[ 1722 -1 1723 ] 1724 1725 _ = client.register_task_definition( 1726 family="test_ecs_task", 1727 containerDefinitions=[ 1728 { 1729 "name": "hello_world", 1730 "image": "docker/hello-world:latest", 1731 "cpu": 1024, 1732 "memory": 400, 1733 "essential": True, 1734 "environment": [ 1735 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 1736 ], 1737 "logConfiguration": {"logDriver": "json-file"}, 1738 } 1739 ], 1740 ) 1741 1742 response = client.start_task( 1743 cluster="test_ecs_cluster", 1744 taskDefinition="test_ecs_task", 1745 overrides={}, 1746 containerInstances=[container_instance_id], 1747 startedBy="moto", 1748 ) 1749 1750 len(response["tasks"]).should.equal(1) 1751 response["tasks"][0]["taskArn"].should.contain( 1752 "arn:aws:ecs:us-east-1:{}:task/".format(ACCOUNT_ID) 1753 ) 1754 response["tasks"][0]["clusterArn"].should.equal( 1755 "arn:aws:ecs:us-east-1:{}:cluster/test_ecs_cluster".format(ACCOUNT_ID) 1756 ) 1757 response["tasks"][0]["taskDefinitionArn"].should.equal( 1758 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:1".format(ACCOUNT_ID) 1759 ) 1760 response["tasks"][0]["containerInstanceArn"].should.equal( 1761 "arn:aws:ecs:us-east-1:{0}:container-instance/{1}".format( 1762 ACCOUNT_ID, container_instance_id 1763 ) 1764 ) 1765 response["tasks"][0]["overrides"].should.equal({}) 1766 response["tasks"][0]["lastStatus"].should.equal("RUNNING") 1767 response["tasks"][0]["desiredStatus"].should.equal("RUNNING") 1768 response["tasks"][0]["startedBy"].should.equal("moto") 1769 response["tasks"][0]["stoppedReason"].should.equal("") 1770 1771 1772@mock_ecs 1773def test_start_task_exceptions(): 1774 client = boto3.client("ecs", region_name="us-east-1") 1775 _ = client.register_task_definition( 1776 family="test_ecs_task", 1777 containerDefinitions=[ 1778 { 1779 "name": "hello_world", 1780 "image": "docker/hello-world:latest", 1781 "cpu": 1024, 1782 "memory": 400, 1783 } 1784 ], 1785 ) 1786 1787 client.start_task.when.called_with( 1788 taskDefinition="test_ecs_task", containerInstances=["not_a_container_instance"] 1789 ).should.throw(ClientError, ClusterNotFoundException().message) 1790 1791 _ = client.create_cluster() 1792 client.start_task.when.called_with( 1793 taskDefinition="test_ecs_task", containerInstances=[] 1794 ).should.throw( 1795 ClientError, InvalidParameterException("Container Instances cannot be empty.") 1796 ) 1797 1798 1799@mock_ec2 1800@mock_ecs 1801def test_list_tasks(): 1802 client = boto3.client("ecs", region_name="us-east-1") 1803 ec2 = boto3.resource("ec2", region_name="us-east-1") 1804 1805 _ = client.create_cluster() 1806 1807 test_instance = ec2.create_instances( 1808 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 1809 )[0] 1810 1811 instance_id_document = json.dumps( 1812 ec2_utils.generate_instance_identity_document(test_instance) 1813 ) 1814 1815 _ = client.register_container_instance( 1816 instanceIdentityDocument=instance_id_document 1817 ) 1818 1819 container_instances = client.list_container_instances() 1820 container_instance_id = container_instances["containerInstanceArns"][0].split("/")[ 1821 -1 1822 ] 1823 1824 _ = client.register_task_definition( 1825 family="test_ecs_task", 1826 containerDefinitions=[ 1827 { 1828 "name": "hello_world", 1829 "image": "docker/hello-world:latest", 1830 "cpu": 1024, 1831 "memory": 400, 1832 "essential": True, 1833 "environment": [ 1834 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 1835 ], 1836 "logConfiguration": {"logDriver": "json-file"}, 1837 } 1838 ], 1839 ) 1840 1841 _ = client.start_task( 1842 taskDefinition="test_ecs_task", 1843 overrides={}, 1844 containerInstances=[container_instance_id], 1845 startedBy="foo", 1846 ) 1847 1848 _ = client.start_task( 1849 taskDefinition="test_ecs_task", 1850 overrides={}, 1851 containerInstances=[container_instance_id], 1852 startedBy="bar", 1853 ) 1854 1855 assert len(client.list_tasks()["taskArns"]).should.equal(2) 1856 assert len(client.list_tasks(startedBy="foo")["taskArns"]).should.equal(1) 1857 1858 1859@mock_ecs 1860def test_list_tasks_exceptions(): 1861 client = boto3.client("ecs", region_name="us-east-1") 1862 client.list_tasks.when.called_with(cluster="not_a_cluster").should.throw( 1863 ClientError, ClusterNotFoundException().message 1864 ) 1865 1866 1867@mock_ec2 1868@mock_ecs 1869def test_describe_tasks(): 1870 client = boto3.client("ecs", region_name="us-east-1") 1871 ec2 = boto3.resource("ec2", region_name="us-east-1") 1872 1873 test_cluster_name = "test_ecs_cluster" 1874 1875 _ = client.create_cluster(clusterName=test_cluster_name) 1876 1877 test_instance = ec2.create_instances( 1878 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 1879 )[0] 1880 1881 instance_id_document = json.dumps( 1882 ec2_utils.generate_instance_identity_document(test_instance) 1883 ) 1884 1885 response = client.register_container_instance( 1886 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 1887 ) 1888 1889 _ = client.register_task_definition( 1890 family="test_ecs_task", 1891 containerDefinitions=[ 1892 { 1893 "name": "hello_world", 1894 "image": "docker/hello-world:latest", 1895 "cpu": 1024, 1896 "memory": 400, 1897 "essential": True, 1898 "environment": [ 1899 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 1900 ], 1901 "logConfiguration": {"logDriver": "json-file"}, 1902 } 1903 ], 1904 ) 1905 tasks_arns = [ 1906 task["taskArn"] 1907 for task in client.run_task( 1908 cluster="test_ecs_cluster", 1909 overrides={}, 1910 taskDefinition="test_ecs_task", 1911 count=2, 1912 startedBy="moto", 1913 )["tasks"] 1914 ] 1915 response = client.describe_tasks(cluster="test_ecs_cluster", tasks=tasks_arns) 1916 1917 len(response["tasks"]).should.equal(2) 1918 set( 1919 [response["tasks"][0]["taskArn"], response["tasks"][1]["taskArn"]] 1920 ).should.equal(set(tasks_arns)) 1921 1922 # Test we can pass task ids instead of ARNs 1923 response = client.describe_tasks( 1924 cluster="test_ecs_cluster", tasks=[tasks_arns[0].split("/")[-1]] 1925 ) 1926 len(response["tasks"]).should.equal(1) 1927 1928 1929@mock_ecs 1930def test_describe_tasks_exceptions(): 1931 client = boto3.client("ecs", region_name="us-east-1") 1932 1933 client.describe_tasks.when.called_with(tasks=[]).should.throw( 1934 ClientError, ClusterNotFoundException().message 1935 ) 1936 1937 _ = client.create_cluster() 1938 client.describe_tasks.when.called_with(tasks=[]).should.throw( 1939 ClientError, InvalidParameterException("Tasks cannot be empty.").message 1940 ) 1941 1942 1943@mock_ecs 1944def test_describe_task_definition_by_family(): 1945 client = boto3.client("ecs", region_name="us-east-1") 1946 container_definition = { 1947 "name": "hello_world", 1948 "image": "docker/hello-world:latest", 1949 "cpu": 1024, 1950 "memory": 400, 1951 "essential": True, 1952 "environment": [{"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}], 1953 "logConfiguration": {"logDriver": "json-file"}, 1954 } 1955 task_definition = client.register_task_definition( 1956 family="test_ecs_task", containerDefinitions=[container_definition] 1957 ) 1958 family = task_definition["taskDefinition"]["family"] 1959 task = client.describe_task_definition(taskDefinition=family)["taskDefinition"] 1960 task["containerDefinitions"][0].should.equal( 1961 dict( 1962 container_definition, 1963 **{"mountPoints": [], "portMappings": [], "volumesFrom": []}, 1964 ) 1965 ) 1966 task["taskDefinitionArn"].should.equal( 1967 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:1".format(ACCOUNT_ID) 1968 ) 1969 task["volumes"].should.equal([]) 1970 task["status"].should.equal("ACTIVE") 1971 1972 1973@mock_ec2 1974@mock_ecs 1975def test_stop_task(): 1976 client = boto3.client("ecs", region_name="us-east-1") 1977 ec2 = boto3.resource("ec2", region_name="us-east-1") 1978 1979 test_cluster_name = "test_ecs_cluster" 1980 1981 _ = client.create_cluster(clusterName=test_cluster_name) 1982 1983 test_instance = ec2.create_instances( 1984 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 1985 )[0] 1986 1987 instance_id_document = json.dumps( 1988 ec2_utils.generate_instance_identity_document(test_instance) 1989 ) 1990 1991 _ = client.register_container_instance( 1992 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 1993 ) 1994 1995 _ = client.register_task_definition( 1996 family="test_ecs_task", 1997 containerDefinitions=[ 1998 { 1999 "name": "hello_world", 2000 "image": "docker/hello-world:latest", 2001 "cpu": 1024, 2002 "memory": 400, 2003 "essential": True, 2004 "environment": [ 2005 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 2006 ], 2007 "logConfiguration": {"logDriver": "json-file"}, 2008 } 2009 ], 2010 ) 2011 run_response = client.run_task( 2012 cluster="test_ecs_cluster", 2013 overrides={}, 2014 taskDefinition="test_ecs_task", 2015 count=1, 2016 startedBy="moto", 2017 ) 2018 stop_response = client.stop_task( 2019 cluster="test_ecs_cluster", 2020 task=run_response["tasks"][0].get("taskArn"), 2021 reason="moto testing", 2022 ) 2023 2024 stop_response["task"]["taskArn"].should.equal( 2025 run_response["tasks"][0].get("taskArn") 2026 ) 2027 stop_response["task"]["lastStatus"].should.equal("STOPPED") 2028 stop_response["task"]["desiredStatus"].should.equal("STOPPED") 2029 stop_response["task"]["stoppedReason"].should.equal("moto testing") 2030 2031 2032@mock_ecs 2033def test_stop_task_exceptions(): 2034 client = boto3.client("ecs", region_name="us-east-1") 2035 2036 client.stop_task.when.called_with(task="fake_task").should.throw( 2037 ClientError, ClusterNotFoundException().message 2038 ) 2039 2040 2041@mock_ec2 2042@mock_ecs 2043def test_resource_reservation_and_release(): 2044 client = boto3.client("ecs", region_name="us-east-1") 2045 ec2 = boto3.resource("ec2", region_name="us-east-1") 2046 2047 test_cluster_name = "test_ecs_cluster" 2048 2049 _ = client.create_cluster(clusterName=test_cluster_name) 2050 2051 test_instance = ec2.create_instances( 2052 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 2053 )[0] 2054 2055 instance_id_document = json.dumps( 2056 ec2_utils.generate_instance_identity_document(test_instance) 2057 ) 2058 2059 _ = client.register_container_instance( 2060 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 2061 ) 2062 2063 _ = client.register_task_definition( 2064 family="test_ecs_task", 2065 containerDefinitions=[ 2066 { 2067 "name": "hello_world", 2068 "image": "docker/hello-world:latest", 2069 "cpu": 1024, 2070 "memory": 400, 2071 "essential": True, 2072 "environment": [ 2073 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 2074 ], 2075 "logConfiguration": {"logDriver": "json-file"}, 2076 "portMappings": [{"hostPort": 80, "containerPort": 8080}], 2077 } 2078 ], 2079 ) 2080 run_response = client.run_task( 2081 cluster="test_ecs_cluster", 2082 overrides={}, 2083 taskDefinition="test_ecs_task", 2084 count=1, 2085 startedBy="moto", 2086 ) 2087 container_instance_arn = run_response["tasks"][0].get("containerInstanceArn") 2088 container_instance_description = client.describe_container_instances( 2089 cluster="test_ecs_cluster", containerInstances=[container_instance_arn] 2090 )["containerInstances"][0] 2091 remaining_resources, registered_resources = _fetch_container_instance_resources( 2092 container_instance_description 2093 ) 2094 remaining_resources["CPU"].should.equal(registered_resources["CPU"] - 1024) 2095 remaining_resources["MEMORY"].should.equal(registered_resources["MEMORY"] - 400) 2096 registered_resources["PORTS"].append("80") 2097 remaining_resources["PORTS"].should.equal(registered_resources["PORTS"]) 2098 container_instance_description["runningTasksCount"].should.equal(1) 2099 client.stop_task( 2100 cluster="test_ecs_cluster", 2101 task=run_response["tasks"][0].get("taskArn"), 2102 reason="moto testing", 2103 ) 2104 container_instance_description = client.describe_container_instances( 2105 cluster="test_ecs_cluster", containerInstances=[container_instance_arn] 2106 )["containerInstances"][0] 2107 remaining_resources, registered_resources = _fetch_container_instance_resources( 2108 container_instance_description 2109 ) 2110 remaining_resources["CPU"].should.equal(registered_resources["CPU"]) 2111 remaining_resources["MEMORY"].should.equal(registered_resources["MEMORY"]) 2112 remaining_resources["PORTS"].should.equal(registered_resources["PORTS"]) 2113 container_instance_description["runningTasksCount"].should.equal(0) 2114 2115 2116@mock_ec2 2117@mock_ecs 2118def test_resource_reservation_and_release_memory_reservation(): 2119 client = boto3.client("ecs", region_name="us-east-1") 2120 ec2 = boto3.resource("ec2", region_name="us-east-1") 2121 2122 test_cluster_name = "test_ecs_cluster" 2123 2124 _ = client.create_cluster(clusterName=test_cluster_name) 2125 2126 test_instance = ec2.create_instances( 2127 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 2128 )[0] 2129 2130 instance_id_document = json.dumps( 2131 ec2_utils.generate_instance_identity_document(test_instance) 2132 ) 2133 2134 _ = client.register_container_instance( 2135 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 2136 ) 2137 2138 _ = client.register_task_definition( 2139 family="test_ecs_task", 2140 containerDefinitions=[ 2141 { 2142 "name": "hello_world", 2143 "image": "docker/hello-world:latest", 2144 "memoryReservation": 400, 2145 "essential": True, 2146 "environment": [ 2147 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 2148 ], 2149 "logConfiguration": {"logDriver": "json-file"}, 2150 "portMappings": [{"containerPort": 8080}], 2151 } 2152 ], 2153 ) 2154 run_response = client.run_task( 2155 cluster="test_ecs_cluster", 2156 overrides={}, 2157 taskDefinition="test_ecs_task", 2158 count=1, 2159 startedBy="moto", 2160 ) 2161 container_instance_arn = run_response["tasks"][0].get("containerInstanceArn") 2162 container_instance_description = client.describe_container_instances( 2163 cluster="test_ecs_cluster", containerInstances=[container_instance_arn] 2164 )["containerInstances"][0] 2165 remaining_resources, registered_resources = _fetch_container_instance_resources( 2166 container_instance_description 2167 ) 2168 remaining_resources["CPU"].should.equal(registered_resources["CPU"]) 2169 remaining_resources["MEMORY"].should.equal(registered_resources["MEMORY"] - 400) 2170 remaining_resources["PORTS"].should.equal(registered_resources["PORTS"]) 2171 container_instance_description["runningTasksCount"].should.equal(1) 2172 client.stop_task( 2173 cluster="test_ecs_cluster", 2174 task=run_response["tasks"][0].get("taskArn"), 2175 reason="moto testing", 2176 ) 2177 container_instance_description = client.describe_container_instances( 2178 cluster="test_ecs_cluster", containerInstances=[container_instance_arn] 2179 )["containerInstances"][0] 2180 remaining_resources, registered_resources = _fetch_container_instance_resources( 2181 container_instance_description 2182 ) 2183 remaining_resources["CPU"].should.equal(registered_resources["CPU"]) 2184 remaining_resources["MEMORY"].should.equal(registered_resources["MEMORY"]) 2185 remaining_resources["PORTS"].should.equal(registered_resources["PORTS"]) 2186 container_instance_description["runningTasksCount"].should.equal(0) 2187 2188 2189@mock_ec2 2190@mock_ecs 2191def test_task_definitions_unable_to_be_placed(): 2192 client = boto3.client("ecs", region_name="us-east-1") 2193 ec2 = boto3.resource("ec2", region_name="us-east-1") 2194 2195 test_cluster_name = "test_ecs_cluster" 2196 2197 _ = client.create_cluster(clusterName=test_cluster_name) 2198 2199 test_instance = ec2.create_instances( 2200 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 2201 )[0] 2202 2203 instance_id_document = json.dumps( 2204 ec2_utils.generate_instance_identity_document(test_instance) 2205 ) 2206 2207 response = client.register_container_instance( 2208 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 2209 ) 2210 2211 _ = client.register_task_definition( 2212 family="test_ecs_task", 2213 containerDefinitions=[ 2214 { 2215 "name": "hello_world", 2216 "image": "docker/hello-world:latest", 2217 "cpu": 5000, 2218 "memory": 40000, 2219 "essential": True, 2220 "environment": [ 2221 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 2222 ], 2223 "logConfiguration": {"logDriver": "json-file"}, 2224 } 2225 ], 2226 ) 2227 response = client.run_task( 2228 cluster="test_ecs_cluster", 2229 overrides={}, 2230 taskDefinition="test_ecs_task", 2231 count=2, 2232 startedBy="moto", 2233 ) 2234 len(response["tasks"]).should.equal(0) 2235 2236 2237@mock_ec2 2238@mock_ecs 2239def test_task_definitions_with_port_clash(): 2240 client = boto3.client("ecs", region_name="us-east-1") 2241 ec2 = boto3.resource("ec2", region_name="us-east-1") 2242 2243 test_cluster_name = "test_ecs_cluster" 2244 2245 _ = client.create_cluster(clusterName=test_cluster_name) 2246 2247 test_instance = ec2.create_instances( 2248 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 2249 )[0] 2250 2251 instance_id_document = json.dumps( 2252 ec2_utils.generate_instance_identity_document(test_instance) 2253 ) 2254 2255 response = client.register_container_instance( 2256 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 2257 ) 2258 2259 _ = client.register_task_definition( 2260 family="test_ecs_task", 2261 containerDefinitions=[ 2262 { 2263 "name": "hello_world", 2264 "image": "docker/hello-world:latest", 2265 "cpu": 256, 2266 "memory": 512, 2267 "essential": True, 2268 "environment": [ 2269 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 2270 ], 2271 "logConfiguration": {"logDriver": "json-file"}, 2272 "portMappings": [{"hostPort": 80, "containerPort": 8080}], 2273 } 2274 ], 2275 ) 2276 response = client.run_task( 2277 cluster="test_ecs_cluster", 2278 overrides={}, 2279 taskDefinition="test_ecs_task", 2280 count=2, 2281 startedBy="moto", 2282 ) 2283 len(response["tasks"]).should.equal(1) 2284 response["tasks"][0]["taskArn"].should.contain( 2285 "arn:aws:ecs:us-east-1:{}:task/".format(ACCOUNT_ID) 2286 ) 2287 response["tasks"][0]["clusterArn"].should.equal( 2288 "arn:aws:ecs:us-east-1:{}:cluster/test_ecs_cluster".format(ACCOUNT_ID) 2289 ) 2290 response["tasks"][0]["taskDefinitionArn"].should.equal( 2291 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:1".format(ACCOUNT_ID) 2292 ) 2293 response["tasks"][0]["containerInstanceArn"].should.contain( 2294 "arn:aws:ecs:us-east-1:{}:container-instance/".format(ACCOUNT_ID) 2295 ) 2296 response["tasks"][0]["overrides"].should.equal({}) 2297 response["tasks"][0]["lastStatus"].should.equal("RUNNING") 2298 response["tasks"][0]["desiredStatus"].should.equal("RUNNING") 2299 response["tasks"][0]["startedBy"].should.equal("moto") 2300 response["tasks"][0]["stoppedReason"].should.equal("") 2301 2302 2303@mock_ec2 2304@mock_ecs 2305def test_attributes(): 2306 # Combined put, list delete attributes into the same test due to the amount of setup 2307 ecs_client = boto3.client("ecs", region_name="us-east-1") 2308 ec2 = boto3.resource("ec2", region_name="us-east-1") 2309 2310 test_cluster_name = "test_ecs_cluster" 2311 2312 _ = ecs_client.create_cluster(clusterName=test_cluster_name) 2313 2314 instances = [] 2315 test_instance = ec2.create_instances( 2316 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 2317 )[0] 2318 instances.append(test_instance) 2319 2320 instance_id_document = json.dumps( 2321 ec2_utils.generate_instance_identity_document(test_instance) 2322 ) 2323 2324 response = ecs_client.register_container_instance( 2325 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 2326 ) 2327 2328 response["containerInstance"]["ec2InstanceId"].should.equal(test_instance.id) 2329 full_arn1 = response["containerInstance"]["containerInstanceArn"] 2330 2331 test_instance = ec2.create_instances( 2332 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 2333 )[0] 2334 instances.append(test_instance) 2335 2336 instance_id_document = json.dumps( 2337 ec2_utils.generate_instance_identity_document(test_instance) 2338 ) 2339 2340 response = ecs_client.register_container_instance( 2341 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 2342 ) 2343 2344 response["containerInstance"]["ec2InstanceId"].should.equal(test_instance.id) 2345 full_arn2 = response["containerInstance"]["containerInstanceArn"] 2346 partial_arn2 = full_arn2.rsplit("/", 1)[-1] 2347 2348 full_arn2.should_not.equal( 2349 full_arn1 2350 ) # uuid1 isnt unique enough when the pc is fast ;-) 2351 2352 # Ok set instance 1 with 1 attribute, instance 2 with another, and all of them with a 3rd. 2353 ecs_client.put_attributes( 2354 cluster=test_cluster_name, 2355 attributes=[ 2356 {"name": "env", "value": "prod"}, 2357 {"name": "attr1", "value": "instance1", "targetId": full_arn1}, 2358 { 2359 "name": "attr1", 2360 "value": "instance2", 2361 "targetId": partial_arn2, 2362 "targetType": "container-instance", 2363 }, 2364 ], 2365 ) 2366 2367 resp = ecs_client.list_attributes( 2368 cluster=test_cluster_name, targetType="container-instance" 2369 ) 2370 attrs = resp["attributes"] 2371 2372 NUM_CUSTOM_ATTRIBUTES = 4 # 2 specific to individual machines and 1 global, going to both machines (2 + 1*2) 2373 NUM_DEFAULT_ATTRIBUTES = 4 2374 len(attrs).should.equal( 2375 NUM_CUSTOM_ATTRIBUTES + (NUM_DEFAULT_ATTRIBUTES * len(instances)) 2376 ) 2377 2378 # Tests that the attrs have been set properly 2379 len(list(filter(lambda item: item["name"] == "env", attrs))).should.equal(2) 2380 len( 2381 list( 2382 filter( 2383 lambda item: item["name"] == "attr1" and item["value"] == "instance1", 2384 attrs, 2385 ) 2386 ) 2387 ).should.equal(1) 2388 2389 ecs_client.delete_attributes( 2390 cluster=test_cluster_name, 2391 attributes=[ 2392 { 2393 "name": "attr1", 2394 "value": "instance2", 2395 "targetId": partial_arn2, 2396 "targetType": "container-instance", 2397 } 2398 ], 2399 ) 2400 NUM_CUSTOM_ATTRIBUTES -= 1 2401 2402 resp = ecs_client.list_attributes( 2403 cluster=test_cluster_name, targetType="container-instance" 2404 ) 2405 attrs = resp["attributes"] 2406 len(attrs).should.equal( 2407 NUM_CUSTOM_ATTRIBUTES + (NUM_DEFAULT_ATTRIBUTES * len(instances)) 2408 ) 2409 2410 2411@mock_ecs 2412def test_poll_endpoint(): 2413 # Combined put, list delete attributes into the same test due to the amount of setup 2414 ecs_client = boto3.client("ecs", region_name="us-east-1") 2415 2416 # Just a placeholder until someone actually wants useless data, just testing it doesnt raise an exception 2417 resp = ecs_client.discover_poll_endpoint(cluster="blah", containerInstance="blah") 2418 resp.should.contain("endpoint") 2419 resp.should.contain("telemetryEndpoint") 2420 2421 2422@mock_ecs 2423def test_list_task_definition_families(): 2424 client = boto3.client("ecs", region_name="us-east-1") 2425 client.register_task_definition( 2426 family="test_ecs_task", 2427 containerDefinitions=[ 2428 { 2429 "name": "hello_world", 2430 "image": "docker/hello-world:latest", 2431 "cpu": 1024, 2432 "memory": 400, 2433 "essential": True, 2434 "environment": [ 2435 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 2436 ], 2437 "logConfiguration": {"logDriver": "json-file"}, 2438 } 2439 ], 2440 ) 2441 client.register_task_definition( 2442 family="alt_test_ecs_task", 2443 containerDefinitions=[ 2444 { 2445 "name": "hello_world", 2446 "image": "docker/hello-world:latest", 2447 "cpu": 1024, 2448 "memory": 400, 2449 "essential": True, 2450 "environment": [ 2451 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 2452 ], 2453 "logConfiguration": {"logDriver": "json-file"}, 2454 } 2455 ], 2456 ) 2457 2458 resp1 = client.list_task_definition_families() 2459 resp2 = client.list_task_definition_families(familyPrefix="alt") 2460 2461 len(resp1["families"]).should.equal(2) 2462 len(resp2["families"]).should.equal(1) 2463 2464 2465@mock_ec2 2466@mock_ecs 2467def test_default_container_instance_attributes(): 2468 ecs_client = boto3.client("ecs", region_name="us-east-1") 2469 ec2 = boto3.resource("ec2", region_name="us-east-1") 2470 2471 test_cluster_name = "test_ecs_cluster" 2472 2473 # Create cluster and EC2 instance 2474 _ = ecs_client.create_cluster(clusterName=test_cluster_name) 2475 2476 test_instance = ec2.create_instances( 2477 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 2478 )[0] 2479 2480 instance_id_document = json.dumps( 2481 ec2_utils.generate_instance_identity_document(test_instance) 2482 ) 2483 2484 # Register container instance 2485 response = ecs_client.register_container_instance( 2486 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 2487 ) 2488 2489 response["containerInstance"]["ec2InstanceId"].should.equal(test_instance.id) 2490 2491 default_attributes = response["containerInstance"]["attributes"] 2492 assert len(default_attributes) == 4 2493 expected_result = [ 2494 { 2495 "name": "ecs.availability-zone", 2496 "value": test_instance.placement["AvailabilityZone"], 2497 }, 2498 {"name": "ecs.ami-id", "value": test_instance.image_id}, 2499 {"name": "ecs.instance-type", "value": test_instance.instance_type}, 2500 {"name": "ecs.os-type", "value": test_instance.platform or "linux"}, 2501 ] 2502 assert sorted(default_attributes, key=lambda item: item["name"]) == sorted( 2503 expected_result, key=lambda item: item["name"] 2504 ) 2505 2506 2507@mock_ec2 2508@mock_ecs 2509def test_describe_container_instances_with_attributes(): 2510 ecs_client = boto3.client("ecs", region_name="us-east-1") 2511 ec2 = boto3.resource("ec2", region_name="us-east-1") 2512 2513 test_cluster_name = "test_ecs_cluster" 2514 2515 # Create cluster and EC2 instance 2516 _ = ecs_client.create_cluster(clusterName=test_cluster_name) 2517 2518 test_instance = ec2.create_instances( 2519 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 2520 )[0] 2521 2522 instance_id_document = json.dumps( 2523 ec2_utils.generate_instance_identity_document(test_instance) 2524 ) 2525 2526 # Register container instance 2527 response = ecs_client.register_container_instance( 2528 cluster=test_cluster_name, instanceIdentityDocument=instance_id_document 2529 ) 2530 2531 response["containerInstance"]["ec2InstanceId"].should.equal(test_instance.id) 2532 full_arn = response["containerInstance"]["containerInstanceArn"] 2533 container_instance_id = full_arn.rsplit("/", 1)[-1] 2534 default_attributes = response["containerInstance"]["attributes"] 2535 2536 # Set attributes on container instance, one without a value 2537 attributes = [ 2538 {"name": "env", "value": "prod"}, 2539 { 2540 "name": "attr1", 2541 "value": "instance1", 2542 "targetId": container_instance_id, 2543 "targetType": "container-instance", 2544 }, 2545 {"name": "attr_without_value"}, 2546 ] 2547 ecs_client.put_attributes(cluster=test_cluster_name, attributes=attributes) 2548 2549 # Describe container instance, should have attributes previously set 2550 described_instance = ecs_client.describe_container_instances( 2551 cluster=test_cluster_name, containerInstances=[container_instance_id] 2552 ) 2553 2554 assert len(described_instance["containerInstances"]) == 1 2555 assert isinstance(described_instance["containerInstances"][0]["attributes"], list) 2556 2557 # Remove additional info passed to put_attributes 2558 cleaned_attributes = [] 2559 for attribute in attributes: 2560 attribute.pop("targetId", None) 2561 attribute.pop("targetType", None) 2562 cleaned_attributes.append(attribute) 2563 described_attributes = sorted( 2564 described_instance["containerInstances"][0]["attributes"], 2565 key=lambda item: item["name"], 2566 ) 2567 expected_attributes = sorted( 2568 default_attributes + cleaned_attributes, key=lambda item: item["name"] 2569 ) 2570 assert described_attributes == expected_attributes 2571 2572 2573def _fetch_container_instance_resources(container_instance_description): 2574 remaining_resources = {} 2575 registered_resources = {} 2576 remaining_resources_list = container_instance_description["remainingResources"] 2577 registered_resources_list = container_instance_description["registeredResources"] 2578 remaining_resources["CPU"] = [ 2579 x["integerValue"] for x in remaining_resources_list if x["name"] == "CPU" 2580 ][0] 2581 remaining_resources["MEMORY"] = [ 2582 x["integerValue"] for x in remaining_resources_list if x["name"] == "MEMORY" 2583 ][0] 2584 remaining_resources["PORTS"] = [ 2585 x["stringSetValue"] for x in remaining_resources_list if x["name"] == "PORTS" 2586 ][0] 2587 registered_resources["CPU"] = [ 2588 x["integerValue"] for x in registered_resources_list if x["name"] == "CPU" 2589 ][0] 2590 registered_resources["MEMORY"] = [ 2591 x["integerValue"] for x in registered_resources_list if x["name"] == "MEMORY" 2592 ][0] 2593 registered_resources["PORTS"] = [ 2594 x["stringSetValue"] for x in registered_resources_list if x["name"] == "PORTS" 2595 ][0] 2596 return remaining_resources, registered_resources 2597 2598 2599@mock_ecs 2600def test_create_service_load_balancing(): 2601 client = boto3.client("ecs", region_name="us-east-1") 2602 client.create_cluster(clusterName="test_ecs_cluster") 2603 client.register_task_definition( 2604 family="test_ecs_task", 2605 containerDefinitions=[ 2606 { 2607 "name": "hello_world", 2608 "image": "docker/hello-world:latest", 2609 "cpu": 1024, 2610 "memory": 400, 2611 "essential": True, 2612 "environment": [ 2613 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 2614 ], 2615 "logConfiguration": {"logDriver": "json-file"}, 2616 } 2617 ], 2618 ) 2619 response = client.create_service( 2620 cluster="test_ecs_cluster", 2621 serviceName="test_ecs_service", 2622 taskDefinition="test_ecs_task", 2623 desiredCount=2, 2624 loadBalancers=[ 2625 { 2626 "targetGroupArn": "test_target_group_arn", 2627 "loadBalancerName": "test_load_balancer_name", 2628 "containerName": "test_container_name", 2629 "containerPort": 123, 2630 } 2631 ], 2632 ) 2633 response["service"]["clusterArn"].should.equal( 2634 "arn:aws:ecs:us-east-1:{}:cluster/test_ecs_cluster".format(ACCOUNT_ID) 2635 ) 2636 response["service"]["desiredCount"].should.equal(2) 2637 len(response["service"]["events"]).should.equal(0) 2638 len(response["service"]["loadBalancers"]).should.equal(1) 2639 response["service"]["loadBalancers"][0]["targetGroupArn"].should.equal( 2640 "test_target_group_arn" 2641 ) 2642 response["service"]["loadBalancers"][0]["loadBalancerName"].should.equal( 2643 "test_load_balancer_name" 2644 ) 2645 response["service"]["loadBalancers"][0]["containerName"].should.equal( 2646 "test_container_name" 2647 ) 2648 response["service"]["loadBalancers"][0]["containerPort"].should.equal(123) 2649 response["service"]["pendingCount"].should.equal(0) 2650 response["service"]["runningCount"].should.equal(0) 2651 response["service"]["serviceArn"].should.equal( 2652 "arn:aws:ecs:us-east-1:{}:service/test_ecs_service".format(ACCOUNT_ID) 2653 ) 2654 response["service"]["serviceName"].should.equal("test_ecs_service") 2655 response["service"]["status"].should.equal("ACTIVE") 2656 response["service"]["taskDefinition"].should.equal( 2657 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:1".format(ACCOUNT_ID) 2658 ) 2659 2660 2661@mock_ecs 2662def test_list_tags_for_resource(): 2663 client = boto3.client("ecs", region_name="us-east-1") 2664 response = client.register_task_definition( 2665 family="test_ecs_task", 2666 containerDefinitions=[ 2667 { 2668 "name": "hello_world", 2669 "image": "docker/hello-world:latest", 2670 "cpu": 1024, 2671 "memory": 400, 2672 "essential": True, 2673 "environment": [ 2674 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 2675 ], 2676 "logConfiguration": {"logDriver": "json-file"}, 2677 } 2678 ], 2679 tags=[ 2680 {"key": "createdBy", "value": "moto-unittest"}, 2681 {"key": "foo", "value": "bar"}, 2682 ], 2683 ) 2684 type(response["taskDefinition"]).should.be(dict) 2685 response["taskDefinition"]["revision"].should.equal(1) 2686 response["taskDefinition"]["taskDefinitionArn"].should.equal( 2687 "arn:aws:ecs:us-east-1:{}:task-definition/test_ecs_task:1".format(ACCOUNT_ID) 2688 ) 2689 2690 task_definition_arn = response["taskDefinition"]["taskDefinitionArn"] 2691 response = client.list_tags_for_resource(resourceArn=task_definition_arn) 2692 2693 type(response["tags"]).should.be(list) 2694 response["tags"].should.equal( 2695 [{"key": "createdBy", "value": "moto-unittest"}, {"key": "foo", "value": "bar"}] 2696 ) 2697 2698 2699@mock_ecs 2700def test_list_tags_exceptions(): 2701 client = boto3.client("ecs", region_name="us-east-1") 2702 client.list_tags_for_resource.when.called_with( 2703 resourceArn="arn:aws:ecs:us-east-1:012345678910:service/fake_service:1" 2704 ).should.throw(ClientError, ServiceNotFoundException().message) 2705 client.list_tags_for_resource.when.called_with( 2706 resourceArn="arn:aws:ecs:us-east-1:012345678910:task-definition/fake_task:1" 2707 ).should.throw(ClientError, TaskDefinitionNotFoundException().message) 2708 2709 2710@mock_ecs 2711def test_list_tags_for_resource_ecs_service(): 2712 client = boto3.client("ecs", region_name="us-east-1") 2713 _ = client.create_cluster(clusterName="test_ecs_cluster") 2714 _ = client.register_task_definition( 2715 family="test_ecs_task", 2716 containerDefinitions=[ 2717 { 2718 "name": "hello_world", 2719 "image": "docker/hello-world:latest", 2720 "cpu": 1024, 2721 "memory": 400, 2722 "essential": True, 2723 "environment": [ 2724 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 2725 ], 2726 "logConfiguration": {"logDriver": "json-file"}, 2727 } 2728 ], 2729 ) 2730 response = client.create_service( 2731 cluster="test_ecs_cluster", 2732 serviceName="test_ecs_service", 2733 taskDefinition="test_ecs_task", 2734 desiredCount=2, 2735 tags=[ 2736 {"key": "createdBy", "value": "moto-unittest"}, 2737 {"key": "foo", "value": "bar"}, 2738 ], 2739 ) 2740 response = client.list_tags_for_resource( 2741 resourceArn=response["service"]["serviceArn"] 2742 ) 2743 type(response["tags"]).should.be(list) 2744 response["tags"].should.equal( 2745 [{"key": "createdBy", "value": "moto-unittest"}, {"key": "foo", "value": "bar"}] 2746 ) 2747 2748 2749@mock_ecs 2750def test_ecs_service_tag_resource(): 2751 client = boto3.client("ecs", region_name="us-east-1") 2752 _ = client.create_cluster(clusterName="test_ecs_cluster") 2753 _ = client.register_task_definition( 2754 family="test_ecs_task", 2755 containerDefinitions=[ 2756 { 2757 "name": "hello_world", 2758 "image": "docker/hello-world:latest", 2759 "cpu": 1024, 2760 "memory": 400, 2761 "essential": True, 2762 "environment": [ 2763 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 2764 ], 2765 "logConfiguration": {"logDriver": "json-file"}, 2766 } 2767 ], 2768 ) 2769 response = client.create_service( 2770 cluster="test_ecs_cluster", 2771 serviceName="test_ecs_service", 2772 taskDefinition="test_ecs_task", 2773 desiredCount=2, 2774 ) 2775 client.tag_resource( 2776 resourceArn=response["service"]["serviceArn"], 2777 tags=[ 2778 {"key": "createdBy", "value": "moto-unittest"}, 2779 {"key": "foo", "value": "bar"}, 2780 ], 2781 ) 2782 response = client.list_tags_for_resource( 2783 resourceArn=response["service"]["serviceArn"] 2784 ) 2785 type(response["tags"]).should.be(list) 2786 response["tags"].should.equal( 2787 [{"key": "createdBy", "value": "moto-unittest"}, {"key": "foo", "value": "bar"}] 2788 ) 2789 2790 2791@mock_ecs 2792def test_ecs_service_tag_resource_overwrites_tag(): 2793 client = boto3.client("ecs", region_name="us-east-1") 2794 _ = client.create_cluster(clusterName="test_ecs_cluster") 2795 _ = client.register_task_definition( 2796 family="test_ecs_task", 2797 containerDefinitions=[ 2798 { 2799 "name": "hello_world", 2800 "image": "docker/hello-world:latest", 2801 "cpu": 1024, 2802 "memory": 400, 2803 "essential": True, 2804 "environment": [ 2805 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 2806 ], 2807 "logConfiguration": {"logDriver": "json-file"}, 2808 } 2809 ], 2810 ) 2811 response = client.create_service( 2812 cluster="test_ecs_cluster", 2813 serviceName="test_ecs_service", 2814 taskDefinition="test_ecs_task", 2815 desiredCount=2, 2816 tags=[{"key": "foo", "value": "bar"}], 2817 ) 2818 client.tag_resource( 2819 resourceArn=response["service"]["serviceArn"], 2820 tags=[ 2821 {"key": "createdBy", "value": "moto-unittest"}, 2822 {"key": "foo", "value": "hello world"}, 2823 ], 2824 ) 2825 response = client.list_tags_for_resource( 2826 resourceArn=response["service"]["serviceArn"] 2827 ) 2828 type(response["tags"]).should.be(list) 2829 response["tags"].should.equal( 2830 [ 2831 {"key": "createdBy", "value": "moto-unittest"}, 2832 {"key": "foo", "value": "hello world"}, 2833 ] 2834 ) 2835 2836 2837@mock_ecs 2838def test_ecs_service_untag_resource(): 2839 client = boto3.client("ecs", region_name="us-east-1") 2840 _ = client.create_cluster(clusterName="test_ecs_cluster") 2841 _ = client.register_task_definition( 2842 family="test_ecs_task", 2843 containerDefinitions=[ 2844 { 2845 "name": "hello_world", 2846 "image": "docker/hello-world:latest", 2847 "cpu": 1024, 2848 "memory": 400, 2849 "essential": True, 2850 "environment": [ 2851 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 2852 ], 2853 "logConfiguration": {"logDriver": "json-file"}, 2854 } 2855 ], 2856 ) 2857 response = client.create_service( 2858 cluster="test_ecs_cluster", 2859 serviceName="test_ecs_service", 2860 taskDefinition="test_ecs_task", 2861 desiredCount=2, 2862 tags=[{"key": "foo", "value": "bar"}], 2863 ) 2864 client.untag_resource( 2865 resourceArn=response["service"]["serviceArn"], tagKeys=["foo"] 2866 ) 2867 response = client.list_tags_for_resource( 2868 resourceArn=response["service"]["serviceArn"] 2869 ) 2870 response["tags"].should.equal([]) 2871 2872 2873@mock_ecs 2874def test_ecs_service_untag_resource_multiple_tags(): 2875 client = boto3.client("ecs", region_name="us-east-1") 2876 _ = client.create_cluster(clusterName="test_ecs_cluster") 2877 _ = client.register_task_definition( 2878 family="test_ecs_task", 2879 containerDefinitions=[ 2880 { 2881 "name": "hello_world", 2882 "image": "docker/hello-world:latest", 2883 "cpu": 1024, 2884 "memory": 400, 2885 "essential": True, 2886 "environment": [ 2887 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 2888 ], 2889 "logConfiguration": {"logDriver": "json-file"}, 2890 } 2891 ], 2892 ) 2893 response = client.create_service( 2894 cluster="test_ecs_cluster", 2895 serviceName="test_ecs_service", 2896 taskDefinition="test_ecs_task", 2897 desiredCount=2, 2898 tags=[ 2899 {"key": "foo", "value": "bar"}, 2900 {"key": "createdBy", "value": "moto-unittest"}, 2901 {"key": "hello", "value": "world"}, 2902 ], 2903 ) 2904 client.untag_resource( 2905 resourceArn=response["service"]["serviceArn"], tagKeys=["foo", "createdBy"] 2906 ) 2907 response = client.list_tags_for_resource( 2908 resourceArn=response["service"]["serviceArn"] 2909 ) 2910 response["tags"].should.equal([{"key": "hello", "value": "world"}]) 2911 2912 2913@mock_ecs 2914def test_ecs_task_definition_placement_constraints(): 2915 client = boto3.client("ecs", region_name="us-east-1") 2916 response = client.register_task_definition( 2917 family="test_ecs_task", 2918 containerDefinitions=[ 2919 { 2920 "name": "hello_world", 2921 "image": "docker/hello-world:latest", 2922 "cpu": 1024, 2923 "memory": 400, 2924 "essential": True, 2925 "environment": [ 2926 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 2927 ], 2928 "logConfiguration": {"logDriver": "json-file"}, 2929 } 2930 ], 2931 networkMode="bridge", 2932 tags=[ 2933 {"key": "createdBy", "value": "moto-unittest"}, 2934 {"key": "foo", "value": "bar"}, 2935 ], 2936 placementConstraints=[ 2937 {"type": "memberOf", "expression": "attribute:ecs.instance-type =~ t2.*"} 2938 ], 2939 ) 2940 type(response["taskDefinition"]["placementConstraints"]).should.be(list) 2941 response["taskDefinition"]["placementConstraints"].should.equal( 2942 [{"type": "memberOf", "expression": "attribute:ecs.instance-type =~ t2.*"}] 2943 ) 2944 2945 2946@mock_ecs 2947def test_create_task_set(): 2948 cluster_name = "test_ecs_cluster" 2949 service_name = "test_ecs_service" 2950 task_def_name = "test_ecs_task" 2951 2952 client = boto3.client("ecs", region_name="us-east-1") 2953 _ = client.create_cluster(clusterName=cluster_name) 2954 _ = client.register_task_definition( 2955 family="test_ecs_task", 2956 containerDefinitions=[ 2957 { 2958 "name": "hello_world", 2959 "image": "docker/hello-world:latest", 2960 "cpu": 1024, 2961 "memory": 400, 2962 "essential": True, 2963 "environment": [ 2964 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 2965 ], 2966 "logConfiguration": {"logDriver": "json-file"}, 2967 } 2968 ], 2969 ) 2970 _ = client.create_service( 2971 cluster=cluster_name, 2972 serviceName=service_name, 2973 taskDefinition=task_def_name, 2974 desiredCount=2, 2975 deploymentController={"type": "EXTERNAL"}, 2976 ) 2977 load_balancers = [ 2978 { 2979 "targetGroupArn": "arn:aws:elasticloadbalancing:us-east-1:01234567890:targetgroup/c26b93c1bc35466ba792d5b08fe6a5bc/ec39113f8831453a", 2980 "containerName": "hello_world", 2981 "containerPort": 8080, 2982 }, 2983 ] 2984 2985 task_set = client.create_task_set( 2986 cluster=cluster_name, 2987 service=service_name, 2988 taskDefinition=task_def_name, 2989 loadBalancers=load_balancers, 2990 )["taskSet"] 2991 2992 cluster_arn = client.describe_clusters(clusters=[cluster_name])["clusters"][0][ 2993 "clusterArn" 2994 ] 2995 service_arn = client.describe_services( 2996 cluster=cluster_name, services=[service_name] 2997 )["services"][0]["serviceArn"] 2998 task_set["clusterArn"].should.equal(cluster_arn) 2999 task_set["serviceArn"].should.equal(service_arn) 3000 task_set["taskDefinition"].should.match("{0}:1$".format(task_def_name)) 3001 task_set["scale"].should.equal({"value": 100.0, "unit": "PERCENT"}) 3002 task_set["loadBalancers"][0]["targetGroupArn"].should.equal( 3003 "arn:aws:elasticloadbalancing:us-east-1:01234567890:targetgroup/" 3004 "c26b93c1bc35466ba792d5b08fe6a5bc/ec39113f8831453a" 3005 ) 3006 task_set["loadBalancers"][0]["containerPort"].should.equal(8080) 3007 task_set["loadBalancers"][0]["containerName"].should.equal("hello_world") 3008 task_set["launchType"].should.equal("EC2") 3009 3010 3011@mock_ecs 3012def test_create_task_set_errors(): 3013 # given 3014 cluster_name = "test_ecs_cluster" 3015 service_name = "test_ecs_service" 3016 task_def_name = "test_ecs_task" 3017 3018 client = boto3.client("ecs", region_name="us-east-1") 3019 _ = client.create_cluster(clusterName=cluster_name) 3020 _ = client.register_task_definition( 3021 family="test_ecs_task", 3022 containerDefinitions=[ 3023 { 3024 "name": "hello_world", 3025 "image": "docker/hello-world:latest", 3026 "cpu": 1024, 3027 "memory": 400, 3028 "essential": True, 3029 "environment": [ 3030 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 3031 ], 3032 "logConfiguration": {"logDriver": "json-file"}, 3033 } 3034 ], 3035 ) 3036 _ = client.create_service( 3037 cluster=cluster_name, 3038 serviceName=service_name, 3039 taskDefinition=task_def_name, 3040 desiredCount=2, 3041 deploymentController={"type": "EXTERNAL"}, 3042 ) 3043 3044 # not existing launch type 3045 # when 3046 with pytest.raises(ClientError) as e: 3047 client.create_task_set( 3048 cluster=cluster_name, 3049 service=service_name, 3050 taskDefinition=task_def_name, 3051 launchType="SOMETHING", 3052 ) 3053 3054 # then 3055 ex = e.value 3056 ex.operation_name.should.equal("CreateTaskSet") 3057 ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) 3058 ex.response["Error"]["Code"].should.contain("ClientException") 3059 ex.response["Error"]["Message"].should.equal( 3060 "launch type should be one of [EC2,FARGATE]" 3061 ) 3062 3063 3064@mock_ecs 3065def test_describe_task_sets(): 3066 cluster_name = "test_ecs_cluster" 3067 service_name = "test_ecs_service" 3068 task_def_name = "test_ecs_task" 3069 3070 client = boto3.client("ecs", region_name="us-east-1") 3071 _ = client.create_cluster(clusterName=cluster_name) 3072 _ = client.register_task_definition( 3073 family=task_def_name, 3074 containerDefinitions=[ 3075 { 3076 "name": "hello_world", 3077 "image": "docker/hello-world:latest", 3078 "cpu": 1024, 3079 "memory": 400, 3080 "essential": True, 3081 "environment": [ 3082 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 3083 ], 3084 "logConfiguration": {"logDriver": "json-file"}, 3085 } 3086 ], 3087 ) 3088 _ = client.create_service( 3089 cluster=cluster_name, 3090 serviceName=service_name, 3091 taskDefinition=task_def_name, 3092 desiredCount=2, 3093 deploymentController={"type": "EXTERNAL"}, 3094 ) 3095 3096 load_balancers = [ 3097 { 3098 "targetGroupArn": "arn:aws:elasticloadbalancing:us-east-1:01234567890:targetgroup/c26b93c1bc35466ba792d5b08fe6a5bc/ec39113f8831453a", 3099 "containerName": "hello_world", 3100 "containerPort": 8080, 3101 } 3102 ] 3103 3104 _ = client.create_task_set( 3105 cluster=cluster_name, 3106 service=service_name, 3107 taskDefinition=task_def_name, 3108 loadBalancers=load_balancers, 3109 ) 3110 task_sets = client.describe_task_sets(cluster=cluster_name, service=service_name)[ 3111 "taskSets" 3112 ] 3113 assert "tags" not in task_sets[0] 3114 3115 task_sets = client.describe_task_sets( 3116 cluster=cluster_name, service=service_name, include=["TAGS"], 3117 )["taskSets"] 3118 3119 cluster_arn = client.describe_clusters(clusters=[cluster_name])["clusters"][0][ 3120 "clusterArn" 3121 ] 3122 3123 service_arn = client.describe_services( 3124 cluster=cluster_name, services=[service_name] 3125 )["services"][0]["serviceArn"] 3126 3127 task_sets[0].should.have.key("tags") 3128 task_sets.should.have.length_of(1) 3129 task_sets[0]["taskDefinition"].should.match("{0}:1$".format(task_def_name)) 3130 task_sets[0]["clusterArn"].should.equal(cluster_arn) 3131 task_sets[0]["serviceArn"].should.equal(service_arn) 3132 task_sets[0]["serviceArn"].should.match("{0}$".format(service_name)) 3133 task_sets[0]["scale"].should.equal({"value": 100.0, "unit": "PERCENT"}) 3134 task_sets[0]["taskSetArn"].should.match("{0}$".format(task_sets[0]["id"])) 3135 task_sets[0]["loadBalancers"][0]["targetGroupArn"].should.equal( 3136 "arn:aws:elasticloadbalancing:us-east-1:01234567890:targetgroup/" 3137 "c26b93c1bc35466ba792d5b08fe6a5bc/ec39113f8831453a" 3138 ) 3139 task_sets[0]["loadBalancers"][0]["containerPort"].should.equal(8080) 3140 task_sets[0]["loadBalancers"][0]["containerName"].should.equal("hello_world") 3141 task_sets[0]["launchType"].should.equal("EC2") 3142 3143 3144@mock_ecs 3145def test_delete_task_set(): 3146 cluster_name = "test_ecs_cluster" 3147 service_name = "test_ecs_service" 3148 task_def_name = "test_ecs_task" 3149 3150 client = boto3.client("ecs", region_name="us-east-1") 3151 _ = client.create_cluster(clusterName=cluster_name) 3152 _ = client.register_task_definition( 3153 family=task_def_name, 3154 containerDefinitions=[ 3155 { 3156 "name": "hello_world", 3157 "image": "docker/hello-world:latest", 3158 "cpu": 1024, 3159 "memory": 400, 3160 "essential": True, 3161 "environment": [ 3162 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 3163 ], 3164 "logConfiguration": {"logDriver": "json-file"}, 3165 } 3166 ], 3167 ) 3168 _ = client.create_service( 3169 cluster=cluster_name, 3170 serviceName=service_name, 3171 taskDefinition=task_def_name, 3172 desiredCount=2, 3173 deploymentController={"type": "EXTERNAL"}, 3174 ) 3175 3176 task_set = client.create_task_set( 3177 cluster=cluster_name, service=service_name, taskDefinition=task_def_name, 3178 )["taskSet"] 3179 3180 task_sets = client.describe_task_sets( 3181 cluster=cluster_name, service=service_name, taskSets=[task_set["taskSetArn"]], 3182 )["taskSets"] 3183 3184 assert len(task_sets) == 1 3185 3186 response = client.delete_task_set( 3187 cluster=cluster_name, service=service_name, taskSet=task_set["taskSetArn"], 3188 ) 3189 assert response["taskSet"]["taskSetArn"] == task_set["taskSetArn"] 3190 3191 task_sets = client.describe_task_sets( 3192 cluster=cluster_name, service=service_name, taskSets=[task_set["taskSetArn"]], 3193 )["taskSets"] 3194 3195 assert len(task_sets) == 0 3196 3197 with pytest.raises(ClientError): 3198 _ = client.delete_task_set( 3199 cluster=cluster_name, service=service_name, taskSet=task_set["taskSetArn"], 3200 ) 3201 3202 3203@mock_ecs 3204def test_update_service_primary_task_set(): 3205 cluster_name = "test_ecs_cluster" 3206 service_name = "test_ecs_service" 3207 task_def_name = "test_ecs_task" 3208 3209 client = boto3.client("ecs", region_name="us-east-1") 3210 _ = client.create_cluster(clusterName=cluster_name) 3211 _ = client.register_task_definition( 3212 family="test_ecs_task", 3213 containerDefinitions=[ 3214 { 3215 "name": "hello_world", 3216 "image": "docker/hello-world:latest", 3217 "cpu": 1024, 3218 "memory": 400, 3219 "essential": True, 3220 "environment": [ 3221 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 3222 ], 3223 "logConfiguration": {"logDriver": "json-file"}, 3224 } 3225 ], 3226 ) 3227 _ = client.create_service( 3228 cluster=cluster_name, 3229 serviceName=service_name, 3230 desiredCount=2, 3231 deploymentController={"type": "EXTERNAL"}, 3232 ) 3233 3234 task_set = client.create_task_set( 3235 cluster=cluster_name, service=service_name, taskDefinition=task_def_name, 3236 )["taskSet"] 3237 3238 service = client.describe_services(cluster=cluster_name, services=[service_name],)[ 3239 "services" 3240 ][0] 3241 3242 _ = client.update_service_primary_task_set( 3243 cluster=cluster_name, 3244 service=service_name, 3245 primaryTaskSet=task_set["taskSetArn"], 3246 ) 3247 3248 service = client.describe_services(cluster=cluster_name, services=[service_name],)[ 3249 "services" 3250 ][0] 3251 assert service["taskSets"][0]["status"] == "PRIMARY" 3252 assert service["taskDefinition"] == service["taskSets"][0]["taskDefinition"] 3253 3254 another_task_set = client.create_task_set( 3255 cluster=cluster_name, service=service_name, taskDefinition=task_def_name, 3256 )["taskSet"] 3257 service = client.describe_services(cluster=cluster_name, services=[service_name],)[ 3258 "services" 3259 ][0] 3260 assert service["taskSets"][1]["status"] == "ACTIVE" 3261 3262 _ = client.update_service_primary_task_set( 3263 cluster=cluster_name, 3264 service=service_name, 3265 primaryTaskSet=another_task_set["taskSetArn"], 3266 ) 3267 service = client.describe_services(cluster=cluster_name, services=[service_name],)[ 3268 "services" 3269 ][0] 3270 assert service["taskSets"][0]["status"] == "ACTIVE" 3271 assert service["taskSets"][1]["status"] == "PRIMARY" 3272 assert service["taskDefinition"] == service["taskSets"][1]["taskDefinition"] 3273 3274 3275@mock_ecs 3276def test_update_task_set(): 3277 cluster_name = "test_ecs_cluster" 3278 service_name = "test_ecs_service" 3279 task_def_name = "test_ecs_task" 3280 3281 client = boto3.client("ecs", region_name="us-east-1") 3282 _ = client.create_cluster(clusterName=cluster_name) 3283 _ = client.register_task_definition( 3284 family=task_def_name, 3285 containerDefinitions=[ 3286 { 3287 "name": "hello_world", 3288 "image": "docker/hello-world:latest", 3289 "cpu": 1024, 3290 "memory": 400, 3291 "essential": True, 3292 "environment": [ 3293 {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"} 3294 ], 3295 "logConfiguration": {"logDriver": "json-file"}, 3296 } 3297 ], 3298 ) 3299 _ = client.create_service( 3300 cluster=cluster_name, 3301 serviceName=service_name, 3302 desiredCount=2, 3303 deploymentController={"type": "EXTERNAL"}, 3304 ) 3305 3306 task_set = client.create_task_set( 3307 cluster=cluster_name, service=service_name, taskDefinition=task_def_name, 3308 )["taskSet"] 3309 3310 another_task_set = client.create_task_set( 3311 cluster=cluster_name, service=service_name, taskDefinition=task_def_name, 3312 )["taskSet"] 3313 assert another_task_set["scale"]["unit"] == "PERCENT" 3314 assert another_task_set["scale"]["value"] == 100.0 3315 3316 client.update_task_set( 3317 cluster=cluster_name, 3318 service=service_name, 3319 taskSet=task_set["taskSetArn"], 3320 scale={"value": 25.0, "unit": "PERCENT"}, 3321 ) 3322 3323 updated_task_set = client.describe_task_sets( 3324 cluster=cluster_name, service=service_name, taskSets=[task_set["taskSetArn"]], 3325 )["taskSets"][0] 3326 assert updated_task_set["scale"]["value"] == 25.0 3327 assert updated_task_set["scale"]["unit"] == "PERCENT" 3328 3329 3330@mock_ec2 3331@mock_ecs 3332def test_list_tasks_with_filters(): 3333 ecs = boto3.client("ecs", region_name="us-east-1") 3334 ec2 = boto3.resource("ec2", region_name="us-east-1") 3335 3336 _ = ecs.create_cluster(clusterName="test_cluster_1") 3337 _ = ecs.create_cluster(clusterName="test_cluster_2") 3338 3339 test_instance = ec2.create_instances( 3340 ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 3341 )[0] 3342 3343 instance_id_document = json.dumps( 3344 ec2_utils.generate_instance_identity_document(test_instance) 3345 ) 3346 3347 _ = ecs.register_container_instance( 3348 cluster="test_cluster_1", instanceIdentityDocument=instance_id_document 3349 ) 3350 _ = ecs.register_container_instance( 3351 cluster="test_cluster_2", instanceIdentityDocument=instance_id_document 3352 ) 3353 3354 container_instances = ecs.list_container_instances(cluster="test_cluster_1") 3355 container_id_1 = container_instances["containerInstanceArns"][0].split("/")[-1] 3356 container_instances = ecs.list_container_instances(cluster="test_cluster_2") 3357 container_id_2 = container_instances["containerInstanceArns"][0].split("/")[-1] 3358 3359 test_container_def = { 3360 "name": "hello_world", 3361 "image": "docker/hello-world:latest", 3362 "cpu": 1024, 3363 "memory": 400, 3364 "essential": True, 3365 "environment": [{"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}], 3366 "logConfiguration": {"logDriver": "json-file"}, 3367 } 3368 3369 _ = ecs.register_task_definition( 3370 family="test_task_def_1", containerDefinitions=[test_container_def], 3371 ) 3372 3373 _ = ecs.register_task_definition( 3374 family="test_task_def_2", containerDefinitions=[test_container_def], 3375 ) 3376 3377 _ = ecs.start_task( 3378 cluster="test_cluster_1", 3379 taskDefinition="test_task_def_1", 3380 overrides={}, 3381 containerInstances=[container_id_1], 3382 startedBy="foo", 3383 ) 3384 3385 resp = ecs.start_task( 3386 cluster="test_cluster_2", 3387 taskDefinition="test_task_def_2", 3388 overrides={}, 3389 containerInstances=[container_id_2], 3390 startedBy="foo", 3391 ) 3392 task_to_stop = resp["tasks"][0]["taskArn"] 3393 3394 _ = ecs.start_task( 3395 cluster="test_cluster_1", 3396 taskDefinition="test_task_def_1", 3397 overrides={}, 3398 containerInstances=[container_id_1], 3399 startedBy="bar", 3400 ) 3401 3402 len(ecs.list_tasks(cluster="test_cluster_1")["taskArns"]).should.equal(2) 3403 len(ecs.list_tasks(cluster="test_cluster_2")["taskArns"]).should.equal(1) 3404 3405 len( 3406 ecs.list_tasks(cluster="test_cluster_1", containerInstance="bad-id")["taskArns"] 3407 ).should.equal(0) 3408 len( 3409 ecs.list_tasks(cluster="test_cluster_1", containerInstance=container_id_1)[ 3410 "taskArns" 3411 ] 3412 ).should.equal(2) 3413 len( 3414 ecs.list_tasks(cluster="test_cluster_2", containerInstance=container_id_2)[ 3415 "taskArns" 3416 ] 3417 ).should.equal(1) 3418 3419 len( 3420 ecs.list_tasks(cluster="test_cluster_1", family="non-existent-family")[ 3421 "taskArns" 3422 ] 3423 ).should.equal(0) 3424 len( 3425 ecs.list_tasks(cluster="test_cluster_1", family="test_task_def_1")["taskArns"] 3426 ).should.equal(2) 3427 len( 3428 ecs.list_tasks(cluster="test_cluster_2", family="test_task_def_2")["taskArns"] 3429 ).should.equal(1) 3430 3431 len( 3432 ecs.list_tasks(cluster="test_cluster_1", startedBy="non-existent-entity")[ 3433 "taskArns" 3434 ] 3435 ).should.equal(0) 3436 len( 3437 ecs.list_tasks(cluster="test_cluster_1", startedBy="foo")["taskArns"] 3438 ).should.equal(1) 3439 len( 3440 ecs.list_tasks(cluster="test_cluster_1", startedBy="bar")["taskArns"] 3441 ).should.equal(1) 3442 len( 3443 ecs.list_tasks(cluster="test_cluster_2", startedBy="foo")["taskArns"] 3444 ).should.equal(1) 3445 3446 len( 3447 ecs.list_tasks(cluster="test_cluster_1", desiredStatus="RUNNING")["taskArns"] 3448 ).should.equal(2) 3449 len( 3450 ecs.list_tasks(cluster="test_cluster_2", desiredStatus="RUNNING")["taskArns"] 3451 ).should.equal(1) 3452 _ = ecs.stop_task(cluster="test_cluster_2", task=task_to_stop, reason="for testing") 3453 len( 3454 ecs.list_tasks(cluster="test_cluster_1", desiredStatus="RUNNING")["taskArns"] 3455 ).should.equal(2) 3456 len( 3457 ecs.list_tasks(cluster="test_cluster_2", desiredStatus="STOPPED")["taskArns"] 3458 ).should.equal(1) 3459 3460 resp = ecs.list_tasks(cluster="test_cluster_1", startedBy="foo") 3461 len(resp["taskArns"]).should.equal(1) 3462 3463 resp = ecs.list_tasks( 3464 cluster="test_cluster_1", containerInstance=container_id_1, startedBy="bar" 3465 ) 3466 len(resp["taskArns"]).should.equal(1) 3467