2542 lines
		
	
	
		
			89 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			2542 lines
		
	
	
		
			89 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from __future__ import unicode_literals
 | |
| from datetime import datetime
 | |
| 
 | |
| from copy import deepcopy
 | |
| 
 | |
| from botocore.exceptions import ClientError
 | |
| import boto3
 | |
| import sure  # noqa
 | |
| import json
 | |
| from moto.ec2 import utils as ec2_utils
 | |
| from uuid import UUID
 | |
| 
 | |
| from moto import mock_cloudformation, mock_elbv2
 | |
| from moto import mock_ecs
 | |
| from moto import mock_ec2
 | |
| from nose.tools import assert_raises
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_create_cluster():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     response = client.create_cluster(clusterName="test_ecs_cluster")
 | |
|     response["cluster"]["clusterName"].should.equal("test_ecs_cluster")
 | |
|     response["cluster"]["clusterArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:cluster/test_ecs_cluster"
 | |
|     )
 | |
|     response["cluster"]["status"].should.equal("ACTIVE")
 | |
|     response["cluster"]["registeredContainerInstancesCount"].should.equal(0)
 | |
|     response["cluster"]["runningTasksCount"].should.equal(0)
 | |
|     response["cluster"]["pendingTasksCount"].should.equal(0)
 | |
|     response["cluster"]["activeServicesCount"].should.equal(0)
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_list_clusters():
 | |
|     client = boto3.client("ecs", region_name="us-east-2")
 | |
|     _ = client.create_cluster(clusterName="test_cluster0")
 | |
|     _ = client.create_cluster(clusterName="test_cluster1")
 | |
|     response = client.list_clusters()
 | |
|     response["clusterArns"].should.contain(
 | |
|         "arn:aws:ecs:us-east-2:012345678910:cluster/test_cluster0"
 | |
|     )
 | |
|     response["clusterArns"].should.contain(
 | |
|         "arn:aws:ecs:us-east-2:012345678910:cluster/test_cluster1"
 | |
|     )
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_describe_clusters():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     response = client.describe_clusters(clusters=["some-cluster"])
 | |
|     response["failures"].should.contain(
 | |
|         {
 | |
|             "arn": "arn:aws:ecs:us-east-1:012345678910:cluster/some-cluster",
 | |
|             "reason": "MISSING",
 | |
|         }
 | |
|     )
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_delete_cluster():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.create_cluster(clusterName="test_ecs_cluster")
 | |
|     response = client.delete_cluster(cluster="test_ecs_cluster")
 | |
|     response["cluster"]["clusterName"].should.equal("test_ecs_cluster")
 | |
|     response["cluster"]["clusterArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:cluster/test_ecs_cluster"
 | |
|     )
 | |
|     response["cluster"]["status"].should.equal("ACTIVE")
 | |
|     response["cluster"]["registeredContainerInstancesCount"].should.equal(0)
 | |
|     response["cluster"]["runningTasksCount"].should.equal(0)
 | |
|     response["cluster"]["pendingTasksCount"].should.equal(0)
 | |
|     response["cluster"]["activeServicesCount"].should.equal(0)
 | |
| 
 | |
|     response = client.list_clusters()
 | |
|     len(response["clusterArns"]).should.equal(0)
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_register_task_definition():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     response = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|         networkMode="bridge",
 | |
|         tags=[
 | |
|             {"key": "createdBy", "value": "moto-unittest"},
 | |
|             {"key": "foo", "value": "bar"},
 | |
|         ],
 | |
|     )
 | |
|     type(response["taskDefinition"]).should.be(dict)
 | |
|     response["taskDefinition"]["revision"].should.equal(1)
 | |
|     response["taskDefinition"]["taskDefinitionArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task:1"
 | |
|     )
 | |
|     response["taskDefinition"]["containerDefinitions"][0]["name"].should.equal(
 | |
|         "hello_world"
 | |
|     )
 | |
|     response["taskDefinition"]["containerDefinitions"][0]["image"].should.equal(
 | |
|         "docker/hello-world:latest"
 | |
|     )
 | |
|     response["taskDefinition"]["containerDefinitions"][0]["cpu"].should.equal(1024)
 | |
|     response["taskDefinition"]["containerDefinitions"][0]["memory"].should.equal(400)
 | |
|     response["taskDefinition"]["containerDefinitions"][0]["essential"].should.equal(
 | |
|         True
 | |
|     )
 | |
|     response["taskDefinition"]["containerDefinitions"][0]["environment"][0][
 | |
|         "name"
 | |
|     ].should.equal("AWS_ACCESS_KEY_ID")
 | |
|     response["taskDefinition"]["containerDefinitions"][0]["environment"][0][
 | |
|         "value"
 | |
|     ].should.equal("SOME_ACCESS_KEY")
 | |
|     response["taskDefinition"]["containerDefinitions"][0]["logConfiguration"][
 | |
|         "logDriver"
 | |
|     ].should.equal("json-file")
 | |
|     response["taskDefinition"]["networkMode"].should.equal("bridge")
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_list_task_definitions():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world2",
 | |
|                 "image": "docker/hello-world2:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY2"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     response = client.list_task_definitions()
 | |
|     len(response["taskDefinitionArns"]).should.equal(2)
 | |
|     response["taskDefinitionArns"][0].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task:1"
 | |
|     )
 | |
|     response["taskDefinitionArns"][1].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task:2"
 | |
|     )
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_list_task_definitions_with_family_prefix():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task_a",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task_a",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task_b",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world2",
 | |
|                 "image": "docker/hello-world2:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY2"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     empty_response = client.list_task_definitions(familyPrefix="test_ecs_task")
 | |
|     len(empty_response["taskDefinitionArns"]).should.equal(0)
 | |
|     filtered_response = client.list_task_definitions(familyPrefix="test_ecs_task_a")
 | |
|     len(filtered_response["taskDefinitionArns"]).should.equal(2)
 | |
|     filtered_response["taskDefinitionArns"][0].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task_a:1"
 | |
|     )
 | |
|     filtered_response["taskDefinitionArns"][1].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task_a:2"
 | |
|     )
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_describe_task_definition():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world2",
 | |
|                 "image": "docker/hello-world2:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY2"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world3",
 | |
|                 "image": "docker/hello-world3:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY3"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     response = client.describe_task_definition(taskDefinition="test_ecs_task")
 | |
|     response["taskDefinition"]["taskDefinitionArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task:3"
 | |
|     )
 | |
| 
 | |
|     response = client.describe_task_definition(taskDefinition="test_ecs_task:2")
 | |
|     response["taskDefinition"]["taskDefinitionArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task:2"
 | |
|     )
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_deregister_task_definition():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     response = client.deregister_task_definition(taskDefinition="test_ecs_task:1")
 | |
|     type(response["taskDefinition"]).should.be(dict)
 | |
|     response["taskDefinition"]["taskDefinitionArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task:1"
 | |
|     )
 | |
|     response["taskDefinition"]["containerDefinitions"][0]["name"].should.equal(
 | |
|         "hello_world"
 | |
|     )
 | |
|     response["taskDefinition"]["containerDefinitions"][0]["image"].should.equal(
 | |
|         "docker/hello-world:latest"
 | |
|     )
 | |
|     response["taskDefinition"]["containerDefinitions"][0]["cpu"].should.equal(1024)
 | |
|     response["taskDefinition"]["containerDefinitions"][0]["memory"].should.equal(400)
 | |
|     response["taskDefinition"]["containerDefinitions"][0]["essential"].should.equal(
 | |
|         True
 | |
|     )
 | |
|     response["taskDefinition"]["containerDefinitions"][0]["environment"][0][
 | |
|         "name"
 | |
|     ].should.equal("AWS_ACCESS_KEY_ID")
 | |
|     response["taskDefinition"]["containerDefinitions"][0]["environment"][0][
 | |
|         "value"
 | |
|     ].should.equal("SOME_ACCESS_KEY")
 | |
|     response["taskDefinition"]["containerDefinitions"][0]["logConfiguration"][
 | |
|         "logDriver"
 | |
|     ].should.equal("json-file")
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_create_service():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.create_cluster(clusterName="test_ecs_cluster")
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     response = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=2,
 | |
|     )
 | |
|     response["service"]["clusterArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:cluster/test_ecs_cluster"
 | |
|     )
 | |
|     response["service"]["desiredCount"].should.equal(2)
 | |
|     len(response["service"]["events"]).should.equal(0)
 | |
|     len(response["service"]["loadBalancers"]).should.equal(0)
 | |
|     response["service"]["pendingCount"].should.equal(0)
 | |
|     response["service"]["runningCount"].should.equal(0)
 | |
|     response["service"]["serviceArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:service/test_ecs_service"
 | |
|     )
 | |
|     response["service"]["serviceName"].should.equal("test_ecs_service")
 | |
|     response["service"]["status"].should.equal("ACTIVE")
 | |
|     response["service"]["taskDefinition"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task:1"
 | |
|     )
 | |
|     response["service"]["schedulingStrategy"].should.equal("REPLICA")
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_create_service_scheduling_strategy():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.create_cluster(clusterName="test_ecs_cluster")
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     response = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=2,
 | |
|         schedulingStrategy="DAEMON",
 | |
|     )
 | |
|     response["service"]["clusterArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:cluster/test_ecs_cluster"
 | |
|     )
 | |
|     response["service"]["desiredCount"].should.equal(2)
 | |
