Running cloudformation template yaml using boto gives validation error - amazon-web-services

I have created a yaml template file. I want to tag a lambda function based on a condition as given in the documentation https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html
Following is my yaml-
AWSTemplateFormatVersion: '2012-10-10'
Description: "Cloud formation template"
Parameters:
tagName:
Type: String
Description: "tag name for the resource"
Default: test
Conditions:
isConditionalTag:
- Fn::Equals:
- Ref: tagName
- "test"
Resources:
TestambdaFunction:
Properties:
Code:
S3Bucket: "abc-test"
S3Key: xyz-RELEASE.jar
Description: Test Lambda function
Environment:
Variables:
DATA_TYPE: "test-data"
FunctionName: TestFunction
Handler: com.test.testLambda::handleRequest
MemorySize: 200
Role: "arn:aws:iam::user:role/general"
Runtime: java8
Timeout: 300
Tags:
- Key: "component"
Value:
Fn::If:
- isConditionalTag
- Ref: tagName
- "newValue"
Type: AWS::Lambda::Function
There are no formatting errors while runnning the template using boto gives validation error as
boto.exception.BotoServerError: BotoServerError: 400 Bad Request
{"Error":{"Code":"ValidationError","Message":"Template format error: Conditions can only be boolean operations on parameters and other conditions","Type":"Sender"},"RequestId":"30250a23-4a66-11e8-a3bd-a14cac12563"}

You won't need to use a Condition to get this done.
Conditions are used to define whether or not a resource is created in Cloudformation.
Based on the documentation,
The optional Conditions section includes statements that define when a
resource is created or when a property is defined. For example, you
can compare whether a value is equal to another value. Based on the
result of that condition, you can conditionally create resources
You should be able to solve this doing something like this (untested):
Parameters:
tagName:
Type: String
Description: "tag name for the resource"
Default: test
Resources:
TestambdaFunction:
Properties:
Code:
S3Bucket: "abc-test"
S3Key: xyz-RELEASE.jar
Description: Test Lambda function
Environment:
Variables:
DATA_TYPE: "test-data"
FunctionName: TestFunction
Handler: com.test.testLambda::handleRequest
MemorySize: 256
Role: "arn:aws:iam::user:role/general"
Runtime: java8
Timeout: 300
Tags:
- Key: "component"
Value: !Ref tagName
Type: AWS::Lambda::Function
Note that Lambda functions need memory in increments of 64MB

Related

Cloudformation YAML custom variable

I am trying to achieve something similar to below in a AWS Cloudformation YAML file:
AWSTemplateFormatVersion: 2010-09-09
testAttribute = "test"
Resources:
Lambda:
Type: AWS::Lambda::Function
Properties:
Runtime: python3.7
Role: !GetAtt iam.Arn
MemorySize: 128
Timeout: 10
Handler: lambda_function.lambda_handler
FunctionName: "testName"+${testAttribute}
Description: 'This is my lambda'
Code:
S3Bucket: myBucket
S3Key: "lambda/testName"+${testAttribute}+".zip"
I know that above isn't quite correct, but I cant find a good answer when searching how to achieve it. Anyone who have some guidance on this matter?
It depends on the use case but if the "variable" would be static and you don't need the change it when deploying the stack, I would suggest an alternative solution, to use the Mappings section.
This allows you to define some static values without sending them when deploying the stack (you will have much cleaner deploy commands, and the logic would be on the template side instead of the deploy side).
In this case, I'm using !Sub intrinsic function with a mapping (you can set multiple variables to be substituted using !Sub):
AWSTemplateFormatVersion: 2010-09-09
Mappings:
attributes:
lambda:
testAttribute: "test"
Resources:
Lambda:
Type: AWS::Lambda::Function
Properties:
Runtime: python3.7
Role: !GetAtt iam.Arn
MemorySize: 128
Timeout: 10
Handler: lambda_function.lambda_handler
FunctionName: !Sub
- "testName${attr}"
- {attr: !FindInMap [attributes, lambda, testAttribute]}
Description: 'This is my lambda'
Code:
S3Bucket: myBucket
S3Key: !Sub
- "lambda/testName${attr}.zip"
- {attr: !FindInMap [attributes, lambda, testAttribute]}
Note: Mappings have a mandatory three-level nesting, take this into consideration while designing your solution
You could use Parameters with a default value, and Sub later in the template:
AWSTemplateFormatVersion: 2010-09-09
Parameters:
testAttribute:
Type: String
Default: test
Resources:
Lambda:
Type: AWS::Lambda::Function
Properties:
Runtime: python3.7
Role: !GetAtt iam.Arn
MemorySize: 128
Timeout: 10
Handler: lambda_function.lambda_handler
FunctionName: !Sub "testName${testAttribute}"
Description: 'This is my lambda'
Code:
S3Bucket: myBucket
S3Key: !Sub "lambda/testName${testAttribute}.zip"
[Edited for typo]

