AWS ECS - Unable to specify service name in cloudformation template - amazon-web-services

I am trying to create a AWS - ECS service using cloudformation template
"service": {
"ServiceName": "XXX",
"Type": "AWS::ECS::Service",
"DependsOn": [
"AutoScalingGroup"
],
"Properties": {
"Cluster": {
"Ref": "ECSCluster"
},
"DesiredCount": "1",
"TaskDefinition": {
"Ref": "taskdefinition"
}
}
},
But I am getting an error.
Failed: Invalid template resource property 'ServiceName'
I had same problem when using Name/serviceName. I can see serviceName is a parameter based on docs. But couldn't figure out why it fails. It works if I don't specify name. But I need to specify name so that I can use the same name in a different system that updates the service.
Could you please help?

This is slightly confusing, but the service name is set by the name of the resource you create. There is no ServiceName or Name property. The following will create an ECS service with the name MyService.
"MyService": {
"Type": "AWS::ECS::Service",
"DependsOn": [
"AutoScalingGroup"
],
"Properties": {
"Cluster": {
"Ref": "ECSCluster"
},
"DesiredCount": "1",
"TaskDefinition": {
"Ref": "taskdefinition"
}
}
}
Obviously if you refer to your service within the CloudFormation template you will also need to update your references.

Related

Use env variables inside cloudformation templates

i have an amplify app with multiple branches.
I have added an custom cloudformation template with amplify add custom
It looks like:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters": { "env": { "Type": "String" } },
"Resources": {
"db": {
"Type": "AWS::Timestream::Database",
"Properties": { "DatabaseName": "dev_db" }
},
"timestreamtable": {
"DependsOn": "db",
"Type": "AWS::Timestream::Table",
"Properties": {
"DatabaseName": "dev_db",
"TableName": "avg_16_4h",
"MagneticStoreWriteProperties": { "EnableMagneticStoreWrites": true },
"RetentionProperties": {
"MemoryStoreRetentionPeriodInHours": "8640",
"MagneticStoreRetentionPeriodInDays": "1825"
}
}
}
},
"Outputs": {},
"Description": "{\"createdOn\":\"Windows\",\"createdBy\":\"Amplify\",\"createdWith\":\"8.3.1\",\"stackType\":\"custom-customCloudformation\",\"metadata\":{}}"
}
You can see there is a field called DatabaseName. In my amplify app i have written an env variable named TIMESTREAM_DB and i want to use it inside of this cloudformation file.
Is this possible or do i need to write it all by hand in it?
Templates cannot access arbitrary env vars. Instead, CloudFormation injects deploy-time values into a template with Parameters.
Amplify helpfully adds the env variable as a parameter. A la the Amplify docs, use the env value as the AWS::Timestream::Database name suffix:
"DatabaseName": "Fn::Join": [ "", [ "my-timestream-db-name-", { "Ref": "env" } ] ]
The AWS::Timestream::Table resource also requires a DatabaseName parameter. You could repeat the above, but it's more DRY to get the name via the Database's Ref:
"DatabaseName": { "Ref" : "db" }

How can I instruct an AWS CloudFormation template to create resources in a specific region?

