from __future__ import unicode_literals 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'} } ] ) 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') @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')