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-1')
    _ = 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-1:012345678910:cluster/test_cluster0')
    response['clusterArns'].should.contain(
        'arn:aws:ecs:us-east-1: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'}
            }
        ],
        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')


@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_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_existant_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')


@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='testTaskDefinition')
    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')
