Get updated AWS Lambda URL after deployment - amazon-web-services

I have set up CI/CD for an AWS Lambda function such that the new version is automatically deployed using GitHub actions. By default, AWS creates a new Lambda ID (and thus URL) for this lambda function. This means that the front-end portion of my code will need to be updated to contain the updated URL. Is there a way to automatically perform such updating? By e.g. saving the URL as an environment variable and inserting it in the code with a GitHub action?
Or is there alternatively a way to re-use the old Lambda function URL for new deployments?

You can get the updated Lambda URL by using SAM template outputs as follows:
Resources:
MyFunction:
Type: 'AWS::Serverless::Function'
Outputs:
MyFunctionUrlEndpoint:
Description: "My Lambda Function URL Endpoint"
Value: !GetAtt MyFunctionUrl.FunctionUrl
Then you can access the output as described in this answer:
aws cloudformation describe-stacks --stack-name stack_name --query 'Stacks[0].Outputs[?OutputKey==`MyFunctionUrlEndpoint`].OutputValue' --output text
which can then be further processed in e.g. your front-end code.
There may be easier methods, but this should work!

Related

Does AWS sam cli print template.yaml config file with all variables resolved

I have switched from serverless to sam cli. One useful function serverless had was serverless print which allowed you to print the output of your yaml file with all the local variables resolved. This was a useful tool for checking if your syntax is correct or if the variables are resolving as you expect.
Is that any way to do this with AWS sam cli?
e.g.
sam print
You can achieve this using Outputs section of SAM template.
You can check the AWS SAM template anatomy to understand better.
Outputs (optional)
The values that are returned whenever you view your stack's properties. For example, you can declare an output for an S3 bucket
name, and then call the aws cloudformation describe-stacks AWS Command
Line Interface (AWS CLI) command to view the name. This section corresponds directly with the Outputs section of AWS CloudFormation templates.
You will need to make use of Intrinsic functions within your Outputs section to print out the final resolved value at runtime.
Outputs:
BackupLoadBalancerDNSName:
Description: The DNSName of the backup load balancer
Value: !GetAtt BackupLoadBalancer.DNSName
Condition: CreateProdResources
InstanceID:
Description: The Instance ID
Value: !Ref EC2Instance
If you just wish to validate if your SAM is correct or not you could use the following command:
$ sam validate
Posting the answer here so that it may help others in future!

AWS CloudFormation pseudo parameters are incorrect locally

I am working on AWS Serverless application using SAM. My template.yaml has this line for defining an S3 bucket name:
BucketName: !Sub ${AWS::StackName}-visit-attachments-${AWS::AccountID}
When I deploy to AWS using sam deploy the variables are substituted correctly.
But when I execute the lambda function locally, the resulting string is local-visit-attachments-123456789012. I can't find where the local and 123456789012 are coming from since I don't have them anywhere in the configs.
How can I make it so it uses the same values locally as when I deploy to AWS?
sam local invoke takes --env-vars parameter. You should be able to overwrite these default values by setting AWS_REGION and AWS_ACCOUNT_ID.

Function not found after manually deleting a function in a SAM CloudFormation stack

