How to name an Auto Scaling Group in a CloudFormation template? - amazon-web-services

I have a CloudFormation template that creates an auto scaling group (among other things). How can I give the auto scaling group a name in the template?
The AWS docs do not mention anything (http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-group.html), and its possible to do if I create it trough the AWS website. (I need to give a group a name because I need to find this group from another script)
EDIT: I've tried to add a tag called "Name", but it still does not work:
"Resources": {
"MyServerGroup" : {
"Type" : "AWS::AutoScaling::AutoScalingGroup",
"Properties" : {
"AvailabilityZones" : { "Fn::GetAZs" : ""},
"LaunchConfigurationName" : { "Ref" : "LaunchConfig" },
"MinSize" : { "Ref" : "ServerCount" },
"MaxSize" : { "Ref" : "ServerCount" },
"DesiredCapacity" : { "Ref" : "ServerCount" },
"LoadBalancerNames" : [ { "Ref" : "ElasticLoadBalancerName" } ],
"Tags" : [ {
"Key" : "Name",
"Value" : { "Ref" : "ServerName" },
"PropagateAtLaunch" : "true"
} ]
},
"CreationPolicy": {
"ResourceSignal": {
"Count": "2",
"Timeout": "PT5M"
}
}
},
The name column in the AWS console still displays something like "MyStackName-MyServerGroup-345MH3NF34N7E", and in the Tags field I can see the key-value pair for the Name tag that I added.

Although naming the AutoScalingGroup (ASG) doesn't seem to be possible, you can export the name assigned when the ASG is created by the CloudFormation (CF) template by using the following:
Outputs:
AutoScalingGroupName:
Description: "AutoScalingGroup Name"
Export:
Name:
Fn::Sub: ${AWS::StackName}-autoscalinggroupname
Value: { Ref: AutoScalingGroup }
The ASG name can then be used in other CF templates, although this is perhaps not what the OP means by "find this group from another script".

CloudFormation now has a property called: AutoScalingGroupName
Description: "The name of the Auto Scaling group. Minimum length of 1. Maximum length of 255. Must follow the following pattern: [\u0020-\uD7FF\uE000-\uFFFD\uD800\uDC00-\uDBFF\uDFFF\r\n\t]*"
Type: String
Required: No
see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-group.html

Create a tag with for the ASG with the key "Name" (the capital N is important). This will be used for the Name column in the console.
Note that you could find the ASG by searching for a well known tag other than Name from your other script. Tags are a great way to search for resources.

Clearly from the AWS Tagging Auto Scaling Groups and Instances doc, you can not set value of tag prefixed with aws:.
I guess, value you have read from console "MyStackName-MyServerGroup-345MH3NF34N7E" is of tag aws:autoscaling:groupName. So its obvious you can not set Auto Scaling Group Name in CloudFormation Template.
Unfortunately, from my experience, you can not pass tag value in CloudFormation template. But best, you can use AWS SDK to read tag value from launched EC2 instances.

The attribute "AutoscalingGroupName" within AWS::AutoScaling::AutoScalingGroup entity works.
Sample template :
"Autoscaling1"
{
"Type" : "AWS::AutoScaling::AutoScalingGroup",
"Properties" : {
"AutoScalingGroupName" : String,
"AvailabilityZones" : [ String, ... ],
"Cooldown" : String,
"DesiredCapacity" : String,
"HealthCheckGracePeriod" : Integer,
"HealthCheckType" : String,
"InstanceId" : String,
"LaunchConfigurationName" : String,
"LifecycleHookSpecificationList" : [ LifecycleHookSpecification, ... ],
"LoadBalancerNames" : [ String, ... ],
"MaxSize" : String,
"MetricsCollection" : [ MetricsCollection, ... ],
"MinSize" : String,
"NotificationConfigurations" : [ NotificationConfiguration, ... ],
"PlacementGroup" : String,
"Tags" : [ TagProperty, ... ],
"TargetGroupARNs" : [ String, ... ],
"TerminationPolicies" : [ String, ... ],
"VPCZoneIdentifier" : [ String, ... ]
}
}
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-group.html#cfn-autoscaling-autoscalinggroup-autoscalinggroupname

Related

AWS Cloudformation Cross stack ref for Security group - error

I have below 2 stacks
1) Stack 1 - this is network stack, defines vpc, subnets and security group
2) Stack 2 - this stack defines ec2 instance
Network stack exports following
WebServerSG:
Description : "Web Server Security Group"
Value: !GetAtt InstanceSecurityGroup.GroupId
Export:
Name: !Sub ${AWS::StackName}-WebServerSG
The ec2 instance stack accepts a parameter "NetworkStack" and uses the network stack to refer to the security group as follows
"Resources" : {
"WebServerInstance": {
"Type": "AWS::EC2::Instance",
"Properties": {
"ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" },
{ "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } ] },
"InstanceType" : { "Ref" : "InstanceType" },
"SubnetId" : {"Fn::ImportValue" : {"Fn::Sub" : "${NetworkStack}-SubnetADMZ"}},
"SecurityGroupIds" : {"Fn::ImportValue" : {"Fn::Sub" : "${NetworkStack}-WebServerSG"}},
"KeyName" : { "Ref" : "KeyName" }
}
}
},
The ec2 instance stack fails with the error , "Value of property SecurityGroupIds must be of type List of String"
I tried to use SecurityGroups instead , but received similar error
Even if you want to specify only 1 security group, CloudFormation wants a list. The solution here is to make a list of one element, the element being the imported security group. In your case it will look like this (notice the brackets):
...
"SecurityGroupIds" : [{"Fn::ImportValue" : {"Fn::Sub" : "${NetworkStack}-WebServerSG"}}],
...
Laurent Jalbert Simard answer is correct. Fn:ImportValue should be enclosed in [] to provide imported value as list.

