How to refer a derived variable in CloudFormation? - amazon-web-services

I am looking for small help in CloudFormation and could not find help from documentation or may be not searching the question in right way.
Here is the question.
I am getting availability zones for the environment from mappings as follows.
"AvailabilityZone": {
"Fn::Select": [
"1",
{
"Fn::FindInMap": [
"Environment",
{
"Ref": "EnvType"
},
"AvailabilityZones"
]
}
]
}
I need to use the AZ name in my volume naming convention. How could refer the derived variable "AvailabilityZone" again.?
Currently i am doing this.
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "NamePrefix"
},
{
"Ref": "EnvType"
},
"myconstant",
{
"Fn::Select": [
"2",
{
"Fn::Split": [
"-",
{
"Fn::Select": [
"1",
{
"Fn::FindInMap": [
"Environment",
{
"Ref": "EnvType"
},
"AvailabilityZones"
]
}
]
}
]
}
]
}
]
]
}
}
I am doing the same code twice.
How can i re-use the derived variable here.?

Unfortunately, the short answer is you can't. Hopefully someday AWS supports variables in CloudFormation.
There are some hacks that might be of interest. Emphasis on hack!
Use a CloudFormation pre-processor that does what you want (eg, Troposphere)
Use a Custom Resource that outputs the value, then use GetAtt to refer to the value. (http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html)
Use the AWS::Include transform to refer to a template snippet in S3 (http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/create-reusable-transform-function-snippets-and-add-to-your-template-with-aws-include-transform.html), in that case you're not really using variables, off course.

Related

Pass parameters to AWS Cloudwatch event target lambda function

I want to pass parameters to my lambda function invoked by AWS Cloudwatch events. The parameter name is alarmActions and my CFT template for the event rule is as follows:
"LambdaInvokeScheduler": {
"Type": "AWS::Events::Rule",
"Properties": {
"Description": "Scheduled Rule for invoking lambda function",
"EventPattern": {
"source": [
"aws.ecs"
],
"detail-type": [
"ECS Container Instance State Change"
],
"detail": {
"clusterArn": [
{ "Fn::GetAtt": ["WindowsCluster", "Arn"] }
]
}
},
"State": "ENABLED",
"Targets": [{
"Arn": { "Fn::GetAtt": ["AlarmCreationLambdaFunction", "Arn"] },
"Id": "AlarmCreationLambdaFunction",
"Input": { "Fn::Join" : ["", [ "{ \"alarmActions\": \"", { "Fn::Join" : [":", [ "arn:aws:sns", { "Ref" : "AWS::Region" }, { "Ref" : "AWS::AccountId" }, "CloudWatch"]] }, "\" }"]] }
}]
}
}
I have used the Input parameter to pass a JSON text. There is not much documentation around it. I just wanted to find the right way to do it.
I found the solution. I was referring the parameter in lambda in a wrong way.
My lambda function was like this:
def func(event, context, alarmActions)
{
print(alarmActions)
}
It worked when i made the following update:
def func(event, context)
{
print(event['alarmActions'])
}

Value of property VPCZoneIdentifier must be of type List of String

"wordpressASG": {
"Type": "AWS::AutoScaling::AutoScalingGroup",
"Properties": {
"AvailabilityZones": [
"ap-southeast-2a",
"ap-southeast-2b"
],
"VPCZoneIdentifier": [
{
"ref": "subnetA"
},
{
"ref": "subnetB"
}
],
"MinSize": "0",
"HealthCheckGracePeriod": 300,
"MaxSize": "0",
"Cooldown": "300",
"LaunchTemplate": {
"LaunchTemplateId": {
"Ref": "wordpressTemplate"
},
"Version": {
"Fn::GetAtt": [
"wordpressTemplate",
"LatestVersionNumber"
]
}
},
"MetricsCollection": [
{
"Granularity": "1Minute",
"Metrics": [
"GroupMinSize",
"GroupMaxSize"
]
}
],
"TargetGroupARNs": [
{
"Ref": "wordpressTG"
}
]
}
}
Probably not a new question, but all examples are of using a subnet parameter. List needs to be string, but ref Should give strings for this thing. The Subnets are being created in the same script.
Based on the comments.
The issue was the use ref instead of Ref when listing subsets in VPCZoneIdentifier.
To be honest for your parameter use List<AWS::EC2::Subnet::Id> and then just use the value of that rather than trying to use individual subnets in your list.
More parameters: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html
In YAML format
VPCZoneIdentifier: !Split [',', !Ref Subnets]
Define Subnets as a String parameter and pass in like:
ParameterKey=Subnets,ParameterValue=\"subnet-0d...d5,subnet-01...03\"

Error defining ALB with 2 subnets in differents AZ

