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.
Related
I have the following parameter in my CloudFormation script:
CloudFormationURL:
Type: String
Description: S3 URL for nested CloudFormation templates
Default: ""
This parameter covers the CloudFormation scripts in a nested folder of my deployment config.
I use it with a resource like this:
CloudWatchDashboardStack:
Type: "AWS::CloudFormation::Stack"
Properties:
TemplateURL: !Sub "${CloudFormationURL}/cloudwatch-dashboard.cfn.yaml"
Parameters:
AppName: !Ref AppName
DeployPhase: !Ref DeployPhase
DeveloperPrefix: !Ref DeveloperPrefix
Environment: !Ref Environment
Which works fine, and has worked for months.
I needed to add another resource, so I added this:
BatchDNSResources:
Type: "AWS::CloudFormation::Stack"
Properties:
Parameters:
AppName: !Ref AppName
Environment: !Ref Environment
DeveloperPrefix: !Ref DeveloperPrefix
DeployPhase: !Ref DeployPhase
AppVersion: !Ref AppVersion
SharedBucketName: !Ref SharedBucketName
S3Version: !Ref S3Version
HostedZone: !Ref HostedZone
VPCStackName: !FindInMap
- EnvironmentMap
- !Ref Environment
- VpcStackName
Company: !Ref Company
CostCenter: !Ref CostCenter
Team: !Ref Team
TemplateURL: !Sub "${CloudFormationURL}/batch-dns.cfn.yaml"
CloudFormation throws this error and then fails:
Parameters: [CloudFormationURL] must have values
Checking the changeset for the stack I can see the following value for the CloudFormationURL:
s3://application-shared-dev/application-name/qa/cf/nested/KShyDj205UK8mz6W_XUA5TnEF8nqPWHS
Checking the application predeploy logs I can see:
upload: deploy/cloudformation/templates/nested/batch-dns.cfn.yaml to s3://application-shared-dev/application-name/qa/cf/nested/KShyDj205UK8mz6W_XUA5TnEF8nqPWHS/batch-dns.cfn.yaml
And I can see the file in the S3 bucket.
If I remove BatchDNSResource the stack completes successfully.
What the heck am I missing here?
Sometimes, the smallest things will get you.
I had copied the Parameters from the master CloudFormation script, including this one, into the nested script:
CloudFormationURL:
Type: String
Description: S3 URL for nested CloudFormation templates
Default: ""
If you look closely, you will see that I did not pass the parameter into the nested script when calling the resource:
BatchDNSResources:
Type: "AWS::CloudFormation::Stack"
Properties:
Parameters:
AppName: !Ref AppName
Environment: !Ref Environment
DeveloperPrefix: !Ref DeveloperPrefix
DeployPhase: !Ref DeployPhase
AppVersion: !Ref AppVersion
SharedBucketName: !Ref SharedBucketName
S3Version: !Ref S3Version
HostedZone: !Ref HostedZone
VPCStackName: !FindInMap
- EnvironmentMap
- !Ref Environment
- VpcStackName
Company: !Ref Company
CostCenter: !Ref CostCenter
Team: !Ref Team
TemplateURL: !Sub "${CloudFormationURL}/batch-dns.cfn.yaml"
Because the CloudFormation console was saying the issue was with the BatchDNSResources I kept looking at the master script for the problem and missing the reference in the other script. There are two ways to solve this problem:
Keep CloudFormationURL as a parameter in the nested script (if you need it for some reason) and pass the value from the master script.
Remove the parameter from the nested script (if it is not needed)
Sometimes just asking for an extra set of eyeballs and getting a little rest will help you to find the issues. I want to leave this question/answer in place here because when I was searching for the error here and elsewhere no one ever mentioned (probably out of embarrassment) that the mistake is simply overlooking something like this. I hope this answer prompts others to check everything when they run across this type of error.
I am using aws-cli to deploy my stack across several environments and need to parametrize the subnets / security groups available to my stack.
I have a section in my SAM template defining the subnets and security groups as such:
EnvSubnets:
Description: Define subnet ids
Type: 'List<AWS::EC2::Subnet::Id>'
EnvSecGroups:
Description: Security Groups
Type: 'List<AWS::EC2::SecurityGroup::Id>'
I specify the arguments using `aws cloudformation deploy ... --parameter-overrides file://env.json' but cannot find a single format that passes the arrays to cloudformation.
I keep getting the followign errors:
#/VpcConfig/SecurityGroupIds: expected type: JSONArray, found: String #/VpcConfig/SubnetIds: expected type: JSONArray, found: String
Any hints?
It seems that at the current time this is not supported - I ended-up using a nested template driven by a user-overridable parameter:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: 'SAM Template for XXXXX XXXXX'
Parameters:
LambdaRole:
Description: Define exiting Lambda role to provide permissions
Type: String
LambdaImage:
Description: Define Lambda image URI
Type: String
LambdaVPCInclude:
Description: S3 URI of the YAML for the S3 VPC section
Type: String
Resources:
FOO:
Type: AWS::Serverless::Function
Properties:
PackageType: Image
ImageUri: !Ref LambdaImage
Architectures:
- x86_64
MemorySize: 1024
Timeout: 900
Role: !Ref LambdaRole
'Fn::Transform':
Name: 'AWS::Include'
Parameters:
Location: !Ref LambdaVPCInclude
Metadata:
SamResourceId: FOO
Outputs:
QuantUniverse:
Description: FOO Lambda Function ARN
Value: !GetAtt FOO.Arn
and in an S3 bucket I have a file with my VPC config:
VpcConfig:
SubnetIds:
- subnet-*****************
- subnet-*****************
- subnet-*****************
SecurityGroupIds:
- sg-*****************
- sg-*****************
and pass the S3 URI of this file as the override for LambdaVPCInclude in aws cloudformation deploy
Hope this helps others.
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.
I have AWS SAM template, part of which looks like this:
# .......
InternalApiKey:
Type: AWS::ApiGateway::ApiKey
Properties:
Enabled: true
Name: !Sub internal_api_key_${Env}
Value: !Ref InternalApiKeyValue
StageKeys:
- RestApiId: !Ref ServerlessRestApi
StageName: Prod
InternalUsagePlan:
Type: AWS::ApiGateway::UsagePlan
Properties:
ApiStages:
- ApiId: !Ref ServerlessRestApi
Stage: Prod
InternalUsagePlanKey:
Type: AWS::ApiGateway::UsagePlanKey
Properties:
KeyId: !Ref InternalApiKey
KeyType: API_KEY
UsagePlanId: !Ref InternalUsagePlan
#......
Deploying this template as two distinct application (CloudFormation stack) with sam deploy --stack-name=stack-a and sam deploy --stack-name=stack-b fails with the following error even when api key names are different:
API Key already exists (Service: AmazonApiGateway; Status Code: 409; Error Code: ConflictException; Request ID:
redacted; Proxy:
null)
How can I deploy two stacks from this template?
A different key value and your problem will go away. So if you are setting the api key value yourself ensure they are unique. Not sure why that's a constraint between different stages.
Do you really have to provide a value for your key? It's an optional parameter. You can remove it from your template and AWS will generate a unique key for you in each deployment.
I am new to AWS Cloudformation world. I am trying to create an elasticbeanstalk configuration template. For it's one of the setting, I need to use two security groups. So, I have given it as following
MyConfigurationTemplate:
Type: AWS::ElasticBeanstalk::ConfigurationTemplate
Properties:
Properties:
ApplicationName: MyApplication
Description: A default Application
SolutionStackName: SolutionStack
OptionSettings:
....
....
- Namespace: aws:autoscaling:launchconfiguration
OptionName: SecurityGroups
Value:
!If
- ConditionIsTrue
- [!Ref FirstGroup, !ImportValue SecondGroup]
- !Ref FirstGroup
....
....
I read from AWS docs here, that SecurityGroups is a list and we can provide comma seprated list. But it is not working for me. AWS throws following error
Value of property Value must be of type String
I tried giving value of security groups in following ways but none of them worked.
1) "!Ref FirstGroup, !ImportValue SecondGroup"
2) !Ref FirstGroup, !ImportValue SecondGroup
Any idea how this list of security groups should be provided?
I got it myself with some trial and error. As it accepts comma separated list. We need to use !join as follows.
MyConfigurationTemplate:
Type: AWS::ElasticBeanstalk::ConfigurationTemplate
Properties:
ApplicationName: MyApplication
Description: A default Application
SolutionStackName: SolutionStack
OptionSettings:
....
....
- Namespace: aws:autoscaling:launchconfiguration
OptionName: SecurityGroups
Value:
!If
- ConditionIsTrue
- !Join [',', [!Ref FirstGroup, !ImportValue SecondGroup]]
- !Ref FirstGroup
....
....