|     len(response["service"]["events"]).should.equal(0)
 | |
|     len(response["service"]["loadBalancers"]).should.equal(0)
 | |
|     response["service"]["pendingCount"].should.equal(0)
 | |
|     response["service"]["runningCount"].should.equal(0)
 | |
|     response["service"]["serviceArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:service/test_ecs_service"
 | |
|     )
 | |
|     response["service"]["serviceName"].should.equal("test_ecs_service")
 | |
|     response["service"]["status"].should.equal("ACTIVE")
 | |
|     response["service"]["taskDefinition"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task:1"
 | |
|     )
 | |
|     response["service"]["schedulingStrategy"].should.equal("DAEMON")
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_list_services():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.create_cluster(clusterName="test_ecs_cluster")
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     _ = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service1",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         schedulingStrategy="REPLICA",
 | |
|         desiredCount=2,
 | |
|     )
 | |
|     _ = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service2",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         schedulingStrategy="DAEMON",
 | |
|         desiredCount=2,
 | |
|     )
 | |
|     unfiltered_response = client.list_services(cluster="test_ecs_cluster")
 | |
|     len(unfiltered_response["serviceArns"]).should.equal(2)
 | |
|     unfiltered_response["serviceArns"][0].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:service/test_ecs_service1"
 | |
|     )
 | |
|     unfiltered_response["serviceArns"][1].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:service/test_ecs_service2"
 | |
|     )
 | |
| 
 | |
|     filtered_response = client.list_services(
 | |
|         cluster="test_ecs_cluster", schedulingStrategy="REPLICA"
 | |
|     )
 | |
|     len(filtered_response["serviceArns"]).should.equal(1)
 | |
|     filtered_response["serviceArns"][0].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:service/test_ecs_service1"
 | |
|     )
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_describe_services():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.create_cluster(clusterName="test_ecs_cluster")
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     _ = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service1",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=2,
 | |
|     )
 | |
|     _ = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service2",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=2,
 | |
|     )
 | |
|     _ = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service3",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=2,
 | |
|     )
 | |
|     response = client.describe_services(
 | |
|         cluster="test_ecs_cluster",
 | |
|         services=[
 | |
|             "test_ecs_service1",
 | |
|             "arn:aws:ecs:us-east-1:012345678910:service/test_ecs_service2",
 | |
|         ],
 | |
|     )
 | |
|     len(response["services"]).should.equal(2)
 | |
|     response["services"][0]["serviceArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:service/test_ecs_service1"
 | |
|     )
 | |
|     response["services"][0]["serviceName"].should.equal("test_ecs_service1")
 | |
|     response["services"][1]["serviceArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:service/test_ecs_service2"
 | |
|     )
 | |
|     response["services"][1]["serviceName"].should.equal("test_ecs_service2")
 | |
| 
 | |
|     response["services"][0]["deployments"][0]["desiredCount"].should.equal(2)
 | |
|     response["services"][0]["deployments"][0]["pendingCount"].should.equal(2)
 | |
|     response["services"][0]["deployments"][0]["runningCount"].should.equal(0)
 | |
|     response["services"][0]["deployments"][0]["status"].should.equal("PRIMARY")
 | |
|     (
 | |
|         datetime.now()
 | |
|         - response["services"][0]["deployments"][0]["createdAt"].replace(tzinfo=None)
 | |
|     ).seconds.should.be.within(0, 10)
 | |
|     (
 | |
|         datetime.now()
 | |
|         - response["services"][0]["deployments"][0]["updatedAt"].replace(tzinfo=None)
 | |
|     ).seconds.should.be.within(0, 10)
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_describe_services_scheduling_strategy():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.create_cluster(clusterName="test_ecs_cluster")
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     _ = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service1",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=2,
 | |
|     )
 | |
|     _ = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service2",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=2,
 | |
|         schedulingStrategy="DAEMON",
 | |
|     )
 | |
|     _ = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service3",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=2,
 | |
|     )
 | |
|     response = client.describe_services(
 | |
|         cluster="test_ecs_cluster",
 | |
|         services=[
 | |
|             "test_ecs_service1",
 | |
|             "arn:aws:ecs:us-east-1:012345678910:service/test_ecs_service2",
 | |
|             "test_ecs_service3",
 | |
|         ],
 | |
|     )
 | |
|     len(response["services"]).should.equal(3)
 | |
|     response["services"][0]["serviceArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:service/test_ecs_service1"
 | |
|     )
 | |
|     response["services"][0]["serviceName"].should.equal("test_ecs_service1")
 | |
|     response["services"][1]["serviceArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:service/test_ecs_service2"
 | |
|     )
 | |
|     response["services"][1]["serviceName"].should.equal("test_ecs_service2")
 | |
| 
 | |
|     response["services"][0]["deployments"][0]["desiredCount"].should.equal(2)
 | |
|     response["services"][0]["deployments"][0]["pendingCount"].should.equal(2)
 | |
|     response["services"][0]["deployments"][0]["runningCount"].should.equal(0)
 | |
|     response["services"][0]["deployments"][0]["status"].should.equal("PRIMARY")
 | |
| 
 | |
|     response["services"][0]["schedulingStrategy"].should.equal("REPLICA")
 | |
|     response["services"][1]["schedulingStrategy"].should.equal("DAEMON")
 | |
|     response["services"][2]["schedulingStrategy"].should.equal("REPLICA")
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_update_service():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.create_cluster(clusterName="test_ecs_cluster")
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     response = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=2,
 | |
|     )
 | |
|     response["service"]["desiredCount"].should.equal(2)
 | |
| 
 | |
|     response = client.update_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         service="test_ecs_service",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=0,
 | |
|     )
 | |
|     response["service"]["desiredCount"].should.equal(0)
 | |
|     response["service"]["schedulingStrategy"].should.equal("REPLICA")
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_update_missing_service():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.create_cluster(clusterName="test_ecs_cluster")
 | |
| 
 | |
|     client.update_service.when.called_with(
 | |
|         cluster="test_ecs_cluster",
 | |
|         service="test_ecs_service",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=0,
 | |
|     ).should.throw(ClientError)
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_delete_service():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.create_cluster(clusterName="test_ecs_cluster")
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     _ = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=2,
 | |
|     )
 | |
|     _ = client.update_service(
 | |
|         cluster="test_ecs_cluster", service="test_ecs_service", desiredCount=0
 | |
|     )
 | |
|     response = client.delete_service(
 | |
|         cluster="test_ecs_cluster", service="test_ecs_service"
 | |
|     )
 | |
|     response["service"]["clusterArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:cluster/test_ecs_cluster"
 | |
|     )
 | |
|     response["service"]["desiredCount"].should.equal(0)
 | |
|     len(response["service"]["events"]).should.equal(0)
 | |
|     len(response["service"]["loadBalancers"]).should.equal(0)
 | |
|     response["service"]["pendingCount"].should.equal(0)
 | |
|     response["service"]["runningCount"].should.equal(0)
 | |
|     response["service"]["serviceArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:service/test_ecs_service"
 | |
|     )
 | |
|     response["service"]["serviceName"].should.equal("test_ecs_service")
 | |
|     response["service"]["status"].should.equal("ACTIVE")
 | |
|     response["service"]["schedulingStrategy"].should.equal("REPLICA")
 | |
|     response["service"]["taskDefinition"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task:1"
 | |
|     )
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_update_non_existent_service():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     try:
 | |
|         client.update_service(
 | |
|             cluster="my-clustet", service="my-service", desiredCount=0
 | |
|         )
 | |
|     except ClientError as exc:
 | |
|         error_code = exc.response["Error"]["Code"]
 | |
|         error_code.should.equal("ServiceNotFoundException")
 | |
|     else:
 | |
|         raise Exception("Didn't raise ClientError")
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_register_container_instance():
 | |
|     ecs_client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
| 
 | |
|     _ = ecs_client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     test_instance = ec2.create_instances(
 | |
|         ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|     )[0]
 | |
| 
 | |
|     instance_id_document = json.dumps(
 | |
|         ec2_utils.generate_instance_identity_document(test_instance)
 | |
|     )
 | |
| 
 | |
|     response = ecs_client.register_container_instance(
 | |
|         cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|     )
 | |
| 
 | |
|     response["containerInstance"]["ec2InstanceId"].should.equal(test_instance.id)
 | |
|     full_arn = response["containerInstance"]["containerInstanceArn"]
 | |
|     arn_part = full_arn.split("/")
 | |
|     arn_part[0].should.equal("arn:aws:ecs:us-east-1:012345678910:container-instance")
 | |
|     arn_part[1].should.equal(str(UUID(arn_part[1])))
 | |
|     response["containerInstance"]["status"].should.equal("ACTIVE")
 | |
|     len(response["containerInstance"]["registeredResources"]).should.equal(4)
 | |
|     len(response["containerInstance"]["remainingResources"]).should.equal(4)
 | |
|     response["containerInstance"]["agentConnected"].should.equal(True)
 | |
|     response["containerInstance"]["versionInfo"]["agentVersion"].should.equal("1.0.0")
 | |
|     response["containerInstance"]["versionInfo"]["agentHash"].should.equal("4023248")
 | |
|     response["containerInstance"]["versionInfo"]["dockerVersion"].should.equal(
 | |
|         "DockerVersion: 1.5.0"
 | |
|     )
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_deregister_container_instance():
 | |
|     ecs_client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
| 
 | |
