From 670e340271119da8b5a3841bf28841fca1c1ed24 Mon Sep 17 00:00:00 2001 From: Florian Stadler Date: Fri, 8 Nov 2024 19:03:17 +0100 Subject: [PATCH] Review comments --- examples/cfn-custom-resource/ami-lookup.js | 56 +++++++++---------- examples/cfn-custom-resource/index.ts | 4 +- examples/examples_nodejs_test.go | 5 +- .../pulumi-resource-aws-native/schema.json | 2 +- .../docs/content/cfn-custom-resource.md | 1 - .../CloudFormation/CustomResourceEmulator.cs | 1 - .../cloudformation/customResourceEmulator.go | 1 - .../cloudformation/customResourceEmulator.ts | 1 - 8 files changed, 33 insertions(+), 38 deletions(-) diff --git a/examples/cfn-custom-resource/ami-lookup.js b/examples/cfn-custom-resource/ami-lookup.js index cf82fef965..afd29f6b93 100644 --- a/examples/cfn-custom-resource/ami-lookup.js +++ b/examples/cfn-custom-resource/ami-lookup.js @@ -8,46 +8,44 @@ var archToAMINamePattern = { "HVM64": "al2023-ami-2023.*-kernel-*-x86_64", "HVMG2": "amzn-ami-graphics-hvm*x86_64-ebs*" }; -var aws = require("aws-sdk"); - -exports.handler = function(event, context) { - - console.log("REQUEST RECEIVED:\n" + JSON.stringify(event)); +const { EC2Client, DescribeImagesCommand } = require("@aws-sdk/client-ec2"); + +exports.handler = async function(event, context) { + const redactedEvent = { ...event, ResponseURL: "REDACTED" }; + console.log("REQUEST RECEIVED:\n" + JSON.stringify(redactedEvent)); // For Delete requests, immediately send a SUCCESS response. if (event.RequestType == "Delete") { - sendResponse(event, context, "SUCCESS"); + await sendResponse(event, context, "SUCCESS"); return; } var responseStatus = "FAILED"; var responseData = {}; - var ec2 = new aws.EC2({region: event.ResourceProperties.Region}); - var describeImagesParams = { + const ec2Client = new EC2Client({ region: event.ResourceProperties.Region }); + const describeImagesParams = { Filters: [{ Name: "name", Values: [archToAMINamePattern[event.ResourceProperties.Architecture]]}], Owners: [event.ResourceProperties.Architecture == "HVMG2" ? "679593333241" : "amazon"] }; - // Get AMI IDs with the specified name pattern and owner - ec2.describeImages(describeImagesParams, function(err, describeImagesResult) { - if (err) { - responseData = {Error: "DescribeImages call failed"}; - console.log(responseData.Error + ":\n", err); + try { + const describeImagesResult = await ec2Client.send(new DescribeImagesCommand(describeImagesParams)); + var images = describeImagesResult.Images; + // Sort images by name in descending order. The names contain the AMI version, formatted as YYYY.MM.Ver. + images.sort((x, y) => y.Name.localeCompare(x.Name)); + for (var j = 0; j < images.length; j++) { + if (isBeta(images[j].Name)) continue; + responseStatus = "SUCCESS"; + responseData["Id"] = images[j].ImageId; + break; } - else { - var images = describeImagesResult.Images; - // Sort images by name in decscending order. The names contain the AMI version, formatted as YYYY.MM.Ver. - images.sort(function(x, y) { return y.Name.localeCompare(x.Name); }); - for (var j = 0; j < images.length; j++) { - if (isBeta(images[j].Name)) continue; - responseStatus = "SUCCESS"; - responseData["Id"] = images[j].ImageId; - break; - } - } - sendResponse(event, context, responseStatus, responseData); - }); + } catch (err) { + responseData = { Error: "DescribeImages call failed" }; + console.log(responseData.Error + ":\n", err); + } + + await sendResponse(event, context, responseStatus, responseData); }; // Check if the image is a beta or rc image. The Lambda function won't return any of those images. @@ -55,10 +53,8 @@ function isBeta(imageName) { return imageName.toLowerCase().indexOf("beta") > -1 || imageName.toLowerCase().indexOf(".rc") > -1; } - // Send response to the pre-signed S3 URL -function sendResponse(event, context, responseStatus, responseData) { - +async function sendResponse(event, context, responseStatus, responseData) { var responseBody = JSON.stringify({ Status: responseStatus, Reason: "See the details in CloudWatch Log Stream: " + context.logStreamName, @@ -104,4 +100,4 @@ function sendResponse(event, context, responseStatus, responseData) { // write data to request body request.write(responseBody); request.end(); -} \ No newline at end of file +} diff --git a/examples/cfn-custom-resource/index.ts b/examples/cfn-custom-resource/index.ts index 9f96c757e9..c3da73c853 100644 --- a/examples/cfn-custom-resource/index.ts +++ b/examples/cfn-custom-resource/index.ts @@ -32,7 +32,7 @@ const rpa2 = new awsClassic.iam.RolePolicyAttachment("lambdaRolePolicyAttachment policyArn: awsClassic.iam.ManagedPolicies.AWSLambdaBasicExecutionRole, }); -const bucket = new awsClassic.s3.Bucket('custom-resource-emulator', { +const bucket = new awsClassic.s3.BucketV2('custom-resource-emulator', { forceDestroy: true, }); @@ -46,7 +46,7 @@ const handlerCode = new awsClassic.s3.BucketObjectv2("handler-code", { // Create the Lambda function for the custom resource const lambdaFunction = new awsClassic.lambda.Function("ami-lookup-custom-resource", { - runtime: awsClassic.types.enums.lambda.Runtime.NodeJS16dX, + runtime: awsClassic.types.enums.lambda.Runtime.NodeJS20dX, s3Bucket: bucket.bucket, s3Key: handlerCode.key, handler: "index.handler", diff --git a/examples/examples_nodejs_test.go b/examples/examples_nodejs_test.go index 71c2752706..457af00889 100644 --- a/examples/examples_nodejs_test.go +++ b/examples/examples_nodejs_test.go @@ -54,11 +54,14 @@ func TestCustomResourceEmulator(t *testing.T) { test := pulumitest.NewPulumiTest(t, filepath.Join(cwd, "cfn-custom-resource"), options...) test.SetConfig(t, "amiRegion", "us-west-2") + previewResult := test.Preview(t) + t.Logf("#%v", previewResult.ChangeSummary) + upResult := test.Up(t) t.Logf("#%v", upResult.Summary) crossTest(t, upResult.Outputs) - previewResult := test.Preview(t) + previewResult = test.Preview(t) assertpreview.HasNoChanges(t, previewResult) test.SetConfig(t, "amiRegion", "us-east-1") diff --git a/provider/cmd/pulumi-resource-aws-native/schema.json b/provider/cmd/pulumi-resource-aws-native/schema.json index e2821a2f9c..46d0141770 100644 --- a/provider/cmd/pulumi-resource-aws-native/schema.json +++ b/provider/cmd/pulumi-resource-aws-native/schema.json @@ -181222,7 +181222,7 @@ ] }, "aws-native:cloudformation:CustomResourceEmulator": { - "description": "The Custom Resource Emulator allows you to use AWS CloudFormation Custom Resources directly in your Pulumi programs. It provides a way to invoke AWS Lambda functions that implement custom provisioning logic following the CloudFormation Custom Resource protocol.\n\n\u003e **Note**: Currently, only Lambda-backed Custom Resources are supported. SNS-backed Custom Resources are not supported at this time.\n\n## Example Usage\n\n```typescript\nimport * as aws from \"@pulumi/aws-native\";\n\nconst bucket = new aws.s3.Bucket('custom-resource-emulator');\n\n// Create a Custom Resource that invokes a Lambda function\nconst cr = new aws.cloudformation.CustomResourceEmulator('cr', {\n bucketName: bucket.id,\n bucketKeyPrefix: 'custom-resource-emulator',\n customResourceProperties: {\n hello: \"world\"\n },\n serviceToken: \"arn:aws:lambda:us-west-2:123456789012:function:my-custom-resource\",\n resourceType: 'Custom::MyResource',\n}, { customTimeouts: { create: '5m', update: '5m', delete: '5m' } });\n\n// Access the response data\nexport const customResourceData = customResource.data;\n```\n\n## About CloudFormation Custom Resources\n\nCloudFormation Custom Resources allow you to write custom provisioning logic for resources that aren't directly available as AWS CloudFormation resource types. Common use cases include:\n\n- Managing resources outside of AWS (e.g., GitHub repositories, external APIs)\n- Implementing complex provisioning logic\n- Performing custom validations or transformations\n- Integrating with third-party services\n- Implementing organization-specific infrastructure patterns\n\nFor more information about CloudFormation Custom Resources, see [Custom Resources](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html) in the AWS CloudFormation User Guide.\n\n## Permissions\n\nThe IAM principal used by your Pulumi program must have the following permissions:\n\n1. `lambda:InvokeFunction` on the Lambda function specified in `serviceToken`\n2. S3 permissions on the bucket specified in `bucketName`:\n - `s3:PutObject`\n - `s3:GetObject`\n - `s3:HeadObject`\n\n## Lambda Function Requirements\n\nThe Lambda function specified in `serviceToken` must implement the CloudFormation Custom Resource lifecycle.\nFor detailed information about implementing Lambda-backed Custom Resources, see [AWS Lambda-backed Custom Resources](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources-lambda.html) in the AWS CloudFormation User Guide.\n\n## Timeouts\n\nCustom Resources have a default timeout of 60 minutes, matching the CloudFormation timeout for custom resource operations. You can customize it using the [`customTimeouts`](https://www.pulumi.com/docs/iac/concepts/options/customtimeouts/) resource option.\n", + "description": "The Custom Resource Emulator allows you to use AWS CloudFormation Custom Resources directly in your Pulumi programs. It provides a way to invoke AWS Lambda functions that implement custom provisioning logic following the CloudFormation Custom Resource protocol.\n\n\u003e **Note**: Currently, only Lambda-backed Custom Resources are supported. SNS-backed Custom Resources are not supported at this time.\n\n## Example Usage\n\n```typescript\nimport * as aws from \"@pulumi/aws-native\";\n\nconst bucket = new aws.s3.Bucket('custom-resource-emulator');\n\n// Create a Custom Resource that invokes a Lambda function\nconst cr = new aws.cloudformation.CustomResourceEmulator('cr', {\n bucketName: bucket.id,\n bucketKeyPrefix: 'custom-resource-emulator',\n customResourceProperties: {\n hello: \"world\"\n },\n serviceToken: \"arn:aws:lambda:us-west-2:123456789012:function:my-custom-resource\",\n resourceType: 'Custom::MyResource',\n}, { customTimeouts: { create: '5m', update: '5m', delete: '5m' } });\n\n// Access the response data\nexport const customResourceData = customResource.data;\n```\n\n## About CloudFormation Custom Resources\n\nCloudFormation Custom Resources allow you to write custom provisioning logic for resources that aren't directly available as AWS CloudFormation resource types. Common use cases include:\n\n- Implementing complex provisioning logic\n- Performing custom validations or transformations\n- Integrating with third-party services\n- Implementing organization-specific infrastructure patterns\n\nFor more information about CloudFormation Custom Resources, see [Custom Resources](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html) in the AWS CloudFormation User Guide.\n\n## Permissions\n\nThe IAM principal used by your Pulumi program must have the following permissions:\n\n1. `lambda:InvokeFunction` on the Lambda function specified in `serviceToken`\n2. S3 permissions on the bucket specified in `bucketName`:\n - `s3:PutObject`\n - `s3:GetObject`\n - `s3:HeadObject`\n\n## Lambda Function Requirements\n\nThe Lambda function specified in `serviceToken` must implement the CloudFormation Custom Resource lifecycle.\nFor detailed information about implementing Lambda-backed Custom Resources, see [AWS Lambda-backed Custom Resources](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources-lambda.html) in the AWS CloudFormation User Guide.\n\n## Timeouts\n\nCustom Resources have a default timeout of 60 minutes, matching the CloudFormation timeout for custom resource operations. You can customize it using the [`customTimeouts`](https://www.pulumi.com/docs/iac/concepts/options/customtimeouts/) resource option.\n", "properties": { "bucket": { "type": "string", diff --git a/provider/pkg/schema/docs/content/cfn-custom-resource.md b/provider/pkg/schema/docs/content/cfn-custom-resource.md index 831f89f5b9..2bbeac6342 100644 --- a/provider/pkg/schema/docs/content/cfn-custom-resource.md +++ b/provider/pkg/schema/docs/content/cfn-custom-resource.md @@ -28,7 +28,6 @@ export const customResourceData = customResource.data; CloudFormation Custom Resources allow you to write custom provisioning logic for resources that aren't directly available as AWS CloudFormation resource types. Common use cases include: -- Managing resources outside of AWS (e.g., GitHub repositories, external APIs) - Implementing complex provisioning logic - Performing custom validations or transformations - Integrating with third-party services diff --git a/sdk/dotnet/CloudFormation/CustomResourceEmulator.cs b/sdk/dotnet/CloudFormation/CustomResourceEmulator.cs index 3f9c57c191..423f1e3db2 100644 --- a/sdk/dotnet/CloudFormation/CustomResourceEmulator.cs +++ b/sdk/dotnet/CloudFormation/CustomResourceEmulator.cs @@ -20,7 +20,6 @@ namespace Pulumi.AwsNative.CloudFormation /// /// CloudFormation Custom Resources allow you to write custom provisioning logic for resources that aren't directly available as AWS CloudFormation resource types. Common use cases include: /// - /// - Managing resources outside of AWS (e.g., GitHub repositories, external APIs) /// - Implementing complex provisioning logic /// - Performing custom validations or transformations /// - Integrating with third-party services diff --git a/sdk/go/aws/cloudformation/customResourceEmulator.go b/sdk/go/aws/cloudformation/customResourceEmulator.go index 06a46ad881..1e3e266d87 100644 --- a/sdk/go/aws/cloudformation/customResourceEmulator.go +++ b/sdk/go/aws/cloudformation/customResourceEmulator.go @@ -22,7 +22,6 @@ import ( // // CloudFormation Custom Resources allow you to write custom provisioning logic for resources that aren't directly available as AWS CloudFormation resource types. Common use cases include: // -// - Managing resources outside of AWS (e.g., GitHub repositories, external APIs) // - Implementing complex provisioning logic // - Performing custom validations or transformations // - Integrating with third-party services diff --git a/sdk/nodejs/cloudformation/customResourceEmulator.ts b/sdk/nodejs/cloudformation/customResourceEmulator.ts index d85a89b75d..0c2a04c5f9 100644 --- a/sdk/nodejs/cloudformation/customResourceEmulator.ts +++ b/sdk/nodejs/cloudformation/customResourceEmulator.ts @@ -35,7 +35,6 @@ import * as utilities from "../utilities"; * * CloudFormation Custom Resources allow you to write custom provisioning logic for resources that aren't directly available as AWS CloudFormation resource types. Common use cases include: * - * - Managing resources outside of AWS (e.g., GitHub repositories, external APIs) * - Implementing complex provisioning logic * - Performing custom validations or transformations * - Integrating with third-party services