Add ECS CloudFormation support (#795)

* Add cloudformation support to AWS::ECS::Cluster

* Add CloudFormation support to AWS::ECS::TaskDefinition

* Add CloudFormation support to AWS::ECS::Service

* Add support to update AWS::ECS::Cluster through CloudFormation

* Fix Cluster.update_from_cloudformation_json to return original_resource if nothing changed

* Implement TaskDefinition.update_from_cloudformation_json

* Implement Service.update_from_cloudformation_json
This commit is contained in:
Hugo Lopes Tavares 2016-12-20 10:37:18 -05:00 committed by Steve Pulec
commit 0115267f2a
3 changed files with 366 additions and 2 deletions

View file

@ -1,10 +1,14 @@
from __future__ import unicode_literals
from copy import deepcopy
import boto3
import sure # noqa
import json
from moto.ec2 import utils as ec2_utils
from uuid import UUID
from moto import mock_cloudformation
from moto import mock_ecs
from moto import mock_ec2
@ -918,3 +922,254 @@ def test_stop_task():
stop_response['task']['lastStatus'].should.equal('STOPPED')
stop_response['task']['desiredStatus'].should.equal('STOPPED')
stop_response['task']['stoppedReason'].should.equal('moto testing')
@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)
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')
cfn_conn.create_stack(
StackName="test_stack",
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)
@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)