|     _ = ecs_client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     test_instance = ec2.create_instances(
 | |
|         ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|     )[0]
 | |
| 
 | |
|     instance_id_document = json.dumps(
 | |
|         ec2_utils.generate_instance_identity_document(test_instance)
 | |
|     )
 | |
| 
 | |
|     response = ecs_client.register_container_instance(
 | |
|         cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|     )
 | |
|     container_instance_id = response["containerInstance"]["containerInstanceArn"]
 | |
|     response = ecs_client.deregister_container_instance(
 | |
|         cluster=test_cluster_name, containerInstance=container_instance_id
 | |
|     )
 | |
|     container_instances_response = ecs_client.list_container_instances(
 | |
|         cluster=test_cluster_name
 | |
|     )
 | |
|     len(container_instances_response["containerInstanceArns"]).should.equal(0)
 | |
| 
 | |
|     response = ecs_client.register_container_instance(
 | |
|         cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|     )
 | |
|     container_instance_id = response["containerInstance"]["containerInstanceArn"]
 | |
|     _ = ecs_client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
| 
 | |
|     response = ecs_client.start_task(
 | |
|         cluster="test_ecs_cluster",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         overrides={},
 | |
|         containerInstances=[container_instance_id],
 | |
|         startedBy="moto",
 | |
|     )
 | |
|     with assert_raises(Exception) as e:
 | |
|         ecs_client.deregister_container_instance(
 | |
|             cluster=test_cluster_name, containerInstance=container_instance_id
 | |
|         ).should.have.raised(Exception)
 | |
|     container_instances_response = ecs_client.list_container_instances(
 | |
|         cluster=test_cluster_name
 | |
|     )
 | |
|     len(container_instances_response["containerInstanceArns"]).should.equal(1)
 | |
|     ecs_client.deregister_container_instance(
 | |
|         cluster=test_cluster_name, containerInstance=container_instance_id, force=True
 | |
|     )
 | |
|     container_instances_response = ecs_client.list_container_instances(
 | |
|         cluster=test_cluster_name
 | |
|     )
 | |
|     len(container_instances_response["containerInstanceArns"]).should.equal(0)
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_list_container_instances():
 | |
|     ecs_client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
|     _ = ecs_client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     instance_to_create = 3
 | |
|     test_instance_arns = []
 | |
|     for i in range(0, instance_to_create):
 | |
|         test_instance = ec2.create_instances(
 | |
|             ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|         )[0]
 | |
| 
 | |
|         instance_id_document = json.dumps(
 | |
|             ec2_utils.generate_instance_identity_document(test_instance)
 | |
|         )
 | |
| 
 | |
|         response = ecs_client.register_container_instance(
 | |
|             cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|         )
 | |
| 
 | |
|         test_instance_arns.append(response["containerInstance"]["containerInstanceArn"])
 | |
| 
 | |
|     response = ecs_client.list_container_instances(cluster=test_cluster_name)
 | |
| 
 | |
|     len(response["containerInstanceArns"]).should.equal(instance_to_create)
 | |
|     for arn in test_instance_arns:
 | |
|         response["containerInstanceArns"].should.contain(arn)
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_describe_container_instances():
 | |
|     ecs_client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
|     _ = ecs_client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     instance_to_create = 3
 | |
|     test_instance_arns = []
 | |
|     for i in range(0, instance_to_create):
 | |
|         test_instance = ec2.create_instances(
 | |
|             ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|         )[0]
 | |
| 
 | |
|         instance_id_document = json.dumps(
 | |
|             ec2_utils.generate_instance_identity_document(test_instance)
 | |
|         )
 | |
| 
 | |
|         response = ecs_client.register_container_instance(
 | |
|             cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|         )
 | |
| 
 | |
|         test_instance_arns.append(response["containerInstance"]["containerInstanceArn"])
 | |
| 
 | |
|     test_instance_ids = list(map((lambda x: x.split("/")[1]), test_instance_arns))
 | |
|     response = ecs_client.describe_container_instances(
 | |
|         cluster=test_cluster_name, containerInstances=test_instance_ids
 | |
|     )
 | |
|     len(response["failures"]).should.equal(0)
 | |
|     len(response["containerInstances"]).should.equal(instance_to_create)
 | |
|     response_arns = [
 | |
|         ci["containerInstanceArn"] for ci in response["containerInstances"]
 | |
|     ]
 | |
|     for arn in test_instance_arns:
 | |
|         response_arns.should.contain(arn)
 | |
|     for instance in response["containerInstances"]:
 | |
|         instance.keys().should.contain("runningTasksCount")
 | |
|         instance.keys().should.contain("pendingTasksCount")
 | |
| 
 | |
|     with assert_raises(ClientError) as e:
 | |
|         ecs_client.describe_container_instances(
 | |
|             cluster=test_cluster_name, containerInstances=[]
 | |
|         )
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_update_container_instances_state():
 | |
|     ecs_client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
|     _ = ecs_client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     instance_to_create = 3
 | |
|     test_instance_arns = []
 | |
|     for i in range(0, instance_to_create):
 | |
|         test_instance = ec2.create_instances(
 | |
|             ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|         )[0]
 | |
| 
 | |
|         instance_id_document = json.dumps(
 | |
|             ec2_utils.generate_instance_identity_document(test_instance)
 | |
|         )
 | |
| 
 | |
|         response = ecs_client.register_container_instance(
 | |
|             cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|         )
 | |
| 
 | |
|         test_instance_arns.append(response["containerInstance"]["containerInstanceArn"])
 | |
| 
 | |
|     test_instance_ids = list(map((lambda x: x.split("/")[1]), test_instance_arns))
 | |
|     response = ecs_client.update_container_instances_state(
 | |
|         cluster=test_cluster_name,
 | |
|         containerInstances=test_instance_ids,
 | |
|         status="DRAINING",
 | |
|     )
 | |
|     len(response["failures"]).should.equal(0)
 | |
|     len(response["containerInstances"]).should.equal(instance_to_create)
 | |
|     response_statuses = [ci["status"] for ci in response["containerInstances"]]
 | |
|     for status in response_statuses:
 | |
|         status.should.equal("DRAINING")
 | |
|     response = ecs_client.update_container_instances_state(
 | |
|         cluster=test_cluster_name,
 | |
|         containerInstances=test_instance_ids,
 | |
|         status="DRAINING",
 | |
|     )
 | |
|     len(response["failures"]).should.equal(0)
 | |
|     len(response["containerInstances"]).should.equal(instance_to_create)
 | |
|     response_statuses = [ci["status"] for ci in response["containerInstances"]]
 | |
|     for status in response_statuses:
 | |
|         status.should.equal("DRAINING")
 | |
|     response = ecs_client.update_container_instances_state(
 | |
|         cluster=test_cluster_name, containerInstances=test_instance_ids, status="ACTIVE"
 | |
|     )
 | |
|     len(response["failures"]).should.equal(0)
 | |
|     len(response["containerInstances"]).should.equal(instance_to_create)
 | |
|     response_statuses = [ci["status"] for ci in response["containerInstances"]]
 | |
|     for status in response_statuses:
 | |
|         status.should.equal("ACTIVE")
 | |
|     ecs_client.update_container_instances_state.when.called_with(
 | |
|         cluster=test_cluster_name,
 | |
|         containerInstances=test_instance_ids,
 | |
|         status="test_status",
 | |
|     ).should.throw(Exception)
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_update_container_instances_state_by_arn():
 | |
|     ecs_client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
|     _ = ecs_client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     instance_to_create = 3
 | |
|     test_instance_arns = []
 | |
|     for i in range(0, instance_to_create):
 | |
|         test_instance = ec2.create_instances(
 | |
|             ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|         )[0]
 | |
| 
 | |
|         instance_id_document = json.dumps(
 | |
|             ec2_utils.generate_instance_identity_document(test_instance)
 | |
|         )
 | |
| 
 | |
|         response = ecs_client.register_container_instance(
 | |
|             cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|         )
 | |
| 
 | |
|         test_instance_arns.append(response["containerInstance"]["containerInstanceArn"])
 | |
| 
 | |
|     response = ecs_client.update_container_instances_state(
 | |
|         cluster=test_cluster_name,
 | |
|         containerInstances=test_instance_arns,
 | |
|         status="DRAINING",
 | |
|     )
 | |
|     len(response["failures"]).should.equal(0)
 | |
|     len(response["containerInstances"]).should.equal(instance_to_create)
 | |
|     response_statuses = [ci["status"] for ci in response["containerInstances"]]
 | |
|     for status in response_statuses:
 | |
|         status.should.equal("DRAINING")
 | |
|     response = ecs_client.update_container_instances_state(
 | |
|         cluster=test_cluster_name,
 | |
|         containerInstances=test_instance_arns,
 | |
|         status="DRAINING",
 | |
|     )
 | |
|     len(response["failures"]).should.equal(0)
 | |
|     len(response["containerInstances"]).should.equal(instance_to_create)
 | |
|     response_statuses = [ci["status"] for ci in response["containerInstances"]]
 | |
|     for status in response_statuses:
 | |
|         status.should.equal("DRAINING")
 | |
|     response = ecs_client.update_container_instances_state(
 | |
|         cluster=test_cluster_name,
 | |
|         containerInstances=test_instance_arns,
 | |
|         status="ACTIVE",
 | |
|     )
 | |
|     len(response["failures"]).should.equal(0)
 | |
|     len(response["containerInstances"]).should.equal(instance_to_create)
 | |