I am new to CloudFormation templates. I have basic template in yaml that creates an EC2 Instance. Every time I create a stack and use this template, the EC2 Instance is ALWAYS created on US East N. Virginia region. I am trying to change this so that the EC2 Instance resides in US-WEST-2 region. After some research, it appears that this is something that is not specified within the template. Instead, I need to change the region to us-west-2 in AWS console and then create a new stack. Is my understanding correct?
Unfortunately, you can't specify the region in a cloudformation template.
You should either pass region as a command line argument
aws --region eu-west-1 cloudformation create-stack --stack-name ...
or, specify the default region in aws cli config file ~/.aws/config
[default]
region=eu-west-1
What am I missing here? I am sure we can specify region where the stack is created in CFN template using parameters and we do have active templates which creates our stack in respective region based on the parameter value.
The AWS::Region pseudo parameter is a value that AWS CloudFormation resolves as the region where the stack is created.
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/gettingstarted.templatebasics.html
Here is a sub-section of sample template
{
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters": {
"InstanceType": {
"Description": "Instance Type",
"Type": "String",
"Default": "t2.xlarge"
},
"SubnetUSEAST1": {
"Description": "Subnet on which Ec2 instance needs to be created",
"Type": "String",
"Default": "subnet-xxxxxxxx"
},
"SubnetUSWEST2": {
"Description": "Subnet on which Ec2 instance needs to be created",
"Type": "String",
"Default": "subnet-yyyyyyyy"
}
},
"Conditions": {
"useast1": {
"Fn::Equals": [
{
"Ref": "AWS::Region"
},
"us-east-1"
]
},
"uswest2": {
"Fn::Equals": [
{
"Ref": "AWS::Region"
},
"us-west-2"
]
}
},
"Resources": {
"EC2Instance": {
"Type": "AWS::EC2::Instance",
"Properties": {
"InstanceType": {
"Ref": "InstanceType"
},
"NetworkInterfaces": [
{
"SubnetId": {
"Fn::If": [
"useast1",
{
"Ref": "SubnetUSEAST1"
},
{
"Ref": "SubnetUSWEST2"
}
]
},
"AssociatePublicIpAddress": "false",
"DeviceIndex": "0"
}
]
}
}
}
}
If you are able to split your template into parts, you could deploy to different regions at once via some orchestration and StackSets.

Security Group not accepting in CloudFormation Template

I am trying to pass the SecurityGroup name as parameter in CloudFormation Template.While creating stack its providing me dropdown list of all security group and i am providing one but its failing with below error
"Parameter validation failed: parameter value launch-wizard-1 for parameter name SecurityGroup does not exist. Rollback requested by user."
{
"Description": "Create an EC2 instance running the latest amazon Linux AMI.",
"Parameters": {
"KeyPair": {
"Description": "The EC2 key Pair to allow SSH access to the instance",
"Type": "String"
},
"SecurityGroup": {
"Description": "Name of security group",
"Type": "AWS::EC2::SecurityGroup::GroupName"
}
},
"Resources": {
"EC2Instance": {
"Properties": {
"ImageId": "ami-0080e4c5bc078760e",
"InstanceType": "t2.micro",
"KeyName": {
"Ref": "KeyPair"
},
"SecurityGroups" : [ {"Ref" : "SecurityGroup"} ]
},
"Type": "AWS::EC2::Instance"
}
},
"Outputs": {
"InstanceId": {
"Description": "The InstanceId of newly created EC2 instance",
"Value": {
"Ref": "EC2Instance"
}
}
},
"AWSTemplateFormatVersion": "2010-09-09"
}
I tested your template (replacing the AMI and using my own Security Group name) and it worked fine.
It is possible that the instance is being launched in a different VPC to the Security Group.

Developing an app to create a stack from a cloudformation template

