From e189b326e2b7d63a68983ca26ca8efd6d611d0a9 Mon Sep 17 00:00:00 2001 From: Stephen Firrincieli Date: Thu, 19 Oct 2023 11:09:07 -0400 Subject: [PATCH] Add extension to Lambda handlers using custom runtimes (#219) * Add extension for custom runtimes * Add unit tests * Add integration test for provided_al2 runtime * Add integration test for provided_al2 ARM handler --- ...ct-lambda-provided-arm-stack-snapshot.json | 583 ++++++++++++++++++ ...orrect-lambda-provided-stack-snapshot.json | 580 +++++++++++++++++ ...st-lambda-provided-arm-stack-snapshot.json | 583 ++++++++++++++++++ .../test-lambda-provided-stack-snapshot.json | 580 +++++++++++++++++ .../stacks/lambda-provided-arm-stack.ts | 49 ++ .../stacks/lambda-provided-stack.ts | 48 ++ v2/scripts/run_integration_tests.sh | 2 +- v2/src/constants.ts | 3 + v2/src/redirect.ts | 2 + v2/test/layer.spec.ts | 57 ++ 10 files changed, 2486 insertions(+), 1 deletion(-) create mode 100644 v2/integration_tests/snapshots/correct-lambda-provided-arm-stack-snapshot.json create mode 100644 v2/integration_tests/snapshots/correct-lambda-provided-stack-snapshot.json create mode 100644 v2/integration_tests/snapshots/test-lambda-provided-arm-stack-snapshot.json create mode 100644 v2/integration_tests/snapshots/test-lambda-provided-stack-snapshot.json create mode 100644 v2/integration_tests/stacks/lambda-provided-arm-stack.ts create mode 100644 v2/integration_tests/stacks/lambda-provided-stack.ts diff --git a/v2/integration_tests/snapshots/correct-lambda-provided-arm-stack-snapshot.json b/v2/integration_tests/snapshots/correct-lambda-provided-arm-stack-snapshot.json new file mode 100644 index 000000000..38d8d16c0 --- /dev/null +++ b/v2/integration_tests/snapshots/correct-lambda-provided-arm-stack-snapshot.json @@ -0,0 +1,583 @@ +{ + "Resources": { + "exampleBucketB33BA2C4": { + "Type": "AWS::S3::Bucket", + "Properties": { + "OwnershipControls": { + "Rules": [ + { + "ObjectOwnership": "BucketOwnerEnforced" + } + ] + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/exampleBucket/Resource" + } + }, + "HelloHandlerServiceRoleXXXXXXXX": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/HelloHandler/ServiceRole/Resource" + } + }, + "HelloHandlerServiceRoleXXXXXXXX": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "exampleBucketB33BA2C4", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "exampleBucketB33BA2C4", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "HelloHandlerServiceRoleXXXXXXXX", + "Roles": [ + { + "Ref": "HelloHandlerServiceRoleXXXXXXXX" + } + ] + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/HelloHandler/ServiceRole/DefaultPolicy/Resource" + } + }, + "HelloHandlerXXXXXXXX": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Architectures": [ + "arm64" + ], + "Code": { + "S3Bucket": { + "Ref": "exampleBucketB33BA2C4" + }, + "S3Key": "serverless/dd-cdk-construct-integration-test/dev/XXXXXXXXXXXXX-XXXX-XX-XXXXX:XX:XX.XXXX/dd-cdk-construct-integration-test.zip" + }, + "Environment": { + "Variables": { + "DD_LAMBDA_HANDLER": "handler.handler", + "DD_TRACE_ENABLED": "true", + "DD_SERVERLESS_APPSEC_ENABLED": "false", + "DD_MERGE_XRAY_TRACES": "false", + "DD_LOGS_INJECTION": "false", + "DD_SERVERLESS_LOGS_ENABLED": "true", + "DD_CAPTURE_LAMBDA_PAYLOAD": "false", + "DD_FLUSH_TO_LOG": "false", + "DD_SITE": "datadoghq.com", + "DD_API_KEY": "1234" + } + }, + "Handler": "handler.handler", + "Layers": [ + "arn:aws:lambda:sa-east-1:464622532012:layer:Datadog-Extension-ARM:49" + ], + "Role": { + "Fn::GetAtt": [ + "HelloHandlerServiceRoleXXXXXXXX", + "Arn" + ] + }, + "Runtime": "provided.al2", + "Tags": [ + { + "Key": "dd_cdk_construct", + "Value": "vX.XX.X" + } + ] + }, + "DependsOn": [ + "HelloHandlerServiceRoleXXXXXXXX", + "HelloHandlerServiceRoleXXXXXXXX" + ], + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/HelloHandler/Resource" + } + }, + "restLogGroupXXXXXXXX": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "RetentionInDays": 731 + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/restLogGroup/Resource" + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Name": "rest-test" + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Resource" + } + }, + "resttestCloudWatchRoleXXXXXXXX": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "apigateway.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + ] + } + ] + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/CloudWatchRole/Resource" + } + }, + "resttestAccountXXXXXXXX": { + "Type": "AWS::ApiGateway::Account", + "Properties": { + "CloudWatchRoleArn": { + "Fn::GetAtt": [ + "resttestCloudWatchRoleXXXXXXXX", + "Arn" + ] + } + }, + "DependsOn": [ + "resttestXXXXXXXX" + ], + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Account" + } + }, + "resttestDeploymentXXXXXXXX": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "Description": "Automatically created by the RestApi construct", + "RestApiId": { + "Ref": "resttestXXXXXXXX" + } + }, + "DependsOn": [ + "resttestproxyANYXXXXXXXX", + "resttestproxyXXXXXXXX", + "resttestANYXXXXXXXX" + ], + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Deployment/Resource" + } + }, + "resttestDeploymentStageprodXXXXXXXX": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "AccessLogSetting": { + "DestinationArn": { + "Fn::GetAtt": [ + "restLogGroupXXXXXXXX", + "Arn" + ] + }, + "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" + }, + "DeploymentId": { + "Ref": "resttestDeploymentXXXXXXXX" + }, + "RestApiId": { + "Ref": "resttestXXXXXXXX" + }, + "StageName": "prod" + }, + "DependsOn": [ + "resttestAccountXXXXXXXX" + ], + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/DeploymentStage.prod/Resource" + } + }, + "resttestproxyXXXXXXXX": { + "Type": "AWS::ApiGateway::Resource", + "Properties": { + "ParentId": { + "Fn::GetAtt": [ + "resttestXXXXXXXX", + "RootResourceId" + ] + }, + "PathPart": "{proxy+}", + "RestApiId": { + "Ref": "resttestXXXXXXXX" + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Default/{proxy+}/Resource" + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:sa-east-1:601427279990:", + { + "Ref": "resttestXXXXXXXX" + }, + "/", + { + "Ref": "resttestDeploymentStageprodXXXXXXXX" + }, + "/*/*" + ] + ] + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Default/{proxy+}/ANY/ApiPermission.lambdaprovidedarmstackresttest0907B3D2.ANY..{proxy+}" + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:sa-east-1:601427279990:", + { + "Ref": "resttestXXXXXXXX" + }, + "/test-invoke-stage/*/*" + ] + ] + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Default/{proxy+}/ANY/ApiPermission.Test.lambdaprovidedarmstackresttest0907B3D2.ANY..{proxy+}" + } + }, + "resttestproxyANYXXXXXXXX": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "AuthorizationType": "NONE", + "HttpMethod": "ANY", + "Integration": { + "IntegrationHttpMethod": "POST", + "Type": "AWS_PROXY", + "Uri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:sa-east-1:lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "/invocations" + ] + ] + } + }, + "ResourceId": { + "Ref": "resttestproxyXXXXXXXX" + }, + "RestApiId": { + "Ref": "resttestXXXXXXXX" + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Default/{proxy+}/ANY/Resource" + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:sa-east-1:601427279990:", + { + "Ref": "resttestXXXXXXXX" + }, + "/", + { + "Ref": "resttestDeploymentStageprodXXXXXXXX" + }, + "/*/" + ] + ] + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Default/ANY/ApiPermission.lambdaprovidedarmstackresttest0907B3D2.ANY.." + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:sa-east-1:601427279990:", + { + "Ref": "resttestXXXXXXXX" + }, + "/test-invoke-stage/*/" + ] + ] + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Default/ANY/ApiPermission.Test.lambdaprovidedarmstackresttest0907B3D2.ANY.." + } + }, + "resttestANYXXXXXXXX": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "AuthorizationType": "NONE", + "HttpMethod": "ANY", + "Integration": { + "IntegrationHttpMethod": "POST", + "Type": "AWS_PROXY", + "Uri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:sa-east-1:lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "/invocations" + ] + ] + } + }, + "ResourceId": { + "Fn::GetAtt": [ + "resttestXXXXXXXX", + "RootResourceId" + ] + }, + "RestApiId": { + "Ref": "resttestXXXXXXXX" + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Default/ANY/Resource" + } + }, + "CDKMetadata": { + "Type": "AWS::CDK::Metadata", + "Properties": { + "Analytics": "vX:XXXXXX:XXXXXX" + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/CDKMetadata/Default" + } + } + }, + "Outputs": { + "resttestEndpointXXXXXXXX": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Ref": "resttestXXXXXXXX" + }, + ".execute-api.sa-east-1.", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "resttestDeploymentStageprodXXXXXXXX" + }, + "/" + ] + ] + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/v2/integration_tests/snapshots/correct-lambda-provided-stack-snapshot.json b/v2/integration_tests/snapshots/correct-lambda-provided-stack-snapshot.json new file mode 100644 index 000000000..05f826f2b --- /dev/null +++ b/v2/integration_tests/snapshots/correct-lambda-provided-stack-snapshot.json @@ -0,0 +1,580 @@ +{ + "Resources": { + "exampleBucketB33BA2C4": { + "Type": "AWS::S3::Bucket", + "Properties": { + "OwnershipControls": { + "Rules": [ + { + "ObjectOwnership": "BucketOwnerEnforced" + } + ] + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/exampleBucket/Resource" + } + }, + "HelloHandlerServiceRoleXXXXXXXX": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/HelloHandler/ServiceRole/Resource" + } + }, + "HelloHandlerServiceRoleXXXXXXXX": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "exampleBucketB33BA2C4", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "exampleBucketB33BA2C4", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "HelloHandlerServiceRoleXXXXXXXX", + "Roles": [ + { + "Ref": "HelloHandlerServiceRoleXXXXXXXX" + } + ] + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/HelloHandler/ServiceRole/DefaultPolicy/Resource" + } + }, + "HelloHandlerXXXXXXXX": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "exampleBucketB33BA2C4" + }, + "S3Key": "serverless/dd-cdk-construct-integration-test/dev/XXXXXXXXXXXXX-XXXX-XX-XXXXX:XX:XX.XXXX/dd-cdk-construct-integration-test.zip" + }, + "Environment": { + "Variables": { + "DD_LAMBDA_HANDLER": "handler.handler", + "DD_TRACE_ENABLED": "true", + "DD_SERVERLESS_APPSEC_ENABLED": "false", + "DD_MERGE_XRAY_TRACES": "false", + "DD_LOGS_INJECTION": "false", + "DD_SERVERLESS_LOGS_ENABLED": "true", + "DD_CAPTURE_LAMBDA_PAYLOAD": "false", + "DD_FLUSH_TO_LOG": "false", + "DD_SITE": "datadoghq.com", + "DD_API_KEY": "1234" + } + }, + "Handler": "handler.handler", + "Layers": [ + "arn:aws:lambda:sa-east-1:464622532012:layer:Datadog-Extension:XXX" + ], + "Role": { + "Fn::GetAtt": [ + "HelloHandlerServiceRoleXXXXXXXX", + "Arn" + ] + }, + "Runtime": "provided.al2", + "Tags": [ + { + "Key": "dd_cdk_construct", + "Value": "vX.XX.X" + } + ] + }, + "DependsOn": [ + "HelloHandlerServiceRoleXXXXXXXX", + "HelloHandlerServiceRoleXXXXXXXX" + ], + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/HelloHandler/Resource" + } + }, + "restLogGroupXXXXXXXX": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "RetentionInDays": 731 + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/restLogGroup/Resource" + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Name": "rest-test" + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Resource" + } + }, + "resttestCloudWatchRoleXXXXXXXX": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "apigateway.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + ] + } + ] + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/CloudWatchRole/Resource" + } + }, + "resttestAccountXXXXXXXX": { + "Type": "AWS::ApiGateway::Account", + "Properties": { + "CloudWatchRoleArn": { + "Fn::GetAtt": [ + "resttestCloudWatchRoleXXXXXXXX", + "Arn" + ] + } + }, + "DependsOn": [ + "resttestXXXXXXXX" + ], + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Account" + } + }, + "resttestDeploymentXXXXXXXX": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "Description": "Automatically created by the RestApi construct", + "RestApiId": { + "Ref": "resttestXXXXXXXX" + } + }, + "DependsOn": [ + "resttestproxyANYXXXXXXXX", + "resttestproxyXXXXXXXX", + "resttestANYXXXXXXXX" + ], + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Deployment/Resource" + } + }, + "resttestDeploymentStageprodXXXXXXXX": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "AccessLogSetting": { + "DestinationArn": { + "Fn::GetAtt": [ + "restLogGroupXXXXXXXX", + "Arn" + ] + }, + "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" + }, + "DeploymentId": { + "Ref": "resttestDeploymentXXXXXXXX" + }, + "RestApiId": { + "Ref": "resttestXXXXXXXX" + }, + "StageName": "prod" + }, + "DependsOn": [ + "resttestAccountXXXXXXXX" + ], + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/DeploymentStage.prod/Resource" + } + }, + "resttestproxyXXXXXXXX": { + "Type": "AWS::ApiGateway::Resource", + "Properties": { + "ParentId": { + "Fn::GetAtt": [ + "resttestXXXXXXXX", + "RootResourceId" + ] + }, + "PathPart": "{proxy+}", + "RestApiId": { + "Ref": "resttestXXXXXXXX" + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Default/{proxy+}/Resource" + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:sa-east-1:601427279990:", + { + "Ref": "resttestXXXXXXXX" + }, + "/", + { + "Ref": "resttestDeploymentStageprodXXXXXXXX" + }, + "/*/*" + ] + ] + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Default/{proxy+}/ANY/ApiPermission.lambdaprovidedstackresttest651D1AB2.ANY..{proxy+}" + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:sa-east-1:601427279990:", + { + "Ref": "resttestXXXXXXXX" + }, + "/test-invoke-stage/*/*" + ] + ] + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Default/{proxy+}/ANY/ApiPermission.Test.lambdaprovidedstackresttest651D1AB2.ANY..{proxy+}" + } + }, + "resttestproxyANYXXXXXXXX": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "AuthorizationType": "NONE", + "HttpMethod": "ANY", + "Integration": { + "IntegrationHttpMethod": "POST", + "Type": "AWS_PROXY", + "Uri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:sa-east-1:lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "/invocations" + ] + ] + } + }, + "ResourceId": { + "Ref": "resttestproxyXXXXXXXX" + }, + "RestApiId": { + "Ref": "resttestXXXXXXXX" + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Default/{proxy+}/ANY/Resource" + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:sa-east-1:601427279990:", + { + "Ref": "resttestXXXXXXXX" + }, + "/", + { + "Ref": "resttestDeploymentStageprodXXXXXXXX" + }, + "/*/" + ] + ] + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Default/ANY/ApiPermission.lambdaprovidedstackresttest651D1AB2.ANY.." + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:sa-east-1:601427279990:", + { + "Ref": "resttestXXXXXXXX" + }, + "/test-invoke-stage/*/" + ] + ] + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Default/ANY/ApiPermission.Test.lambdaprovidedstackresttest651D1AB2.ANY.." + } + }, + "resttestANYXXXXXXXX": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "AuthorizationType": "NONE", + "HttpMethod": "ANY", + "Integration": { + "IntegrationHttpMethod": "POST", + "Type": "AWS_PROXY", + "Uri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:sa-east-1:lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "/invocations" + ] + ] + } + }, + "ResourceId": { + "Fn::GetAtt": [ + "resttestXXXXXXXX", + "RootResourceId" + ] + }, + "RestApiId": { + "Ref": "resttestXXXXXXXX" + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Default/ANY/Resource" + } + }, + "CDKMetadata": { + "Type": "AWS::CDK::Metadata", + "Properties": { + "Analytics": "vX:XXXXXX:XXXXXX" + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/CDKMetadata/Default" + } + } + }, + "Outputs": { + "resttestEndpointXXXXXXXX": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Ref": "resttestXXXXXXXX" + }, + ".execute-api.sa-east-1.", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "resttestDeploymentStageprodXXXXXXXX" + }, + "/" + ] + ] + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/v2/integration_tests/snapshots/test-lambda-provided-arm-stack-snapshot.json b/v2/integration_tests/snapshots/test-lambda-provided-arm-stack-snapshot.json new file mode 100644 index 000000000..38d8d16c0 --- /dev/null +++ b/v2/integration_tests/snapshots/test-lambda-provided-arm-stack-snapshot.json @@ -0,0 +1,583 @@ +{ + "Resources": { + "exampleBucketB33BA2C4": { + "Type": "AWS::S3::Bucket", + "Properties": { + "OwnershipControls": { + "Rules": [ + { + "ObjectOwnership": "BucketOwnerEnforced" + } + ] + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/exampleBucket/Resource" + } + }, + "HelloHandlerServiceRoleXXXXXXXX": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/HelloHandler/ServiceRole/Resource" + } + }, + "HelloHandlerServiceRoleXXXXXXXX": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "exampleBucketB33BA2C4", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "exampleBucketB33BA2C4", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "HelloHandlerServiceRoleXXXXXXXX", + "Roles": [ + { + "Ref": "HelloHandlerServiceRoleXXXXXXXX" + } + ] + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/HelloHandler/ServiceRole/DefaultPolicy/Resource" + } + }, + "HelloHandlerXXXXXXXX": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Architectures": [ + "arm64" + ], + "Code": { + "S3Bucket": { + "Ref": "exampleBucketB33BA2C4" + }, + "S3Key": "serverless/dd-cdk-construct-integration-test/dev/XXXXXXXXXXXXX-XXXX-XX-XXXXX:XX:XX.XXXX/dd-cdk-construct-integration-test.zip" + }, + "Environment": { + "Variables": { + "DD_LAMBDA_HANDLER": "handler.handler", + "DD_TRACE_ENABLED": "true", + "DD_SERVERLESS_APPSEC_ENABLED": "false", + "DD_MERGE_XRAY_TRACES": "false", + "DD_LOGS_INJECTION": "false", + "DD_SERVERLESS_LOGS_ENABLED": "true", + "DD_CAPTURE_LAMBDA_PAYLOAD": "false", + "DD_FLUSH_TO_LOG": "false", + "DD_SITE": "datadoghq.com", + "DD_API_KEY": "1234" + } + }, + "Handler": "handler.handler", + "Layers": [ + "arn:aws:lambda:sa-east-1:464622532012:layer:Datadog-Extension-ARM:49" + ], + "Role": { + "Fn::GetAtt": [ + "HelloHandlerServiceRoleXXXXXXXX", + "Arn" + ] + }, + "Runtime": "provided.al2", + "Tags": [ + { + "Key": "dd_cdk_construct", + "Value": "vX.XX.X" + } + ] + }, + "DependsOn": [ + "HelloHandlerServiceRoleXXXXXXXX", + "HelloHandlerServiceRoleXXXXXXXX" + ], + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/HelloHandler/Resource" + } + }, + "restLogGroupXXXXXXXX": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "RetentionInDays": 731 + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/restLogGroup/Resource" + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Name": "rest-test" + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Resource" + } + }, + "resttestCloudWatchRoleXXXXXXXX": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "apigateway.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + ] + } + ] + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/CloudWatchRole/Resource" + } + }, + "resttestAccountXXXXXXXX": { + "Type": "AWS::ApiGateway::Account", + "Properties": { + "CloudWatchRoleArn": { + "Fn::GetAtt": [ + "resttestCloudWatchRoleXXXXXXXX", + "Arn" + ] + } + }, + "DependsOn": [ + "resttestXXXXXXXX" + ], + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Account" + } + }, + "resttestDeploymentXXXXXXXX": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "Description": "Automatically created by the RestApi construct", + "RestApiId": { + "Ref": "resttestXXXXXXXX" + } + }, + "DependsOn": [ + "resttestproxyANYXXXXXXXX", + "resttestproxyXXXXXXXX", + "resttestANYXXXXXXXX" + ], + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Deployment/Resource" + } + }, + "resttestDeploymentStageprodXXXXXXXX": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "AccessLogSetting": { + "DestinationArn": { + "Fn::GetAtt": [ + "restLogGroupXXXXXXXX", + "Arn" + ] + }, + "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" + }, + "DeploymentId": { + "Ref": "resttestDeploymentXXXXXXXX" + }, + "RestApiId": { + "Ref": "resttestXXXXXXXX" + }, + "StageName": "prod" + }, + "DependsOn": [ + "resttestAccountXXXXXXXX" + ], + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/DeploymentStage.prod/Resource" + } + }, + "resttestproxyXXXXXXXX": { + "Type": "AWS::ApiGateway::Resource", + "Properties": { + "ParentId": { + "Fn::GetAtt": [ + "resttestXXXXXXXX", + "RootResourceId" + ] + }, + "PathPart": "{proxy+}", + "RestApiId": { + "Ref": "resttestXXXXXXXX" + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Default/{proxy+}/Resource" + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:sa-east-1:601427279990:", + { + "Ref": "resttestXXXXXXXX" + }, + "/", + { + "Ref": "resttestDeploymentStageprodXXXXXXXX" + }, + "/*/*" + ] + ] + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Default/{proxy+}/ANY/ApiPermission.lambdaprovidedarmstackresttest0907B3D2.ANY..{proxy+}" + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:sa-east-1:601427279990:", + { + "Ref": "resttestXXXXXXXX" + }, + "/test-invoke-stage/*/*" + ] + ] + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Default/{proxy+}/ANY/ApiPermission.Test.lambdaprovidedarmstackresttest0907B3D2.ANY..{proxy+}" + } + }, + "resttestproxyANYXXXXXXXX": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "AuthorizationType": "NONE", + "HttpMethod": "ANY", + "Integration": { + "IntegrationHttpMethod": "POST", + "Type": "AWS_PROXY", + "Uri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:sa-east-1:lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "/invocations" + ] + ] + } + }, + "ResourceId": { + "Ref": "resttestproxyXXXXXXXX" + }, + "RestApiId": { + "Ref": "resttestXXXXXXXX" + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Default/{proxy+}/ANY/Resource" + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:sa-east-1:601427279990:", + { + "Ref": "resttestXXXXXXXX" + }, + "/", + { + "Ref": "resttestDeploymentStageprodXXXXXXXX" + }, + "/*/" + ] + ] + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Default/ANY/ApiPermission.lambdaprovidedarmstackresttest0907B3D2.ANY.." + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:sa-east-1:601427279990:", + { + "Ref": "resttestXXXXXXXX" + }, + "/test-invoke-stage/*/" + ] + ] + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Default/ANY/ApiPermission.Test.lambdaprovidedarmstackresttest0907B3D2.ANY.." + } + }, + "resttestANYXXXXXXXX": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "AuthorizationType": "NONE", + "HttpMethod": "ANY", + "Integration": { + "IntegrationHttpMethod": "POST", + "Type": "AWS_PROXY", + "Uri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:sa-east-1:lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "/invocations" + ] + ] + } + }, + "ResourceId": { + "Fn::GetAtt": [ + "resttestXXXXXXXX", + "RootResourceId" + ] + }, + "RestApiId": { + "Ref": "resttestXXXXXXXX" + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/rest-test/Default/ANY/Resource" + } + }, + "CDKMetadata": { + "Type": "AWS::CDK::Metadata", + "Properties": { + "Analytics": "vX:XXXXXX:XXXXXX" + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-arm-stack/CDKMetadata/Default" + } + } + }, + "Outputs": { + "resttestEndpointXXXXXXXX": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Ref": "resttestXXXXXXXX" + }, + ".execute-api.sa-east-1.", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "resttestDeploymentStageprodXXXXXXXX" + }, + "/" + ] + ] + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/v2/integration_tests/snapshots/test-lambda-provided-stack-snapshot.json b/v2/integration_tests/snapshots/test-lambda-provided-stack-snapshot.json new file mode 100644 index 000000000..05f826f2b --- /dev/null +++ b/v2/integration_tests/snapshots/test-lambda-provided-stack-snapshot.json @@ -0,0 +1,580 @@ +{ + "Resources": { + "exampleBucketB33BA2C4": { + "Type": "AWS::S3::Bucket", + "Properties": { + "OwnershipControls": { + "Rules": [ + { + "ObjectOwnership": "BucketOwnerEnforced" + } + ] + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/exampleBucket/Resource" + } + }, + "HelloHandlerServiceRoleXXXXXXXX": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/HelloHandler/ServiceRole/Resource" + } + }, + "HelloHandlerServiceRoleXXXXXXXX": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "exampleBucketB33BA2C4", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "exampleBucketB33BA2C4", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "HelloHandlerServiceRoleXXXXXXXX", + "Roles": [ + { + "Ref": "HelloHandlerServiceRoleXXXXXXXX" + } + ] + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/HelloHandler/ServiceRole/DefaultPolicy/Resource" + } + }, + "HelloHandlerXXXXXXXX": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "exampleBucketB33BA2C4" + }, + "S3Key": "serverless/dd-cdk-construct-integration-test/dev/XXXXXXXXXXXXX-XXXX-XX-XXXXX:XX:XX.XXXX/dd-cdk-construct-integration-test.zip" + }, + "Environment": { + "Variables": { + "DD_LAMBDA_HANDLER": "handler.handler", + "DD_TRACE_ENABLED": "true", + "DD_SERVERLESS_APPSEC_ENABLED": "false", + "DD_MERGE_XRAY_TRACES": "false", + "DD_LOGS_INJECTION": "false", + "DD_SERVERLESS_LOGS_ENABLED": "true", + "DD_CAPTURE_LAMBDA_PAYLOAD": "false", + "DD_FLUSH_TO_LOG": "false", + "DD_SITE": "datadoghq.com", + "DD_API_KEY": "1234" + } + }, + "Handler": "handler.handler", + "Layers": [ + "arn:aws:lambda:sa-east-1:464622532012:layer:Datadog-Extension:XXX" + ], + "Role": { + "Fn::GetAtt": [ + "HelloHandlerServiceRoleXXXXXXXX", + "Arn" + ] + }, + "Runtime": "provided.al2", + "Tags": [ + { + "Key": "dd_cdk_construct", + "Value": "vX.XX.X" + } + ] + }, + "DependsOn": [ + "HelloHandlerServiceRoleXXXXXXXX", + "HelloHandlerServiceRoleXXXXXXXX" + ], + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/HelloHandler/Resource" + } + }, + "restLogGroupXXXXXXXX": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "RetentionInDays": 731 + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/restLogGroup/Resource" + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Name": "rest-test" + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Resource" + } + }, + "resttestCloudWatchRoleXXXXXXXX": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "apigateway.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + ] + } + ] + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/CloudWatchRole/Resource" + } + }, + "resttestAccountXXXXXXXX": { + "Type": "AWS::ApiGateway::Account", + "Properties": { + "CloudWatchRoleArn": { + "Fn::GetAtt": [ + "resttestCloudWatchRoleXXXXXXXX", + "Arn" + ] + } + }, + "DependsOn": [ + "resttestXXXXXXXX" + ], + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Account" + } + }, + "resttestDeploymentXXXXXXXX": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "Description": "Automatically created by the RestApi construct", + "RestApiId": { + "Ref": "resttestXXXXXXXX" + } + }, + "DependsOn": [ + "resttestproxyANYXXXXXXXX", + "resttestproxyXXXXXXXX", + "resttestANYXXXXXXXX" + ], + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Deployment/Resource" + } + }, + "resttestDeploymentStageprodXXXXXXXX": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "AccessLogSetting": { + "DestinationArn": { + "Fn::GetAtt": [ + "restLogGroupXXXXXXXX", + "Arn" + ] + }, + "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" + }, + "DeploymentId": { + "Ref": "resttestDeploymentXXXXXXXX" + }, + "RestApiId": { + "Ref": "resttestXXXXXXXX" + }, + "StageName": "prod" + }, + "DependsOn": [ + "resttestAccountXXXXXXXX" + ], + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/DeploymentStage.prod/Resource" + } + }, + "resttestproxyXXXXXXXX": { + "Type": "AWS::ApiGateway::Resource", + "Properties": { + "ParentId": { + "Fn::GetAtt": [ + "resttestXXXXXXXX", + "RootResourceId" + ] + }, + "PathPart": "{proxy+}", + "RestApiId": { + "Ref": "resttestXXXXXXXX" + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Default/{proxy+}/Resource" + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:sa-east-1:601427279990:", + { + "Ref": "resttestXXXXXXXX" + }, + "/", + { + "Ref": "resttestDeploymentStageprodXXXXXXXX" + }, + "/*/*" + ] + ] + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Default/{proxy+}/ANY/ApiPermission.lambdaprovidedstackresttest651D1AB2.ANY..{proxy+}" + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:sa-east-1:601427279990:", + { + "Ref": "resttestXXXXXXXX" + }, + "/test-invoke-stage/*/*" + ] + ] + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Default/{proxy+}/ANY/ApiPermission.Test.lambdaprovidedstackresttest651D1AB2.ANY..{proxy+}" + } + }, + "resttestproxyANYXXXXXXXX": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "AuthorizationType": "NONE", + "HttpMethod": "ANY", + "Integration": { + "IntegrationHttpMethod": "POST", + "Type": "AWS_PROXY", + "Uri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:sa-east-1:lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "/invocations" + ] + ] + } + }, + "ResourceId": { + "Ref": "resttestproxyXXXXXXXX" + }, + "RestApiId": { + "Ref": "resttestXXXXXXXX" + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Default/{proxy+}/ANY/Resource" + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:sa-east-1:601427279990:", + { + "Ref": "resttestXXXXXXXX" + }, + "/", + { + "Ref": "resttestDeploymentStageprodXXXXXXXX" + }, + "/*/" + ] + ] + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Default/ANY/ApiPermission.lambdaprovidedstackresttest651D1AB2.ANY.." + } + }, + "resttestXXXXXXXX": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:sa-east-1:601427279990:", + { + "Ref": "resttestXXXXXXXX" + }, + "/test-invoke-stage/*/" + ] + ] + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Default/ANY/ApiPermission.Test.lambdaprovidedstackresttest651D1AB2.ANY.." + } + }, + "resttestANYXXXXXXXX": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "AuthorizationType": "NONE", + "HttpMethod": "ANY", + "Integration": { + "IntegrationHttpMethod": "POST", + "Type": "AWS_PROXY", + "Uri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:sa-east-1:lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "HelloHandlerXXXXXXXX", + "Arn" + ] + }, + "/invocations" + ] + ] + } + }, + "ResourceId": { + "Fn::GetAtt": [ + "resttestXXXXXXXX", + "RootResourceId" + ] + }, + "RestApiId": { + "Ref": "resttestXXXXXXXX" + } + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/rest-test/Default/ANY/Resource" + } + }, + "CDKMetadata": { + "Type": "AWS::CDK::Metadata", + "Properties": { + "Analytics": "vX:XXXXXX:XXXXXX" + }, + "Metadata": { + "aws:cdk:path": "lambda-provided-stack/CDKMetadata/Default" + } + } + }, + "Outputs": { + "resttestEndpointXXXXXXXX": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Ref": "resttestXXXXXXXX" + }, + ".execute-api.sa-east-1.", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "resttestDeploymentStageprodXXXXXXXX" + }, + "/" + ] + ] + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/v2/integration_tests/stacks/lambda-provided-arm-stack.ts b/v2/integration_tests/stacks/lambda-provided-arm-stack.ts new file mode 100644 index 000000000..868d70128 --- /dev/null +++ b/v2/integration_tests/stacks/lambda-provided-arm-stack.ts @@ -0,0 +1,49 @@ +import * as lambda from "aws-cdk-lib/aws-lambda"; +import * as s3 from "aws-cdk-lib/aws-s3"; +import { LambdaRestApi, LogGroupLogDestination } from "aws-cdk-lib/aws-apigateway"; +import { LogGroup } from "aws-cdk-lib/aws-logs"; +import { Stack, StackProps, App } from "aws-cdk-lib"; +import { Datadog } from "../../src/index"; + +export class ExampleStack extends Stack { + constructor(scope: App, id: string, props?: StackProps) { + super(scope, id, props); + + const s3Bucket = new s3.Bucket(this, "exampleBucket", { + objectOwnership: s3.ObjectOwnership.BUCKET_OWNER_ENFORCED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + }); + + const providedLambda = new lambda.Function(this, "HelloHandler", { + runtime: lambda.Runtime.PROVIDED_AL2, + code: lambda.Code.fromBucket(s3Bucket, "fake-key-for-test"), + handler: "handler.handler", + architecture: lambda.Architecture.ARM_64, + }); + + s3Bucket.grantRead(providedLambda); + + const restLogGroup = new LogGroup(this, "restLogGroup"); + new LambdaRestApi(this, "rest-test", { + handler: providedLambda, + deployOptions: { + accessLogDestination: new LogGroupLogDestination(restLogGroup), + }, + }); + + const datadogCDK = new Datadog(this, "Datadog", { + extensionLayerVersion: 49, + apiKey: "1234", + site: "datadoghq.com", + sourceCodeIntegration: false, + }); + datadogCDK.addLambdaFunctions([providedLambda]); + datadogCDK.addForwarderToNonLambdaLogGroups([restLogGroup]); + } +} + +const app = new App(); +const env = { account: "601427279990", region: "sa-east-1" }; +const stack = new ExampleStack(app, "lambda-provided-arm-stack", { env: env }); +console.log("Stack name: " + stack.stackName); +app.synth(); diff --git a/v2/integration_tests/stacks/lambda-provided-stack.ts b/v2/integration_tests/stacks/lambda-provided-stack.ts new file mode 100644 index 000000000..7d27bb7ca --- /dev/null +++ b/v2/integration_tests/stacks/lambda-provided-stack.ts @@ -0,0 +1,48 @@ +import * as lambda from "aws-cdk-lib/aws-lambda"; +import * as s3 from "aws-cdk-lib/aws-s3"; +import { LambdaRestApi, LogGroupLogDestination } from "aws-cdk-lib/aws-apigateway"; +import { LogGroup } from "aws-cdk-lib/aws-logs"; +import { Stack, StackProps, App } from "aws-cdk-lib"; +import { Datadog } from "../../src/index"; + +export class ExampleStack extends Stack { + constructor(scope: App, id: string, props?: StackProps) { + super(scope, id, props); + + const s3Bucket = new s3.Bucket(this, "exampleBucket", { + objectOwnership: s3.ObjectOwnership.BUCKET_OWNER_ENFORCED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + }); + + const providedLambda = new lambda.Function(this, "HelloHandler", { + runtime: lambda.Runtime.PROVIDED_AL2, + code: lambda.Code.fromBucket(s3Bucket, "fake-key-for-test"), + handler: "handler.handler", + }); + + s3Bucket.grantRead(providedLambda); + + const restLogGroup = new LogGroup(this, "restLogGroup"); + new LambdaRestApi(this, "rest-test", { + handler: providedLambda, + deployOptions: { + accessLogDestination: new LogGroupLogDestination(restLogGroup), + }, + }); + + const datadogCDK = new Datadog(this, "Datadog", { + extensionLayerVersion: 49, + apiKey: "1234", + site: "datadoghq.com", + sourceCodeIntegration: false, + }); + datadogCDK.addLambdaFunctions([providedLambda]); + datadogCDK.addForwarderToNonLambdaLogGroups([restLogGroup]); + } +} + +const app = new App(); +const env = { account: "601427279990", region: "sa-east-1" }; +const stack = new ExampleStack(app, "lambda-provided-stack", { env: env }); +console.log("Stack name: " + stack.stackName); +app.synth(); diff --git a/v2/scripts/run_integration_tests.sh b/v2/scripts/run_integration_tests.sh index 544578715..05bc13c4c 100755 --- a/v2/scripts/run_integration_tests.sh +++ b/v2/scripts/run_integration_tests.sh @@ -11,7 +11,7 @@ set -e # To add new tests create a new ts file in the 'integration_tests/stacks' directory, append its file name to the STACK_CONFIGS array. # Note: Each ts file will have its respective snapshot built in the snapshots directory, e.g. lambda-function-stack.ts # will generate both snapshots/test-lambda-function-stack-snapshot.json and snapshots/correct-lambda-function-stack-snapshot.json -STACK_CONFIGS=("lambda-singleton-function-stack" "lambda-function-arm-stack" "lambda-function-stack" "lambda-nodejs-function-stack" "lambda-python-function-stack" "lambda-java-function-stack") +STACK_CONFIGS=("lambda-provided-stack" "lambda-provided-arm-stack" "lambda-singleton-function-stack" "lambda-function-arm-stack" "lambda-function-stack" "lambda-nodejs-function-stack" "lambda-python-function-stack" "lambda-java-function-stack") SCRIPT_PATH=${BASH_SOURCE[0]} SCRIPTS_DIR=$(dirname $SCRIPT_PATH) diff --git a/v2/src/constants.ts b/v2/src/constants.ts index 8ba54d7bd..4dcb64246 100644 --- a/v2/src/constants.ts +++ b/v2/src/constants.ts @@ -22,6 +22,7 @@ export enum RuntimeType { NODE, PYTHON, JAVA, + CUSTOM, UNSUPPORTED, } @@ -60,6 +61,8 @@ export const runtimeLookup: { [key: string]: RuntimeType } = { "java8.al2": RuntimeType.JAVA, "java11": RuntimeType.JAVA, "java17": RuntimeType.JAVA, + "provided": RuntimeType.CUSTOM, + "provided.al2": RuntimeType.CUSTOM, }; export const runtimeToLayerName: { [key: string]: string } = { diff --git a/v2/src/redirect.ts b/v2/src/redirect.ts index a778cb0fa..803de976c 100644 --- a/v2/src/redirect.ts +++ b/v2/src/redirect.ts @@ -62,6 +62,8 @@ function getDDHandler(lambdaRuntime: RuntimeType, addLayers: boolean) { return addLayers ? JS_HANDLER_WITH_LAYERS : JS_HANDLER; case RuntimeType.PYTHON: return PYTHON_HANDLER; + case RuntimeType.CUSTOM: + return null; case RuntimeType.JAVA: return null; } diff --git a/v2/test/layer.spec.ts b/v2/test/layer.spec.ts index 595a41446..e36daf887 100644 --- a/v2/test/layer.spec.ts +++ b/v2/test/layer.spec.ts @@ -262,6 +262,63 @@ describe("applyLayers", () => { }); }); + it("adds extension layer to provided runtime", () => { + const app = new App(); + const stack = new Stack(app, "stack", { + env: { + region: "us-west-2", + }, + }); + const hello = new lambda.Function(stack, "HelloHandler", { + runtime: lambda.Runtime.PROVIDED_AL2, + code: lambda.Code.fromAsset("test"), + handler: "hello.handler", + }); + const datadogCdk = new Datadog(stack, "Datadog", { + extensionLayerVersion: EXTENSION_LAYER_VERSION, + apiKmsKey: "1234", + addLayers: true, + enableDatadogTracing: false, + flushMetricsToLogs: true, + site: "datadoghq.com", + }); + datadogCdk.addLambdaFunctions([hello]); + + Template.fromStack(stack).hasResourceProperties("AWS::Lambda::Function", { + Layers: [`arn:aws:lambda:${stack.region}:${DD_ACCOUNT_ID}:layer:Datadog-Extension:${EXTENSION_LAYER_VERSION}`], + }); + }); + + it("adds extension ARM layer to provided runtime using ARM", () => { + const app = new App(); + const stack = new Stack(app, "stack", { + env: { + region: "us-west-2", + }, + }); + const hello = new lambda.Function(stack, "HelloHandler", { + runtime: lambda.Runtime.PROVIDED_AL2, + code: lambda.Code.fromAsset("test"), + handler: "hello.handler", + architecture: lambda.Architecture.ARM_64, + }); + const datadogCdk = new Datadog(stack, "Datadog", { + extensionLayerVersion: EXTENSION_LAYER_VERSION, + apiKmsKey: "1234", + addLayers: true, + enableDatadogTracing: false, + flushMetricsToLogs: true, + site: "datadoghq.com", + }); + datadogCdk.addLambdaFunctions([hello]); + + Template.fromStack(stack).hasResourceProperties("AWS::Lambda::Function", { + Layers: [ + `arn:aws:lambda:${stack.region}:${DD_ACCOUNT_ID}:layer:Datadog-Extension-ARM:${EXTENSION_LAYER_VERSION}`, + ], + }); + }); + it("doesn't add layer to container image Lambda with extension and layer versions", () => { const app = new App(); const stack = new Stack(app, "stack", {