|     response_statuses = [ci["status"] for ci in response["containerInstances"]]
 | |
|     for status in response_statuses:
 | |
|         status.should.equal("ACTIVE")
 | |
|     ecs_client.update_container_instances_state.when.called_with(
 | |
|         cluster=test_cluster_name,
 | |
|         containerInstances=test_instance_arns,
 | |
|         status="test_status",
 | |
|     ).should.throw(Exception)
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_run_task():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
| 
 | |
|     _ = client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     test_instance = ec2.create_instances(
 | |
|         ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|     )[0]
 | |
| 
 | |
|     instance_id_document = json.dumps(
 | |
|         ec2_utils.generate_instance_identity_document(test_instance)
 | |
|     )
 | |
| 
 | |
|     response = client.register_container_instance(
 | |
|         cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|     )
 | |
| 
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     response = client.run_task(
 | |
|         cluster="test_ecs_cluster",
 | |
|         overrides={},
 | |
|         taskDefinition="test_ecs_task",
 | |
|         count=2,
 | |
|         startedBy="moto",
 | |
|     )
 | |
|     len(response["tasks"]).should.equal(2)
 | |
|     response["tasks"][0]["taskArn"].should.contain(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task/"
 | |
|     )
 | |
|     response["tasks"][0]["clusterArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:cluster/test_ecs_cluster"
 | |
|     )
 | |
|     response["tasks"][0]["taskDefinitionArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task:1"
 | |
|     )
 | |
|     response["tasks"][0]["containerInstanceArn"].should.contain(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:container-instance/"
 | |
|     )
 | |
|     response["tasks"][0]["overrides"].should.equal({})
 | |
|     response["tasks"][0]["lastStatus"].should.equal("RUNNING")
 | |
|     response["tasks"][0]["desiredStatus"].should.equal("RUNNING")
 | |
|     response["tasks"][0]["startedBy"].should.equal("moto")
 | |
|     response["tasks"][0]["stoppedReason"].should.equal("")
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_start_task():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
| 
 | |
|     _ = client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     test_instance = ec2.create_instances(
 | |
|         ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|     )[0]
 | |
| 
 | |
|     instance_id_document = json.dumps(
 | |
|         ec2_utils.generate_instance_identity_document(test_instance)
 | |
|     )
 | |
| 
 | |
|     response = client.register_container_instance(
 | |
|         cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|     )
 | |
| 
 | |
|     container_instances = client.list_container_instances(cluster=test_cluster_name)
 | |
|     container_instance_id = container_instances["containerInstanceArns"][0].split("/")[
 | |
|         -1
 | |
|     ]
 | |
| 
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
| 
 | |
|     response = client.start_task(
 | |
|         cluster="test_ecs_cluster",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         overrides={},
 | |
|         containerInstances=[container_instance_id],
 | |
|         startedBy="moto",
 | |
|     )
 | |
| 
 | |
|     len(response["tasks"]).should.equal(1)
 | |
|     response["tasks"][0]["taskArn"].should.contain(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task/"
 | |
|     )
 | |
|     response["tasks"][0]["clusterArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:cluster/test_ecs_cluster"
 | |
|     )
 | |
|     response["tasks"][0]["taskDefinitionArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task:1"
 | |
|     )
 | |
|     response["tasks"][0]["containerInstanceArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:container-instance/{0}".format(
 | |
|             container_instance_id
 | |
|         )
 | |
|     )
 | |
|     response["tasks"][0]["overrides"].should.equal({})
 | |
|     response["tasks"][0]["lastStatus"].should.equal("RUNNING")
 | |
|     response["tasks"][0]["desiredStatus"].should.equal("RUNNING")
 | |
|     response["tasks"][0]["startedBy"].should.equal("moto")
 | |
|     response["tasks"][0]["stoppedReason"].should.equal("")
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_list_tasks():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
| 
 | |
|     _ = client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     test_instance = ec2.create_instances(
 | |
|         ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|     )[0]
 | |
| 
 | |
|     instance_id_document = json.dumps(
 | |
|         ec2_utils.generate_instance_identity_document(test_instance)
 | |
|     )
 | |
| 
 | |
|     _ = client.register_container_instance(
 | |
|         cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|     )
 | |
| 
 | |
|     container_instances = client.list_container_instances(cluster=test_cluster_name)
 | |
|     container_instance_id = container_instances["containerInstanceArns"][0].split("/")[
 | |
|         -1
 | |
|     ]
 | |
| 
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
| 
 | |
|     _ = client.start_task(
 | |
|         cluster="test_ecs_cluster",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         overrides={},
 | |
|         containerInstances=[container_instance_id],
 | |
|         startedBy="foo",
 | |
|     )
 | |
| 
 | |
|     _ = client.start_task(
 | |
|         cluster="test_ecs_cluster",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         overrides={},
 | |
|         containerInstances=[container_instance_id],
 | |
|         startedBy="bar",
 | |
|     )
 | |
| 
 | |
|     assert len(client.list_tasks()["taskArns"]).should.equal(2)
 | |
|     assert len(client.list_tasks(cluster="test_ecs_cluster")["taskArns"]).should.equal(
 | |
|         2
 | |
|     )
 | |
|     assert len(client.list_tasks(startedBy="foo")["taskArns"]).should.equal(1)
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_describe_tasks():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
| 
 | |
|     _ = client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     test_instance = ec2.create_instances(
 | |
|         ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|     )[0]
 | |
| 
 | |
|     instance_id_document = json.dumps(
 | |
|         ec2_utils.generate_instance_identity_document(test_instance)
 | |
|     )
 | |
| 
 | |
|     response = client.register_container_instance(
 | |
|         cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|     )
 | |
| 
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     tasks_arns = [
 | |
|         task["taskArn"]
 | |
|         for task in client.run_task(
 | |
|             cluster="test_ecs_cluster",
 | |
|             overrides={},
 | |
|             taskDefinition="test_ecs_task",
 | |
|             count=2,
 | |
|             startedBy="moto",
 | |
|         )["tasks"]
 | |
|     ]
 | |
|     response = client.describe_tasks(cluster="test_ecs_cluster", tasks=tasks_arns)
 | |
| 
 | |
|     len(response["tasks"]).should.equal(2)
 | |
|     set(
 | |
|         [response["tasks"][0]["taskArn"], response["tasks"][1]["taskArn"]]
 | |
|     ).should.equal(set(tasks_arns))
 | |
| 
 | |
|     # Test we can pass task ids instead of ARNs
 | |
|     response = client.describe_tasks(
 | |
|         cluster="test_ecs_cluster", tasks=[tasks_arns[0].split("/")[-1]]
 | |
|     )
 | |