I am new to AWS and am currently working on simple tasks.
I have created a free tier EC2 instance using a cloudformation template. Now my next task is to write a simple application that uses respective AWS SDK to call CloudFormation API to create a stack from the template.
Here is the cloudformation template:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Ec2 Template",
"Metadata": {
"Copyright":[
"Copyright 2017, All rights reserved"
],
"Comments":[
"Create an EC2"
]
},
"Parameters": {
"KeyName": {
"Type": "AWS::EC2::KeyPair::KeyName",
"Description": "Name of an existing EC2 KeyPair to enable access to join ECS instances."
},
"InstanceTypeParameter":{
"Type": "String",
"Default": "t2.micro",
"AllowedValues": [
"t2.micro",
"m1.small",
"m1.large"
],
"Description": "Enter t2.micro, m1.small, or m1.large. Default is t2.micro."
},
"EcsSecurityGroupLb":{
"Type": "AWS::EC2::SecurityGroup::Id",
"Description":"The ECS ELB Security Group."
},
"vpcid":{
"Type": "AWS::EC2::VPC::Id"
},
"mySubnetIDs": {
"Description":"Subnet IDs",
"Type":"AWS::EC2::Subnet::Id"
}
},
"Resources":{
"Ec2Instance":{
"Type":"AWS::EC2::Instance",
"Properties":{
"ImageId": "ami-bf4193c7",
"KeyName": {
"Ref": "KeyName"
},
"InstanceType":{
"Ref": "InstanceTypeParameter"
},
"NetworkInterfaces":[
{
"AssociatePublicIpAddress":"true",
"DeviceIndex":"0",
"SubnetId":{
"Ref":"mySubnetIDs"
},
"GroupSet":[
{
"Ref": "EcsSecurityGroupLb"
}
]
}
],
"BlockDeviceMappings":[
{
"DeviceName": "/dev/sdc",
"VirtualName":"ephemeral0"
}
]
}
}
},
"Outputs":{
"Ec2Instance":{
"Description": "InstanceId of newly created EC2 instance",
"Value": {
"Ref": "Ec2Instance"
}
},
"InstanceIPAddress":{
"Value":{ "Fn::GetAtt": ["Ec2Instance", "PublicIp"]},
"Description": "Public IP address of instance"
}
}
}
I have gone through a lot of documentation but haven't really understood as to how to proceed. I would like to know if there are any good tutorials on this.
Looking for suggestions with respect to the steps as well.
Thanks!
Since you have to (as a task requirement) write the application yourself, you'll need to use one of the AWS SDKs that are available.
The SDK you choose will depend on what programming language you are most comfortable using (or required by your task).
Roughly, your program will need to do the following:
With the AWS SDK, create an AWS session which uses your IAM user's API keys.
Grab the Cloudformation template off of your local system.
With the AWS SDK, invoke Cloudformation to create the resource stack with your template.
(Optionally) Wait until the stack is complete and output a report on the stack status.
Good luck!

Howto specify 'Raw Message Delivery' for an SNS subscription using AWS CloudFormation?

I've got an AWS CloudFormation template that creates an SNS topic and a subscription:
"AcceptedTopic":{
"Type": "AWS::SNS::Topic",
"Properties": {
"DisplayName": {"Fn::Join": ["", ["Accepted-", {"Ref": "Env"}]]},
"TopicName": {"Fn::Join": ["", ["Accepted-", {"Ref": "Env"}]]},
"Subscription": [{
"Endpoint": {"Fn::GetAtt" : [ "SomeQueue" , "Arn" ]},
"Protocol": "sqs"
}]
}
}
I need to specify the 'Raw Message Delivery' subscription attribute. How can I do that in AWS CloudFormation?
As of this writing, AWS CloudFormation doesn't support that natively. As an alternate, you can create a Lambda-backed custom resource to get around this limitation and set that attribute using set-subscription-attributes instead. Here are some helpful resources to help accomplish that:
Lambda-backed custom resources
SNS' set-subscription-attributes API
Now AWS CloudFormation supports it with AWS::SNS::Subscription. So instead of adding the subscription as a property of the topic, add an Subscription resource linked above.
A caveat though, is that if you already created a topic with that subscription and are now trying to add the attribute, it'd fail miserably with Invalid Parameter error. The cause is it's considering the standalone Subscription added in the template as a new resource and trying to create it. I haven't found a good way around this other than deleting that subscription manually, which is not good practice in production environment.
My solution around this is separating it into 2 steps. First, remove the property subscription from the topic and add a Subscription resource. Then, add new attributes to the subscription resource.
First:
{
"AcceptedTopic": {
"Type": "AWS::SNS::Topic",
"Properties": {
"DisplayName": {
"Fn::Join": ["", ["Accepted-", {"Ref": "Env"}]]
},
"TopicName": {
"Fn::Join": ["", ["Accepted-", {"Ref": "Env"}]]
}
}
}
"AcceptedTopicSubscription": {
"TopicArn": { "Ref": "AcceptedTopic" },
"Endpoint": {
"Fn::GetAtt": ["SomeQueue", "Arn"]
},
"Protocol": "Sqs"
}
}
Then:
{
...
"AcceptedTopicSubscription": {
"TopicArn": { "Ref": "AcceptedTopic" },
"Endpoint": {
"Fn::GetAtt": ["SomeQueue", "Arn"]
},
"Protocol": "Sqs",
"RawMessageDelivery": "true"
}
}