Get Value from a Lambda using Cloud Formation and check condition to branch

I have attached the sample to give you some clarity of what i am trying to solve.
AWSTemplateFormatVersion: '2010-09-09'
Description: Project Service Catalog get lambda data
Parameters:
Environment:
Type: String
Description: Environment of the SageMaker
ProjectId:
Type: String
Description: Project ID of the SageMaker
SsmRoleLambdaArn:
Type: AWS::SSM::Parameter::Value<String>
Default: '/data-science/role-lambda/arn'
Description: Arn to lookup Role of the Session using project id
Resource:
IdentifyUserRole:
Type: Custom::GetParam
Properties:
ServiceToken: !Ref SsmRoleLambdaArn
pl_role: !Sub '${Environment}-sso-data-science-${ProjectId}-pl-role'
ds_role: !Sub '${Environment}-sso-data-science-${ProjectId}-ds-role'
KmsKey:
Type: AWS::KMS::Key
Properties:
Description: !Sub 'Encryption for ${Environment}-${ProjectId}-${Prid}-${NotebookInstanceNameSuffix}'
EnableKeyRotation: true
Tags:
- Key: Environment
Value: !Ref Environment
- Key: Owner
Value: !Ref Owner
- Key: ProjectId
Value: !Ref ProjectId
- Key: PrincipalId
Value: !Sub
- "${RoleId}:${Prid}"
- RoleId:
Fn::If: [!Equals [!GetAtt IdentifyUserRole.value, true], !GetAtt PORoleId.value, !GetAtt DSRoleId.value]
I am getting error at the IF condition in the PrincipalID tag. Please help solve this condition with some sample templates. I can't use !GetAtt in the Conditions block as well because we are not supposed to use get attributes.
Error Message - During stack validation
An error occurred (ValidationError) when calling the ValidateTemplate operation: Template error: Fn::If requires a list argument with the first element being a condition
You can't hard code the condition in the If like you are attempting:
Fn::If: [!Equals [!GetAtt IdentifyUserRole.value, true], !GetAtt PORoleId.value, !GetAtt DSRoleId.value]
The first argument must be condition from Conditions section (docs):
reference to a condition in the Conditions section.
Subsequently, you can't construct conditions based on GetAtt or any other resources from Resources section.
The same docs also write:
You can only reference other conditions and values from the Parameters and Mappings sections of a template. For example, you can reference a value from an input parameter, but you cannot reference the logical ID of a resource in a condition.

Cloudformation template Lambda environment variable error - Value of property Variables must be an object with String