elasticache how to duplicate the configuration group default.redis3.2 in order to change one parameter without writing the 103 unchanged keys

I use AWS elasticache using this parameter group default.redis3.2, as you can see in this cloudformation sample :
"itophubElastiCacheReplicationGroup" : {
"Type" : "AWS::ElastiCache::ReplicationGroup",
"Properties" : {
"ReplicationGroupDescription" : "Hub WebServer redis cache cluster",
"AutomaticFailoverEnabled" : "false",
"AutoMinorVersionUpgrade" : "true",
"CacheNodeType" : "cache.t2.small",
"CacheParameterGroupName" : "default.redis3.2",
"CacheSubnetGroupName" : { "Ref": "cachesubnethubprivatecachesubnetgroup" },
"Engine" : "redis",
"EngineVersion" : "3.2.4",
"NumCacheClusters" : { "Ref" : "ElasticacheRedisNumCacheClusters" },
"PreferredMaintenanceWindow" : "sun:04:00-sun:05:00",
"SecurityGroupIds" : [ { "Fn::GetAtt": ["sgpHubCacheSG", "GroupId"] } ]
}
},
what I want to achieve is to have more than the default 16 databases, to do so, I have to change the key databases in the parameter group. Since default.redis3.2 is read only, I have to create my own, I want to have every parameters but databases identical to default.redis3.2.
It represent 104 parameters, I don't want to copy past each one of them by hand, so :
I'd like to know if there is a way to copy/inherit the parameters of default.redis3.2 created by aws ?
(If possible using cloudformation)
Having no response, I created manually the conf. comparing it to default.redis3.2 every default values was the same, so I ended up changeing only databases.
I created it manually, and then, I've recreated it this way :
"hubElastiCacheParameterGroup" : {
"Type": "AWS::ElastiCache::ParameterGroup",
"Properties": {
"CacheParameterGroupFamily" : "redis3.2",
"Description" : "parameter group to match itop hub needs",
"Properties" : {
"databases": "200"
}
}
},
using it here :
"hubElastiCacheReplicationGroup01" : {
"Type" : "AWS::ElastiCache::ReplicationGroup",
"Properties" : {
[...]
"CacheParameterGroupName" : { "Ref" : "hubElastiCacheParameterGroup" },
[...]
}
},

AWS CloudFormation: How to output a machine's PublicIP?

I wrote a CloudFormation template which creates a linux docker host.
I want to display the PublicIP of the machine under the "Outputs" section.
This is the relevant portion of the template:
"Outputs" : {
"ServerAddress" : {
"Value" : { "Fn::GetAtt" : [ "Server", "PublicDnsName" ] },
"Description" : "Server Domain Name"
},
"SecurityGroup" : {
"Value" : { "Fn::GetAtt" : [ "ServerSecurityGroup", "GroupId" ] },
"Description" : "Server Security Group Id"
},
"PublicIp" : {
"Value" : { "Fn::GetAtt" : [ "ServerPublicIp", "PublicIp" ]},
"Description" : "Server's PublicIp Address"
},
}
I've read in the official AWS documentation about using "Fn::GetAtt" and tried to implement it in my template, but when I try to create the stack I get the following error:
Error
Template validation error: Template error: instance of Fn::GetAtt references undefined resource ServerPublicIp
As far as I understand, the first part in the GetAtt line is a LogicalName (which I can choose?) and the second one is the real attribute as appears on the above link.
So my question is how to display the PublicIP of the server under the Outputs section?
Assuming your have an EC2 instance resource in your template named Server:
"Server" : {
"Type" : "AWS::EC2::Instance",
"Properties" : {
}
}
You output the public IP address referencing it's resource name:
"Outputs" : {
"PublicIp" : {
"Value" : { "Fn::GetAtt" : [ "Server", "PublicIp" ]},
"Description" : "Server's PublicIp Address"
}
}
As mentioned in the docs, the outputs can optionally be exported for cross-stack references. In case that is your use-case:
JSON:
"Outputs" : {
"PublicIp" : {
"Value" : { "Fn::GetAtt" : ["Server", "PublicIp"]},
"Description" : "Server Public IP"
"Export" : {
"Name" : {"Fn::Sub": "${AWS::StackName}-PublicIP"}
}
}
}
YAML:
Outputs:
PublicIp:
Description: Server Public IP
Value: !GetAtt Server.PublicIp
Export:
Name: !Sub "${AWS::StackName}-PublicIp"
See also:
AWS::EC2::Instance properties and return values in the docs.

