diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/apiDefaultTestDeployAssert018781F2.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/apiDefaultTestDeployAssert018781F2.assets.json new file mode 100644 index 0000000000000..b64db41dec007 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/apiDefaultTestDeployAssert018781F2.assets.json @@ -0,0 +1,20 @@ +{ + "version": "48.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "apiDefaultTestDeployAssert018781F2 Template", + "source": { + "path": "apiDefaultTestDeployAssert018781F2.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region-d8d86b35": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/apiDefaultTestDeployAssert018781F2.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/apiDefaultTestDeployAssert018781F2.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/apiDefaultTestDeployAssert018781F2.template.json @@ -0,0 +1,36 @@ +{ + "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/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/cdk.out new file mode 100644 index 0000000000000..523a9aac37cbf --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"48.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/integ.json new file mode 100644 index 0000000000000..a3b66ad1faa2e --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "48.0.0", + "testCases": { + "api/DefaultTest": { + "stacks": [ + "stack" + ], + "assertionStack": "api/DefaultTest/DeployAssert", + "assertionStackName": "apiDefaultTestDeployAssert018781F2" + } + }, + "minimumCliVersion": "2.1027.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/manifest.json new file mode 100644 index 0000000000000..8c10f914c3f86 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/manifest.json @@ -0,0 +1,633 @@ +{ + "version": "48.0.0", + "artifacts": { + "stack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "stack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "stack.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/5978e43c234e3aadc6878c3aaa6db36536a016b2746f164fc1576568340ce0ab.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "stack.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "stack.assets" + ], + "metadata": { + "/stack/EnhancedMetrics": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "name": "*", + "definition": "*" + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addSchemaDependency": [ + "*" + ] + } + } + ], + "/stack/EnhancedMetrics/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "EnhancedMetricsBBD0CBEA" + } + ], + "/stack/EnhancedMetrics/Schema": [ + { + "type": "aws:cdk:logicalId", + "data": "EnhancedMetricsSchema3325364E" + } + ], + "/stack/EnhancedMetrics/DefaultApiKey": [ + { + "type": "aws:cdk:logicalId", + "data": "EnhancedMetricsDefaultApiKey7D8F4837" + } + ], + "/stack/EnhancedMetrics/none/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "EnhancedMetricsnoneEB4FD168" + } + ], + "/stack/EnhancedMetrics/QuerygetServiceVersion/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "EnhancedMetricsQuerygetServiceVersionD7E03714" + } + ], + "/stack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/stack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "stack" + }, + "apiDefaultTestDeployAssert018781F2.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "apiDefaultTestDeployAssert018781F2.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "apiDefaultTestDeployAssert018781F2": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "apiDefaultTestDeployAssert018781F2.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "apiDefaultTestDeployAssert018781F2.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "apiDefaultTestDeployAssert018781F2.assets" + ], + "metadata": { + "/api/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/api/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "api/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "aws-cdk-lib/feature-flag-report": { + "type": "cdk:feature-flag-report", + "properties": { + "module": "aws-cdk-lib", + "flags": { + "@aws-cdk/aws-signer:signingProfileNamePassedToCfn": { + "recommendedValue": true, + "explanation": "Pass signingProfileName to CfnSigningProfile" + }, + "@aws-cdk/core:newStyleStackSynthesis": { + "recommendedValue": true, + "explanation": "Switch to new stack synthesis method which enables CI/CD", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:stackRelativeExports": { + "recommendedValue": true, + "explanation": "Name exports based on the construct paths relative to the stack, rather than the global construct path", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-ecs-patterns:secGroupsDisablesImplicitOpenListener": { + "recommendedValue": true, + "explanation": "Disable implicit openListener when custom security groups are provided" + }, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": { + "recommendedValue": true, + "explanation": "Force lowercasing of RDS Cluster names in CDK", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": { + "recommendedValue": true, + "explanation": "Allow adding/removing multiple UsagePlanKeys independently", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-lambda:recognizeVersionProps": { + "recommendedValue": true, + "explanation": "Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-lambda:recognizeLayerVersion": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`." + }, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": { + "recommendedValue": true, + "explanation": "Enable this feature flag to have cloudfront distributions use the security policy TLSv1.2_2021 by default.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:checkSecretUsage": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this flag to make it impossible to accidentally use SecretValues in unsafe locations" + }, + "@aws-cdk/core:target-partitions": { + "recommendedValue": [ + "aws", + "aws-cn" + ], + "explanation": "What regions to include in lookup tables of environment agnostic stacks" + }, + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": { + "userValue": true, + "recommendedValue": true, + "explanation": "ECS extensions will automatically add an `awslogs` driver if no logging is specified" + }, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to have Launch Templates generated by the `InstanceRequireImdsv2Aspect` use unique names." + }, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": { + "userValue": true, + "recommendedValue": true, + "explanation": "ARN format used by ECS. In the new ARN format, the cluster name is part of the resource ID." + }, + "@aws-cdk/aws-iam:minimizePolicies": { + "userValue": true, + "recommendedValue": true, + "explanation": "Minimize IAM policies by combining Statements" + }, + "@aws-cdk/core:validateSnapshotRemovalPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Error on snapshot removal policies on resources that do not support it." + }, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate key aliases that include the stack name" + }, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to create an S3 bucket policy by default in cases where an AWS service would automatically create the Policy if one does not exist." + }, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": { + "userValue": true, + "recommendedValue": true, + "explanation": "Restrict KMS key policy for encrypted Queues a bit more" + }, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": { + "userValue": true, + "recommendedValue": true, + "explanation": "Make default CloudWatch Role behavior safe for multiple API Gateways in one environment" + }, + "@aws-cdk/core:enablePartitionLiterals": { + "userValue": true, + "recommendedValue": true, + "explanation": "Make ARNs concrete if AWS partition is known" + }, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": { + "userValue": true, + "recommendedValue": true, + "explanation": "Event Rules may only push to encrypted SQS queues in the same account" + }, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": { + "userValue": true, + "recommendedValue": true, + "explanation": "Avoid setting the \"ECS\" deployment controller when adding a circuit breaker" + }, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature to by default create default policy names for imported roles that depend on the stack the role is in." + }, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use S3 Bucket Policy instead of ACLs for Server Access Logging" + }, + "@aws-cdk/aws-route53-patters:useCertificate": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use the official `Certificate` resource instead of `DnsValidatedCertificate`" + }, + "@aws-cdk/customresources:installLatestAwsSdkDefault": { + "userValue": false, + "recommendedValue": false, + "explanation": "Whether to install the latest SDK by default in AwsCustomResource" + }, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use unique resource name for Database Proxy" + }, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "Remove CloudWatch alarms from deployment group" + }, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Include authorizer configuration in the calculation of the API deployment logical ID." + }, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": { + "userValue": true, + "recommendedValue": true, + "explanation": "Define user data for a launch template by default when a machine image is provided." + }, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": { + "userValue": true, + "recommendedValue": true, + "explanation": "SecretTargetAttachments uses the ResourcePolicy of the attached Secret." + }, + "@aws-cdk/aws-redshift:columnId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Whether to use an ID to track Redshift column changes" + }, + "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable AmazonEMRServicePolicy_v2 managed policies" + }, + "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "Restrict access to the VPC default security group" + }, + "@aws-cdk/aws-apigateway:requestValidatorUniqueId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate a unique id for each RequestValidator added to a method" + }, + "@aws-cdk/aws-kms:aliasNameRef": { + "userValue": true, + "recommendedValue": true, + "explanation": "KMS Alias name and keyArn will have implicit reference to KMS Key" + }, + "@aws-cdk/aws-kms:applyImportedAliasPermissionsToPrincipal": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable grant methods on Aliases imported by name to use kms:ResourceAliases condition" + }, + "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate a launch template when creating an AutoScalingGroup" + }, + "@aws-cdk/core:includePrefixInUniqueNameGeneration": { + "userValue": true, + "recommendedValue": true, + "explanation": "Include the stack prefix in the stack name generation process" + }, + "@aws-cdk/aws-efs:denyAnonymousAccess": { + "userValue": true, + "recommendedValue": true, + "explanation": "EFS denies anonymous clients accesses" + }, + "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables support for Multi-AZ with Standby deployment for opensearch domains" + }, + "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables aws-lambda-nodejs.Function to use the latest available NodeJs runtime as the default" + }, + "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, mount targets will have a stable logicalId that is linked to the associated subnet." + }, + "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, a scope of InstanceParameterGroup for AuroraClusterInstance with each parameters will change." + }, + "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, will always use the arn for identifiers for CfnSourceApiAssociation in the GraphqlApi construct rather than id." + }, + "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, creating an RDS database cluster from a snapshot will only render credentials for snapshot credentials." + }, + "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the CodeCommit source action is using the default branch name 'main'." + }, + "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the logical ID of a Lambda permission for a Lambda action includes an alarm ID." + }, + "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables Pipeline to set the default value for crossAccountKeys to false." + }, + "@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables Pipeline to set the default pipeline type to V2." + }, + "@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, IAM Policy created from KMS key grant will reduce the resource scope to this key only." + }, + "@aws-cdk/pipelines:reduceAssetRoleTrustScope": { + "recommendedValue": true, + "explanation": "Remove the root account principal from PipelineAssetsFileRole trust policy", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-eks:nodegroupNameAttribute": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, nodegroupName attribute of the provisioned EKS NodeGroup will not have the cluster name prefix." + }, + "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default volume type of the EBS volume will be GP3" + }, + "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, remove default deployment alarm settings" + }, + "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": { + "userValue": false, + "recommendedValue": false, + "explanation": "When enabled, the custom resource used for `AwsCustomResource` will configure the `logApiResponseData` property as true by default" + }, + "@aws-cdk/aws-s3:keepNotificationInImportedBucket": { + "userValue": false, + "recommendedValue": false, + "explanation": "When enabled, Adding notifications to a bucket in the current stack will not remove notification from imported stack." + }, + "@aws-cdk/aws-stepfunctions-tasks:useNewS3UriParametersForBedrockInvokeModelTask": { + "recommendedValue": true, + "explanation": "When enabled, use new props for S3 URI field in task definition of state machine for bedrock invoke model.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:explicitStackTags": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, stack tags need to be assigned explicitly on a Stack." + }, + "@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature": { + "userValue": false, + "recommendedValue": false, + "explanation": "When set to true along with canContainersAccessInstanceRole=false in ECS cluster, new updated commands will be added to UserData to block container accessing IMDS. **Applicable to Linux only. IMPORTANT: See [details.](#aws-cdkaws-ecsenableImdsBlockingDeprecatedFeature)**" + }, + "@aws-cdk/aws-ecs:disableEcsImdsBlocking": { + "userValue": true, + "recommendedValue": true, + "explanation": "When set to true, CDK synth will throw exception if canContainersAccessInstanceRole is false. **IMPORTANT: See [details.](#aws-cdkaws-ecsdisableEcsImdsBlocking)**" + }, + "@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, we will only grant the necessary permissions when users specify cloudwatch log group through logConfiguration" + }, + "@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled will allow you to specify a resource policy per replica, and not copy the source table policy to all replicas" + }, + "@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, initOptions.timeout and resourceSignalTimeout values will be summed together." + }, + "@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, a Lambda authorizer Permission created when using GraphqlApi will be properly scoped with a SourceArn." + }, + "@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the value of property `instanceResourceId` in construct `DatabaseInstanceReadReplica` will be set to the correct value which is `DbiResourceId` instead of currently `DbInstanceArn`" + }, + "@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CFN templates added with `cfn-include` will error if the template contains Resource Update or Create policies with CFN Intrinsics that include non-primitive values." + }, + "@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, both `@aws-sdk` and `@smithy` packages will be excluded from the Lambda Node.js 18.x runtime to prevent version mismatches in bundled applications." + }, + "@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the resource of IAM Run Ecs policy generated by SFN EcsRunTask will reference the definition, instead of constructing ARN." + }, + "@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the BastionHost construct will use the latest Amazon Linux 2023 AMI, instead of Amazon Linux 2." + }, + "@aws-cdk/core:aspectStabilization": { + "recommendedValue": true, + "explanation": "When enabled, a stabilization loop will be run when invoking Aspects during synthesis.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, use a new method for DNS Name of user pool domain target without creating a custom resource." + }, + "@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default security group ingress rules will allow IPv6 ingress from anywhere" + }, + "@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default behaviour of OIDC provider will reject unauthorized connections" + }, + "@aws-cdk/core:enableAdditionalMetadataCollection": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK will expand the scope of usage data collected to better inform CDK development and improve communication for security concerns and emerging issues." + }, + "@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": { + "userValue": false, + "recommendedValue": false, + "explanation": "[Deprecated] When enabled, Lambda will create new inline policies with AddToRolePolicy instead of adding to the Default Policy Statement" + }, + "@aws-cdk/aws-s3:setUniqueReplicationRoleName": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK will automatically generate a unique role name that is used for s3 object replication." + }, + "@aws-cdk/pipelines:reduceStageRoleTrustScope": { + "recommendedValue": true, + "explanation": "Remove the root account principal from Stage addActions trust policy", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-events:requireEventBusPolicySid": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, grantPutEventsTo() will use resource policies with Statement IDs for service principals." + }, + "@aws-cdk/core:aspectPrioritiesMutating": { + "userValue": true, + "recommendedValue": true, + "explanation": "When set to true, Aspects added by the construct library on your behalf will be given a priority of MUTATING." + }, + "@aws-cdk/aws-dynamodb:retainTableReplica": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, table replica will be default to the removal policy of source table unless specified otherwise." + }, + "@aws-cdk/cognito:logUserPoolClientSecretValue": { + "recommendedValue": false, + "explanation": "When disabled, the value of the user pool client secret will not be logged in the custom resource lambda function logs." + }, + "@aws-cdk/pipelines:reduceCrossAccountActionRoleTrustScope": { + "recommendedValue": true, + "explanation": "When enabled, scopes down the trust policy for the cross-account action role", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-stepfunctions:useDistributedMapResultWriterV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the resultWriterV2 property of DistributedMap will be used insted of resultWriter" + }, + "@aws-cdk/s3-notifications:addS3TrustKeyPolicyForSnsSubscriptions": { + "userValue": true, + "recommendedValue": true, + "explanation": "Add an S3 trust policy to a KMS key resource policy for SNS subscriptions." + }, + "@aws-cdk/aws-ec2:requirePrivateSubnetsForEgressOnlyInternetGateway": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the EgressOnlyGateway resource is only created if private subnets are defined in the dual-stack VPC." + }, + "@aws-cdk/aws-ec2-alpha:useResourceIdForVpcV2Migration": { + "recommendedValue": false, + "explanation": "When enabled, use resource IDs for VPC V2 migration" + }, + "@aws-cdk/aws-s3:publicAccessBlockedByDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, setting any combination of options for BlockPublicAccess will automatically set true for any options not defined." + }, + "@aws-cdk/aws-lambda:useCdkManagedLogGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK creates and manages loggroup for the lambda function" + } + } + } + } + }, + "minimumCliVersion": "2.1027.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/stack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/stack.assets.json new file mode 100644 index 0000000000000..c2fc789f53d13 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/stack.assets.json @@ -0,0 +1,20 @@ +{ + "version": "48.0.0", + "files": { + "5978e43c234e3aadc6878c3aaa6db36536a016b2746f164fc1576568340ce0ab": { + "displayName": "stack Template", + "source": { + "path": "stack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region-115483fe": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "5978e43c234e3aadc6878c3aaa6db36536a016b2746f164fc1576568340ce0ab.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/stack.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/stack.template.json new file mode 100644 index 0000000000000..74ed421d69ee3 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/stack.template.json @@ -0,0 +1,112 @@ +{ + "Resources": { + "EnhancedMetricsBBD0CBEA": { + "Type": "AWS::AppSync::GraphQLApi", + "Properties": { + "AuthenticationType": "API_KEY", + "EnhancedMetricsConfig": { + "DataSourceLevelMetricsBehavior": "PER_DATA_SOURCE_METRICS", + "OperationLevelMetricsConfig": "ENABLED", + "ResolverLevelMetricsBehavior": "PER_RESOLVER_METRICS" + }, + "Name": "EnhancedMetrics" + } + }, + "EnhancedMetricsSchema3325364E": { + "Type": "AWS::AppSync::GraphQLSchema", + "Properties": { + "ApiId": { + "Fn::GetAtt": [ + "EnhancedMetricsBBD0CBEA", + "ApiId" + ] + }, + "Definition": "type test {\n version: String!\n}\ntype Query {\n getTests: [test]!\n}\ntype Mutation {\n addTest(version: String!): test\n}\n" + } + }, + "EnhancedMetricsDefaultApiKey7D8F4837": { + "Type": "AWS::AppSync::ApiKey", + "Properties": { + "ApiId": { + "Fn::GetAtt": [ + "EnhancedMetricsBBD0CBEA", + "ApiId" + ] + } + }, + "DependsOn": [ + "EnhancedMetricsSchema3325364E" + ] + }, + "EnhancedMetricsnoneEB4FD168": { + "Type": "AWS::AppSync::DataSource", + "Properties": { + "ApiId": { + "Fn::GetAtt": [ + "EnhancedMetricsBBD0CBEA", + "ApiId" + ] + }, + "MetricsConfig": "ENABLED", + "Name": "None", + "Type": "NONE" + } + }, + "EnhancedMetricsQuerygetServiceVersionD7E03714": { + "Type": "AWS::AppSync::Resolver", + "Properties": { + "ApiId": { + "Fn::GetAtt": [ + "EnhancedMetricsBBD0CBEA", + "ApiId" + ] + }, + "DataSourceName": "None", + "FieldName": "getTests", + "Kind": "UNIT", + "MetricsConfig": "ENABLED", + "RequestMappingTemplate": "{\"version\":\"2017-02-28\"}", + "ResponseMappingTemplate": "{\"version\":\"v1\"}", + "TypeName": "Query" + }, + "DependsOn": [ + "EnhancedMetricsnoneEB4FD168", + "EnhancedMetricsSchema3325364E" + ] + } + }, + "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/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/tree.json new file mode 100644 index 0000000000000..8663526781251 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.js.snapshot/tree.json @@ -0,0 +1 @@ +{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"aws-cdk-lib.App","version":"0.0.0"},"children":{"stack":{"id":"stack","path":"stack","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"EnhancedMetrics":{"id":"EnhancedMetrics","path":"stack/EnhancedMetrics","constructInfo":{"fqn":"aws-cdk-lib.aws_appsync.GraphqlApi","version":"0.0.0","metadata":[{"name":"*","definition":"*"},{"addSchemaDependency":["*"]}]},"children":{"Resource":{"id":"Resource","path":"stack/EnhancedMetrics/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_appsync.CfnGraphQLApi","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::AppSync::GraphQLApi","aws:cdk:cloudformation:props":{"authenticationType":"API_KEY","enhancedMetricsConfig":{"dataSourceLevelMetricsBehavior":"PER_DATA_SOURCE_METRICS","operationLevelMetricsConfig":"ENABLED","resolverLevelMetricsBehavior":"PER_RESOLVER_METRICS"},"name":"EnhancedMetrics"}}},"Schema":{"id":"Schema","path":"stack/EnhancedMetrics/Schema","constructInfo":{"fqn":"aws-cdk-lib.aws_appsync.CfnGraphQLSchema","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::AppSync::GraphQLSchema","aws:cdk:cloudformation:props":{"apiId":{"Fn::GetAtt":["EnhancedMetricsBBD0CBEA","ApiId"]},"definition":"type test {\n version: String!\n}\ntype Query {\n getTests: [test]!\n}\ntype Mutation {\n addTest(version: String!): test\n}\n"}}},"DefaultApiKey":{"id":"DefaultApiKey","path":"stack/EnhancedMetrics/DefaultApiKey","constructInfo":{"fqn":"aws-cdk-lib.aws_appsync.CfnApiKey","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::AppSync::ApiKey","aws:cdk:cloudformation:props":{"apiId":{"Fn::GetAtt":["EnhancedMetricsBBD0CBEA","ApiId"]}}}},"LogGroup":{"id":"LogGroup","path":"stack/EnhancedMetrics/LogGroup","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":[]}},"none":{"id":"none","path":"stack/EnhancedMetrics/none","constructInfo":{"fqn":"aws-cdk-lib.aws_appsync.NoneDataSource","version":"0.0.0"},"children":{"Resource":{"id":"Resource","path":"stack/EnhancedMetrics/none/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_appsync.CfnDataSource","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::AppSync::DataSource","aws:cdk:cloudformation:props":{"apiId":{"Fn::GetAtt":["EnhancedMetricsBBD0CBEA","ApiId"]},"metricsConfig":"ENABLED","name":"None","type":"NONE"}}}}},"QuerygetServiceVersion":{"id":"QuerygetServiceVersion","path":"stack/EnhancedMetrics/QuerygetServiceVersion","constructInfo":{"fqn":"aws-cdk-lib.aws_appsync.Resolver","version":"0.0.0"},"children":{"Resource":{"id":"Resource","path":"stack/EnhancedMetrics/QuerygetServiceVersion/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_appsync.CfnResolver","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::AppSync::Resolver","aws:cdk:cloudformation:props":{"apiId":{"Fn::GetAtt":["EnhancedMetricsBBD0CBEA","ApiId"]},"dataSourceName":"None","fieldName":"getTests","kind":"UNIT","metricsConfig":"ENABLED","requestMappingTemplate":"{\"version\":\"2017-02-28\"}","responseMappingTemplate":"{\"version\":\"v1\"}","typeName":"Query"}}}}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"stack/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"stack/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}},"api":{"id":"api","path":"api","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"},"children":{"DefaultTest":{"id":"DefaultTest","path":"api/DefaultTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"},"children":{"Default":{"id":"Default","path":"api/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"api/DefaultTest/DeployAssert","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"api/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"api/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}}}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}}} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.ts new file mode 100644 index 0000000000000..3260d1685621c --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-appsync/test/integ.appsync-enhanced-metrics.ts @@ -0,0 +1,38 @@ +import { join } from 'path'; +import * as cdk from 'aws-cdk-lib'; +import * as appsync from 'aws-cdk-lib/aws-appsync'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'stack'); + +const api = new appsync.GraphqlApi(stack, 'EnhancedMetrics', { + name: 'EnhancedMetrics', + definition: appsync.Definition.fromFile(join(__dirname, 'appsync.test.graphql')), + enhancedMetricsConfig: { + dataSourceLevelMetricsBehavior: appsync.DataSourceLevelMetricsBehavior.PER_DATA_SOURCE_METRICS, + operationLevelMetricsEnabled: true, + resolverLevelMetricsBehavior: appsync.ResolverLevelMetricsBehavior.PER_RESOLVER_METRICS, + }, +}); + +const noneDS = api.addNoneDataSource('none', { + name: 'None', + enhancedMetricsEnabled: true, +}); + +noneDS.createResolver('QuerygetServiceVersion', { + typeName: 'Query', + fieldName: 'getTests', + requestMappingTemplate: appsync.MappingTemplate.fromString(JSON.stringify({ + version: '2017-02-28', + })), + responseMappingTemplate: appsync.MappingTemplate.fromString(JSON.stringify({ + version: 'v1', + })), + enhancedMetricsEnabled: true, +}); + +new IntegTest(app, 'api', { + testCases: [stack], +}); diff --git a/packages/aws-cdk-lib/aws-appsync/README.md b/packages/aws-cdk-lib/aws-appsync/README.md index 5ff80a900112c..fbb270d8f8f3a 100644 --- a/packages/aws-cdk-lib/aws-appsync/README.md +++ b/packages/aws-cdk-lib/aws-appsync/README.md @@ -933,6 +933,48 @@ const api = new appsync.GraphqlApi(this, 'OwnerContact', { }); ``` +### Enhanced Metrics + +Enables and controls the enhanced metrics feature. Enhanced metrics emit granular data on API usage and performance such as AppSync request and error counts, latency, and cache hits/misses. All enhanced metric data is sent to your CloudWatch account, and you can configure the types of data that will be sent. + +```ts +const schema = new appsync.SchemaFile({ filePath: 'mySchemaFile' }) +new appsync.GraphqlApi(this, 'api', { + name: 'myApi', + definition: appsync.Definition.fromSchema(schema), + enhancedMetricsConfig: { + dataSourceLevelMetricsBehavior: appsync.DataSourceLevelMetricsBehavior.FULL_REQUEST_DATA_SOURCE_METRICS, + operationLevelMetricsEnabled: true, + resolverLevelMetricsBehavior: appsync.ResolverLevelMetricsBehavior.FULL_REQUEST_RESOLVER_METRICS, + }, +}); +``` + +If you wish to enable enhanced monitoring only for subset of data sources or resolvers you are use following configuration + +```ts +const schema = new appsync.SchemaFile({ filePath: 'mySchemaFile' }) +const api = new appsync.GraphqlApi(this, 'api', { + name: 'myApi', + definition: appsync.Definition.fromSchema(schema), + enhancedMetricsConfig: { + dataSourceLevelMetricsBehavior: appsync.DataSourceLevelMetricsBehavior.PER_DATA_SOURCE_METRICS, + operationLevelMetricsEnabled: true, + resolverLevelMetricsBehavior: appsync.ResolverLevelMetricsBehavior.PER_RESOLVER_METRICS, + }, +}); + +const noneDS = api.addNoneDataSource('none', { + enhancedMetricsEnabled: true, +}); + +noneDS.createResolver('noneResolver', { + typeName: 'Mutation', + fieldName: 'addDemoMetricsConfig', + enhancedMetricsEnabled: true, +}); +``` + ## Events ### Example diff --git a/packages/aws-cdk-lib/aws-appsync/lib/data-source.ts b/packages/aws-cdk-lib/aws-appsync/lib/data-source.ts index 94a4e8106e12c..6d7caf0165b1d 100644 --- a/packages/aws-cdk-lib/aws-appsync/lib/data-source.ts +++ b/packages/aws-cdk-lib/aws-appsync/lib/data-source.ts @@ -34,6 +34,14 @@ export interface BaseDataSourceProps { * @default - None */ readonly description?: string; + + /** + * Whether to enable enhanced metrics of the data source + * Value will be ignored, if `enhancedMetricsConfig.dataSourceLevelMetricsBehavior` on AppSync GraphqlApi construct is set to `FULL_REQUEST_DATA_SOURCE_METRICS` + * + * @default - Enhance metrics are disabled + */ + readonly enhancedMetricsEnabled?: boolean; } /** @@ -128,11 +136,14 @@ export abstract class BaseDataSource extends Construct { // Replace unsupported characters from DataSource name. The only allowed pattern is: {[_A-Za-z][_0-9A-Za-z]*} const name = (props.name ?? id); const supportedName = Token.isUnresolved(name) ? name : name.replace(/[\W]+/g, ''); + const metricsConfig = props.enhancedMetricsEnabled === undefined ? undefined + : (props.enhancedMetricsEnabled ? 'ENABLED': 'DISABLED'); this.ds = new CfnDataSource(this, 'Resource', { apiId: props.api.apiId, name: supportedName, description: props.description, serviceRoleArn: this.serviceRole?.roleArn, + metricsConfig: metricsConfig, ...extended, }); this.name = supportedName; diff --git a/packages/aws-cdk-lib/aws-appsync/lib/graphqlapi-base.ts b/packages/aws-cdk-lib/aws-appsync/lib/graphqlapi-base.ts index bee46be04dd73..9cd9f13fe4064 100644 --- a/packages/aws-cdk-lib/aws-appsync/lib/graphqlapi-base.ts +++ b/packages/aws-cdk-lib/aws-appsync/lib/graphqlapi-base.ts @@ -37,6 +37,14 @@ export interface DataSourceOptions { * @default - No description */ readonly description?: string; + + /** + * Whether to enable enhanced metrics of the data source + * Value will be ignored, if `enhancedMetricsConfig.dataSourceLevelMetricsBehavior` on AppSync GraphqlApi construct is set to `FULL_REQUEST_DATA_SOURCE_METRICS` + * + * @default - Enhance metrics are disabled + */ + readonly enhancedMetricsEnabled?: boolean; } /** @@ -377,6 +385,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi { api: this, name: options?.name, description: options?.description, + enhancedMetricsEnabled: options?.enhancedMetricsEnabled, }); } @@ -393,6 +402,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi { table, name: options?.name, description: options?.description, + enhancedMetricsEnabled: options?.enhancedMetricsEnabled, }); } @@ -409,6 +419,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi { endpoint, name: options?.name, description: options?.description, + enhancedMetricsEnabled: options?.enhancedMetricsEnabled, authorizationConfig: options?.authorizationConfig, }); } @@ -426,6 +437,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi { lambdaFunction, name: options?.name, description: options?.description, + enhancedMetricsEnabled: options?.enhancedMetricsEnabled, }); } @@ -448,6 +460,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi { api: this, name: options?.name, description: options?.description, + enhancedMetricsEnabled: options?.enhancedMetricsEnabled, serverlessCluster, secretStore, databaseName, @@ -473,6 +486,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi { api: this, name: options?.name, description: options?.description, + enhancedMetricsEnabled: options?.enhancedMetricsEnabled, serverlessCluster, secretStore, databaseName, @@ -492,6 +506,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi { api: this, name: options?.name, description: options?.description, + enhancedMetricsEnabled: options?.enhancedMetricsEnabled, domain, }); } @@ -508,6 +523,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi { eventBus, name: options?.name, description: options?.description, + enhancedMetricsEnabled: options?.enhancedMetricsEnabled, }); } @@ -523,6 +539,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi { api: this, name: options?.name, description: options?.description, + enhancedMetricsEnabled: options?.enhancedMetricsEnabled, domain, }); } diff --git a/packages/aws-cdk-lib/aws-appsync/lib/graphqlapi.ts b/packages/aws-cdk-lib/aws-appsync/lib/graphqlapi.ts index 4f51df490fbd3..1b1d638a0a47b 100644 --- a/packages/aws-cdk-lib/aws-appsync/lib/graphqlapi.ts +++ b/packages/aws-cdk-lib/aws-appsync/lib/graphqlapi.ts @@ -244,6 +244,54 @@ export interface LogConfig { readonly retention?: RetentionDays; } +/** + * Controls how data source metrics will be emitted to CloudWatch. + */ +export enum DataSourceLevelMetricsBehavior { + /** + * Records and emits metric data for all data sources in the request. + */ + FULL_REQUEST_DATA_SOURCE_METRICS = 'FULL_REQUEST_DATA_SOURCE_METRICS', + /** + * Records and emits metric data for data sources that have the MetricsConfig value set to ENABLED. + */ + PER_DATA_SOURCE_METRICS = 'PER_DATA_SOURCE_METRICS', +} + +/** + * Controls how resolver metrics will be emitted to CloudWatch. + */ +export enum ResolverLevelMetricsBehavior { + /** + * Records and emits metric data for all resolvers in the request. + */ + FULL_REQUEST_RESOLVER_METRICS = 'FULL_REQUEST_RESOLVER_METRICS', + /** + * Records and emits metric data for resolvers that have the MetricsConfig value set to ENABLED. + */ + PER_RESOLVER_METRICS = 'PER_RESOLVER_METRICS', +} + +/** + * Enhanced metrics configuration for AppSync + */ +export interface EnhancedMetricsConfig { + /** + * Controls how data source metrics will be emitted to CloudWatch. + */ + readonly dataSourceLevelMetricsBehavior: DataSourceLevelMetricsBehavior; + /** + * Controls how operation metrics will be emitted to CloudWatch. + * + * @default disabled + */ + readonly operationLevelMetricsEnabled?: boolean; + /** + * Controls how resolver metrics will be emitted to CloudWatch. + */ + readonly resolverLevelMetricsBehavior: ResolverLevelMetricsBehavior; +} + /** * Domain name configuration for AppSync */ @@ -450,6 +498,13 @@ export interface GraphqlApiProps { * @default - No owner contact. */ readonly ownerContact?: string; + + /** + * Enables and controls the enhanced metrics feature. + * + * @default - Enhanced metrics disabled. + */ + readonly enhancedMetricsConfig?: EnhancedMetricsConfig; } /** @@ -676,6 +731,7 @@ export class GraphqlApi extends GraphqlApiBase { resolverCountLimit: props.resolverCountLimit, environmentVariables: Lazy.any({ produce: () => this.renderEnvironmentVariables() }), ownerContact: props.ownerContact, + enhancedMetricsConfig: this.setupEnhancedMetricsConfig(props.enhancedMetricsConfig), }); this.apiId = this.api.attrApiId; @@ -920,6 +976,19 @@ export class GraphqlApi extends GraphqlApiBase { ], []); } + private setupEnhancedMetricsConfig(config?: EnhancedMetricsConfig) { + if (!config) return undefined; + const dataSourceLevelMetricsBehavior = config.dataSourceLevelMetricsBehavior; + const operationLevelMetricsEnabled = config.operationLevelMetricsEnabled + ? 'ENABLED' : 'DISABLED'; + const resolverLevelMetricsBehavior = config.resolverLevelMetricsBehavior; + return { + dataSourceLevelMetricsBehavior: dataSourceLevelMetricsBehavior, + operationLevelMetricsConfig: operationLevelMetricsEnabled, + resolverLevelMetricsBehavior: resolverLevelMetricsBehavior, + }; + } + private createAPIKey(config?: ApiKeyConfig) { if (config?.expires?.isBefore(Duration.days(1)) || config?.expires?.isAfter(Duration.days(365))) { throw Error('API key expiration must be between 1 and 365 days.'); diff --git a/packages/aws-cdk-lib/aws-appsync/lib/resolver.ts b/packages/aws-cdk-lib/aws-appsync/lib/resolver.ts index cbd7b3c18dcfd..76cf0a91edf95 100644 --- a/packages/aws-cdk-lib/aws-appsync/lib/resolver.ts +++ b/packages/aws-cdk-lib/aws-appsync/lib/resolver.ts @@ -66,6 +66,14 @@ export interface BaseResolverProps { * @default - no code is used */ readonly code?: Code; + + /** + * Whether to enable enhanced metrics + * Value will be ignored, if `enhancedMetricsConfig.resolverLevelMetricsBehavior` on AppSync GraphqlApi construct is set to `FULL_REQUEST_RESOLVER_METRICS` + * + * @default - Enhanced metrics are disabled + */ + readonly enhancedMetricsEnabled?: boolean; } /** @@ -133,6 +141,8 @@ export class Resolver extends Construct { } const code = props.code?.bind(this); + const metricsConfig = props.enhancedMetricsEnabled === undefined ? undefined + : (props.enhancedMetricsEnabled ? 'ENABLED': 'DISABLED'); this.resolver = new CfnResolver(this, 'Resource', { apiId: props.api.apiId, typeName: props.typeName, @@ -147,6 +157,7 @@ export class Resolver extends Construct { responseMappingTemplate: props.responseMappingTemplate ? props.responseMappingTemplate.renderTemplate() : undefined, cachingConfig: this.createCachingConfig(props.cachingConfig), maxBatchSize: props.maxBatchSize, + metricsConfig: metricsConfig, }); props.api.addSchemaDependency(this.resolver); if (props.dataSource) { diff --git a/packages/aws-cdk-lib/aws-appsync/test/appsync-dynamodb.test.ts b/packages/aws-cdk-lib/aws-appsync/test/appsync-dynamodb.test.ts index de9efb9ea9daa..cb053c9b056be 100644 --- a/packages/aws-cdk-lib/aws-appsync/test/appsync-dynamodb.test.ts +++ b/packages/aws-cdk-lib/aws-appsync/test/appsync-dynamodb.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { Template } from '../../assertions'; +import { Match, Template } from '../../assertions'; import * as db from '../../aws-dynamodb'; import * as cdk from '../../core'; import * as appsync from '../lib'; @@ -71,6 +71,23 @@ describe('DynamoDb Data Source configuration', () => { }); }); + test.each([ + [true, 'ENABLED'], + [false, 'DISABLED'], + [undefined, Match.absent()], + ])('appsync configures metrics config correctly to set %s', (enhancedMetricsEnabled, metricsConfig) => { + // WHEN + api.addDynamoDbDataSource('ds', table, { + enhancedMetricsEnabled: enhancedMetricsEnabled, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'AMAZON_DYNAMODB', + MetricsConfig: metricsConfig, + }); + }); + test('appsync errors when creating multiple dynamo db data sources with no configuration', () => { // THEN expect(() => { diff --git a/packages/aws-cdk-lib/aws-appsync/test/appsync-elasticsearch.test.ts b/packages/aws-cdk-lib/aws-appsync/test/appsync-elasticsearch.test.ts index 77f1eb1c65966..1604d86cd603c 100644 --- a/packages/aws-cdk-lib/aws-appsync/test/appsync-elasticsearch.test.ts +++ b/packages/aws-cdk-lib/aws-appsync/test/appsync-elasticsearch.test.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import { describeDeprecated } from '@aws-cdk/cdk-build-tools'; -import { Template } from '../../assertions'; +import { Match, Template } from '../../assertions'; import * as es from '../../aws-elasticsearch'; import * as cdk from '../../core'; import * as appsync from '../lib'; @@ -109,6 +109,23 @@ describeDeprecated('Appsync Elasticsearch integration', () => { }); }); + test.each([ + [true, 'ENABLED'], + [false, 'DISABLED'], + [undefined, Match.absent()], + ])('appsync configures metrics config correctly to set %s', (enhancedMetricsEnabled, metricsConfig) => { + // WHEN + api.addElasticsearchDataSource('ds', domain, { + enhancedMetricsEnabled: enhancedMetricsEnabled, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'AMAZON_ELASTICSEARCH', + MetricsConfig: metricsConfig, + }); + }); + test('appsync errors when creating multiple elasticsearch data sources with no configuration', () => { // WHEN const when = () => { diff --git a/packages/aws-cdk-lib/aws-appsync/test/appsync-eventbridge.test.ts b/packages/aws-cdk-lib/aws-appsync/test/appsync-eventbridge.test.ts index de49a2219a50f..266b67c11b4b5 100644 --- a/packages/aws-cdk-lib/aws-appsync/test/appsync-eventbridge.test.ts +++ b/packages/aws-cdk-lib/aws-appsync/test/appsync-eventbridge.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { Template } from '../../assertions'; +import { Match, Template } from '../../assertions'; import * as eventBridge from '../../aws-events'; import * as cdk from '../../core'; import * as appsync from '../lib'; @@ -88,6 +88,23 @@ describe('EventBridge Data Source Configuration', () => { }); }); + test.each([ + [true, 'ENABLED'], + [false, 'DISABLED'], + [undefined, Match.absent()], + ])('appsync configures metrics config correctly to set %s', (enhancedMetricsEnabled, metricsConfig) => { + // WHEN + api.addEventBridgeDataSource('ds', eventBus, { + enhancedMetricsEnabled: enhancedMetricsEnabled, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'AMAZON_EVENTBRIDGE', + MetricsConfig: metricsConfig, + }); + }); + test('An error occurs when creating multiple EventBridge data sources with the same name', () => { // WHEN const when = () => { diff --git a/packages/aws-cdk-lib/aws-appsync/test/appsync-http.test.ts b/packages/aws-cdk-lib/aws-appsync/test/appsync-http.test.ts index cbe21aaab7789..d67162293b4c4 100644 --- a/packages/aws-cdk-lib/aws-appsync/test/appsync-http.test.ts +++ b/packages/aws-cdk-lib/aws-appsync/test/appsync-http.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { Template } from '../../assertions'; +import { Match, Template } from '../../assertions'; import * as sfn from '../../aws-stepfunctions'; import * as cdk from '../../core'; import * as appsync from '../lib'; @@ -57,6 +57,23 @@ describe('Http Data Source configuration', () => { }); }); + test.each([ + [true, 'ENABLED'], + [false, 'DISABLED'], + [undefined, Match.absent()], + ])('appsync configures metrics config correctly to set %s', (enhancedMetricsEnabled, metricsConfig) => { + // WHEN + api.addHttpDataSource('ds', endpoint, { + enhancedMetricsEnabled: enhancedMetricsEnabled, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'HTTP', + MetricsConfig: metricsConfig, + }); + }); + test('appsync configures name, authorizationConfig correctly', () => { // WHEN api.addHttpDataSource('ds', endpoint, { diff --git a/packages/aws-cdk-lib/aws-appsync/test/appsync-lambda.test.ts b/packages/aws-cdk-lib/aws-appsync/test/appsync-lambda.test.ts index e709e445b2d98..3a433fcb5e262 100644 --- a/packages/aws-cdk-lib/aws-appsync/test/appsync-lambda.test.ts +++ b/packages/aws-cdk-lib/aws-appsync/test/appsync-lambda.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { Template } from '../../assertions'; +import { Match, Template } from '../../assertions'; import * as lambda from '../../aws-lambda'; import * as cdk from '../../core'; import * as appsync from '../lib'; @@ -65,6 +65,23 @@ describe('Lambda Data Source configuration', () => { }); }); + test.each([ + [true, 'ENABLED'], + [false, 'DISABLED'], + [undefined, Match.absent()], + ])('appsync configures metrics config correctly to set %s', (enhancedMetricsEnabled, metricsConfig) => { + // WHEN + api.addLambdaDataSource('ds', func, { + enhancedMetricsEnabled: enhancedMetricsEnabled, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'AWS_LAMBDA', + MetricsConfig: metricsConfig, + }); + }); + test('appsync sanitized datasource name from unsupported characters', () => { const badCharacters = [...'!@#$%^&*()+-=[]{}\\|;:\'",<>?/']; diff --git a/packages/aws-cdk-lib/aws-appsync/test/appsync-none.test.ts b/packages/aws-cdk-lib/aws-appsync/test/appsync-none.test.ts index f2720237f6a0c..b6d118f52e179 100644 --- a/packages/aws-cdk-lib/aws-appsync/test/appsync-none.test.ts +++ b/packages/aws-cdk-lib/aws-appsync/test/appsync-none.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { Template } from '../../assertions'; +import { Match, Template } from '../../assertions'; import * as cdk from '../../core'; import * as appsync from '../lib'; @@ -82,6 +82,23 @@ describe('None Data Source configuration', () => { }); }); + test.each([ + [true, 'ENABLED'], + [false, 'DISABLED'], + [undefined, Match.absent()], + ])('appsync configures metrics config correctly to set %s', (enhancedMetricsEnabled, metricsConfig) => { + // WHEN + api.addNoneDataSource('ds', { + enhancedMetricsEnabled: enhancedMetricsEnabled, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'NONE', + MetricsConfig: metricsConfig, + }); + }); + test('appsync errors when creating multiple none data sources with no configuration', () => { // THEN expect(() => { diff --git a/packages/aws-cdk-lib/aws-appsync/test/appsync-opensearch.test.ts b/packages/aws-cdk-lib/aws-appsync/test/appsync-opensearch.test.ts index e2b77bc9acecf..9b3c0f853373f 100644 --- a/packages/aws-cdk-lib/aws-appsync/test/appsync-opensearch.test.ts +++ b/packages/aws-cdk-lib/aws-appsync/test/appsync-opensearch.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { Template } from '../../assertions'; +import { Match, Template } from '../../assertions'; import * as opensearch from '../../aws-opensearchservice'; import * as cdk from '../../core'; import * as appsync from '../lib'; @@ -106,6 +106,23 @@ describe('OpenSearch Data Source Configuration', () => { }); }); + test.each([ + [true, 'ENABLED'], + [false, 'DISABLED'], + [undefined, Match.absent()], + ])('appsync configures metrics config correctly to set %s', (enhancedMetricsEnabled, metricsConfig) => { + // WHEN + api.addOpenSearchDataSource('ds', domain, { + enhancedMetricsEnabled: enhancedMetricsEnabled, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'AMAZON_OPENSEARCH_SERVICE', + MetricsConfig: metricsConfig, + }); + }); + test('appsync errors when creating multiple openSearch data sources with no configuration', () => { // WHEN const when = () => { diff --git a/packages/aws-cdk-lib/aws-appsync/test/appsync-rds.test.ts b/packages/aws-cdk-lib/aws-appsync/test/appsync-rds.test.ts index ab140fbb4d722..087945a76a6ce 100644 --- a/packages/aws-cdk-lib/aws-appsync/test/appsync-rds.test.ts +++ b/packages/aws-cdk-lib/aws-appsync/test/appsync-rds.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { Template } from '../../assertions'; +import { Match, Template } from '../../assertions'; import { Vpc, SecurityGroup, SubnetType } from '../../aws-ec2'; import { DatabaseSecret, DatabaseClusterEngine, AuroraMysqlEngineVersion, ServerlessCluster, DatabaseCluster, ClusterInstance, AuroraPostgresEngineVersion } from '../../aws-rds'; import * as cdk from '../../core'; @@ -230,6 +230,23 @@ describe('Rds Data Source configuration', () => { }); }); + test.each([ + [true, 'ENABLED'], + [false, 'DISABLED'], + [undefined, Match.absent()], + ])('appsync configures metrics config correctly to set %s', (enhancedMetricsEnabled, metricsConfig) => { + // WHEN + api.addRdsDataSource('ds', serverlessCluster, secret, undefined, { + enhancedMetricsEnabled: enhancedMetricsEnabled, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'RELATIONAL_DATABASE', + MetricsConfig: metricsConfig, + }); + }); + test('appsync errors when creating multiple rds data sources with no configuration', () => { // WHEN const when = () => { diff --git a/packages/aws-cdk-lib/aws-appsync/test/appsync.test.ts b/packages/aws-cdk-lib/aws-appsync/test/appsync.test.ts index 60181a10b6058..c555aa92776cd 100644 --- a/packages/aws-cdk-lib/aws-appsync/test/appsync.test.ts +++ b/packages/aws-cdk-lib/aws-appsync/test/appsync.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { Template } from '../../assertions'; +import { Match, Template } from '../../assertions'; import { Certificate } from '../../aws-certificatemanager'; import * as iam from '../../aws-iam'; import * as logs from '../../aws-logs'; @@ -96,6 +96,24 @@ test('appsync should configure resolver as unit when pipelineConfig is empty arr }); }); +test.each([ + [true, 'ENABLED'], + [false, 'DISABLED'], + [undefined, Match.absent()], +])('appsync resolver has MetricConfig set to %s', (enhancedMetricsEnabled, metricsConfig) => { + // WHEN + api.createResolver('Resolver', { + typeName: 'test', + fieldName: 'test2', + enhancedMetricsEnabled: enhancedMetricsEnabled, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::Resolver', { + MetricsConfig: metricsConfig, + }); +}); + test('when xray is enabled should not throw an Error', () => { // WHEN new appsync.GraphqlApi(stack, 'api-x-ray', { @@ -417,3 +435,46 @@ test('when owner contact exceeds 256 characters, it throws an error', () => { expect(() => buildWithOwnerContact()).toThrow('You must specify `ownerContact` as a string of 256 characters or less.'); }); + +test('GraphqlApi with attach enhanced metrics', () => { + // WHEN + new appsync.GraphqlApi(stack, 'minimal-enhanced-metrics', { + name: 'enhanced-metrics', + schema: appsync.SchemaFile.fromAsset(path.join(__dirname, 'appsync.test.graphql')), + enhancedMetricsConfig: { + dataSourceLevelMetricsBehavior: appsync.DataSourceLevelMetricsBehavior.PER_DATA_SOURCE_METRICS, + resolverLevelMetricsBehavior: appsync.ResolverLevelMetricsBehavior.PER_RESOLVER_METRICS, + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::GraphQLApi', { + EnhancedMetricsConfig: { + DataSourceLevelMetricsBehavior: appsync.DataSourceLevelMetricsBehavior.PER_DATA_SOURCE_METRICS, + OperationLevelMetricsConfig: 'DISABLED', + ResolverLevelMetricsBehavior: appsync.ResolverLevelMetricsBehavior.PER_RESOLVER_METRICS, + }, + }); +}); + +test('GraphqlApi with attach enhanced metrics to all data sources', () => { + // WHEN + new appsync.GraphqlApi(stack, 'full-enhanced-metrics', { + name: 'enhanced-metrics', + schema: appsync.SchemaFile.fromAsset(path.join(__dirname, 'appsync.test.graphql')), + enhancedMetricsConfig: { + dataSourceLevelMetricsBehavior: appsync.DataSourceLevelMetricsBehavior.FULL_REQUEST_DATA_SOURCE_METRICS, + operationLevelMetricsEnabled: true, + resolverLevelMetricsBehavior: appsync.ResolverLevelMetricsBehavior.FULL_REQUEST_RESOLVER_METRICS, + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::GraphQLApi', { + EnhancedMetricsConfig: { + DataSourceLevelMetricsBehavior: appsync.DataSourceLevelMetricsBehavior.FULL_REQUEST_DATA_SOURCE_METRICS, + OperationLevelMetricsConfig: 'ENABLED', + ResolverLevelMetricsBehavior: appsync.ResolverLevelMetricsBehavior.FULL_REQUEST_RESOLVER_METRICS, + }, + }); +});