I want to set environment variiable for my lambda function using cloudformation mappings. Hence I am using Fn::FindInMap to get the value of variable from a mapping. But I am getting the error - Value of property Variables must be an object with String (or simple type) properties
Mappings:
DomainResourceMapping:
DUBCrossAccountIAMRole:
beta: "xyz"
prod: "act"
Resources:
LambdaFunction:
Type: AWS::Serverless::Function
Properties:
Handler: '...t'
Runtime: java8
CodeUri:
Bucket: ...
Key: ...
Description: nn
Timeout: 20
MemorySize: 512
Environment:
Variables:
DUB_CROSS_ACCOUNT_IAM_ROLE:
- Fn::FindInMap:
- DomainResourceMapping
- DUBCrossAccountIAMRole
- {Ref: Stage}
You are setting DUB_CROSS_ACCOUNT_IAM_ROLE to be an array. Try
Environment:
Variables:
DUB_CROSS_ACCOUNT_IAM_ROLE:
Fn::FindInMap:
- DomainResourceMapping
- DUBCrossAccountIAMRole
- {Ref: Stage}
or using the short syntax
Environment:
Variables:
DUB_CROSS_ACCOUNT_IAM_ROLE: !FindInMap [ DomainResourceMapping, DUBCrossAccountIAMRole, !Ref Stage

Specify different environment variable's values for different AWS Lambda function versions in CloudFormation template

I have AWS CloudFormation template for Lambda function which contains function's configuration and configuration of two function's versions, something like this:
AWSTemplateFormatVersion: "2010-09-09"
Transform: "AWS::Serverless-2016-10-31"
Description: Lambda function configuration
Resources:
EndpointLambda:
Type: "AWS::Lambda::Function"
Properties:
FunctionName: "endpoint-endpoint"
Handler: "com.test.aws.RequestHandler::handleRequest"
Runtime: java8
Code:
S3Bucket: "lambda-functions"
S3Key: "test-endpoint-lambda-0.0.1.jar"
Description: Test Lambda function
MemorySize: 256
Timeout: 60
Environment:
Variables:
VAR1: "test value 1"
VAR2: "test value 2"
LambdaFunctionVersion1:
Type: "AWS::Lambda::Version"
Properties:
FunctionName:
Ref: "EndpointLambda"
Description: "version 1"
LambdaFunctionVersion2:
Type: "AWS::Lambda::Version"
Properties:
FunctionName:
Ref: "EndpointLambda"
Description: "version 2"
How can I specify different values for environment variables VAR1 and VAR2 for LambdaFunctionVersion1 and LambdaFunctionVersion2?

AWS Cloudformation interprets conditionnal function as a resource property

I'm having a strange behavior with cloudformation template. This my template, where I create a bucket and want to notification configuration depending on a condition :
AWSTemplateFormatVersion: '2010-09-09'
Description: "Setup Artifacts Bucket"
Parameters:
BucketName:
Description: Name of the pipeline setup arctifact bucket
Type: String
Default: "s3-pipeline-setup"
NotificationCondition:
Description: Conditionally add Notification configuration to the artifact bucket
Type: String
Default: false
Conditions:
AddNotificationConfiguration: !Equals [ !Ref NotificationCondition, true ]
Resources:
ArtifactBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref BucketName
Fn::If:
- AddNotificationConfiguration
-
NotificationConfiguration:
LambdaConfigurations:
-
Function: "arn:aws:lambda:eu-west-1:341292222222227:function:lambda-ops-trigger-pipeline-setup"
Event: "s3:ObjectCreated:*"
Filter:
S3Key:
Rules:
-
Name: prefix
Value: "appstackcodes/"
-
Name: suffix
Value: "txt"
- !Ref AWS::NoValue
When I try a deploy it fails with this error :
00:28:10
UTC+0200 CREATE_FAILED AWS::S3::Bucket ArtifactBucket Encountered
unsupported property Fn::If
I don't really understand the matter.. Can someone try and let me know the mistake there please?
Thanks
Unfortunately you can not do what you intended in cloudformation.
The Fn::If can basically just be used as a ternary expression. E.g.
key: Fn::If: [condition_name, value_if_true, value_if_false]
It can't be used as logic flow like you would in a programming language. There are ways around it. You actually already seemed to have discovered the AWS::NoValue, so it's just a matter of moving the NotificationConfiguration assignment to outside the if.
Resources:
ArtifactBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref BucketName
NotificationConfiguration:
Fn::If:
- AddNotificationConfiguration
- LambdaConfigurations:
-
Function: "arn:aws:lambda:eu-west-1:341294322147:function:lambda-itops-trigger-pipeline-setup"
Event: "s3:ObjectCreated:*"
Filter:
S3Key:
Rules:
-
Name: prefix
Value: "appstackcodes/"
-
Name: suffix
Value: "txt"
- !Ref AWS::NoValue
Effectively you are always assigning something to NotificationConfiguration, but sometimes it's the magic AWS::NoValue. This works in the majority of cases, although there are times when this just isn't sufficient and more creativity is required!