AWS specific parameters and EC2 SecurityGroupIds List String Error

I have a rather annoying issue which I am unable to resolve and will do my best to explain.
The following cut down example works in which I am able to reference a parameter and assign the security groups to my instance via the SecurityGroupIds property:
"Parameters" : {
"pDefaultSg" : {
"Description" : "AWS2 VPC default security groups",
"Type" : "List<AWS::EC2::SecurityGroup::Id>",
"Default" : "sg-245xxxxx,sg-275xxxxx,sg-235xxxxx"
}
}
"Resources" : {
"ec2Instance" : {
"Type" : "AWS::EC2::Instance",
"Properties" : {
"SecurityGroupIds" : { "Ref" : "pDefaultSg" }
}
}
The issue begins when I also want to add a second value to the SecurityGroupIds property referencing a security group resource instantiated within the same template:
"Resources" : {
"ec2Instance" : { ...
"SecurityGroupIds" : [ { "Ref" : "pDefaultSg" }, { "Fn::GetAtt" : "sgDb", "GroupId" } ],
....
"sgDb" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : { ...
I am then unable to avoid the following error causing the Cloudformation stack to rollback:
Value of property SecurityGroupIds must be of type List of String
I would really appreciate any pointers.
Many Thanks
The issue is that when pDefaultSg is accessed via the Ref intrinsic function it returns a list, therefore your SecurityGroupIds Property looks like
[["sg-245xxxxx","sg-275xxxxx","sg-235xxxxx"],"sg-1234DB"]
The solution is to change your SecurityGroupIds Property to Fn::Join the pDefaultSg List to a comma separated string followed by the sgDb:
"SecurityGroupIds": [
{"Fn::Join":
[",",
{"Ref": "pDefaultSg"}
]
},
{ "Fn::GetAtt" : ["sgDb", "GroupId"] }
]

how to construct a string of physical subnet ids to create db subnet group on the fly in a cloudformation script?

I'm trying to build a CLoudFormation script that launches an instance and a db into a vpc at the same time. the issue is the db requires two AZ's so i create a second subnet and now i just need to reference the two subnet physical ids in a 'MyDBSubnetGroup' var. I can get the logical IDs for the subnets i created but dont know how to ref those physical IDs. ANyone know? THanks!!
Heres my code:
"MyDBSubnetGroup" : {
"Type" : "AWS::RDS::DBSubnetGroup",
"Properties" : {
"DBSubnetGroupDescription" : "Subnets available for the RDS DB Instance",
"SubnetIds" : { "Fn::Join" : [ " ", [{"Ref" : "PublicSubnetAZ1"}, ", ", {"Ref" : "PublicSubnetAZ2"}, " " ]]}
}
},
I run into the same issue, after working with AWS support I understood that List of String does not mean what we initially thought. Also, if you want to place the DB inside a VPC you must not use AWS::RDS::DBSecurityGroup objects.
Here is a full sample, it took me a while to get it working:
"dbSubnetGroup" : {
"Type" : "AWS::RDS::DBSubnetGroup",
"Properties" : {
"DBSubnetGroupDescription" : "Availability Zones for RDS DB",
"SubnetIds" : [ { "Ref" : "subnetPrivate1" },
{ "Ref" : "subnetPrivate2" } ]
}
},
"dbInstance" : {
"Type" : "AWS::RDS::DBInstance",
"Properties" : {
"DBInstanceIdentifier" : { "Fn::Join" : [ "",
[ { "Ref" : "AWS::StackName" },
"DB" ] ] },
"DBName" : "dbname",
"DBSubnetGroupName" : { "Ref" : "dbSubnetGroup" },
"MultiAZ" : "true",
"AllocatedStorage" : "8",
"BackupRetentionPeriod" : "0",
"DBInstanceClass" : "db.m1.medium",
"Engine" : "postgres",
"MasterUserPassword" : "masteruserpassword",
"MasterUsername" : "masterusername",
"VPCSecurityGroups" : [ { "Ref" : "sgVpc" }, { "Ref" : "sgDB" } ]
}
},
If you map the subnet ids you can access them with something like this.
"AWSRegionSubnet":{
"us-east-1":{
"RDSSubnets":[
"subnet-aaaaaaaa",
"subnet-bbbbbbbb"
]
},
"us-west-2":{
"RDSSubnets":[
"subnet-cccccccc",
"subnet-dddddddd"
]
}
}
"RDSSubnet":{
"Type":"AWS::RDS::DBSubnetGroup",
"Properties":{
"DBSubnetGroupDescription":"Some cool notes here",
"SubnetIds":{
"Fn::FindInMap":[
"AWSRegionSubnet",
{
"Ref":"AWS::Region"
},
"RDSSubnets"
]
}
}
}