I am using sam deploy to deploy lambda function and API gateway. It works fine but it doesn't work after I manually deleted the lambda function via AWS console. I got below error:
"ResourceStatusReason": "Function not found:
arn:aws:lambda:ap-southeast-2:286334053171:function:polaroid (Service:
AWSLambdaInternal; Status Code: 404; Error Code: ResourceNotFoundException;
Request ID: b431cbfc-7772-11e9-8022-1b92fa2cfa9e)
What is the proper way to delete the lambda and do a refresh deployment? If this happens, how can I force SAM to create the missing lambda function?
My lambda in template yaml looks like:
...
Resources:
PolaroidFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: test
CodeUri: ./lambdas
Handler: lib/index.fun
Runtime: nodejs8.10
Events:
polaroid:
Type: Api
Properties:
Path: /test
Method: post
...
I guess you already learnt the hard way that you should never manually delete resources managed by SAM or CloudFormation.
In general, if you just want to change the function, you can just call sam build and sam deploy, and the new version of it will be deployed. There is no need to delete anything. If you need a more advanced workflow, you will need to read blog posts. There is no one right way to do this.
To fix your immediate problem however, here is what you can do.1
Firstly, you need to get the generated AWS CloudFormation template:
▶ aws cloudformation get-template --stack-name HelloWorld \
--template-stage Processed --query TemplateBody | cfn-flip -y > processed.yml
Next, you need to comment out the function in the processed.yml file you just created, and also comment out the Lambda Permissions that refer to it. Save a backup of the original processed.yml file too.
Also, update any other template references to it if possible with the actual values CloudFormation computed when you built the stack, by getting them from your AWS console. For example, if you had references to ${HelloWorldFunction.Arn} you might have to update those references in the template with a string like arn:aws:lambda:ap-southeast-2:123456789012:function:HelloWorld-HelloWorldFunction-1NJGQI7GEAUM1.
Next, validate the template using AWS CloudFormation commands:
▶ aws cloudformation validate-template --template-body file://processed.yml
{
"CapabilitiesReason": "The following resource(s) require capabilities: [AWS::IAM::Role]",
"Description": "sam-app\nSample SAM Template for sam-app\n",
"Parameters": [],
"Capabilities": [
"CAPABILITY_IAM"
]
}
Next, you will update the stack using this modified template. By updating the stack this way, you get your template and real state to be back in sync from CloudFormation's point of view:
▶ aws cloudformation update-stack --template-body file://processed.yml --stack-name HelloWorld --capabilities CAPABILITY_IAM
{
"StackId": "arn:aws:cloudformation:ap-southeast-2:885164491973:stack/HelloWorld/af2c6810-7884-11e9-9bb3-068b1a8e1450"
}
If all goes well, your stack goes into UPDATE_COMPLETE state. Great!
Finally, uncomment all the resources you commented out, and restore all the original values. Then update stack a second time, and your stack should be restored to its original state.
See also:
AWS Knowledge Base, 2016, 2019, How do I update an AWS CloudFormation stack that's failing because of a resource that I manually deleted?.
More on the cfn-flip utility, if you don't have it.
1 Note that I tested this method using the default HelloWorld Python 2.7 example that ships with SAM.
I had a similar issue. In my case I had deleted the Lambda as an experiment while trying to reset the TRIM_HORIZON to get it to reprocess old events in a DynamoDB Stream.
I found a simpler solution:
Go into the CloudFormation Console and delete the deployed Stack.
sam deploy works fine again after that.
So as suggested in other answers I deleted the function manually from the console.
I was deploying the stack from CDK
The solution
comment the lambda function code (in cdk) of the function I deleted manually.
Deploy stack
Un-comment the code and deploy again
If you want to avoid deleting the stack and deploying it back again, or avoid aligning the CloudFormation template file, perhaps you can just align the resources in AWS to the template file.
That means, if you deleted a certain Lambda (for example) that was created initially from the template file, just create the same Lambda MANUALLY in AWS (either GUI or aws cli).
Now run 'sam deploy' again - you should be aligned.
Now remove the Lambda definition from the template file and deploy again - the Lambda should be removed and the CloudFormation will be aligned.

How to describe AWS Lambda function test events in CloudFormation template?

I describe existing AWS Lambda function in CloudFormation template and I face with the next issue. In our Lambda we configured few test events which helps us to verify some usecases (I mean functionality from the screenshot below).
But I don't see any abilities to add these test events to the CloudFormation template. AWS documentation don't help me with that. Is that possible at all or are there any workarounds how to export and import Lambda function test events?
Lambda test functionality is available only in the UI console, You can use Cloudformation Custom Resource to invoke a function from a cloudformation template. Resource properties allow AWS CloudFormation to create a custom payload to send to the Lambda function.
Sample code:
Resources:
EnableLogs:
Type: Custom::EnableLogs
Version: '1.0'
Properties:
ServiceToken: arn:aws:lambda:us-east-1:acc:function:rds-EnableRDSLogs-1O6XLL6LWNR5Z
DBInstanceIdentifier: mydb
the event parameter provides the resource properties. ex:
event['ResourceProperties']['DBInstanceIdentifier']

Access AWS auto-generated URL for deployed resources

Is there a way to access auto-generated URLs for deployed resources before the deployment is finished? (like db host, lambda function URL, etc.)
I can access them after the deployment is finished, but sometimes I need to access them while building my stack. (E.g. use them in other resources).
What is a good solution to handle this use-case? I was thinking about outputting them into the SSM parameter store from CloudFormation template, but I'm not sure if this is even possible.
Thanks for any suggestion or guidance!
If "use them in other resources" means another serverless service or another CloudFormation stack, then use CloudFormation Outputs to export the values you are interested in. Then use CloudFormation ImportValue function to reference that value in another stack.
See https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html and https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-importvalue.html
Within Serverless Framework, you can access a CloudFormation Output value using https://serverless.com/framework/docs/providers/aws/guide/variables/#reference-cloudformation-outputs
If you want to use the autogenerated value within the same stack, then just use CloudFormation GetAtt function. See https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html.
For example, I have a CloudFormation stack that outputs the URL for an ElasticSearch cluster.
Resources:
Search:
Type: AWS::Elasticsearch::Domain
Properties: <redacted>
Outputs:
SearchUrl:
Value: !GetAtt Search.DomainEndpoint
Export:
Name: myapp:search-url
Assuming that the CloudFormation stack name is "mystack", then in my Serverless service, I can reference the SearchUrl by:
custom:
searchUrl: ${cf:mystack.SearchUrl}
To add to bwinant's answer, ${cf:<stack name>.<output name>} does not work if you want to reference a variable in another stack which is located in another region. There is a plugin to achieve this called serverless-plugin-cloudformation-cross-region-variables. You can use it like so
plugins:
- serverless-plugin-cloudformation-cross-region-variables
custom:
myVariable: ${cfcr:ca-central-1:my-other-stack:MyVariable}