- Newest
- Most votes
- Most comments
The reason resources are being deleted is because you are checking if the resources exist and only instantiating them in your CDK application if they do not. This an imperative method whereas CloudFormation is declarative. When you do not declare the resources, the resulting CloudFormation template will not contain the definition of the resources and CloudFormation will delete the resources. You can override this by applying the RemovalPolicy.RETAIN, but you have only done so for the Lambda function and the API Gateway. All the other resources such as the API Gateway deployment, stage, resources do not have the removal policy applied to them so they will be deleted.
There are a lot of direct AWS SDK calls being made in your example. Unless you have a specific use case to be doing this, you generally should not be checking for the existence of resources within your CDK application or updating with directly AWS SDK. You should simply declare the resources and configuration you want to deploy and CloudFormation handles creating new resources or updating existing ones to match the desired configuration.
Here is a rough draft attempt at rewriting your lib/infra-stack.ts file. This is not fully validated or tested, so you should validate that the code runs and is suitable for your use case and environment. This intended just a start to give you an idea of how to work with the declarative method:
async createApiGateway(apiGatewayClient: APIGatewayClient, config: Config) { // Create the API Gateway const api = new apigateway.RestApi(this, config.apigateway, { restApiName: config.apigateway, deploy: false }); console.log(`New APIGateway ${api.restApiId}`) const deployment = new apigateway.Deployment(this, `${config.apigateway}-${this.apiEnv}-deploy`, { api, }); new apigateway.Stage(this, `${config.apigateway}-${this.apiEnv}`, { deployment }); const cfnApi = api.node.defaultChild as apigateway.CfnRestApi; cfnApi.applyRemovalPolicy(cdk.RemovalPolicy.RETAIN); for (const lambdaConfig of config.lambda) { await this.processLambdaConfig(api, lambdaConfig); } } async processLambdaConfig(api: apigateway.IRestApi, lambdaConfig: LambdaConfig) { console.log(`inside processLambdaConfig`) const lambdaAssetPath = path.join(__dirname, lambdaConfig.lambdaPath + '\\index.ts'); const packageLockPath = path.join(__dirname, '../../', '\\package-lock.json'); const lambdaName = `${this.apiEnv}_${lambdaConfig.lambdaName}`; console.log(`packageLockPath ${packageLockPath}`) console.log(`lambdaAssetPath ${lambdaAssetPath}`) if (!fs.existsSync(lambdaAssetPath)) { throw new Error(`Lambda asset path does not exist: ${lambdaAssetPath}`); } const lambdaRole = iam.Role.fromRoleArn(this, `dev-testexecrole-wa-hubb`, `arn:aws:iam::1234567889:role/dev-testexecrole-wa-hubb`); const lambdaFunction = new NodejsFunction(this, `${this.apiEnv}_${lambdaConfig.lambdaName}`, { functionName: `${this.apiEnv}_${lambdaConfig.lambdaName}`, memorySize: lambdaConfig.memorySize, timeout: cdk.Duration.minutes(2), runtime: lambda.Runtime.NODEJS_20_X, handler: lambdaConfig.handler, role: lambdaRole, entry: lambdaAssetPath, bundling: { externalModules: ['aws-lambda'], nodeModules: ['pg'] }, depsLockFilePath: packageLockPath, environment: this.environmentVariables }); const integration = new apigateway.LambdaIntegration(lambdaFunction, { requestTemplates: { 'application/json': '{ "statusCode": "200" }' }, }); const rootResource = api.root.addResource(this.apiEnv); const moduleResource = rootResource.addResource(`${lambdaConfig.module}`); const resource = moduleResource.addResource(lambdaConfig.endpoint); resource.addMethod(lambdaConfig.method, integration); console.log("Resource Created", resource) lambdaFunction.grantInvoke(new iam.ServicePrincipal('apigateway.amazonaws.com')); }
To update the resources in-place instead of replacing them, you need to use the aws_cdk.RemovalPolicy.RETAIN policy for the resources you want to update without replacement.
In your code, you are already applying the RemovalPolicy.RETAIN for the CfnRestApi resource, which might prevent the deletion of the API Gateway during updates. However, you need to apply the same policy for the Lambda functions as well.
In the processLambdaConfig method, after creating the lambdaFunction instance, you can apply the RemovalPolicy.RETAIN policy to the underlying CfnResource of the Lambda function:
const cfnLambdaFunction = lambdaFunction.node.defaultChild as CfnResource;
cfnLambdaFunction.applyRemovalPolicy(cdk.RemovalPolicy.RETAIN);
f you're updating the Lambda function code, you can use the aws_lambda.Code.fromAsset method instead of fs.readFileSync to package and upload the new code. This ensures that the Lambda function is updated with the new code without replacing the entire function:
const lambdaCode = lambda.Code.fromAsset(lambdaConfig.lambdaPath, {
bundling: {
externalModules: ['aws-lambda'],
nodeModules: ['pg'],
},
});
await lambdaClient.send(new UpdateFunctionCodeCommand({
FunctionName: lambdaName,
CodeUri: lambdaCode.location,
Publish: true, // Publish a new version of the Lambda function
}));
By applying the RemovalPolicy.RETAIN policy and using the appropriate methods to update the Lambda function code, you should be able to update your Lambda functions without deleting and recreating them during subsequent deployments.
answered 2 years ago

does lambda.Code.fromAsset take care of compiling the ts to js file ?