Deploy Lambda Function using CodePipeline and CDK generated CloudFormation Template - amazon-web-services

I have a Lambda function that I'm trying to deploy using CodePipeline.
The Lambda function source code is in the same project as the Lambda CDK app. Since they are both in the same repository, the CDK app can reference the Lambda source code directly.
The docs suggest to use lambda.Code.fromAsset(path) when the CDK app can reference the Lambda code directly so I started with the follow definition for my Lambda function.
const fn = new lambda.Function(this, "Fn", {
code: lambda.Code.fromAsset(path/to/lambda/source),
handler: "index.handler",
runtime: lambda.Runtime.NODEJS_10_X
});
In the CodePipeline, I use CodeBuild to run cdk synth and synthesize the CloudFormation template.
The problem with defining my Lambda in this way is the CloudFormation template has parameters for the Lambda source code bucket and key which are seemingly named randomly e.g. AssetParameters3ffd...affdS3Bucket1CFF873D
When you run cdk deploy the CLI knows what the parameters are and populates them with values.
In my case however, I'm not using cdk deploy. I want to use CloudFormation in a CodePipeline.
That means I need to fill the parameters with the values for the Lambda source artifact which is output from my CodeBuild step. Getting the values is easy but I have no way of knowing what the parameters are named.
Next I tried using the following to define the parameter names myself.
const fn = new lambda.Function(this, "Fn", {
code: lambda.Code.fromCfnParameters({
bucketNameParam: new core_1.CfnParameter(this, "LambdaSourceBucket"),
objectKeyParam: new core_1.CfnParameter(this, "LambdaSourceKey"),
}),
handler: "index.handler",
runtime: lambda.Runtime.NODEJS_10_X
});
No luck. cdk synth still modifies the parameter names in the template e.g. AppLambdaSourceBucket8B89D730. That's better than before but I still can't be sure what the parameters will be named so I can assign them in my CodePipeline.
I can't use lambda.Code.fromBucket(bucket, key) because the bucket and key are determined by the CodePipeline/CodeBuild.
I found this example which is doing almost the same thing as me except their CodePipeline is defined in the same CDK app as their Lambda function. That avoids the problem that I'm having because the Lambda definition and CodePipeline definition can both reference the same CfnParametersCode instance.
Unfortunately I can't co-locate my CodePipeline definition with my Lambda like they've done in that example. I feel like this should still be possible without that.
What am I missing?

I'm able to do this with new CfnParametersCode (which should be equivalent to the factory method you're calling). Are you possibly creating this inside another construct and not at the stack level?

Related

Lambda Deployment using CodePipeline and CDK

I'm using CDK and am trying to define a CodePipeline that triggers a Lambda Deployment. It doesn't seem as if there are any CDK constructs to achieve this.
I could only find CodeDeployEcsDeployAction and CodeDeployServerDeployAction.
The problems are:
CodeDeployEcsDeployAction: asks for an ECS task definition
CodeDeployServerDeployAction: only accepts an artifact input for properties. However, it won't pick up the appspec file I have defined in the artifact and there are no properties to define the path
(There is no way to do artifact.atPath('appspec.json'))
(Submitted issue 20782 just in case this is an actual request)
Here's my Lambda CodeDeploy setup
const application = new codedeploy.LambdaApplication(
this,
'CodeDeployLambdaApplication',
{
applicationName: 'LambdaApplication',
},
);
const lambdaDeploymentGroup = new codedeploy.LambdaDeploymentGroup(
this,
'AllAtOnceDeployment',
{
application,
alias,
deploymentConfig: codedeploy.LambdaDeploymentConfig.ALL_AT_ONCE,
},
);
You need to use CodeDeploy and Lambda Action:
https://docs.aws.amazon.com/cdk/api/v1/docs/aws-codedeploy-readme.html for the general docs, specifically:
https://docs.aws.amazon.com/cdk/api/v1/docs/aws-codedeploy-readme.html#lambda-applications
Alternatively, if your program is not that complex and does not need all the additional overhead that CodeDeploy brings (having to synth the template and pass it to CodeDeploy and all) then just use a codebuild, that takes a source from your git repo and runs the command cdk deploy your stack

How do I get container id from AWS CDK Mediastore?