I'm designing a cloudformation to deploy ALB and i got an error that says:
At least two subnets in two different Availability Zones must be specified (Service: AmazonElasticLoadBalancingV2; Status Code: 400; Error Code: ValidationError;
These network was created by other Cloudformation. And now, i go to VPC / SUbnets and i see both created.
The part of code where im defining the subnets in ELB creation is this:
"Subnets": [
{
"Fn::ImportValue": {
"Fn::Join": [
"-",
[
{
"Ref": "ParentSubnetStackName"
},
"PublicSubnet1ID"
]
]
},
"Fn::ImportValue": {
"Fn::Join": [
"-",
[
{
"Ref": "ParentSubnetStackName"
},
"PrivateSubnet2ID"
]
]
}
}
],
The only thing that i think that could be a problem is than im importing by other stack than i dont executing at the same time of this cloudformation.. I don't know if there could be a problem, because the Subnets are created at this moment for sure and they belong to differents AZ.
EDIT:
#jogold The CF is too long. I attach here a piece of the code
"PublicSubnet1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Fn::ImportValue": {
"Fn::Join": [
"-",
[
{
"Ref": "ParentStackName"
},
"VPCID"
]
]
}
},
"CidrBlock": {
"Ref": "PublicSubnet1CIDR"
},
"AvailabilityZone": {
"Ref": "AZ1"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"PublicSubnet1"
]
]
}
}
]
}
And after in the outputs i export it:
"PublicSubnet1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Fn::ImportValue": {
"Fn::Join": [
"-",
[
{
"Ref": "ParentStackName"
},
"VPCID"
]
]
}
},
"CidrBlock": {
"Ref": "PublicSubnet1CIDR"
},
"AvailabilityZone": {
"Ref": "AZ1"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"PublicSubnet1"
]
]
}
}
]
}
All the subnets are created bye the same way.

How we can create Geolocation through AWS:cloudfromation template?

I have implemented this but it says invalid request. It may totally wrong.
I want to create geolocation for particular country
"Geolocation": {
"Type": "AWS::Route53::RecordSet",
"Properties": {
"HostedZoneName": {
"Ref": "Route53Domain"
},
"Name": {
"Fn::Join": [
"$",
[
{
"Ref": "javadns"
},
{
"Ref": "Route53Domain"
}
]
]
},
"Type": "CNAME",
"TTL": "60",
"GeoLocation": {"CountryCode" : "*"},
"ResourceRecords": [
{ "Fn::Join" : [".", ["geoip", { "Ref" : "javadns" }]]}
]
}
},
To create a Geo Location record you must specify the SetIdentifier property in CloudFormation.
i see you are missing that property in your CloudFormation and probably that is why it is throwing you an error.
Also here are the code countries identifiers that are supported by Route53, you must not specify the wildcard in that parameter, countries and continent codes consist of two letters.
Documentation here.

Elasticache replication group id in CloudFormation template

How do you set the Redis ReplicationGroup ID when using a CloudFormation template? All the options in the docs show no way to do that and the CLI you can do this easily. My end goal is to have a Redis replication group with 3 cluster members but I want to choose the name rather than AWS set a unique name for me.
Here's a snippet of my template:
"Resources": {
"mqpReplicationGroup": {
"Type": "AWS::ElastiCache::ReplicationGroup",
"Properties": {
"CacheNodeType": {
"Ref": "CacheNodeType"
},
"CacheSubnetGroupName": {
"Ref": "CacheSubnets"
},
"ReplicationGroupDescription": "Redis Replication Group",
"Engine": "redis",
"EngineVersion": {
"Ref": "RedisVersion"
},
"NumCacheClusters": {
"Ref": "NumberOfCacheNodes"
},
"AutoMinorVersionUpgrade": "true",
"AutomaticFailoverEnabled": "true",
"PreferredMaintenanceWindow": "sat:09:25-sat:22:30",
"SnapshotRetentionLimit": "4",
"SnapshotWindow": "00:05-05:30",
"NotificationTopicArn": {
"Fn::Join" :[":",["arn:aws:sns",{ "Ref" : "AWS::Region" },{ "Ref" : "AWS::AccountId" },"service-aws"]]
},
"SecurityGroupIds": [
{
"Fn::Join": [
",",
{
"Ref": "VpcSecurityGroupIds"
}
]
}
]
}
},
"CacheSubnets": {
"Type": "AWS::ElastiCache::SubnetGroup",
"Properties": {
"Description": "mqp-cache-subnet",
"SubnetIds": {
"Ref": "SubnetIds"
}
}
}
}
As of 2017, this is now possible using ReplicationGroupId property.
Since it is optional, AWS CloudFormation will still generate an unique physical ID when not specified.
Restrictions for Name Type:
Must contain from 1 to 20 alphanumeric characters or hyphens.
First character must be a letter.
Cannot end with a hyphen or contain two consecutive hyphens.
This cannot currently be done with CloudFormation.