So what I am trying to do is, I defined a Parameter called EnvType with allowed values test or production.
What should happen is when the user selects one of these environments test or production, lets say test
then he should be able to select another parameter called InstanceType in which allowed values would be all the 't' type instances in the drop-down list while creating the stack.
If the user selects production as the EnvType then the allowed values under the same parameter called InstanceType must be all instances types except 't' type for eg ('m' type).
And the same must apply for rds as well. Let's say user chooses EnvType as test then allowed values under parameter called DBInstanceType must be 'db.t' type instances otherwise 'db.r' type instances.
Parameters
Parameters:
EnvType:
Default: test
Type: String
AllowedValues:
- production
- test
InstanceType:
Type: String
AllowedValues: !FindInMap
- InstanceTypeMap
- !Ref EnvType
- instanceType
DBInstanceType:
Type: String
AllowedValues: !FindInMap
- InstanceTypeMap
- !Ref EnvType
- dbinstanceType
Mapping
InstanceTypeMap:
production:
instanceType: [m1.small, m1.medium, m1.large, m1.xlarge, m2.xlarge, m2.2xlarge, m2.4xlarge]
dbinstancetype: [db.r5.large, db.r5.xlarge]
test:
instanceType: [t1.micro, t2.nano, t2.micro, t2.small, t2.medium, t2.large]
dbinstancetype: [db.t2.small, db.t2.medium, db.t3.small]
Resources
Resources:
WebServer:
Type: 'AWS::EC2::Instance'
Properties:
InstanceType: !Ref InstanceType
DBInstance:
Type: AWS::RDS::DBInstance
Properties:
DBInstanceClass: !FindInMap
- MyEnvironmentMap
- !Ref EnvType
- dbinstanceType
Well i know the template is not valid, and is prone to errors in allowed values in InstanceType and DBInstanceType parameters but i am seeking an alternative of doing this.
Please help!!
Simply, such functionality is not possible in CloudFormation (CFN). Sadly, there is no alternative in CFN for that. You would have to develop a custom solution for deployment of such templates.
Related
I'm trying to select an AMI dynamically based on the Instance Family. The instance family being determined from the first few letters (before the period) from the InstanceType.
I would think that the following CloudFormation snippet would work. It uses !Select and !Split to find the first few characters of the InstanceType. The Instance Family should be passed as the third argument to FindInMap. However, it fails with the error:
An error occurred (ValidationError) when calling the CreateStack operation: Template error: every Fn::FindInMap object requires three parameters, the map name, map key and the attribute for return value
AWSTemplateFormatVersion: 2010-09-09
Description: my new server
Parameters:
InstanceType:
Description: Instance Type
Type: String
AllowedValues:
- t2.micro
- t3a.small
- t3a.medium
- t4g.micro
- t4g.small
- t4g.medium
Mappings:
AmiMap:
us-east-1:
## AMD64 Instances
t2: ami-0f65ab0fd913bc7be
t3a: ami-0f65ab0fd913bc7be
## Graviton (ARM) Instances
t4g: ami-0cf2a935e8b19b29b
Resources:
LaunchConfig:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
...
ImageId: !FindInMap
- AmiMap
- "us-east-1"
- !Select [0, !Split [".", !Ref InstanceType ]]
Why isn't the !Select ... !Split line returning a string for FindInMap to recognize?
As recognized by #Paolo and #Marcin, !Select can't be used inside a !FindInMap. The full instance type (ie: t4g.small) can't be used as keys inside the Mappings section either, since they contain non alpha-numeric characters.
I feel like this is a better solution, rather than trying to split the instance type (t4g.small) to find the Instance Family, it constructs the InstanceType from an InstanceFamily + InstanceSize. That way, we can use the InstanceFamily inside the Mappings.
AWSTemplateFormatVersion: 2010-09-09
Description: My Server
Parameters:
InstanceFamily:
Description: "Instance Family ie: t4g, t3a, m5)"
Type: String
AllowedValues:
- t2
- t3
- t3a
- t4g
InstanceSize:
Description: "Instance Size (micro, small, medium, large)"
Type: String
AllowedValues:
- micro
- small
- medium
- large
Mappings:
AmiMap:
## Last Updated 2022-07-01
us-east-1:
## AMD64 Instances. Ubuntu 22.04 us-east-1
t2: ami-0f65ab0fd913bc7be
t3: ami-0f65ab0fd913bc7be
t3a: ami-0f65ab0fd913bc7be
## Graviton (ARM) Instances Ubuntu 22.04 us-east-1
t4g: ami-0cf2a935e8b19b29b
Resources:
LaunchConfig:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
AssociatePublicIpAddress: true
BlockDeviceMappings:
...
ImageId: !FindInMap
- AmiMap
- "us-east-1"
- !Ref InstanceFamily
InstanceType: !Join ['.', [!Ref InstanceFamily, !Ref InstanceSize]]
InstanceMonitoring: false
...
I'm trying to add a parameter in my cloud formation stack that will allow the users to choose between on-demand and spot instances for the launch template, which will initiate the EC2 creation. This stack is designed to launch a workstation for a single user.
Currently there only seems to be one value available for the InstanceMarketType Parameter, does anyone know an alternative way of choosing the instance market type?
InstanceMarketTypeParameter:
Type: String
Default: spot
AllowedValues:
- spot
- on-demand
Description: Choose between on-demand and spot instances.
The launch template would look something like this
Ec2LaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: LinuxWorkstation
LaunchTemplateData:
InstanceMarketOptions:
MarketType:
Ref: InstanceMarketTypeParameter
Any ideas are welcome!
You can make InstanceMarketOptions optional using If:
Conditions:
IsOnDemand:
!Equals [!Ref InstanceMarketTypeParameter, "on-demand"]
Resources:
Ec2LaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: LinuxWorkstation
LaunchTemplateData:
InstanceMarketOptions:
!If
- IsOnDemand
- !Ref "AWS::NoValue"
- MarketType:
Ref: InstanceMarketTypeParameter
I am writing a cloudformation template and have a parameter to take in a set of configuration values for AWS resources. One of the value is None as specified on the AWS documentation. However when I input null into the cloudformation, the stack fails with:
Template validation error: [/Parameters/.../AllowedValues/1] 'null' values are not allowed in templates.
For example setting one of the many configurations for elastic beanstalk which defaults to None:
Parameters:
EC2KeyPairName:
Description: EC2 key pair name for SSH access
Type: AWS::EC2::KeyPair::KeyName
Default: null
Resources:
Type: AWS::ElasticBeanstalk::ConfigurationTemplate
Properties:
ApplicationName: !Ref Application
SolutionStackName: !FindInMap [ StackMap, !Ref StackType, stackName ]
OptionSettings:
- Namespace: aws:autoscaling:launchconfiguration
OptionName: EC2KeyName
Value: !Ref EC2KeyPairName
How do I use the None value as one of the options for the parameter?
This is documented as Pseudo parameters on AWS.
Using AWS::NoValue sets the None value for the cloudformation templates.
This is part of the cloudformation template I am writing and getting errors using the Fn::FindInMap function:
Parameters:
VpcStackName:
Description: >-
Name of an active CloudFormation VPC stack that contains the networking
resources, such as the subnet and security group, that will be used in
this stack.
Type: String
MinLength: 1
MaxLength: 255
AllowedPattern: '^[a-zA-Z][-a-zA-Z0-9]*$'
Default: wordpress-dev-vpc
Mappings:
Instance:
development:
AllocatedStorage: 20
DBInstanceClass: db.t2.micro
production:
AllocatedStorage: 25
DBInstanceClass: db.m3.medium
Resources:
DBInstance:
Type: AWS::RDS::DBInstance
DeletionPolicy: Snapshot
Properties:
Engine: MariaDB
StorageType: gp2
MasterUsername: !Ref MasterUsername
MasterUserPassword: !Ref MasterUserPassword
AllocatedStorage:
Fn::FindInMap:
- Instance
- Fn::ImportValue:
Fn::Sub: '${VpcStackName}-Environment'
- AllocatedStorage
DBInstanceClass:
Fn::FindInMap:
- Instance
- Fn::ImportValue:
Fn::Sub: '${VpcStackName}-Environment'
- DBInstanceClass
In another stack, I am exporting ${VpcStackName}-Environment like this:
Outputs:
Environment:
Description: Environment type of this stack
Value: !Ref Environment
Export:
Name: !Sub '${AWS::StackName}-Environment'
When trying to use the Fn::FindInMap function, I get this error:
An error occurred (ValidationError) when calling the ValidateTemplate operation: Template error: every Fn::FindInMap object requires three parameters, the map name, map key and the attribute for return value
Any advice?
Based on the documentation at https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-findinmap.html , the supported functions inside a Fn::FindInMap function are Fn::FindInMap and Ref. So is there another way to do it? For example, storing the value of Fn::ImportValue: !Sub '${VpcStackName}-Environment' in a temporary variable?
According to this document, the Fn::FindInMap function is only usable with these:
Fn::FindInMap
Ref
So Fn::ImportValue and Fn::Sub won't be evaluated.
I have a mapping that looks like this:
Mappings:
AccountToParams:
aws-1234567890:
sshSecurityGroup: sg-abcedf12
And I'd like to retrieve my variables by AccountId, but this doesn't get past the "validation" step
SecurityGroups:
- !FindInMap [AccountToParams, !Sub "aws-${AWS::AccountId}", sshSecurityGroup]
Error is
16/08/2017, 16:36:18 - Template contains errors.: Template error:
every Fn::FindInMap object requires three parameters,
the map name, map key and the attribute for return value
The goal is to have some configuration driven by the account (hence environment) this is run under. And I can't seem to use the accountId as the key in the mapping, otherwise AWS isn't happy because it doesn't contain alphanumeric chars
Change the map to:
Mappings:
AccountToParams:
"1234567890":
sshSecurityGroup: sg-abcedf12
and use !Ref instead of !Sub:
SecurityGroupIds:
- !FindInMap [AccountToParams, !Ref "AWS::AccountId", sshSecurityGroup]
Use FN::Join to prepend "aws" string to account ID if that's required further down the stack.
This works
Mappings:
AccountToParams:
"123456789012":
sshSecurityGroup: sg-abcdef12
Resources:
SecurityGroups: !FindInMap
- AccountToParams
- !Ref 'AWS::AccountId'
- sshSecurityGroup