I'm trying to update the CloudFormation logs retention period under /aws/codebuild/
path to save costing. I've did some testing and reading on AWS Custom-Resource to trigger lambda/scripts during onCreate, onUpdate and onDelete events. I need clarification to move forward because i'm kind of stuck trying to debug this issue. Any pointers would be appreciated.
Custom-resource.ts
import * as cdk from "@aws-cdk/core";
import * as cr from "@aws-cdk/custom-resources";
import * as lambda from "@aws-cdk/aws-lambda";
import * as path from "path";
export class CfCustomResource extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: CfStackProps) {
super(scope, id, props);
const retention = new lambda.Function(this, "OnEventFunction", {
memorySize: 512,
timeout: cdk.Duration.seconds(120),
runtime: lambda.Runtime.NODEJS_14_X,
handler: "onEvent",
code: lambda.Code.fromAsset(path.join(__dirname, 'set_retention_policy'))
});
const getParameter = new cr.AwsCustomResource(this, 'updateRetentionPeriod', {
onCreate:
{
service: 'Lambda',
action: 'invoke',
parameters: {
FunctionName: retention.functionName
},
physicalResourceId: cr.PhysicalResourceId.of(Date.now().toString()),
},
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
}),
});
console.log(getParameter);
}
}
The index.ts onEvent handler is as per below, upon onCreate it will trigger updateRetention()
function as per below
import { CloudFormationCustomResourceEvent, CloudFormationCustomResourceDeleteEvent, CloudFormationCustomResourceUpdateEvent, CloudFormationCustomResourceCreateEvent } from "aws-lambda";
interface Response {
PhysicalResourceId: string
}
export function onEvent(
event: CloudFormationCustomResourceEvent,
): string {
console.log("Event 👉", event);
let response: Response;
switch (event.RequestType){
case "Create":
response = onCreate(event);
break;
case "Delete":
response = onDelete(event);
break;
case "Update":
response = onUpdate(event);
break;
default:
throw new Error("Unknown Request Type of CloudFormation");
}
console.log("Return value:", JSON.stringify(response))
return JSON.stringify(response);
}
function onCreate(event: CloudFormationCustomResourceCreateEvent) : Response {
console.log("We are in the Create Event");
updateRetention();
return {
PhysicalResourceId: "abcdef-" + event.RequestId
}
}
function onDelete(event: CloudFormationCustomResourceDeleteEvent) : Response {
console.log("We are in the Delete Event");
return {
PhysicalResourceId: event.PhysicalResourceId || ""
}
}
function onUpdate(event: CloudFormationCustomResourceUpdateEvent) : Response {
console.log("We are in the Update Event");
return {
PhysicalResourceId: event.PhysicalResourceId || ""
}
}
Upon running the function, i'm getting the follow error:
Received response status [FAILED] from custom resource. Message returned: index.onEvent is undefined or not exported Logs:
I couldn't see any further info from AWS as the function was rolled-back. Any experts have tried perform such usecase to trigger javascript or lambda during the deployment?
I think this is happening because you have not compiled your TypeScript into JavaScript. You can use NodejsFunction which handles that automatically.
I think you also meant to use Provider instead of AwsCustomResource. The latter calls any AWS API for you. But you want to just let the provider framework call the lambda for you. That is evident by the return values of your function.
But all this can be easily skipped. You can create your CodeBuild project with a specific log group that already has log retention set. CDK handles log retention for you when creating log groups. For example:
const logGroup = new logs.LogGroup(
this,
'Logs',
{
retention: RetentionDays.ONE_MONTH,
},
);
pushes to repository
const project = new codebuild.Project(this, 'CodeBuild', {
// ...
logging: {
cloudWatch: {
logGroup,
},
},
});
If you want to keep the /aws/codebuild
prefix, you can manually name your log group that with logGroupName
.