I am trying to define value in one of the attributes for Type: AWS::Lambda::EventSourceMapping
Below is my snippet (latest attempt):
FunctionName: #trigger the echo function previously defined
"Fn::Join": [":", [{"Fn::GetAtt" : ["LambdaName", "Arn"]}, "live" ]]
My cloud formation stack, however fails to deploy with following error:
"StatusReason": "Template error: every Fn::Join object requires two parameters, (1) a string delimiter and (2) a list of strings to be joined or a function that returns a list of strings (such as Fn::GetAZs) to be joined."
I have tried couple of variations with the brackets, however keep getting same error. What am I missing in the syntax?
P.S. I am defining this in a yaml file
My first question is whether LambdaName references something that can be used with GetAtt to provide an ARN. Otherwise, it could just be a formatting issue. I'm not sure AWS CFN can read the embedded curly brackets you're using to wrap the Fn::GetAtt.
Maybe one of these would work better?
FunctionName:
Fn::Join:
- ':'
- - Fn::GetAtt:
- LambdaName
- Arn
- "live"
Or
FunctionName: !Join [':', [!GetAtt LambdaName.Arn, 'live]]
LambdaSourceMapping:
Type: AWS::Lambda::EventSourceMapping
Properties:
Enabled: 'true'
EventSourceArn: <SQS ARN> or <Kinesis ARN> or <DynamoDb ARN>
FunctionName:
Fn::Join:
- ':'
- - Fn::GetAtt:
- LambdaName
- Arn
- 'live'
Related
I am trying to create a Cloudwatch event rule which will use multiple Codepipelines as source and triggers target.
Parameters:
SourcePipeline:
Description: Name of Source codepipeline
Type: CommaDelimitedList
Default: 'test3, test4'
Resources:
PipelineTrigger:
Type: 'AWS::Events::Rule'
Properties:
EventPattern:
source:
- aws.codepipeline
resources: !Split
- ','
- !Sub
- 'arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${pipeline}'
- pipeline: !Join
- ',arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:'
- !Ref SourcePipeline
Expecting resources as below:
"resources": ["arn:aws:codepipeline:us-east-1:123:test3","arn:aws:codepipeline:us-east-1:123:test4"],
Any idea how to pass the list of names as a parameter?
#FYI Reference i am following Using Lists of ARNs
First, it should be !Ref SourcePipelines. Second you forgot about comma. you can't do this the way you want. This is because, the first parameter to join must be literal string, not any CloudFormation expression or function. So you have to hardcode your account id and region:
resources: !Split
- ','
- !Sub
- 'arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${pipeline}'
- pipeline: !Join
- ',arn:aws:codepipeline:us-east-1:12312321:'
- !Ref SourcePipelines
I have serverless.yaml with many SNS topics that I need to build ARNs from names across accounts and regions, so I come with a custom prefix
custom:
snsTopicPrefix:
Fn::Join:
- ":"
- - "arn:aws:sns"
- !Ref "AWS::Region"
- !Ref "AWS::AccountId"
topic01: Topic-01-test
functions:
from-SNS:
handler: src/fromSNS/handler.fromSNS
events:
- sns:
arn: ${self:custom.snsTopicPrefix}:${self:custom.topic01}
topicName: ${self:custom.topic01}
however, when I deploy it I can not pass an error Trying to populate non string value into a string for variable ${self:custom.snsTopicPrefix}. Please make sure the value of the property is a string.
We have a stack that makes use of the other stack's output with cross-stack referencing using Fn::ImportValue within a swagger definition body.
Note: other parts ommitted to shorten the code
SampleApi:
Type: AWS::Serverless::Api
Properties:
StageName: Stage
Variables:
SampleFunctionName:
Fn::ImportValue:
!Sub ${OtherStackName}-SampleFunctionName
DefinitionBody:
swagger: 2.0
paths:
/sample:
get:
x-amazon-apigateway-integration:
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${stageVariables.SampleFunctionName}/invocations
Where ${OtherStackName}-SampleFunctionName is the name of the function that's being imported from other stack.
Now, our problem now is that we cannot put it inside the endpoint's uri. Cloudformation is complaining about it during sam deploy, saying that ${stageVariables.SampleFunctionName} is an illegal attribute inside Fn::Sub.
I have tried several ways including putting the whole uri on the stage variable itself, but still it does not come.
Your thoughts are very much appreciated!
Fn::Sub was supported from the version v0.21.0 of SAM CLI. The versions below 0.21.0 does not support most of the Cloudformation Intrinsic Functions.
Can check the below link for more details:
https://github.com/awslabs/aws-sam-cli/issues/528
https://github.com/awslabs/aws-sam-cli/releases/tag/v0.21.0
If your using the version below the mentioned one you can try using Fn::Join instead of Fn::Sub as a workround
uri: !Join
- ''
- - 'arn:aws:apigateway:'
- !Ref "AWS::Region"
- ':lambda:path/2015-03-31/functions/arn:aws:lambda:'
- !Ref "AWS::Region"
- ':'
- !Ref "AWS::AccountId"
- ':function:${stageVariables.SampleFunctionName}/invocations'
I made it to work this way
x-amazon-apigateway-integration:
uri:
Fn::Join:
- ''
- - Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/
- Fn::ImportValue:
Fn::Sub: ${StackName}-FunctionArn
- /invocations
For some reason, shorthand functions won't work inside uri and ${stageVariables.<somename>} do not work inside an Fn::Sub function.
Note that this only happens inside a swagger definition body
As Jeff had mentioned Stage Variables does not work inside an Fn::Sub function. However, if anyone wishes to use Stage Variables inside uri string, the below code worked for me.
uri:
Fn::Join:
- ''
- - arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/
- Fn::Sub: ${LambaFunctionResource.Arn}
- :${stageVariables.<stageVariableName>}
- /invocations
I am using cloudformation and I want to be able to use the pseudo value
AWS::NoValue within the Fn::Sub like this:
!Sub ["ATL_DATASET_URL=${DatasetURL}",
DatasetURL: !If [IsURLProvided,
!Ref BitbucketDatasetURL,
!Ref "AWS::NoValue"]]
My Template passes validation but does not deploy. Here is the error message I get when I click Create Stack.
Template error: every value of the context object of every Fn::Sub object must be a string or a function that returns a string
If you want to skip setting a value for DatasetURL, make the !If to return an empty string '' when the condition evaluates to false instead of AWS::NoValue.
Returning AWS::NoValue when false, removes the mapping for DatasetURL.
The alternative to #franklinsijo is to swap the If and Sub statements if you want to actually remove the property (e.g. YourPropertyName) if BitbucketDatasetURL is not given.
YourPropertyName: !If
- IsURLProvided
- !Sub ["ATL_DATASET_URL=${DatasetURL}", DatasetURL: !Ref BitbucketDatasetURL]
- !Ref "AWS::NoValue"
Or shorter
YourPropertyName: !If
- IsURLProvided
- !Sub "ATL_DATASET_URL=${BitbucketDatasetURL}"
- !Ref "AWS::NoValue"
I've got a nested CloudFormation template which accepts a number of parameters from its root template to configure it. At the moment I'm only passing simple string parameters but now I need to pass a list of S3 bucket ARNs onto the child template.
ChildLambdaStack:
Type: AWS::CloudFormation::Stack
Properties:
Parameters:
AwsRegion: !Ref AwsRegion
Environment: !Ref Environment
Product: !Ref Product
S3Buckets: "arn:aws:s3:::bucket1,arn:aws:s3:::bucket2"
TemplateURL: "https://s3.amazonaws.com/child-template.yml"
And then in the child template I have this
AWSTemplateFormatVersion: "2010-09-09"
Description: "Child Lambda"
Parameters:
AwsRegion:
Type: String
Environment:
Type: String
Product:
Type: String
S3Buckets:
Type: String
Resources:
DeployerPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- s3:PutObject
- s3:GetObject
- s3:DeleteObject
- s3:CreateBucket
- s3:DeleteBucket
- s3:ListBucket
- s3:PutBucketNotification
Resource:
- Fn::Split:
- ","
- !Ref S3Buckets
My idea is that that list of S3 bucket ARNs that I'm inputting is expanded in the child template like this
Resource:
- arn:aws:s3:::bucket1
- arn:aws:s3:::bucket2
But when I run the template in, it just errors out
Syntax errors in policy. (Service: AmazonIdentityManagement; Status Code: 400; Error Code: MalformedPolicyDocument)
I've tried other variations like using a CommaDelimitedList parameter type, but none work. Is there a simple way to pass in a list of strings as a parameter?
Because the return value of !Split is A list of string values. I would do it in the following way:
[...]
Resource: !Split [",", !Ref S3Buckets]
[...]
As #MaiKaY points out, the flaw in #Liam Mayfair's code is that Fn::Split is preceded by - which results in a list containing a single element which is a list. The fixed code would look like
...
Resource:
Fn::Split:
- ","
- !Ref S3Buckets
On a more general note, you must make sure to use a Parameter type of String not CommaDelimitedList when using Fn::Split as it won't split a CommaDelimitedList.
If you use CommaDelimitedList with Fn::Split you'll get the error Template error: every Fn::Split object requires two parameters, (1) a string delimiter and (2) a string to be split or a function that returns a string to be split
If you use CommaDelimitedList with no Fn::Split you'll get the error Syntax errors in policy
There is actually a much better way. You can use the type List<String> in your CloudFormation Parameters:
# ...
Parameters:
S3Buckets:
Type: List<String>
# ...
Then pass the S3 Bucket list just like you did as comma separated values:
# ...
ChildLambdaStack:
Type: AWS::CloudFormation::Stack
Properties:
Parameters:
AwsRegion: !Ref AwsRegion
Environment: !Ref Environment
Product: !Ref Product
# Next line will be interpreted as a list
S3Buckets: "arn:aws:s3:::bucket1,arn:aws:s3:::bucket2"
TemplateURL: "https://s3.amazonaws.com/child-template.yml"
# ...
You can then assume that the type of the referenced Parameter is a list. So instead of:
# ...
Resource: !Split [",", !Ref S3Buckets]
# ...
You can just use:
# ...
Resource: !Ref S3Buckets
# ...