How do I get container id from AWS CDK Mediastore?
It is being used as below code.
const mediaStoreContainer = new mediastore.CfnContainer(this, 'mediaStoreContainer', {
containerName: 'MediaStoreContainer',
accessLoggingEnabled: true,
})
I've tried many ways, but I can't find it.
mediaStoreContainer.getAtt(mediaStoreContainer.attrEndpoint)...
Please tell me how I can get it.
unfortunately, any time you have to use a Cfn function in CDK, this indicates that that resource/service/thing is not fully hooked into the cdk libraries. these Cfn functions simply are basic parsers that output a json structure for the cloudformation template. getAtt may not even be hooked into all the attributes available to a given item, and most of the time the Cfn versions of a construct can't even be passed to other constructs that would use them (such as having a Role created and passing that role to a Lambda to use)
getAtt just mimics the yaml macro function !getAttr and so can only retrieve what is available from the cloudformation entry for that resource
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-mediastore-container.html - this page indicates its just Endpoint - i believe all you need to use is endpoint = mediaStorecontainer.getAtt("Endpoint")

How to pass aws-lambda function name to generate a cloudwatch alarm using cloudformation template

I have an aws lambda function on top of which I am trying to create a cloudwatch alarm using cloudformation template.
Lets say I have a lambda function named MyPackage-MyLambdaFunctionName but when I see my lambda in the aws console, it says MyPackage-MyLambdaFunctionName-M2DEESRWNF6I.
I am able to create the alarm by passing the below in the dimensions:
Dimensions:
- Name: FunctionName
Value: MyPackage-MyLambdaFunctionName-M2DEESRWNF6I
(Referring to How to set lambda alarm for specific lambda using CloudFormation)
But the issue is the lambda function is having a random component at the end (-M2DEESRWNF6I).
I have a cloudformation template which goes in a few accounts and creates these lambda functions. And since these random identifiers are different in each account, I cant put the above in cloudformation template, since it will work for one account but not for the others.
So, how can I achieve creating these cloudwatch alarms on my lamdba functions using the cloudformation template?
such as does "Value" takes regex? I tried
MyPackage-MyLambdaFunctionName.*
which didnt work. Or is there a way to restrict the lambda function name to be just MyPackage-MyLambdaFunctionName (without the random identifier)
Any guidance/help is appreciated.
Thanks
The random string on the end of your lambda's function name is there because you're not setting the lambda name explicitly when it's created. From docs:
FunctionName
The name of the Lambda function, up to 64 characters in
length. If you don't specify a name, AWS CloudFormation generates one.
In general, this is correct thing to do because if you do set it, you can't change any of the parameters that require replacement (I can't think of any parameters that require that on lambda though).
From the same doc:
If you specify a name, you cannot perform updates that require
replacement of this resource. You can perform updates that require no
or some interruption. If you must replace the resource, specify a new
name.
To create the alarm you can just reference the Lambda function in the alarm creation code.
Like this:
Dimensions:
- Name: "FunctionName"
Value:
Ref: LambdaFunctionReference

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 deploy environment variable using serverless deploy for AWS lambda

I am new to AWS lambda i have i am using serveless deploy to deploy my lambda function declared in serverless.yml file.
In that file i wrote a lambda function i deployed and it is working fine but problem is that whatever environment variable i gave is not available in console of that lambda function. I might be doing some minor mistake or for deploying environment variable there should be some other syntax.
I can go to lambda function in console and add environment variable manually.
But my doubt is can we do it while deploying it through serverless deploy
You can use versions and aliases provided by AWS Lambda
You can create different versions of the same lambda function and give them an alias. Like when you push your lambda code - create a version (say it's 5) - create an alias this (say TEST).
When you're sure that its ready for production, create a version(or choose an existing version and name that (say PROD).
Now whenever your lambda function executes, it gives lambda ARN
which contains alias, by that you can know which alias(in context.invokedFunctionArn) is
executed i.e. that can be used as the environment variable. While
invoking the function, you can mention which function to execute from
your invocation code.
let thisARN = context.invokedFunctionArn;
// Get the last string in ARN - It's either function name or the alias name
let thisAlias = thisARN.split(":").pop();
Now whenever you deploy a new code, just point the alias to that version.
You can use AWS console or CLI for that.
Take a look at this lambda versioning and aliases
For directly deploying to your alias(PROD), you can do this -
aws lambda update-alias \
--region region \
--function-name helloworld \
--function-version 2 \
--name PROD
serverless deploy
Serverless deploy works fine for deployment on any stage it also deploys environment variable in given stage, my case environment variable was not deployed of indentation problem in yaml file, and even serverless deploy command was not throwing error it was deploying function but environment variables were not deployed
In yaml file we can state the the stage where we want to deploy like this
provider:
name: aws
runtime: nodejs6.10
stage: dev
region: eu-west-2
Hope this will help if someone gets similar issue