|     len(response["tasks"]).should.equal(1)
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def describe_task_definition():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     container_definition = {
 | |
|         "name": "hello_world",
 | |
|         "image": "docker/hello-world:latest",
 | |
|         "cpu": 1024,
 | |
|         "memory": 400,
 | |
|         "essential": True,
 | |
|         "environment": [{"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}],
 | |
|         "logConfiguration": {"logDriver": "json-file"},
 | |
|     }
 | |
|     task_definition = client.register_task_definition(
 | |
|         family="test_ecs_task", containerDefinitions=[container_definition]
 | |
|     )
 | |
|     family = task_definition["family"]
 | |
|     task = client.describe_task_definition(taskDefinition=family)
 | |
|     task["containerDefinitions"][0].should.equal(container_definition)
 | |
|     task["taskDefinitionArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task2:1"
 | |
|     )
 | |
|     task["volumes"].should.equal([])
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_stop_task():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
| 
 | |
|     _ = client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     test_instance = ec2.create_instances(
 | |
|         ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|     )[0]
 | |
| 
 | |
|     instance_id_document = json.dumps(
 | |
|         ec2_utils.generate_instance_identity_document(test_instance)
 | |
|     )
 | |
| 
 | |
|     _ = client.register_container_instance(
 | |
|         cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|     )
 | |
| 
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     run_response = client.run_task(
 | |
|         cluster="test_ecs_cluster",
 | |
|         overrides={},
 | |
|         taskDefinition="test_ecs_task",
 | |
|         count=1,
 | |
|         startedBy="moto",
 | |
|     )
 | |
|     stop_response = client.stop_task(
 | |
|         cluster="test_ecs_cluster",
 | |
|         task=run_response["tasks"][0].get("taskArn"),
 | |
|         reason="moto testing",
 | |
|     )
 | |
| 
 | |
|     stop_response["task"]["taskArn"].should.equal(
 | |
|         run_response["tasks"][0].get("taskArn")
 | |
|     )
 | |
|     stop_response["task"]["lastStatus"].should.equal("STOPPED")
 | |
|     stop_response["task"]["desiredStatus"].should.equal("STOPPED")
 | |
|     stop_response["task"]["stoppedReason"].should.equal("moto testing")
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_resource_reservation_and_release():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
| 
 | |
|     _ = client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     test_instance = ec2.create_instances(
 | |
|         ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|     )[0]
 | |
| 
 | |
|     instance_id_document = json.dumps(
 | |
|         ec2_utils.generate_instance_identity_document(test_instance)
 | |
|     )
 | |
| 
 | |
|     _ = client.register_container_instance(
 | |
|         cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|     )
 | |
| 
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|                 "portMappings": [{"hostPort": 80, "containerPort": 8080}],
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     run_response = client.run_task(
 | |
|         cluster="test_ecs_cluster",
 | |
|         overrides={},
 | |
|         taskDefinition="test_ecs_task",
 | |
|         count=1,
 | |
|         startedBy="moto",
 | |
|     )
 | |
|     container_instance_arn = run_response["tasks"][0].get("containerInstanceArn")
 | |
|     container_instance_description = client.describe_container_instances(
 | |
|         cluster="test_ecs_cluster", containerInstances=[container_instance_arn]
 | |
|     )["containerInstances"][0]
 | |
|     remaining_resources, registered_resources = _fetch_container_instance_resources(
 | |
|         container_instance_description
 | |
|     )
 | |
|     remaining_resources["CPU"].should.equal(registered_resources["CPU"] - 1024)
 | |
|     remaining_resources["MEMORY"].should.equal(registered_resources["MEMORY"] - 400)
 | |
|     registered_resources["PORTS"].append("80")
 | |
|     remaining_resources["PORTS"].should.equal(registered_resources["PORTS"])
 | |
|     container_instance_description["runningTasksCount"].should.equal(1)
 | |
|     client.stop_task(
 | |
|         cluster="test_ecs_cluster",
 | |
|         task=run_response["tasks"][0].get("taskArn"),
 | |
|         reason="moto testing",
 | |
|     )
 | |
|     container_instance_description = client.describe_container_instances(
 | |
|         cluster="test_ecs_cluster", containerInstances=[container_instance_arn]
 | |
|     )["containerInstances"][0]
 | |
|     remaining_resources, registered_resources = _fetch_container_instance_resources(
 | |
|         container_instance_description
 | |
|     )
 | |
|     remaining_resources["CPU"].should.equal(registered_resources["CPU"])
 | |
|     remaining_resources["MEMORY"].should.equal(registered_resources["MEMORY"])
 | |
|     remaining_resources["PORTS"].should.equal(registered_resources["PORTS"])
 | |
|     container_instance_description["runningTasksCount"].should.equal(0)
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_resource_reservation_and_release_memory_reservation():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
| 
 | |
|     _ = client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     test_instance = ec2.create_instances(
 | |
|         ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|     )[0]
 | |
| 
 | |
|     instance_id_document = json.dumps(
 | |
|         ec2_utils.generate_instance_identity_document(test_instance)
 | |
|     )
 | |
| 
 | |
|     _ = client.register_container_instance(
 | |
|         cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|     )
 | |
| 
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "memoryReservation": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|                 "portMappings": [{"containerPort": 8080}],
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     run_response = client.run_task(
 | |
|         cluster="test_ecs_cluster",
 | |
|         overrides={},
 | |
|         taskDefinition="test_ecs_task",
 | |
|         count=1,
 | |
|         startedBy="moto",
 | |
|     )
 | |
|     container_instance_arn = run_response["tasks"][0].get("containerInstanceArn")
 | |
|     container_instance_description = client.describe_container_instances(
 | |
|         cluster="test_ecs_cluster", containerInstances=[container_instance_arn]
 | |
|     )["containerInstances"][0]
 | |
|     remaining_resources, registered_resources = _fetch_container_instance_resources(
 | |
|         container_instance_description
 | |
|     )
 | |
|     remaining_resources["CPU"].should.equal(registered_resources["CPU"])
 | |
|     remaining_resources["MEMORY"].should.equal(registered_resources["MEMORY"] - 400)
 | |
|     remaining_resources["PORTS"].should.equal(registered_resources["PORTS"])
 | |
|     container_instance_description["runningTasksCount"].should.equal(1)
 | |
|     client.stop_task(
 | |
|         cluster="test_ecs_cluster",
 | |
|         task=run_response["tasks"][0].get("taskArn"),
 | |
|         reason="moto testing",
 | |
|     )
 | |
|     container_instance_description = client.describe_container_instances(
 | |
|         cluster="test_ecs_cluster", containerInstances=[container_instance_arn]
 | |
|     )["containerInstances"][0]
 | |
|     remaining_resources, registered_resources = _fetch_container_instance_resources(
 | |
|         container_instance_description
 | |
|     )
 | |
|     remaining_resources["CPU"].should.equal(registered_resources["CPU"])
 | |
|     remaining_resources["MEMORY"].should.equal(registered_resources["MEMORY"])
 | |
|     remaining_resources["PORTS"].should.equal(registered_resources["PORTS"])
 | |
|     container_instance_description["runningTasksCount"].should.equal(0)
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| @mock_cloudformation
 | |
| def test_create_cluster_through_cloudformation():
 | |
|     template = {
 | |
|         "AWSTemplateFormatVersion": "2010-09-09",
 | |
|         "Description": "ECS Cluster Test CloudFormation",
 | |
|         "Resources": {
 | |
|             "testCluster": {
 | |
|                 "Type": "AWS::ECS::Cluster",
 | |
|                 "Properties": {"ClusterName": "testcluster"},
 | |
|             }
 | |
|         },
 | |
|     }
 | |
|     template_json = json.dumps(template)
 | |
| 
 | |
|     ecs_conn = boto3.client("ecs", region_name="us-west-1")
 | |
|     resp = ecs_conn.list_clusters()
 | |
|     len(resp["clusterArns"]).should.equal(0)
 | |
| 
 | |
|     cfn_conn = boto3.client("cloudformation", region_name="us-west-1")
 | |
|     cfn_conn.create_stack(StackName="test_stack", TemplateBody=template_json)
 | |
| 
 | |
|     resp = ecs_conn.list_clusters()
 | |
|     len(resp["clusterArns"]).should.equal(1)
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| @mock_cloudformation
 | |
| def test_create_cluster_through_cloudformation_no_name():
 | |
|     # cloudformation should create a cluster name for you if you do not provide it
 | |
|     # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-cluster.html#cfn-ecs-cluster-clustername
 | |
|     template = {
 | |
|         "AWSTemplateFormatVersion": "2010-09-09",
 | |
|         "Description": "ECS Cluster Test CloudFormation",
 | |
|         "Resources": {"testCluster": {"Type": "AWS::ECS::Cluster"}},
 | |
|     }
 | |
|     template_json = json.dumps(template)
 | |
|     cfn_conn = boto3.client("cloudformation", region_name="us-west-1")
 | |
|     cfn_conn.create_stack(StackName="test_stack", TemplateBody=template_json)
 | |
| 
 | |
|     ecs_conn = boto3.client("ecs", region_name="us-west-1")
 | |
|     resp = ecs_conn.list_clusters()
 | |
|     len(resp["clusterArns"]).should.equal(1)
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| @mock_cloudformation
 | |
| def test_update_cluster_name_through_cloudformation_should_trigger_a_replacement():
 | |
|     template1 = {
 | |
|         "AWSTemplateFormatVersion": "2010-09-09",
 | |
|         "Description": "ECS Cluster Test CloudFormation",
 | |
|         "Resources": {
 | |
|             "testCluster": {
 | |
|                 "Type": "AWS::ECS::Cluster",
 | |
|                 "Properties": {"ClusterName": "testcluster1"},
 | |
|             }
 | |
|         },
 | |
|     }
 | |
|     template2 = deepcopy(template1)
 | |
|     template2["Resources"]["testCluster"]["Properties"]["ClusterName"] = "testcluster2"
 | |
|     template1_json = json.dumps(template1)
 | |
|     cfn_conn = boto3.client("cloudformation", region_name="us-west-1")
 | |
|     stack_resp = cfn_conn.create_stack(
 | |
|         StackName="test_stack", TemplateBody=template1_json
 | |
|     )
 | |
| 
 | |
|     template2_json = json.dumps(template2)
 | |
|     cfn_conn.update_stack(StackName=stack_resp["StackId"], TemplateBody=template2_json)
 | |
|     ecs_conn = boto3.client("ecs", region_name="us-west-1")
 | |
|     resp = ecs_conn.list_clusters()
 | |
|     len(resp["clusterArns"]).should.equal(1)
 | |
|     resp["clusterArns"][0].endswith("testcluster2").should.be.true
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| @mock_cloudformation
 | |
| def test_create_task_definition_through_cloudformation():
 | |
|     template = {
 | |
|         "AWSTemplateFormatVersion": "2010-09-09",
 | |
|         "Description": "ECS Cluster Test CloudFormation",
 | |
|         "Resources": {
 | |
|             "testTaskDefinition": {
 | |
|                 "Type": "AWS::ECS::TaskDefinition",
 | |
|                 "Properties": {
 | |
|                     "ContainerDefinitions": [
 | |
|                         {
 | |
|                             "Name": "ecs-sample",
 | |
|                             "Image": "amazon/amazon-ecs-sample",
 | |
|                             "Cpu": "200",
 | |
|                             "Memory": "500",
 | |
|                             "Essential": "true",
 | |
|                         }
 | |
|                     ],
 | |
|                     "Volumes": [],
 | |
|                 },
 | |
|             }
 | |
|         },
 | |
|     }
 | |
|     template_json = json.dumps(template)
 | |
|     cfn_conn = boto3.client("cloudformation", region_name="us-west-1")
 | |
|     stack_name = "test_stack"
 | |
|     cfn_conn.create_stack(StackName=stack_name, TemplateBody=template_json)
 | |
| 
 | |
|     ecs_conn = boto3.client("ecs", region_name="us-west-1")
 | |
|     resp = ecs_conn.list_task_definitions()
 | |
|     len(resp["taskDefinitionArns"]).should.equal(1)
 | |
|     task_definition_arn = resp["taskDefinitionArns"][0]
 | |
| 
 | |
|     task_definition_details = cfn_conn.describe_stack_resource(
 | |
|         StackName=stack_name, LogicalResourceId="testTaskDefinition"
 | |
|     )["StackResourceDetail"]
 | |
|     task_definition_details["PhysicalResourceId"].should.equal(task_definition_arn)
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_task_definitions_unable_to_be_placed():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
| 
 | |
|     _ = client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     test_instance = ec2.create_instances(
 | |
|         ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|     )[0]
 | |
| 
 | |
|     instance_id_document = json.dumps(
 | |
|         ec2_utils.generate_instance_identity_document(test_instance)
 | |
|     )
 | |
| 
 | |
|     response = client.register_container_instance(
 | |
|         cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|     )
 | |
| 
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 5000,
 | |
|                 "memory": 40000,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     response = client.run_task(
 | |
|         cluster="test_ecs_cluster",
 | |
|         overrides={},
 | |
|         taskDefinition="test_ecs_task",
 | |
|         count=2,
 | |
|         startedBy="moto",
 | |
|     )
 | |
|     len(response["tasks"]).should.equal(0)
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_task_definitions_with_port_clash():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
| 
 | |
|     _ = client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     test_instance = ec2.create_instances(
 | |
|         ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|     )[0]
 | |
| 
 | |
|     instance_id_document = json.dumps(
 | |
|         ec2_utils.generate_instance_identity_document(test_instance)
 | |
|     )
 | |
| 
 | |
|     response = client.register_container_instance(
 | |
|         cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|     )
 | |
| 
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 256,
 | |
|                 "memory": 512,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|                 "portMappings": [{"hostPort": 80, "containerPort": 8080}],
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     response = client.run_task(
 | |
|         cluster="test_ecs_cluster",
 | |
|         overrides={},
 | |
|         taskDefinition="test_ecs_task",
 | |
|         count=2,
 | |
|         startedBy="moto",
 | |
|     )
 | |
|     len(response["tasks"]).should.equal(1)
 | |
|     response["tasks"][0]["taskArn"].should.contain(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task/"
 | |
|     )
 | |
|     response["tasks"][0]["clusterArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:cluster/test_ecs_cluster"
 | |
|     )
 | |
|     response["tasks"][0]["taskDefinitionArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task:1"
 | |
|     )
 | |
|     response["tasks"][0]["containerInstanceArn"].should.contain(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:container-instance/"
 | |
|     )
 | |
|     response["tasks"][0]["overrides"].should.equal({})
 | |
|     response["tasks"][0]["lastStatus"].should.equal("RUNNING")
 | |
|     response["tasks"][0]["desiredStatus"].should.equal("RUNNING")
 | |
|     response["tasks"][0]["startedBy"].should.equal("moto")
 | |
|     response["tasks"][0]["stoppedReason"].should.equal("")
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| @mock_cloudformation
 | |
| def test_update_task_definition_family_through_cloudformation_should_trigger_a_replacement():
 | |
|     template1 = {
 | |
|         "AWSTemplateFormatVersion": "2010-09-09",
 | |
|         "Description": "ECS Cluster Test CloudFormation",
 | |
|         "Resources": {
 | |
|             "testTaskDefinition": {
 | |
|                 "Type": "AWS::ECS::TaskDefinition",
 | |
|                 "Properties": {
 | |
|                     "Family": "testTaskDefinition1",
 | |
|                     "ContainerDefinitions": [
 | |
|                         {
 | |
|                             "Name": "ecs-sample",
 | |
|                             "Image": "amazon/amazon-ecs-sample",
 | |
|                             "Cpu": "200",
 | |
|                             "Memory": "500",
 | |
|                             "Essential": "true",
 | |
|                         }
 | |
|                     ],
 | |
|                     "Volumes": [],
 | |
|                 },
 | |
|             }
 | |
|         },
 | |
|     }
 | |
|     template1_json = json.dumps(template1)
 | |
|     cfn_conn = boto3.client("cloudformation", region_name="us-west-1")
 | |
|     cfn_conn.create_stack(StackName="test_stack", TemplateBody=template1_json)
 | |
| 
 | |
|     template2 = deepcopy(template1)
 | |
|     template2["Resources"]["testTaskDefinition"]["Properties"][
 | |
|         "Family"
 | |
|     ] = "testTaskDefinition2"
 | |
|     template2_json = json.dumps(template2)
 | |
|     cfn_conn.update_stack(StackName="test_stack", TemplateBody=template2_json)
 | |
| 
 | |
|     ecs_conn = boto3.client("ecs", region_name="us-west-1")
 | |
|     resp = ecs_conn.list_task_definitions(familyPrefix="testTaskDefinition2")
 | |
|     len(resp["taskDefinitionArns"]).should.equal(1)
 | |
|     resp["taskDefinitionArns"][0].endswith("testTaskDefinition2:1").should.be.true
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| @mock_cloudformation
 | |
| def test_create_service_through_cloudformation():
 | |
|     template = {
 | |
|         "AWSTemplateFormatVersion": "2010-09-09",
 | |
|         "Description": "ECS Cluster Test CloudFormation",
 | |
|         "Resources": {
 | |
|             "testCluster": {
 | |
|                 "Type": "AWS::ECS::Cluster",
 | |
|                 "Properties": {"ClusterName": "testcluster"},
 | |
|             },
 | |
|             "testTaskDefinition": {
 | |
|                 "Type": "AWS::ECS::TaskDefinition",
 | |
|                 "Properties": {
 | |
|                     "ContainerDefinitions": [
 | |
|                         {
 | |
|                             "Name": "ecs-sample",
 | |
|                             "Image": "amazon/amazon-ecs-sample",
 | |
|                             "Cpu": "200",
 | |
|                             "Memory": "500",
 | |
|                             "Essential": "true",
 | |
|                         }
 | |
|                     ],
 | |
|                     "Volumes": [],
 | |
|                 },
 | |
|             },
 | |
|             "testService": {
 | |
|                 "Type": "AWS::ECS::Service",
 | |
|                 "Properties": {
 | |
|                     "Cluster": {"Ref": "testCluster"},
 | |
|                     "DesiredCount": 10,
 | |
|                     "TaskDefinition": {"Ref": "testTaskDefinition"},
 | |
|                 },
 | |
|             },
 | |
|         },
 | |
|     }
 | |
|     template_json = json.dumps(template)
 | |
|     cfn_conn = boto3.client("cloudformation", region_name="us-west-1")
 | |
|     cfn_conn.create_stack(StackName="test_stack", TemplateBody=template_json)
 | |
| 
 | |
|     ecs_conn = boto3.client("ecs", region_name="us-west-1")
 | |
|     resp = ecs_conn.list_services(cluster="testcluster")
 | |
|     len(resp["serviceArns"]).should.equal(1)
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| @mock_cloudformation
 | |
| def test_update_service_through_cloudformation_should_trigger_replacement():
 | |
|     template1 = {
 | |
|         "AWSTemplateFormatVersion": "2010-09-09",
 | |
|         "Description": "ECS Cluster Test CloudFormation",
 | |
|         "Resources": {
 | |
|             "testCluster": {
 | |
|                 "Type": "AWS::ECS::Cluster",
 | |
|                 "Properties": {"ClusterName": "testcluster"},
 | |
|             },
 | |
|             "testTaskDefinition": {
 | |
|                 "Type": "AWS::ECS::TaskDefinition",
 | |
|                 "Properties": {
 | |
|                     "ContainerDefinitions": [
 | |
|                         {
 | |
|                             "Name": "ecs-sample",
 | |
|                             "Image": "amazon/amazon-ecs-sample",
 | |
|                             "Cpu": "200",
 | |
|                             "Memory": "500",
 | |
|                             "Essential": "true",
 | |
|                         }
 | |
|                     ],
 | |
|                     "Volumes": [],
 | |
|                 },
 | |
|             },
 | |
|             "testService": {
 | |
|                 "Type": "AWS::ECS::Service",
 | |
|                 "Properties": {
 | |
|                     "Cluster": {"Ref": "testCluster"},
 | |
|                     "TaskDefinition": {"Ref": "testTaskDefinition"},
 | |
|                     "DesiredCount": 10,
 | |
|                 },
 | |
|             },
 | |
|         },
 | |
|     }
 | |
|     template_json1 = json.dumps(template1)
 | |
|     cfn_conn = boto3.client("cloudformation", region_name="us-west-1")
 | |
|     cfn_conn.create_stack(StackName="test_stack", TemplateBody=template_json1)
 | |
|     template2 = deepcopy(template1)
 | |
|     template2["Resources"]["testService"]["Properties"]["DesiredCount"] = 5
 | |
|     template2_json = json.dumps(template2)
 | |
|     cfn_conn.update_stack(StackName="test_stack", TemplateBody=template2_json)
 | |
| 
 | |
|     ecs_conn = boto3.client("ecs", region_name="us-west-1")
 | |
|     resp = ecs_conn.list_services(cluster="testcluster")
 | |
|     len(resp["serviceArns"]).should.equal(1)
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_attributes():
 | |
|     # Combined put, list delete attributes into the same test due to the amount of setup
 | |
|     ecs_client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
| 
 | |
|     _ = ecs_client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     instances = []
 | |
|     test_instance = ec2.create_instances(
 | |
|         ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|     )[0]
 | |
|     instances.append(test_instance)
 | |
| 
 | |
|     instance_id_document = json.dumps(
 | |
|         ec2_utils.generate_instance_identity_document(test_instance)
 | |
|     )
 | |
| 
 | |
|     response = ecs_client.register_container_instance(
 | |
|         cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|     )
 | |
| 
 | |
|     response["containerInstance"]["ec2InstanceId"].should.equal(test_instance.id)
 | |
|     full_arn1 = response["containerInstance"]["containerInstanceArn"]
 | |
| 
 | |
|     test_instance = ec2.create_instances(
 | |
|         ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|     )[0]
 | |
|     instances.append(test_instance)
 | |
| 
 | |
|     instance_id_document = json.dumps(
 | |
|         ec2_utils.generate_instance_identity_document(test_instance)
 | |
|     )
 | |
| 
 | |
|     response = ecs_client.register_container_instance(
 | |
|         cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|     )
 | |
| 
 | |
|     response["containerInstance"]["ec2InstanceId"].should.equal(test_instance.id)
 | |
|     full_arn2 = response["containerInstance"]["containerInstanceArn"]
 | |
|     partial_arn2 = full_arn2.rsplit("/", 1)[-1]
 | |
| 
 | |
|     full_arn2.should_not.equal(
 | |
|         full_arn1
 | |
|     )  # uuid1 isnt unique enough when the pc is fast ;-)
 | |
| 
 | |
|     # Ok set instance 1 with 1 attribute, instance 2 with another, and all of them with a 3rd.
 | |
|     ecs_client.put_attributes(
 | |
|         cluster=test_cluster_name,
 | |
|         attributes=[
 | |
|             {"name": "env", "value": "prod"},
 | |
|             {"name": "attr1", "value": "instance1", "targetId": full_arn1},
 | |
|             {
 | |
|                 "name": "attr1",
 | |
|                 "value": "instance2",
 | |
|                 "targetId": partial_arn2,
 | |
|                 "targetType": "container-instance",
 | |
|             },
 | |
|         ],
 | |
|     )
 | |
| 
 | |
|     resp = ecs_client.list_attributes(
 | |
|         cluster=test_cluster_name, targetType="container-instance"
 | |
|     )
 | |
|     attrs = resp["attributes"]
 | |
| 
 | |
|     NUM_CUSTOM_ATTRIBUTES = 4  # 2 specific to individual machines and 1 global, going to both machines (2 + 1*2)
 | |
|     NUM_DEFAULT_ATTRIBUTES = 4
 | |
|     len(attrs).should.equal(
 | |
|         NUM_CUSTOM_ATTRIBUTES + (NUM_DEFAULT_ATTRIBUTES * len(instances))
 | |
|     )
 | |
| 
 | |
|     # Tests that the attrs have been set properly
 | |
|     len(list(filter(lambda item: item["name"] == "env", attrs))).should.equal(2)
 | |
|     len(
 | |
|         list(
 | |
|             filter(
 | |
|                 lambda item: item["name"] == "attr1" and item["value"] == "instance1",
 | |
|                 attrs,
 | |
|             )
 | |
|         )
 | |
|     ).should.equal(1)
 | |
| 
 | |
|     ecs_client.delete_attributes(
 | |
|         cluster=test_cluster_name,
 | |
|         attributes=[
 | |
|             {
 | |
|                 "name": "attr1",
 | |
|                 "value": "instance2",
 | |
|                 "targetId": partial_arn2,
 | |
|                 "targetType": "container-instance",
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     NUM_CUSTOM_ATTRIBUTES -= 1
 | |
| 
 | |
|     resp = ecs_client.list_attributes(
 | |
|         cluster=test_cluster_name, targetType="container-instance"
 | |
|     )
 | |
|     attrs = resp["attributes"]
 | |
|     len(attrs).should.equal(
 | |
|         NUM_CUSTOM_ATTRIBUTES + (NUM_DEFAULT_ATTRIBUTES * len(instances))
 | |
|     )
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_poll_endpoint():
 | |
|     # Combined put, list delete attributes into the same test due to the amount of setup
 | |
|     ecs_client = boto3.client("ecs", region_name="us-east-1")
 | |
| 
 | |
|     # Just a placeholder until someone actually wants useless data, just testing it doesnt raise an exception
 | |
|     resp = ecs_client.discover_poll_endpoint(cluster="blah", containerInstance="blah")
 | |
|     resp.should.contain("endpoint")
 | |
|     resp.should.contain("telemetryEndpoint")
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_list_task_definition_families():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     client.register_task_definition(
 | |
|         family="alt_test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
| 
 | |
|     resp1 = client.list_task_definition_families()
 | |
|     resp2 = client.list_task_definition_families(familyPrefix="alt")
 | |
| 
 | |
|     len(resp1["families"]).should.equal(2)
 | |
|     len(resp2["families"]).should.equal(1)
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_default_container_instance_attributes():
 | |
|     ecs_client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
| 
 | |
|     # Create cluster and EC2 instance
 | |
|     _ = ecs_client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     test_instance = ec2.create_instances(
 | |
|         ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|     )[0]
 | |
| 
 | |
|     instance_id_document = json.dumps(
 | |
|         ec2_utils.generate_instance_identity_document(test_instance)
 | |
|     )
 | |
| 
 | |
|     # Register container instance
 | |
|     response = ecs_client.register_container_instance(
 | |
|         cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|     )
 | |
| 
 | |
|     response["containerInstance"]["ec2InstanceId"].should.equal(test_instance.id)
 | |
|     full_arn = response["containerInstance"]["containerInstanceArn"]
 | |
|     container_instance_id = full_arn.rsplit("/", 1)[-1]
 | |
| 
 | |
|     default_attributes = response["containerInstance"]["attributes"]
 | |
|     assert len(default_attributes) == 4
 | |
|     expected_result = [
 | |
|         {
 | |
|             "name": "ecs.availability-zone",
 | |
|             "value": test_instance.placement["AvailabilityZone"],
 | |
|         },
 | |
|         {"name": "ecs.ami-id", "value": test_instance.image_id},
 | |
|         {"name": "ecs.instance-type", "value": test_instance.instance_type},
 | |
|         {"name": "ecs.os-type", "value": test_instance.platform or "linux"},
 | |
|     ]
 | |
|     assert sorted(default_attributes, key=lambda item: item["name"]) == sorted(
 | |
|         expected_result, key=lambda item: item["name"]
 | |
|     )
 | |
| 
 | |
| 
 | |
| @mock_ec2
 | |
| @mock_ecs
 | |
| def test_describe_container_instances_with_attributes():
 | |
|     ecs_client = boto3.client("ecs", region_name="us-east-1")
 | |
|     ec2 = boto3.resource("ec2", region_name="us-east-1")
 | |
| 
 | |
|     test_cluster_name = "test_ecs_cluster"
 | |
| 
 | |
|     # Create cluster and EC2 instance
 | |
|     _ = ecs_client.create_cluster(clusterName=test_cluster_name)
 | |
| 
 | |
|     test_instance = ec2.create_instances(
 | |
|         ImageId="ami-1234abcd", MinCount=1, MaxCount=1
 | |
|     )[0]
 | |
| 
 | |
|     instance_id_document = json.dumps(
 | |
|         ec2_utils.generate_instance_identity_document(test_instance)
 | |
|     )
 | |
| 
 | |
|     # Register container instance
 | |
|     response = ecs_client.register_container_instance(
 | |
|         cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
 | |
|     )
 | |
| 
 | |
|     response["containerInstance"]["ec2InstanceId"].should.equal(test_instance.id)
 | |
|     full_arn = response["containerInstance"]["containerInstanceArn"]
 | |
|     container_instance_id = full_arn.rsplit("/", 1)[-1]
 | |
|     default_attributes = response["containerInstance"]["attributes"]
 | |
| 
 | |
|     # Set attributes on container instance, one without a value
 | |
|     attributes = [
 | |
|         {"name": "env", "value": "prod"},
 | |
|         {
 | |
|             "name": "attr1",
 | |
|             "value": "instance1",
 | |
|             "targetId": container_instance_id,
 | |
|             "targetType": "container-instance",
 | |
|         },
 | |
|         {"name": "attr_without_value"},
 | |
|     ]
 | |
|     ecs_client.put_attributes(cluster=test_cluster_name, attributes=attributes)
 | |
| 
 | |
|     # Describe container instance, should have attributes previously set
 | |
|     described_instance = ecs_client.describe_container_instances(
 | |
|         cluster=test_cluster_name, containerInstances=[container_instance_id]
 | |
|     )
 | |
| 
 | |
|     assert len(described_instance["containerInstances"]) == 1
 | |
|     assert isinstance(described_instance["containerInstances"][0]["attributes"], list)
 | |
| 
 | |
|     # Remove additional info passed to put_attributes
 | |
|     cleaned_attributes = []
 | |
|     for attribute in attributes:
 | |
|         attribute.pop("targetId", None)
 | |
|         attribute.pop("targetType", None)
 | |
|         cleaned_attributes.append(attribute)
 | |
|     described_attributes = sorted(
 | |
|         described_instance["containerInstances"][0]["attributes"],
 | |
|         key=lambda item: item["name"],
 | |
|     )
 | |
|     expected_attributes = sorted(
 | |
|         default_attributes + cleaned_attributes, key=lambda item: item["name"]
 | |
|     )
 | |
|     assert described_attributes == expected_attributes
 | |
| 
 | |
| 
 | |
| def _fetch_container_instance_resources(container_instance_description):
 | |
|     remaining_resources = {}
 | |
|     registered_resources = {}
 | |
|     remaining_resources_list = container_instance_description["remainingResources"]
 | |
|     registered_resources_list = container_instance_description["registeredResources"]
 | |
|     remaining_resources["CPU"] = [
 | |
|         x["integerValue"] for x in remaining_resources_list if x["name"] == "CPU"
 | |
|     ][0]
 | |
|     remaining_resources["MEMORY"] = [
 | |
|         x["integerValue"] for x in remaining_resources_list if x["name"] == "MEMORY"
 | |
|     ][0]
 | |
|     remaining_resources["PORTS"] = [
 | |
|         x["stringSetValue"] for x in remaining_resources_list if x["name"] == "PORTS"
 | |
|     ][0]
 | |
|     registered_resources["CPU"] = [
 | |
|         x["integerValue"] for x in registered_resources_list if x["name"] == "CPU"
 | |
|     ][0]
 | |
|     registered_resources["MEMORY"] = [
 | |
|         x["integerValue"] for x in registered_resources_list if x["name"] == "MEMORY"
 | |
|     ][0]
 | |
|     registered_resources["PORTS"] = [
 | |
|         x["stringSetValue"] for x in registered_resources_list if x["name"] == "PORTS"
 | |
|     ][0]
 | |
|     return remaining_resources, registered_resources
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_create_service_load_balancing():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     client.create_cluster(clusterName="test_ecs_cluster")
 | |
|     client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     response = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=2,
 | |
|         loadBalancers=[
 | |
|             {
 | |
|                 "targetGroupArn": "test_target_group_arn",
 | |
|                 "loadBalancerName": "test_load_balancer_name",
 | |
|                 "containerName": "test_container_name",
 | |
|                 "containerPort": 123,
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     response["service"]["clusterArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:cluster/test_ecs_cluster"
 | |
|     )
 | |
|     response["service"]["desiredCount"].should.equal(2)
 | |
|     len(response["service"]["events"]).should.equal(0)
 | |
|     len(response["service"]["loadBalancers"]).should.equal(1)
 | |
|     response["service"]["loadBalancers"][0]["targetGroupArn"].should.equal(
 | |
|         "test_target_group_arn"
 | |
|     )
 | |
|     response["service"]["loadBalancers"][0]["loadBalancerName"].should.equal(
 | |
|         "test_load_balancer_name"
 | |
|     )
 | |
|     response["service"]["loadBalancers"][0]["containerName"].should.equal(
 | |
|         "test_container_name"
 | |
|     )
 | |
|     response["service"]["loadBalancers"][0]["containerPort"].should.equal(123)
 | |
|     response["service"]["pendingCount"].should.equal(0)
 | |
|     response["service"]["runningCount"].should.equal(0)
 | |
|     response["service"]["serviceArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:service/test_ecs_service"
 | |
|     )
 | |
|     response["service"]["serviceName"].should.equal("test_ecs_service")
 | |
|     response["service"]["status"].should.equal("ACTIVE")
 | |
|     response["service"]["taskDefinition"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task:1"
 | |
|     )
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_list_tags_for_resource():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     response = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|         tags=[
 | |
|             {"key": "createdBy", "value": "moto-unittest"},
 | |
|             {"key": "foo", "value": "bar"},
 | |
|         ],
 | |
|     )
 | |
|     type(response["taskDefinition"]).should.be(dict)
 | |
|     response["taskDefinition"]["revision"].should.equal(1)
 | |
|     response["taskDefinition"]["taskDefinitionArn"].should.equal(
 | |
|         "arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task:1"
 | |
|     )
 | |
| 
 | |
|     task_definition_arn = response["taskDefinition"]["taskDefinitionArn"]
 | |
|     response = client.list_tags_for_resource(resourceArn=task_definition_arn)
 | |
| 
 | |
|     type(response["tags"]).should.be(list)
 | |
|     response["tags"].should.equal(
 | |
|         [{"key": "createdBy", "value": "moto-unittest"}, {"key": "foo", "value": "bar"}]
 | |
|     )
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_list_tags_for_resource_unknown():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     task_definition_arn = "arn:aws:ecs:us-east-1:012345678910:task-definition/unknown:1"
 | |
|     try:
 | |
|         client.list_tags_for_resource(resourceArn=task_definition_arn)
 | |
|     except ClientError as err:
 | |
|         err.response["Error"]["Code"].should.equal("ClientException")
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_list_tags_for_resource_ecs_service():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.create_cluster(clusterName="test_ecs_cluster")
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     response = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=2,
 | |
|         tags=[
 | |
|             {"key": "createdBy", "value": "moto-unittest"},
 | |
|             {"key": "foo", "value": "bar"},
 | |
|         ],
 | |
|     )
 | |
|     response = client.list_tags_for_resource(
 | |
|         resourceArn=response["service"]["serviceArn"]
 | |
|     )
 | |
|     type(response["tags"]).should.be(list)
 | |
|     response["tags"].should.equal(
 | |
|         [{"key": "createdBy", "value": "moto-unittest"}, {"key": "foo", "value": "bar"}]
 | |
|     )
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_list_tags_for_resource_unknown_service():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     service_arn = "arn:aws:ecs:us-east-1:012345678910:service/unknown:1"
 | |
|     try:
 | |
|         client.list_tags_for_resource(resourceArn=service_arn)
 | |
|     except ClientError as err:
 | |
|         err.response["Error"]["Code"].should.equal("ServiceNotFoundException")
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_ecs_service_tag_resource():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.create_cluster(clusterName="test_ecs_cluster")
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     response = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=2,
 | |
|     )
 | |
|     client.tag_resource(
 | |
|         resourceArn=response["service"]["serviceArn"],
 | |
|         tags=[
 | |
|             {"key": "createdBy", "value": "moto-unittest"},
 | |
|             {"key": "foo", "value": "bar"},
 | |
|         ],
 | |
|     )
 | |
|     response = client.list_tags_for_resource(
 | |
|         resourceArn=response["service"]["serviceArn"]
 | |
|     )
 | |
|     type(response["tags"]).should.be(list)
 | |
|     response["tags"].should.equal(
 | |
|         [{"key": "createdBy", "value": "moto-unittest"}, {"key": "foo", "value": "bar"}]
 | |
|     )
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_ecs_service_tag_resource_overwrites_tag():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.create_cluster(clusterName="test_ecs_cluster")
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     response = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=2,
 | |
|         tags=[{"key": "foo", "value": "bar"}],
 | |
|     )
 | |
|     client.tag_resource(
 | |
|         resourceArn=response["service"]["serviceArn"],
 | |
|         tags=[
 | |
|             {"key": "createdBy", "value": "moto-unittest"},
 | |
|             {"key": "foo", "value": "hello world"},
 | |
|         ],
 | |
|     )
 | |
|     response = client.list_tags_for_resource(
 | |
|         resourceArn=response["service"]["serviceArn"]
 | |
|     )
 | |
|     type(response["tags"]).should.be(list)
 | |
|     response["tags"].should.equal(
 | |
|         [
 | |
|             {"key": "createdBy", "value": "moto-unittest"},
 | |
|             {"key": "foo", "value": "hello world"},
 | |
|         ]
 | |
|     )
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_ecs_service_untag_resource():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.create_cluster(clusterName="test_ecs_cluster")
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     response = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=2,
 | |
|         tags=[{"key": "foo", "value": "bar"}],
 | |
|     )
 | |
|     client.untag_resource(
 | |
|         resourceArn=response["service"]["serviceArn"], tagKeys=["foo"]
 | |
|     )
 | |
|     response = client.list_tags_for_resource(
 | |
|         resourceArn=response["service"]["serviceArn"]
 | |
|     )
 | |
|     response["tags"].should.equal([])
 | |
| 
 | |
| 
 | |
| @mock_ecs
 | |
| def test_ecs_service_untag_resource_multiple_tags():
 | |
|     client = boto3.client("ecs", region_name="us-east-1")
 | |
|     _ = client.create_cluster(clusterName="test_ecs_cluster")
 | |
|     _ = client.register_task_definition(
 | |
|         family="test_ecs_task",
 | |
|         containerDefinitions=[
 | |
|             {
 | |
|                 "name": "hello_world",
 | |
|                 "image": "docker/hello-world:latest",
 | |
|                 "cpu": 1024,
 | |
|                 "memory": 400,
 | |
|                 "essential": True,
 | |
|                 "environment": [
 | |
|                     {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
 | |
|                 ],
 | |
|                 "logConfiguration": {"logDriver": "json-file"},
 | |
|             }
 | |
|         ],
 | |
|     )
 | |
|     response = client.create_service(
 | |
|         cluster="test_ecs_cluster",
 | |
|         serviceName="test_ecs_service",
 | |
|         taskDefinition="test_ecs_task",
 | |
|         desiredCount=2,
 | |
|         tags=[
 | |
|             {"key": "foo", "value": "bar"},
 | |
|             {"key": "createdBy", "value": "moto-unittest"},
 | |
|             {"key": "hello", "value": "world"},
 | |
|         ],
 | |
|     )
 | |
|     client.untag_resource(
 | |
|         resourceArn=response["service"]["serviceArn"], tagKeys=["foo", "createdBy"]
 | |
|     )
 | |
|     response = client.list_tags_for_resource(
 | |
|         resourceArn=response["service"]["serviceArn"]
 | |
|     )
 | |
|     response["tags"].should.equal([{"key": "hello", "value": "world"}])
 |