diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7745d97e52ddf..639add0db8a3a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,4 +1,17 @@ ---- +### All Submissions: + +* [ ] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) + +### Adding new Unconventional Dependencies: + +* [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md/#adding-new-unconventional-dependencies) + +### New Features + +* [ ] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/master/INTEGRATION_TESTS.md)? + * [ ] Did you use `cdk-integ` to deploy the infrastructure and generate the snapshot (i.e. `cdk-integ` without `--dry-run`)? + *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* diff --git a/.github/workflows/cr-checklist.yml b/.github/workflows/cr-checklist.yml index cdca37051a4d5..5badcb02eb2ac 100644 --- a/.github/workflows/cr-checklist.yml +++ b/.github/workflows/cr-checklist.yml @@ -9,7 +9,7 @@ jobs: name: Creates a checklist for PRs that contain changes to custom resources steps: - name: Checkout repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Dynamic checklist action uses: vishalsinha21/dynamic-checklist@v1 with: diff --git a/.github/workflows/issue-label-assign.yml b/.github/workflows/issue-label-assign.yml index 97e0de9be71ad..14fe7ff0cde62 100644 --- a/.github/workflows/issue-label-assign.yml +++ b/.github/workflows/issue-label-assign.yml @@ -19,11 +19,11 @@ jobs: github-token: "${{ secrets.GITHUB_TOKEN }}" target: "issues" excluded-expressions: "[CDK CLI Version|TypeScript|Java|Python]" - area-is-keyword: true included-labels: "[needs-triage]" excluded-labels: "[p1|p2|p0|effort-small|effort-medium|effort-large|guidance]" default-area: ${{ env.OSDS_DEVS }} parameters: ${{ env.AREA_PARAMS }} + affixes: ${{ env.AREA_AFFIXES }} guidance-triage-manager: permissions: issues: write @@ -53,6 +53,7 @@ jobs: area-is-keyword: true excluded-labels: "[contribution/core]" parameters: ${{ env.AREA_PARAMS }} + affixes: ${{ env.AREA_AFFIXES }} env: OSDS_DEVS: > @@ -60,51 +61,57 @@ env: "assignees":["NGL321","peterwoodworth","ryparker"] } + AREA_AFFIXES: > + { + "prefixes":["@aws-cdk/"] + } + AREA_PARAMS: > [ - {"area":"package/tools","keywords":["cli","command line","init","synth","diff","bootstrap"],"labels":["package/tools"],"assignees":["rix0rrr"]}, - {"area":"@aws-cdk/alexa-ask","keywords":["alexa-ask","alexa", "cfnskill"],"labels":["@aws-cdk/alexa-ask"],"assignees":["madeline-k"]}, - {"area":"@aws-cdk/app-delivery","keywords":["app-delivery","PipelineDeployStackAction"],"labels":["@aws-cdk/app-delivery"],"assignees":["skinny85"]}, + {"area":"package/tools","keywords":["cli","command line","init","synth","diff","bootstrap"],"labels":["package/tools"],"assignees":["rix0rrr"],"enableGlobalAffixes":false}, + {"area":"@aws-cdk/alexa-ask","keywords":["alexa-ask","alexa"],"labels":["@aws-cdk/alexa-ask"],"assignees":["madeline-k"]}, + {"area":"@aws-cdk/app-delivery","keywords":["app-delivery"],"labels":["@aws-cdk/app-delivery"],"assignees":["skinny85"]}, {"area":"@aws-cdk/assert","keywords":["assert"],"labels":["@aws-cdk/assert"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/assertions","keywords":["assertions"],"labels":["@aws-cdk/assertions"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/assets","keywords":["assets","staging"],"labels":["@aws-cdk/assets"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-accessanalyzer","keywords":["aws-accessanalyzer","accessanalyzer","cfnanalyzer"],"labels":["@aws-cdk/aws-accessanalyzer"],"assignees":["skinny85"]}, + {"area":"@aws-cdk/aws-accessanalyzer","keywords":["aws-accessanalyzer","accessanalyzer"],"labels":["@aws-cdk/aws-accessanalyzer"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-acmpca","keywords":["aws-acmpca","acmpca","certificateauthority"],"labels":["@aws-cdk/aws-acmpca"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-amazonmq","keywords":["aws-amazonmq","amazonmq","cfnbroker"],"labels":["@aws-cdk/aws-amazonmq"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-amplify","keywords":["aws-amplify","amplify","GitHubSourceCodeProvider","CodeCommitSourceCodeProvider","GitLabSourceCodeProvider"],"labels":["@aws-cdk/aws-amplify"],"assignees":["skinny85"]}, + {"area":"@aws-cdk/aws-amazonmq","keywords":["aws-amazonmq","amazonmq"],"labels":["@aws-cdk/aws-amazonmq"],"assignees":["otaviomacedo"]}, + {"area":"@aws-cdk/aws-amplify","keywords":["aws-amplify","amplify","GitHubSourceCodeProvider","CodeCommitSourceCodeProvider","GitLabSourceCodeProvider"],"labels":["@aws-cdk/aws-amplify"],"assignees":["skinny85"],"affixes":{"suffixes":["-alpha"]}}, {"area":"@aws-cdk/aws-apigateway","keywords":["aws-apigateway","api-gateway"],"labels":["@aws-cdk/aws-apigateway"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-apigatewayv2","keywords":["aws-apigatewayv2","api-gateway-v2","apimapping","httpapi","httproute","httpstage","httpauthorizer","httpintegration"],"labels":["@aws-cdk/aws-apigatewayv2"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-apigatewayv2-authorizers","keywords":["(aws-apigatewayv2-authorizers)","(apigatewayv2-authorizers)"],"labels":["@aws-cdk/aws-apigatewayv2-authorizers"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-apigatewayv2-integrations","keywords":["aws-apigatewayv2-integrations","api-gateway-v2-integrations","httpalbintegration","httpnlbintegration","httpproxyintegration","lambdaproxyintegration","httpservicediscoveryintegration","lambdawebsocketintegration"],"labels":["@aws-cdk/aws-apigatewayv2-integrations"],"assignees":["otaviomacedo"]}, + {"area":"@aws-cdk/aws-apigatewayv2","keywords":["aws-apigatewayv2","api-gateway-v2","apimapping","httpapi","httproute","httpstage","httpauthorizer","httpintegration"],"labels":["@aws-cdk/aws-apigatewayv2"],"assignees":["otaviomacedo"],"affixes":{"suffixes":["-alpha"]}}, + {"area":"@aws-cdk/aws-apigatewayv2-authorizers","keywords":["aws-apigatewayv2-authorizers","apigatewayv2-authorizers"],"labels":["@aws-cdk/aws-apigatewayv2-authorizers"],"assignees":["otaviomacedo"],"affixes":{"suffixes":["-alpha"]}}, + {"area":"@aws-cdk/aws-apigatewayv2-integrations","keywords":["aws-apigatewayv2-integrations","apigateway-v2-integrations","httpalbintegration","httpnlbintegration","httpproxyintegration","lambdaproxyintegration","httpservicediscoveryintegration","lambdawebsocketintegration"],"labels":["@aws-cdk/aws-apigatewayv2-integrations"],"assignees":["otaviomacedo"],"affixes":{"suffixes":["-alpha"]}}, {"area":"@aws-cdk/aws-appconfig","keywords":["aws-appconfig","app-config"],"labels":["@aws-cdk/aws-appconfig"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-appflow","keywords":["aws-appflow","appflow"],"labels":["@aws-cdk/aws-appflow"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-appintegrations","keywords":["(aws-appintegrations)","(appintegrations)"],"labels":["@aws-cdk/aws-appintegrations"],"assignees":["skinny85"]}, + {"area":"@aws-cdk/aws-appintegrations","keywords":["aws-appintegrations","appintegrations"],"labels":["@aws-cdk/aws-appintegrations"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-applicationautoscaling","keywords":["aws-applicationautoscaling","application-autoscaling","scalabletarget"],"labels":["@aws-cdk/aws-applicationautoscaling"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-applicationinsights","keywords":["aws-applicationinsights","application-insights"],"labels":["@aws-cdk/aws-applicationinsights"],"assignees":["corymhall"]}, - {"area":"@aws-cdk/aws-appmesh","keywords":["aws-appmesh","app-mesh","GatewayRoute","VirtualGateway","VirtualNode","VirtualRouter","VirtualService"],"labels":["@aws-cdk/aws-appmesh"],"assignees":["Seiya6329"]}, + {"area":"@aws-cdk/aws-appmesh","keywords":["aws-appmesh","app-mesh","GatewayRoute","VirtualGateway","VirtualNode","VirtualRouter","VirtualService"],"labels":["@aws-cdk/aws-appmesh"],"assignees":["ytsssun"]}, + {"area":"@aws-cdk/aws-apprunner","keywords":["apprunner","aws-apprunner"],"labels":["@aws-cdk/aws-apprunner"],"assignees":["corymhall"],"affixes":{"suffixes":["-alpha"]}}, {"area":"@aws-cdk/aws-appstream","keywords":["aws-appstream","app-stream"],"labels":["@aws-cdk/aws-appstream"],"assignees":["madeline-k"]}, - {"area":"@aws-cdk/aws-appsync","keywords":["aws-appsync","app-sync","appsyncfunction","graphqlapi","dynamodbdatasource","lambdadatasource","nonedatasource","rdsdatasource","resolver"],"labels":["@aws-cdk/aws-appsync"],"assignees":["otaviomacedo"]}, + {"area":"@aws-cdk/aws-appsync","keywords":["aws-appsync","app-sync","appsyncfunction","graphqlapi","dynamodbdatasource","lambdadatasource","nonedatasource","rdsdatasource","resolver"],"labels":["@aws-cdk/aws-appsync"],"assignees":["otaviomacedo"],"affixes":{"suffixes":["-alpha"]}}, {"area":"@aws-cdk/aws-athena","keywords":["aws-athena","athena","cfndatacatalog","cfnnamedquery","cfnworkgroup"],"labels":["@aws-cdk/aws-athena"],"assignees":["comcalvi"]}, - {"area":"@aws-cdk/aws-auditmanager","keywords":["(aws-auditmanager)","(auditmanager)"],"labels":["@aws-cdk/aws-auditmanager"],"assignees":["otaviomacedo"]}, + {"area":"@aws-cdk/aws-auditmanager","keywords":["aws-auditmanager","auditmanager"],"labels":["@aws-cdk/aws-auditmanager"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-autoscaling","keywords":["aws-autoscaling","auto-scaling","AutoScalingGroup","LifescycleHook","scheduledaction"],"labels":["@aws-cdk/aws-autoscaling"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-autoscaling-api","keywords":["aws-autoscaling-api","autoscaling-api"],"labels":["@aws-cdk/aws-autoscaling-api"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-autoscaling-common","keywords":["aws-autoscaling-common","autoscaling-common","arbitraryintervals","completescalinginterval","scalinginterval"],"labels":["@aws-cdk/aws-autoscaling-common"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-autoscaling-hooktargets","keywords":["aws-autoscaling-hooktargets","autoscaling hooktargets","functionhook","queuehook","topichook"],"labels":["@aws-cdk/aws-autoscaling-hooktargets"],"assignees":["comcalvi"]}, - {"area":"@aws-cdk/aws-autoscalingplans","keywords":["aws-autoscalingplans","autoscaling-plans","cfnscalingplan"],"labels":["@aws-cdk/aws-autoscalingplans"],"assignees":["comcalvi"]}, - {"area":"@aws-cdk/aws-backup","keywords":["aws-backup","backupplan","backupselection","backupvault"],"labels":["@aws-cdk/aws-backup"],"assignees":["kaizen3031593"]}, - {"area":"@aws-cdk/aws-batch","keywords":["aws-batch","batch","computeenvironment","jobdefinition","jobqueue"],"labels":["@aws-cdk/aws-batch"],"assignees":["madeline-k"]}, - {"area":"@aws-cdk/aws-budgets","keywords":["aws-budgets","budgets","cfnbudget"],"labels":["@aws-cdk/aws-budgets"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-cassandra","keywords":["aws-cassandra","cassandra","cfnkeyspace"],"labels":["@aws-cdk/aws-cassandra"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-ce","keywords":["aws-ce","cfnanomalymonitor","cfncostcategory"],"labels":["@aws-cdk/aws-ce"],"assignees":["corymhall"]}, + {"area":"@aws-cdk/aws-autoscalingplans","keywords":["aws-autoscalingplans","autoscaling-plans"],"labels":["@aws-cdk/aws-autoscalingplans"],"assignees":["comcalvi"]}, + {"area":"@aws-cdk/aws-backup","keywords":["aws-backup","backup","backupselection","backupvault","backupplan"],"labels":["@aws-cdk/aws-backup"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-batch","keywords":["aws-batch","batch","computeenvironment","jobdefinition","jobqueue"],"labels":["@aws-cdk/aws-batch"],"assignees":["madeline-k"],"affixes":{"suffixes":["-alpha"]}}, + {"area":"@aws-cdk/aws-budgets","keywords":["aws-budgets","budgets"],"labels":["@aws-cdk/aws-budgets"],"assignees":["otaviomacedo"]}, + {"area":"@aws-cdk/aws-cassandra","keywords":["aws-cassandra","cassandra"],"labels":["@aws-cdk/aws-cassandra"],"assignees":["otaviomacedo"]}, + {"area":"@aws-cdk/aws-ce","keywords":["aws-ce","costexplorer","cfncostcategory"],"labels":["@aws-cdk/aws-ce"],"assignees":["corymhall"]}, {"area":"@aws-cdk/aws-certificatemanager","keywords":["aws-certificatemanager","certificate-manager","dnsvalidatedcertificate","acm"],"labels":["@aws-cdk/aws-certificatemanager"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-chatbot","keywords":["aws-chatbot","chatbot","slackchannelconfiguration"],"labels":["@aws-cdk/aws-chatbot"],"assignees":["kaizen3031593"]}, - {"area":"@aws-cdk/aws-cloud9","keywords":["aws-cloud9","cloud 9","ec2environment"],"labels":["@aws-cdk/aws-cloud9"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-cloudformation","keywords":["aws-cloudformation","nestedstack"],"labels":["@aws-cdk/aws-cloudformation"],"assignees":["rix0rrr"]}, - {"area":"@aws-cdk/aws-cloudfront","keywords":["aws-cloudfront","cloud front","cachepolicy","cloudfrontwebdistribution"],"labels":["@aws-cdk/aws-cloudfront"],"assignees":["comcalvi"]}, - {"area":"@aws-cdk/aws-cloudfront-origins","keywords":["aws-cloudfront-origins","cloudfront origins"],"labels":["@aws-cdk/aws-cloudfront-origins"],"assignees":["comcalvi"]}, - {"area":"@aws-cdk/aws-cloudtrail","keywords":["aws-cloudtrail","cloud trail","trail"],"labels":["@aws-cdk/aws-cloudtrail"],"assignees":["comcalvi"]}, - {"area":"@aws-cdk/aws-cloudwatch","keywords":["aws-cloudwatch","cloud watch","compositealarm","dashboard"],"labels":["@aws-cdk/aws-cloudwatch"],"assignees":["madeline-k"]}, - {"area":"@aws-cdk/aws-cloudwatch-actions","keywords":["aws-cloudwatch-actions","cloudwatch actions","applicationscalingaction","autoscalingaction","ec2action","snsaction"],"labels":["@aws-cdk/aws-cloudwatch-actions"],"assignees":["madeline-k"]}, + {"area":"@aws-cdk/aws-cloud9","keywords":["aws-cloud9","cloud9","ec2environment"],"labels":["@aws-cdk/aws-cloud9"],"assignees":["skinny85"],"affixes":{"suffixes":["-alpha"]}}, + {"area":"@aws-cdk/aws-cloudformation","keywords":["aws-cloudformation","cloudformation"],"labels":["@aws-cdk/aws-cloudformation"],"assignees":["rix0rrr"]}, + {"area":"@aws-cdk/aws-cloudfront","keywords":["aws-cloudfront","cloudfront","cachepolicy","distribution","cloudfrontwebdistribution"],"labels":["@aws-cdk/aws-cloudfront"],"assignees":["comcalvi"]}, + {"area":"@aws-cdk/aws-cloudfront-origins","keywords":["aws-cloudfront-origins","cloudfront-origins"],"labels":["@aws-cdk/aws-cloudfront-origins"],"assignees":["comcalvi"]}, + {"area":"@aws-cdk/aws-cloudtrail","keywords":["aws-cloudtrail","cloud-trail","trail"],"labels":["@aws-cdk/aws-cloudtrail"],"assignees":["comcalvi"]}, + {"area":"@aws-cdk/aws-cloudwatch","keywords":["aws-cloudwatch","cloudwatch","compositealarm","dashboard"],"labels":["@aws-cdk/aws-cloudwatch"],"assignees":["madeline-k"]}, + {"area":"@aws-cdk/aws-cloudwatch-actions","keywords":["aws-cloudwatch-actions","cloudwatch-actions","applicationscalingaction","autoscalingaction","ec2action","snsaction"],"labels":["@aws-cdk/aws-cloudwatch-actions"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-codeartifact","keywords":["aws-codeartifact","code-artifact"],"labels":["@aws-cdk/aws-codeartifact"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-codebuild","keywords":["aws-codebuild","code-build","bitbucketsourcecredentials","githubenterprisesourcecredentials","githubsourcecredentials","pipelineproject","reportgroup","untrustedcodeboundarypolicy"],"labels":["@aws-cdk/aws-codebuild"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-codecommit","keywords":["aws-codecommit","code-commit"],"labels":["@aws-cdk/aws-codecommit"],"assignees":["skinny85"]}, @@ -113,38 +120,39 @@ env: {"area":"@aws-cdk/aws-codegurureviewer","keywords":["aws-codegurureviewer","codeguru-reviewer"],"labels":["@aws-cdk/aws-codegurureviewer"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-codepipeline","keywords":["aws-codepipeline","code-pipeline"],"labels":["@aws-cdk/aws-codepipeline"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-codepipeline-actions","keywords":["aws-codepipeline-actions","codepipeline-actions","jenkinsprovider"],"labels":["@aws-cdk/aws-codepipeline-actions"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-codestar","keywords":["aws-codestar","codestar","githubrepository"],"labels":["@aws-cdk/aws-codestar"],"assignees":["skinny85"]}, + {"area":"@aws-cdk/aws-codestar","keywords":["aws-codestar","codestar","githubrepository"],"labels":["@aws-cdk/aws-codestar"],"assignees":["skinny85"],"affixes":{"suffixes":["-alpha"]}}, {"area":"@aws-cdk/aws-codestarconnections","keywords":["aws-codestarconnections","codestar-connections"],"labels":["@aws-cdk/aws-codestarconnections"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-codestarnotifications","keywords":["aws-codestarnotifications","codestar-notifications"],"labels":["@aws-cdk/aws-codestarnotifications"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-cognito","keywords":["aws-cognito","cognito","userpool","userpoolclient","userpooldomain"],"labels":["@aws-cdk/aws-cognito"],"assignees":["corymhall"]}, - {"area":"@aws-cdk/aws-config","keywords":["aws-config","accesskeysrotated","CloudFormationStackDriftDetectionCheck","CloudFormationStackNotificationCheck","managedrule"],"labels":["@aws-cdk/aws-config"],"assignees":["rix0rrr"]}, - {"area":"@aws-cdk/aws-customerprofiles","keywords":["(aws-customerprofiles)","(customerprofiles)"],"labels":["@aws-cdk/aws-customerprofiles"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-databrew","keywords":["(aws-databrew)","(databrew)"],"labels":["@aws-cdk/aws-databrew"],"assignees":["kaizen3031593"]}, - {"area":"@aws-cdk/aws-datapipeline","keywords":["aws-datapipeline","data-pipeline"],"labels":["@aws-cdk/aws-datapipeline"],"assignees":["kaizen3031593"]}, - {"area":"@aws-cdk/aws-datasync","keywords":["(aws-datasync)","(datasync)"],"labels":["@aws-cdk/aws-datasync"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-cognito-identitypool","keywords":["aws-cognito-identitypool","cognito-identitypool"],"labels":["@aws-cdk/aws-cognito-identitypool"],"assignees":["corymhall"],"affixes":{"suffixes":["-alpha"]}}, + {"area":"@aws-cdk/aws-config","keywords":["aws-config","config","accesskeysrotated","CloudFormationStackDriftDetectionCheck","CloudFormationStackNotificationCheck","managedrule"],"labels":["@aws-cdk/aws-config"],"assignees":["rix0rrr"]}, + {"area":"@aws-cdk/aws-customerprofiles","keywords":["aws-customerprofiles","customerprofiles"],"labels":["@aws-cdk/aws-customerprofiles"],"assignees":["otaviomacedo"]}, + {"area":"@aws-cdk/aws-databrew","keywords":["aws-databrew","databrew"],"labels":["@aws-cdk/aws-databrew"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-datapipeline","keywords":["aws-datapipeline","datapipeline"],"labels":["@aws-cdk/aws-datapipeline"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-datasync","keywords":["aws-datasync","datasync"],"labels":["@aws-cdk/aws-datasync"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-dax","keywords":["aws-dax","dax"],"labels":["@aws-cdk/aws-dax"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-detective","keywords":["aws-detective","detective"],"labels":["@aws-cdk/aws-detective"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-devopsguru","keywords":["(aws-devopsguru)","(devopsguru)"],"labels":["@aws-cdk/aws-devopsguru"],"assignees":["corymhall"]}, + {"area":"@aws-cdk/aws-devopsguru","keywords":["aws-devopsguru","devopsguru"],"labels":["@aws-cdk/aws-devopsguru"],"assignees":["corymhall"]}, {"area":"@aws-cdk/aws-directoryservice","keywords":["aws-directoryservice","directory-service"],"labels":["@aws-cdk/aws-directoryservice"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-dlm","keywords":["aws-dlm","dlm"],"labels":["@aws-cdk/aws-dlm"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-dms","keywords":["aws-dms","dms"],"labels":["@aws-cdk/aws-dms"],"assignees":["madeline-k"]}, - {"area":"@aws-cdk/aws-docdb","keywords":["aws-docdb","doc-db"],"labels":["@aws-cdk/aws-docdb"],"assignees":["skinny85"]}, + {"area":"@aws-cdk/aws-docdb","keywords":["aws-docdb","docdb"],"labels":["@aws-cdk/aws-docdb"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-dynamodb","keywords":["aws-dynamodb","dynamo-db"],"labels":["@aws-cdk/aws-dynamodb"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-dynamodb-global","keywords":["aws-dynamodb-global","dynamodb global"],"labels":["@aws-cdk/aws-dynamodb-global"],"assignees":["skinny85"]}, + {"area":"@aws-cdk/aws-dynamodb-global","keywords":["aws-dynamodb-global","dynamodb-global"],"labels":["@aws-cdk/aws-dynamodb-global"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-ec2","keywords":["aws-ec2","ec2","vpc","privatesubnet","publicsubnet","vpngateway","vpnconnection","networkacl"],"labels":["@aws-cdk/aws-ec2"],"assignees":["corymhall"]}, {"area":"@aws-cdk/aws-ecr","keywords":["aws-ecr","ecr"],"labels":["@aws-cdk/aws-ecr"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-ecr-assets","keywords":["aws-ecr-assets","ecrassets"],"labels":["@aws-cdk/aws-ecr-assets"],"assignees":["madeline-k"]}, - {"area":"@aws-cdk/aws-ecs","keywords":["(aws-ecs)","(ecs)"],"labels":["@aws-cdk/aws-ecs"],"assignees":["madeline-k"]}, - {"area":"@aws-cdk/aws-ecs-patterns","keywords":["(aws-ecs-patterns)","(ecs-patterns)"],"labels":["@aws-cdk/aws-ecs-patterns"],"assignees":["madeline-k"]}, + {"area":"@aws-cdk/aws-ecs","keywords":["aws-ecs","ecs"],"labels":["@aws-cdk/aws-ecs"],"assignees":["madeline-k"]}, + {"area":"@aws-cdk/aws-ecs-patterns","keywords":["aws-ecs-patterns","ecs-patterns"],"labels":["@aws-cdk/aws-ecs-patterns"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-efs","keywords":["aws-efs","efs","accesspoint"],"labels":["@aws-cdk/aws-efs"],"assignees":["corymhall"]}, {"area":"@aws-cdk/aws-eks","keywords":["aws-eks","eks","fargateprofile","fargatecluster"],"labels":["@aws-cdk/aws-eks"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-eks-legacy","keywords":["(aws-eks-legacy)","(eks-legacy)"],"labels":["@aws-cdk/aws-eks-legacy"],"assignees":["otaviomacedo"]}, + {"area":"@aws-cdk/aws-eks-legacy","keywords":["aws-eks-legacy","eks-legacy"],"labels":["@aws-cdk/aws-eks-legacy"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-elasticache","keywords":["aws-elasticache","elastic-cache"],"labels":["@aws-cdk/aws-elasticache"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-elasticbeanstalk","keywords":["aws-elasticbeanstalk","elastic-beanstalk"],"labels":["@aws-cdk/aws-elasticbeanstalk"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-elasticloadbalancing","keywords":["aws-elasticloadbalancing","elastic-loadbalancing","elb"],"labels":["@aws-cdk/aws-elasticloadbalancing"],"assignees":["corymhall"]}, {"area":"@aws-cdk/aws-elasticloadbalancingv2","keywords":["aws-elasticloadbalancingv2","elastic-loadbalancing-v2","elbv2","applicationlistener","applicationloadbalancer","applicationtargetgroup","networklistener","networkloadbalancer","networktargetgroup"],"labels":["@aws-cdk/aws-elasticloadbalancingv2"],"assignees":["corymhall"]}, - {"area":"@aws-cdk/aws-elasticloadbalancingv2-actions","keywords":["(aws-elasticloadbalancingv2-actions)","(elasticloadbalancingv2-actions)"],"labels":["@aws-cdk/aws-elasticloadbalancingv2-actions"],"assignees":["corymhall"]}, - {"area":"@aws-cdk/aws-elasticloadbalancingv2-targets","keywords":["aws-elasticloadbalancingv2-targets","elbv2 targets"],"labels":["@aws-cdk/aws-elasticloadbalancingv2-targets"],"assignees":["corymhall"]}, + {"area":"@aws-cdk/aws-elasticloadbalancingv2-actions","keywords":["aws-elasticloadbalancingv2-actions","elasticloadbalancingv2-actions"],"labels":["@aws-cdk/aws-elasticloadbalancingv2-actions"],"assignees":["corymhall"]}, + {"area":"@aws-cdk/aws-elasticloadbalancingv2-targets","keywords":["aws-elasticloadbalancingv2-targets","elbv2-targets","elbv2-targets"],"labels":["@aws-cdk/aws-elasticloadbalancingv2-targets"],"assignees":["corymhall"]}, {"area":"@aws-cdk/aws-elasticsearch","keywords":["aws-elasticsearch","elastic-search"],"labels":["@aws-cdk/aws-elasticsearch"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-emr","keywords":["aws-emr","emr"],"labels":["@aws-cdk/aws-emr"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-emrcontainers","keywords":["(aws-emrcontainers)","(emrcontainers)"],"labels":["@aws-cdk/aws-emrcontainers"],"assignees":["kaizen3031593"]}, @@ -156,58 +164,60 @@ env: {"area":"@aws-cdk/aws-fms","keywords":["aws-fms","fms"],"labels":["@aws-cdk/aws-fms"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-frauddetector","keywords":["(aws-frauddetector)","(frauddetector)"],"labels":["@aws-cdk/aws-frauddetector"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-fsx","keywords":["aws-fsx","fsx","lustrefilesystem"],"labels":["@aws-cdk/aws-fsx"],"assignees":["rix0rrr"]}, - {"area":"@aws-cdk/aws-gamelift","keywords":["aws-gamelift","game lift"],"labels":["@aws-cdk/aws-gamelift"],"assignees":["madeline-k"]}, + {"area":"@aws-cdk/aws-gamelift","keywords":["aws-gamelift","gamelift"],"labels":["@aws-cdk/aws-gamelift"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-globalaccelerator","keywords":["aws-globalaccelerator","global-accelerator"],"labels":["@aws-cdk/aws-globalaccelerator"],"assignees":["rix0rrr"]}, - {"area":"@aws-cdk/aws-globalaccelerator-endpoints","keywords":["(aws-globalaccelerator-endpoints)","(globalaccelerator-endpoints)"],"labels":["@aws-cdk/aws-globalaccelerator-endpoints"],"assignees":["rix0rrr"]}, - {"area":"@aws-cdk/aws-glue","keywords":["aws-glue","glue"],"labels":["@aws-cdk/aws-glue"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-globalaccelerator-endpoints","keywords":["aws-globalaccelerator-endpoints","globalaccelerator-endpoints"],"labels":["@aws-cdk/aws-globalaccelerator-endpoints"],"assignees":["rix0rrr"]}, + {"area":"@aws-cdk/aws-glue","keywords":["aws-glue","glue"],"labels":["@aws-cdk/aws-glue"],"assignees":["kaizen3031593"],"affixes":{"suffixes":["-alpha"]}}, {"area":"@aws-cdk/aws-greengrass","keywords":["aws-greengrass","green-grass"],"labels":["@aws-cdk/aws-greengrass"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-greengrassv2","keywords":["(aws-greengrassv2)","(greengrassv2)"],"labels":["@aws-cdk/aws-greengrassv2"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-groundstation","keywords":["(aws-groundstation)","(groundstation)"],"labels":["@aws-cdk/aws-groundstation"],"assignees":["comcalvi"]}, - {"area":"@aws-cdk/aws-guardduty","keywords":["aws-guardduty","guard-duty"],"labels":["@aws-cdk/aws-guardduty"],"assignees":["rix0rrr"]}, + {"area":"@aws-cdk/aws-greengrassv2","keywords":["aws-greengrassv2","greengrassv2"],"labels":["@aws-cdk/aws-greengrassv2"],"assignees":["skinny85"]}, + {"area":"@aws-cdk/aws-groundstation","keywords":["aws-groundstation","groundstation"],"labels":["@aws-cdk/aws-groundstation"],"assignees":["comcalvi"]}, + {"area":"@aws-cdk/aws-guardduty","keywords":["aws-guardduty","guardduty"],"labels":["@aws-cdk/aws-guardduty"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-iam","keywords":["aws-iam","iam","managedpolicy","policy","role"],"labels":["@aws-cdk/aws-iam"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-imagebuilder","keywords":["aws-imagebuilder","imagebuilder"],"labels":["@aws-cdk/aws-imagebuilder"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-inspector","keywords":["aws-inspector","inspector"],"labels":["@aws-cdk/aws-inspector"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-iot","keywords":["internet-of-things","aws-iot","iot"],"labels":["@aws-cdk/aws-iot"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-iot-actions","keywords":["aws-iot-actions","iot-actions"],"labels":["@aws-cdk/aws-iot-actions"],"assignees":["skinny85"]}, + {"area":"@aws-cdk/aws-iot","keywords":["internet-of-things","aws-iot","iot"],"labels":["@aws-cdk/aws-iot"],"assignees":["skinny85"],"affixes":{"suffixes":["-alpha"]}}, + {"area":"@aws-cdk/aws-iot-actions","keywords":["aws-iot-actions","iot-actions"],"labels":["@aws-cdk/aws-iot-actions"],"assignees":["skinny85"],"affixes":{"suffixes":["-alpha"]}}, {"area":"@aws-cdk/aws-iot1click","keywords":["aws-iot1click","iot1click"],"labels":["@aws-cdk/aws-iot1click"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-iotanalytics","keywords":["aws-iotanalytics","iotanalytics"],"labels":["@aws-cdk/aws-iotanalytics"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-iotevents","keywords":["aws-iotevents","iotevents"],"labels":["@aws-cdk/aws-iotevents"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-iotfleethub","keywords":["(aws-iotfleethub)","(iotfleethub)"],"labels":["@aws-cdk/aws-iotfleethub"],"assignees":["skinny85"]}, + {"area":"@aws-cdk/aws-iotevents","keywords":["aws-iotevents","iotevents"],"labels":["@aws-cdk/aws-iotevents"],"assignees":["skinny85"],"affixes":{"suffixes":["-alpha"]}}, + {"area":"@aws-cdk/aws-iotevents-actions","keywords":["aws-iotevents","iotevents-actions"],"labels":["@aws-cdk/aws-iotevents-actions"],"assignees":["skinny85"],"affixes":{"suffixes":["-alpha"]}}, + {"area":"@aws-cdk/aws-iotfleethub","keywords":["aws-iotfleethub","iotfleethub"],"labels":["@aws-cdk/aws-iotfleethub"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-iotsitewise","keywords":["aws-iotsitewise","iot-site-wise"],"labels":["@aws-cdk/aws-iotsitewise"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-iotthingsgraph","keywords":["flow-template","aws-iotthingsgraph","iotthingsgraph"],"labels":["@aws-cdk/aws-iotthingsgraph"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-iotwireless","keywords":["(aws-iotwireless)","(iotwireless)"],"labels":["@aws-cdk/aws-iotwireless"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-ivs","keywords":["interactive-video-service","aws-ivs","ivs"],"labels":["@aws-cdk/aws-ivs"],"assignees":["skinny85"]}, + {"area":"@aws-cdk/aws-iotwireless","keywords":["aws-iotwireless","iotwireless"],"labels":["@aws-cdk/aws-iotwireless"],"assignees":["skinny85"]}, + {"area":"@aws-cdk/aws-ivs","keywords":["interactive-video-service","aws-ivs","ivs"],"labels":["@aws-cdk/aws-ivs"],"assignees":["skinny85"],"affixes":{"suffixes":["-alpha"]}}, {"area":"@aws-cdk/aws-kendra","keywords":["aws-kendra","kendra"],"labels":["@aws-cdk/aws-kendra"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-kinesis","keywords":["stream","aws-kinesis","kinesis"],"labels":["@aws-cdk/aws-kinesis"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-kinesisanalytics","keywords":["aws-kinesisanalytics","kinesisanalytics","kinesis-analytics"],"labels":["@aws-cdk/aws-kinesisanalytics"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-kinesisanalytics-flink","keywords":["(aws-kinesisanalytics-flink)","(kinesisanalytics-flink)"],"labels":["@aws-cdk/aws-kinesisanalytics-flink"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-kinesisfirehose","keywords":["aws-kinesisfirehose","kinesisfirehose"],"labels":["@aws-cdk/aws-kinesisfirehose"],"assignees":["otaviomacedo"]}, + {"area":"@aws-cdk/aws-kinesisanalytics-flink","keywords":["aws-kinesisanalytics-flink","kinesisanalytics-flink"],"labels":["@aws-cdk/aws-kinesisanalytics-flink"],"assignees":["otaviomacedo"],"affixes":{"suffixes":["-alpha"]}}, + {"area":"@aws-cdk/aws-kinesisfirehose","keywords":["aws-kinesisfirehose","kinesisfirehose"],"labels":["@aws-cdk/aws-kinesisfirehose"],"assignees":["otaviomacedo"],"affixes":{"suffixes":["-alpha"]}}, + {"area":"@aws-cdk/aws-kinesisfirehose-destinations","keywords":["aws-kinesisfirehose-destinations","kinesisfirehose-destinations"],"labels":["@aws-cdk/aws-kinesisfirehose"],"assignees":["otaviomacedo"],"affixes":{"suffixes":["-alpha"]}}, {"area":"@aws-cdk/aws-kms","keywords":["key-management-service","aws-kms","kms"],"labels":["@aws-cdk/aws-kms"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-lakeformation","keywords":["data-lake","aws-lakeformation","lakeformation"],"labels":["@aws-cdk/aws-lakeformation"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-lambda","keywords":["function","layerversion","aws-lambda","lambda"],"labels":["@aws-cdk/aws-lambda"],"assignees":["kaizen3031593"]}, - {"area":"@aws-cdk/aws-lambda-destinations","keywords":["(aws-lambda-destinations)","(lambda-destinations)"],"labels":["@aws-cdk/aws-lambda-destinations"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-lambda-destinations","keywords":["aws-lambda-destinations","lambda-destinations"],"labels":["@aws-cdk/aws-lambda-destinations"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-lambda-event-sources","keywords":["dynamoeventsource","aws-lambda-event-sources","lambda-event-sources","apieventsource","kinesiseventsource"],"labels":["@aws-cdk/aws-lambda-event-sources"],"assignees":["kaizen3031593"]}, - {"area":"@aws-cdk/aws-lambda-go","keywords":["(aws-lambda-go)","(lambda-go)"],"labels":["@aws-cdk/aws-lambda-go"],"assignees":["corymhall"]}, + {"area":"@aws-cdk/aws-lambda-go","keywords":["aws-lambda-go","lambda-go"],"labels":["@aws-cdk/aws-lambda-go"],"assignees":["corymhall"],"affixes":{"suffixes":["-alpha"]}}, {"area":"@aws-cdk/aws-lambda-nodejs","keywords":["nodejsfunction","aws-lambda-nodejs","lambda-nodejs"],"labels":["@aws-cdk/aws-lambda-nodejs"],"assignees":["corymhall"]}, - {"area":"@aws-cdk/aws-lambda-python","keywords":["aws-lambda-python","lambda-python","pythonfunction"],"labels":["@aws-cdk/aws-lambda-python"],"assignees":["corymhall"]}, - {"area":"@aws-cdk/aws-licensemanager","keywords":["(aws-licensemanager)","(licensemanager)"],"labels":["@aws-cdk/aws-licensemanager"],"assignees":["madeline-k"]}, + {"area":"@aws-cdk/aws-lambda-python","keywords":["aws-lambda-python","lambda-python","pythonfunction"],"labels":["@aws-cdk/aws-lambda-python"],"assignees":["corymhall"],"affixes":{"suffixes":["-alpha"]}}, + {"area":"@aws-cdk/aws-licensemanager","keywords":["aws-licensemanager","licensemanager"],"labels":["@aws-cdk/aws-licensemanager"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-logs","keywords":["loggroup","aws-logs","logs","logretention"],"labels":["@aws-cdk/aws-logs"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-logs-destinations","keywords":["aws-logs-destinations","lambdadestination","kinesisdestination","logs-destinations"],"labels":["@aws-cdk/aws-logs-destinations"],"assignees":["rix0rrr"]}, - {"area":"@aws-cdk/aws-lookoutmetrics","keywords":["(aws-lookoutmetrics)","(lookoutmetrics)"],"labels":["@aws-cdk/aws-lookoutmetrics"],"assignees":["comcalvi"]}, - {"area":"@aws-cdk/aws-lookoutvision","keywords":["(aws-lookoutvision)","(lookoutvision)"],"labels":["@aws-cdk/aws-lookoutvision"],"assignees":["comcalvi"]}, + {"area":"@aws-cdk/aws-lookoutmetrics","keywords":["aws-lookoutmetrics","lookoutmetrics"],"labels":["@aws-cdk/aws-lookoutmetrics"],"assignees":["comcalvi"]}, + {"area":"@aws-cdk/aws-lookoutvision","keywords":["aws-lookoutvision","lookoutvision"],"labels":["@aws-cdk/aws-lookoutvision"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-macie","keywords":["aws-macie","macie"],"labels":["@aws-cdk/aws-macie"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-managedblockchain","keywords":["aws-managedblockchain","managedblockchain"],"labels":["@aws-cdk/aws-managedblockchain"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-mediaconnect","keywords":["(aws-mediaconnect)","(mediaconnect)"],"labels":["@aws-cdk/aws-mediaconnect"],"assignees":["skinny85"]}, + {"area":"@aws-cdk/aws-mediaconnect","keywords":["aws-mediaconnect","mediaconnect"],"labels":["@aws-cdk/aws-mediaconnect"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-mediaconvert","keywords":["aws-mediaconvert","mediaconvert"],"labels":["@aws-cdk/aws-mediaconvert"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-medialive","keywords":["aws-medialive","medialive"],"labels":["@aws-cdk/aws-medialive"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-mediastore","keywords":["aws-mediastore","mediastore","elemental"],"labels":["@aws-cdk/aws-mediastore"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-mediapackage","keywords":["aws-mediapackage","mediapackage"],"labels":["@aws-cdk/aws-mediapackage"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-msk","keywords":["aws-msk","kafka","msk","managed-streaming"],"labels":["@aws-cdk/aws-msk"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-mwaa","keywords":["(aws-mwaa)","(mwaa)"],"labels":["@aws-cdk/aws-mwaa"],"assignees":["rix0rrr"]}, - {"area":"@aws-cdk/aws-neptune","keywords":["aws-neptune","neptune"],"labels":["@aws-cdk/aws-neptune"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-networkfirewall","keywords":["(aws-networkfirewall)","(networkfirewall)"],"labels":["@aws-cdk/aws-networkfirewall"],"assignees":["skinny85"]}, + {"area":"@aws-cdk/aws-msk","keywords":["aws-msk","kafka","msk","managed-streaming"],"labels":["@aws-cdk/aws-msk"],"assignees":["otaviomacedo"],"affixes":{"suffixes":["-alpha"]}}, + {"area":"@aws-cdk/aws-mwaa","keywords":["aws-mwaa","mwaa"],"labels":["@aws-cdk/aws-mwaa"],"assignees":["rix0rrr"]}, + {"area":"@aws-cdk/aws-neptune","keywords":["aws-neptune","neptune"],"labels":["@aws-cdk/aws-neptune"],"assignees":["skinny85"],"affixes":{"suffixes":["-alpha"]}}, + {"area":"@aws-cdk/aws-networkfirewall","keywords":["aws-networkfirewall","networkfirewall"],"labels":["@aws-cdk/aws-networkfirewall"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-networkmanager","keywords":["aws-networkmanager","networkmanager","globalnetwork"],"labels":["@aws-cdk/aws-networkmanager"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-nimblestudio","keywords":["(aws-nimblestudio)","(nimblestudio)"],"labels":["@aws-cdk/aws-nimblestudio"],"assignees":["madeline-k"]}, + {"area":"@aws-cdk/aws-nimblestudio","keywords":["aws-nimblestudio","nimblestudio"],"labels":["@aws-cdk/aws-nimblestudio"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-opensearchservice","keywords":["aws-opensearchservice","opensearchservice","aws-opensearch","opensearch"],"labels":["@aws-cdk/aws-opensearch"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-opsworks","keywords":["aws-opsworks","opsworks"],"labels":["@aws-cdk/aws-opsworks"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-opsworkscm","keywords":["aws-opsworkscm","opsworkscm"],"labels":["@aws-cdk/aws-opsworkscm"],"assignees":["madeline-k"]}, @@ -215,31 +225,31 @@ env: {"area":"@aws-cdk/aws-pinpoint","keywords":["aws-pinpoint","pinpoint"],"labels":["@aws-cdk/aws-pinpoint"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-pinpointemail","keywords":["aws-pinpointemail","pinpointemail"],"labels":["@aws-cdk/aws-pinpointemail"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-qldb","keywords":["aws-qldb","qldb"],"labels":["@aws-cdk/aws-qldb"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-quicksight","keywords":["(aws-quicksight)","(quicksight)"],"labels":["@aws-cdk/aws-quicksight"],"assignees":["comcalvi"]}, + {"area":"@aws-cdk/aws-quicksight","keywords":["aws-quicksight","quicksight"],"labels":["@aws-cdk/aws-quicksight"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-ram","keywords":["aws-ram","ram", "resource-access-manager"],"labels":["@aws-cdk/aws-ram"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-rds","keywords":["aws-rds","rds", "database-cluster","database-instance"],"labels":["@aws-cdk/aws-rds"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-redshift","keywords":["aws-redshift","redshift"],"labels":["@aws-cdk/aws-redshift"],"assignees":["skinny85"]}, + {"area":"@aws-cdk/aws-redshift","keywords":["aws-redshift","redshift"],"labels":["@aws-cdk/aws-redshift"],"assignees":["skinny85"],"affixes":{"suffixes":["-alpha"]}}, {"area":"@aws-cdk/aws-resourcegroups","keywords":["resourcegroups","aws-resourcegroups"],"labels":["@aws-cdk/aws-resourcegroups"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-robomaker","keywords":["aws-robomaker","robomaker","robot"],"labels":["@aws-cdk/aws-robomaker"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-route53","keywords":["aws-route53","route53","recordset","record","hostedzone"],"labels":["@aws-cdk/aws-route53"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-route53-patterns","keywords":["aws-route53-patterns","route53-patterns"],"labels":["@aws-cdk/aws-route53-patterns"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-route53-targets","keywords":["aws-route53-targets","route53-targets"],"labels":["@aws-cdk/aws-route53-targets"],"assignees":["comcalvi"]}, - {"area":"@aws-cdk/aws-route53resolver","keywords":["aws-route53resolver","route53resolver"],"labels":["@aws-cdk/aws-route53resolver"],"assignees":["comcalvi"]}, + {"area":"@aws-cdk/aws-route53resolver","keywords":["aws-route53resolver","route53resolver"],"labels":["@aws-cdk/aws-route53resolver"],"assignees":["comcalvi"],"affixes":{"suffixes":["-alpha"]}}, {"area":"@aws-cdk/aws-s3","keywords":["bucket","aws-s3","s3"],"labels":["@aws-cdk/aws-s3"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-s3-assets","keywords":["aws-s3-assets","s3-assets"],"labels":["@aws-cdk/aws-s3-assets"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-s3-deployment","keywords":["aws-s3-deployment","s3-deployment"],"labels":["@aws-cdk/aws-s3-deployment"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-s3-notifications","keywords":["aws-s3-notifications","s3-notifications"],"labels":["@aws-cdk/aws-s3-notifications"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-s3objectlambda","keywords":["(aws-s3objectlambda)","(s3objectlambda)"],"labels":["@aws-cdk/aws-s3objectlambda"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-s3outposts","keywords":["(aws-s3outposts)","(s3outposts)"],"labels":["@aws-cdk/aws-s3outposts"],"assignees":["otaviomacedo"]}, + {"area":"@aws-cdk/aws-s3objectlambda","keywords":["aws-s3objectlambda","s3objectlambda"],"labels":["@aws-cdk/aws-s3objectlambda"],"assignees":["otaviomacedo"],"affixes":{"suffixes":["-alpha"]}}, + {"area":"@aws-cdk/aws-s3outposts","keywords":["aws-s3outposts","s3outposts"],"labels":["@aws-cdk/aws-s3outposts"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-sagemaker","keywords":["aws-sagemaker","sagemaker"],"labels":["@aws-cdk/aws-sagemaker"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-sam","keywords":["serverless-application-model","aws-sam","sam"],"labels":["@aws-cdk/aws-sam"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-sdb","keywords":["simpledb","aws-sdb","sdb"],"labels":["@aws-cdk/aws-sdb"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-secretsmanager","keywords":["secret","aws-secretsmanager","secrets-manager"],"labels":["@aws-cdk/aws-secretsmanager"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-securityhub","keywords":["aws-securityhub","security-hub"],"labels":["@aws-cdk/aws-securityhub"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-servicecatalog","keywords":["aws-servicecatalog","service-catalog"],"labels":["@aws-cdk/aws-servicecatalog"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-servicecatalogappregistry","keywords":["(aws-servicecatalogappregistry)","(servicecatalogappregistry)"],"labels":["@aws-cdk/aws-servicecatalogappregistry"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-servicediscovery","keywords":["aws-servicediscovery","service-discovery"],"labels":["@aws-cdk/aws-servicediscovery"],"assignees":["madeline-k"]}, - {"area":"@aws-cdk/aws-ses","keywords":["recipet-filter","reciept-rule","aws-ses","ses"],"labels":["@aws-cdk/aws-ses"],"assignees":["otaviomacedo"]}, + {"area":"@aws-cdk/aws-servicecatalog","keywords":["aws-servicecatalog","service-catalog"],"labels":["@aws-cdk/aws-servicecatalog"],"assignees":["skinny85"],"affixes":{"suffixes":["-alpha"]}}, + {"area":"@aws-cdk/aws-servicecatalogappregistry","keywords":["aws-servicecatalogappregistry","servicecatalogappregistry"],"labels":["@aws-cdk/aws-servicecatalogappregistry"],"assignees":["skinny85"],"affixes":{"suffixes":["-alpha"]}}, + {"area":"@aws-cdk/aws-servicediscovery","keywords":["aws-servicediscovery","servicediscovery"],"labels":["@aws-cdk/aws-servicediscovery"],"assignees":["madeline-k"]}, + {"area":"@aws-cdk/aws-ses","keywords":["receipt-filter","receipt-rule","aws-ses","ses"],"labels":["@aws-cdk/aws-ses"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-ses-actions","keywords":["aws-ses-actions","ses-actions"],"labels":["@aws-cdk/aws-ses-actions"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-signer","keywords":["aws-signer","signer"],"labels":["@aws-cdk/aws-signer"],"assignees":["corymhall"]}, {"area":"@aws-cdk/aws-sns","keywords":["simple-notification-service","aws-sns","sns","topic"],"labels":["@aws-cdk/aws-sns"],"assignees":["kaizen3031593"]}, @@ -247,31 +257,31 @@ env: {"area":"@aws-cdk/aws-sqs","keywords":["queue","simple-queue-service","aws-sqs","sqs","fifo"],"labels":["@aws-cdk/aws-sqs"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-ssm","keywords":["aws-ssm","ssm","systems-manager","stringparameter","stringlistparameter"],"labels":["@aws-cdk/aws-ssm"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-sso","keywords":["aws-sso","sso","single-sign-on"],"labels":["@aws-cdk/aws-sso"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-stepfunctions","keywords":["aws-stepfunctions","stepfunctions","state machine", "chain"],"labels":["@aws-cdk/aws-stepfunctions"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-stepfunctions","keywords":["aws-stepfunctions","stepfunctions","statemachine", "chain"],"labels":["@aws-cdk/aws-stepfunctions"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-stepfunctions-tasks","keywords":["aws-stepfunctions-tasks","stepfunctions-tasks"],"labels":["@aws-cdk/aws-stepfunctions-tasks"],"assignees":["kaizen3031593"]}, - {"area":"@aws-cdk/aws-synthetics","keywords":["aws-synthetics","synthetics", "canary"],"labels":["@aws-cdk/aws-synthetics"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-synthetics","keywords":["aws-synthetics","synthetics", "canary"],"labels":["@aws-cdk/aws-synthetics"],"assignees":["kaizen3031593"],"affixes":{"suffixes":["-alpha"]}}, {"area":"@aws-cdk/aws-timestream","keywords":["aws-timestream","timestream"],"labels":["@aws-cdk/aws-timestream"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-transfer","keywords":["aws-transfer","transfer"],"labels":["@aws-cdk/aws-transfer"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-waf","keywords":["waf","web-application-firewall"],"labels":["@aws-cdk/aws-waf"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-wafregional","keywords":["wafregional","cfnwebacl"],"labels":["@aws-cdk/aws-wafregional"],"assignees":["skinny85"]}, + {"area":"@aws-cdk/aws-waf","keywords":["waf","aws-waf","web-application-firewall"],"labels":["@aws-cdk/aws-waf"],"assignees":["skinny85"]}, + {"area":"@aws-cdk/aws-wafregional","keywords":["aws-wafregional","wafregional","cfnwebacl"],"labels":["@aws-cdk/aws-wafregional"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-wafv2","keywords":["wafv2","aws-wafv2"],"labels":["@aws-cdk/aws-wafv2"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-workspaces","keywords":["aws-workspaces","workspaces"],"labels":["@aws-cdk/aws-workspaces"],"assignees":["madeline-k"]}, - {"area":"@aws-cdk/aws-xray","keywords":["(aws-xray)","(xray)"],"labels":["@aws-cdk/aws-xray"],"assignees":["corymhall"]}, - {"area":"@aws-cdk/cfnspec","keywords":["cfn-spec"],"labels":["@aws-cdk/cfnspec"],"assignees":["rix0rrr"]}, + {"area":"@aws-cdk/aws-xray","keywords":["aws-xray","xray"],"labels":["@aws-cdk/aws-xray"],"assignees":["corymhall"]}, + {"area":"@aws-cdk/cfnspec","keywords":["cfnspec"],"labels":["@aws-cdk/cfnspec"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/cloud-assembly-schema","keywords":["cloud-assembly-schema","manifest"],"labels":["@aws-cdk/cloud-assembly-schema"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/cloudformation-diff","keywords":["cloudformation-diff","cfn-diff"],"labels":["@aws-cdk/cloudformation-diff"],"assignees":["skinny85"]}, {"area":"@aws-cdk/cloudformation-include","keywords":["cloudformation-include","cfn-include"],"labels":["@aws-cdk/cloudformation-include"],"assignees":["comcalvi"]}, - {"area":"@aws-cdk/core","keywords":["cross-account","nested stacks","core"],"labels":["@aws-cdk/core"],"assignees":["rix0rrr"]}, - {"area":"@aws-cdk/custom-resources","keywords":["custom-resource","provider"],"labels":["@aws-cdk/custom-resources"],"assignees":["rix0rrr"]}, + {"area":"@aws-cdk/core","keywords":["core","nested-stack","cross-account"],"labels":["@aws-cdk/core"],"assignees":["rix0rrr"]}, + {"area":"@aws-cdk/custom-resources","keywords":["custom-resource","provider","custom-resources"],"labels":["@aws-cdk/custom-resources"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/cx-api","keywords":["cx-api","cloudartifact","cloudassembly"],"labels":["@aws-cdk/cx-api"],"assignees":["rix0rrr"]}, - {"area":"@aws-cdk/aws-lambda-layer-awscli","keywords":["(aws-lambda-layer-awscli)","(lambda-layer-awscli)"],"labels":["@aws-cdk/aws-lambda-layer-awscli"],"assignees":["rix0rrr"]}, - {"area":"@aws-cdk/aws-lambda-layer-kubectl","keywords":["(aws-lambda-layer-kubectl)","(lambda-layer-kubectl)"],"labels":["@aws-cdk/aws-lambda-layer-kubectl"],"assignees":["otaviomacedo"]}, + {"area":"@aws-cdk/aws-lambda-layer-awscli","keywords":["aws-lambda-layer-awscli","lambda-layer-awscli"],"labels":["@aws-cdk/aws-lambda-layer-awscli"],"assignees":["rix0rrr"]}, + {"area":"@aws-cdk/aws-lambda-layer-kubectl","keywords":["aws-lambda-layer-kubectl","lambda-layer-kubectl"],"labels":["@aws-cdk/aws-lambda-layer-kubectl"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/pipelines","keywords":["pipelines","cdk-pipelines","sourceaction","synthaction"],"labels":["@aws-cdk/pipelines"],"assignees":["rix0rrr"]}, - {"area":"@aws-cdk/region-info","keywords":["region-info","fact"],"labels":["@aws-cdk/region-info"],"assignees":["skinny85"]}, - {"area":"aws-cdk-lib","keywords":["aws-cdk-lib","cdk-v2","v2","ubergen"],"labels":["aws-cdk-lib"],"assignees":["madeline-k"]}, - {"area":"monocdk","keywords":["monocdk","monocdk-experiment"],"labels":["monocdk"],"assignees":["madeline-k"]}, - {"area":"@aws-cdk/yaml-cfn","keywords":["(aws-yaml-cfn)","(yaml-cfn)"],"labels":["@aws-cdk/aws-yaml-cfn"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-apprunner","keywords":["apprunner","aws-apprunner"],"labels":["@aws-cdk/aws-apprunner"],"assignees":["corymhall"]}, + {"area":"@aws-cdk/region-info","keywords":["region-info"],"labels":["@aws-cdk/region-info"],"assignees":["skinny85"]}, + {"area":"aws-cdk-lib","keywords":["aws-cdk-lib","cdk-v2","v2","ubergen"],"labels":["aws-cdk-lib"],"assignees":["madeline-k"],"enableGlobalAffixes":false}, + {"area":"monocdk","keywords":["monocdk","monocdk-experiment"],"labels":["monocdk"],"assignees":["madeline-k"],"enableGlobalAffixes":false}, + {"area":"@aws-cdk/yaml-cfn","keywords":["aws-yaml-cfn","yaml-cfn"],"labels":["@aws-cdk/aws-yaml-cfn"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-lightsail","keywords":["lightsail","aws-lightsail"],"labels":["@aws-cdk/aws-lightsail"],"assignees":["corymhall"]}, - {"area":"@aws-cdk/aws-aps","keywords":["aps","aws-aps","prometheus"],"labels":["@aws-cdk/aws-aps"],"assignees":["corymhall"]} + {"area":"@aws-cdk/aws-aps","keywords":["aps","aws-aps","prometheus"],"labels":["@aws-cdk/aws-aps"],"assignees":["corymhall"]}, + {"area":"@aws-cdk/triggers","keywords":["trigger","triggers"],"labels":["@aws-cdk/triggers"],"assignees":["otaviomacedo"]} ] diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml index 1619f8bc4cc7e..55be270e4d0f7 100644 --- a/.github/workflows/pr-labeler.yml +++ b/.github/workflows/pr-labeler.yml @@ -2,8 +2,11 @@ name: pr-labeler on: - pull_request: - types: [ opened ] + pull_request_target: + types: + - opened + - edited + - reopened jobs: auto-approve: @@ -13,6 +16,16 @@ jobs: pull-requests: write issues: write steps: - - run: gh pr edit ${{ github.event.pull_request.number }} --add-label "auto-approve" -R ${{ github.repository }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - run: gh pr edit ${{ github.event.pull_request.number }} --add-label "auto-approve" -R ${{ github.repository }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + copy-labels: + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - uses: kaizen3031593/pr-triage-manager@main + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + + diff --git a/.github/workflows/pr-linter.yml b/.github/workflows/pr-linter.yml index 8231b94fa2319..73cc7b595e00d 100644 --- a/.github/workflows/pr-linter.yml +++ b/.github/workflows/pr-linter.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install & Build prlint run: yarn install --frozen-lockfile && cd tools/@aws-cdk/prlint && yarn build+test diff --git a/.github/workflows/v2-pull-request.yml b/.github/workflows/v2-pull-request.yml index 351ee2c8c427f..8e7e00acdbc25 100644 --- a/.github/workflows/v2-pull-request.yml +++ b/.github/workflows/v2-pull-request.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: branch: ${{ github.event.pull_request.head.ref }} token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/yarn-upgrade.yml b/.github/workflows/yarn-upgrade.yml index f592be929092b..64e3e6a1ebe70 100644 --- a/.github/workflows/yarn-upgrade.yml +++ b/.github/workflows/yarn-upgrade.yml @@ -15,10 +15,10 @@ jobs: steps: - name: Check Out - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Node - uses: actions/setup-node@v2.5.1 + uses: actions/setup-node@v3 with: node-version: 12 @@ -27,15 +27,19 @@ jobs: run: echo "::set-output name=dir::$(yarn cache dir)" - name: Restore Yarn cache - uses: actions/cache@v2.1.7 + uses: actions/cache@v3 with: path: ${{ steps.yarn-cache.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} restore-keys: |- ${{ runner.os }}-yarn- + - name: Yarn Install + run: yarn install --frozen-lockfile - name: Install Tools run: |- npm -g install lerna npm-check-updates@^9.0.0 + - name: Build CLI + run: cd packages/aws-cdk && ../../scripts/buildup - name: List Mono-Repo Packages id: list-packages # These need to be ignored from the `ncu` runs! @@ -49,6 +53,7 @@ jobs: # We special-case typescript because it's not semantically versionned # We special-case constructs because we want to stay in control of the minimum compatible version # We special-case lerna because we have a patch on it that stops applying if Lerna upgrades. Remove this once https://github.com/lerna/lerna/pull/2874 releases. + # We special-case aws-sdk-mock because of breaking changes in type exports https://github.com/dwyl/aws-sdk-mock/pull/260. We are not respecting `@ts-ignore` run: |- # Upgrade dependencies at repository root ncu --upgrade --filter=@types/node,@types/fs-extra --target=minor @@ -57,13 +62,17 @@ jobs: # Upgrade all the packages lerna exec --parallel ncu -- --upgrade --filter=@types/node,@types/fs-extra --target=minor lerna exec --parallel ncu -- --upgrade --filter=typescript --target=patch - lerna exec --parallel ncu -- --upgrade --reject='@types/node,@types/fs-extra,constructs,typescript,aws-sdk,${{ steps.list-packages.outputs.list }}' --target=minor + lerna exec --parallel ncu -- --upgrade --reject='@types/node,@types/fs-extra,constructs,typescript,aws-sdk,aws-sdk-mock,${{ steps.list-packages.outputs.list }}' --target=minor + # This will ensure the current lockfile is up-to-date with the dependency specifications (necessary for "yarn update" to run) - name: Run "yarn install" run: yarn install - name: Run "yarn upgrade" run: yarn upgrade + + - name: Regenerate CLI attributions + run: cd packages/aws-cdk && yarn pkglint # Next, create and upload the changes as a patch file. This will later be downloaded to create a pull request # Creating a pull request requires write permissions and it's best to keep write privileges isolated. @@ -86,7 +95,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check Out - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Download patch uses: actions/download-artifact@v2 @@ -99,7 +108,7 @@ jobs: }}/upgrade.patch || echo "Empty patch. Skipping."' - name: Make Pull Request - uses: peter-evans/create-pull-request@v3 + uses: peter-evans/create-pull-request@v4 with: # Git commit details branch: automation/yarn-upgrade @@ -114,4 +123,4 @@ jobs: team-reviewers: aws-cdk-team # Github prevents further Github actions to be run if the default Github token is used. # Instead use a privileged token here, so further GH actions can be triggered on this PR. - token: ${{ secrets.AUTOMATION_GITHUB_TOKEN }} + token: ${{ secrets.PROJEN_GITHUB_TOKEN }} diff --git a/.mergify.yml b/.mergify.yml index 3348c3b934909..ca9bdc82b9333 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -10,7 +10,7 @@ pull_request_rules: label: add: [ contribution/core ] conditions: - - author~=^(eladb|RomainMuller|garnaat|nija-at|skinny85|rix0rrr|NGL321|Jerry-AWS|MrArnoldPalmer|NetaNir|iliapolo|njlynch|ericzbeard|ccfife|fulghum|pkandasamy91|SoManyHs|uttarasridhar|otaviomacedo|BenChaimberg|madeline-k|BryanPan342|kaizen3031593|comcalvi|Chriscbr|corymhall|peterwoodworth|ryparker)$ + - author~=^(eladb|RomainMuller|garnaat|nija-at|skinny85|rix0rrr|NGL321|Jerry-AWS|MrArnoldPalmer|NetaNir|iliapolo|njlynch|ericzbeard|ccfife|fulghum|pkandasamy91|SoManyHs|uttarasridhar|otaviomacedo|BenChaimberg|madeline-k|BryanPan342|kaizen3031593|comcalvi|Chriscbr|corymhall|peterwoodworth|ryparker|TheRealAmazonKendra|yuth)$ - -label~="contribution/core" - name: automatic merge actions: diff --git a/CHANGELOG.md b/CHANGELOG.md index dfde649269cc8..1621fa309c36a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,203 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.150.0](https://github.com/aws/aws-cdk/compare/v1.149.0...v1.150.0) (2022-03-26) + + +### Features + +* cloudformation spec v62.0.0 ([#19553](https://github.com/aws/aws-cdk/issues/19553)) ([0352dee](https://github.com/aws/aws-cdk/commit/0352deedb445f070ed0cd27406a75872fb71ea53)) +* **appsync:** support custom domain mappings ([#19368](https://github.com/aws/aws-cdk/issues/19368)) ([8c7a4ac](https://github.com/aws/aws-cdk/commit/8c7a4acbd58975a8f1c4e4ca180ca9a3ea2c750d)), closes [#18040](https://github.com/aws/aws-cdk/issues/18040) +* **autoscaling:** support warm pools ([#19214](https://github.com/aws/aws-cdk/issues/19214)) ([737e611](https://github.com/aws/aws-cdk/commit/737e611577c97b6ad01eaeb05fc544258a9de5ad)) +* **cfnspec:** cloudformation spec v61.0.0 ([#19457](https://github.com/aws/aws-cdk/issues/19457)) ([16d7552](https://github.com/aws/aws-cdk/commit/16d7552683ea05ea1a24b214b925836dcb72871d)) +* **cli:** support SSO ([#19454](https://github.com/aws/aws-cdk/issues/19454)) ([eba6052](https://github.com/aws/aws-cdk/commit/eba6052e1c8011d7163c782e669e86f5d2fd44d0)) +* **cloudwatch:** Additional Properties for Cloudwatch AlarmStatusWidget ([#19387](https://github.com/aws/aws-cdk/issues/19387)) ([3c9ea5f](https://github.com/aws/aws-cdk/commit/3c9ea5f31e3113fb0d2ba5c633fcd665294a70eb)), closes [#19386](https://github.com/aws/aws-cdk/issues/19386) +* **ec2:** add support for x2iezn instances ([#19517](https://github.com/aws/aws-cdk/issues/19517)) ([8f6e20e](https://github.com/aws/aws-cdk/commit/8f6e20e5a070fc3ac2c234013b915315a0e7dcfb)) +* **synthetics:** add support for puppeteer 3.4 runtime ([#19429](https://github.com/aws/aws-cdk/issues/19429)) ([024b890](https://github.com/aws/aws-cdk/commit/024b890c67392e255ea8e82c1aa58bcc6bcf6f86)), closes [#19382](https://github.com/aws/aws-cdk/issues/19382) + + +### Bug Fixes + +* **apigateway:** `StepFunctionsIntegration` does not create required role and responses ([#19486](https://github.com/aws/aws-cdk/issues/19486)) ([d59bee9](https://github.com/aws/aws-cdk/commit/d59bee99768b20427503853eb2ec436959ae7e6f)) +* **bootstrap:** rebootstrap breaks container Functions ([#19446](https://github.com/aws/aws-cdk/issues/19446)) ([49ea263](https://github.com/aws/aws-cdk/commit/49ea26304760801e03dae5479ae03540eaa63f6e)), closes [#18473](https://github.com/aws/aws-cdk/issues/18473) +* **cli:** templates don't include `.gitignore` ([#19482](https://github.com/aws/aws-cdk/issues/19482)) ([5ce0983](https://github.com/aws/aws-cdk/commit/5ce0983955628c5119340d659abf0201da58bcb6)) +* **core:** Aspects from symlinked modules are not applied ([#19491](https://github.com/aws/aws-cdk/issues/19491)) ([eaeaed7](https://github.com/aws/aws-cdk/commit/eaeaed7a508cdb9c84c96911327b085e907aed98)), closes [#18921](https://github.com/aws/aws-cdk/issues/18921) [#18778](https://github.com/aws/aws-cdk/issues/18778) [#19390](https://github.com/aws/aws-cdk/issues/19390) [#18914](https://github.com/aws/aws-cdk/issues/18914) +* **ecr:** setting imageScanningConfiguration to false does nothing on existing repository ([#18078](https://github.com/aws/aws-cdk/issues/18078)) ([78bc870](https://github.com/aws/aws-cdk/commit/78bc8703bb932822ceeb16fd57fa576714aa5732)), closes [#18077](https://github.com/aws/aws-cdk/issues/18077) +* **events:** cannot have more than one cross-account Rule ([#19441](https://github.com/aws/aws-cdk/issues/19441)) ([a257846](https://github.com/aws/aws-cdk/commit/a2578462119d112c6095e06668add97e7721d570)), closes [#12479](https://github.com/aws/aws-cdk/issues/12479) [#12538](https://github.com/aws/aws-cdk/issues/12538) +* **iam:** IAM Policies are too large to deploy ([#19114](https://github.com/aws/aws-cdk/issues/19114)) ([3a4fe33](https://github.com/aws/aws-cdk/commit/3a4fe3304ba32bc205cbf4833f7397f633cc1ece)), closes [#18774](https://github.com/aws/aws-cdk/issues/18774) [#16350](https://github.com/aws/aws-cdk/issues/16350) [#18457](https://github.com/aws/aws-cdk/issues/18457) [#18564](https://github.com/aws/aws-cdk/issues/18564) [#19276](https://github.com/aws/aws-cdk/issues/19276) +* **lambda:** support Lambda's new `Invoke` with `Qualifier` authorization strategy ([#19318](https://github.com/aws/aws-cdk/issues/19318)) ([d06b27f](https://github.com/aws/aws-cdk/commit/d06b27fd4bf351cc9ba5c603352f756c679c34fc)), closes [#19273](https://github.com/aws/aws-cdk/issues/19273) +* **secretsmanager:** secret rotation uses old application versions ([#19490](https://github.com/aws/aws-cdk/issues/19490)) ([0c983ad](https://github.com/aws/aws-cdk/commit/0c983ad748fa57c0717d9bdf852051046f88b3a9)), closes [#19487](https://github.com/aws/aws-cdk/issues/19487) + +## [1.149.0](https://github.com/aws/aws-cdk/compare/v1.148.0...v1.149.0) (2022-03-17) + + +### Features + +* **appsync:** add OpenSearch domain data source ([#16529](https://github.com/aws/aws-cdk/issues/16529)) ([922a9dc](https://github.com/aws/aws-cdk/commit/922a9dcf07174334ac67b9fcbacb01aafdfd9c6a)), closes [#16528](https://github.com/aws/aws-cdk/issues/16528) +* **assertions:** Add the `hasNoXXX` methods. ([#19330](https://github.com/aws/aws-cdk/issues/19330)) ([6bdc9eb](https://github.com/aws/aws-cdk/commit/6bdc9eb52608329f1e66c420cb6c61aa942d17b0)), closes [#18874](https://github.com/aws/aws-cdk/issues/18874) +* **aws-lambda-nodejs:** support additional esbuild configurations ([#17788](https://github.com/aws/aws-cdk/issues/17788)) ([ab313a4](https://github.com/aws/aws-cdk/commit/ab313a4abbec14a1886a7c87673dbc66354811ef)) +* **cfnspec:** cloudformation spec v60.0.0 ([#19347](https://github.com/aws/aws-cdk/issues/19347)) ([20da648](https://github.com/aws/aws-cdk/commit/20da648cebddd6feaf8a54d2bf40f3ba3bd30979)) +* **cli:** parallel asset publishing ([#19367](https://github.com/aws/aws-cdk/issues/19367)) ([c8cafef](https://github.com/aws/aws-cdk/commit/c8cafefc4cd98e7217973cd9eb0e92263a916b4f)), closes [#19193](https://github.com/aws/aws-cdk/issues/19193) +* **ec2:** add support for x2idn and x2iedn instances ([#19334](https://github.com/aws/aws-cdk/issues/19334)) ([9699efc](https://github.com/aws/aws-cdk/commit/9699efc0c0b0e2b265daf824147be2827555cafa)) +* **elbv2:** add name validation for target group and load balancer names ([#19385](https://github.com/aws/aws-cdk/issues/19385)) ([97e0973](https://github.com/aws/aws-cdk/commit/97e09730cbb7c155e6697ace166348064d810449)), closes [/docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-targetgroup.html#cfn-elasticloadbalancingv2](https://github.com/aws//docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-targetgroup.html/issues/cfn-elasticloadbalancingv2) [/docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-loadbalancer.html#cfn-elasticloadbalancingv2](https://github.com/aws//docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-loadbalancer.html/issues/cfn-elasticloadbalancingv2) +* **iotevents:** support SetVariable action ([#19305](https://github.com/aws/aws-cdk/issues/19305)) ([c222b12](https://github.com/aws/aws-cdk/commit/c222b122206e00dc9932639efd54d78a16ebf6d3)) +* **lambda:** dotnet6 runtime ([#19144](https://github.com/aws/aws-cdk/issues/19144)) ([bbed27d](https://github.com/aws/aws-cdk/commit/bbed27d95ab2724db937964d01aec5564a77e84f)) +* **synthetics:** add vpc configuration ([#18447](https://github.com/aws/aws-cdk/issues/18447)) ([c991e92](https://github.com/aws/aws-cdk/commit/c991e92453034330b68daa5b5721119e770b6109)), closes [#11865](https://github.com/aws/aws-cdk/issues/11865) [#9954](https://github.com/aws/aws-cdk/issues/9954) + + +### Bug Fixes + +* **cli:** failure to load malformed YAML is swallowed ([#19338](https://github.com/aws/aws-cdk/issues/19338)) ([1875c28](https://github.com/aws/aws-cdk/commit/1875c28865690d59c22939039a5d0e37039ab63c)), closes [#19335](https://github.com/aws/aws-cdk/issues/19335) +* **lambda-event-sources:** increase batch size restriction ([#19317](https://github.com/aws/aws-cdk/issues/19317)) ([1bc5144](https://github.com/aws/aws-cdk/commit/1bc5144b05938829f90b89001ccda8fd4aefe343)), closes [#19285](https://github.com/aws/aws-cdk/issues/19285) +* **lambda-nodejs:** cannot use esbuildArgs with older esbuild versions ([#19343](https://github.com/aws/aws-cdk/issues/19343)) ([59a4d81](https://github.com/aws/aws-cdk/commit/59a4d81cc712eedfd755232d157a2e492eb3d886)) +* **stepfunctions-tasks:** migrate from deprecated batch properties ([#19298](https://github.com/aws/aws-cdk/issues/19298)) ([75f5b3b](https://github.com/aws/aws-cdk/commit/75f5b3b69abf592b2c6d0ec6c19c374754e50f97)), closes [#18993](https://github.com/aws/aws-cdk/issues/18993) + +## [1.148.0](https://github.com/aws/aws-cdk/compare/v1.147.0...v1.148.0) (2022-03-09) + + +### Features + +* **aws-apigateway:** add ability to include authorizer context in apigw sfn integration ([#18892](https://github.com/aws/aws-cdk/issues/18892)) ([e7c0c75](https://github.com/aws/aws-cdk/commit/e7c0c75dbc7cf71164673626dc0ab63fb3706223)), closes [#18891](https://github.com/aws/aws-cdk/issues/18891) +* **aws-s3objectlambda:** add L2 construct for S3 Object Lambda ([#15833](https://github.com/aws/aws-cdk/issues/15833)) ([fe9f750](https://github.com/aws/aws-cdk/commit/fe9f750bd9dd9974b9ae6f73c78fcd12ab2edd91)), closes [#13675](https://github.com/aws/aws-cdk/issues/13675) +* **cfnspec:** cloudformation spec v59.0.0 ([#19236](https://github.com/aws/aws-cdk/issues/19236)) ([f46a14d](https://github.com/aws/aws-cdk/commit/f46a14da9bec1aad7096b62666cb80ce42f04b53)) +* **codebuild:** improved support for ARM build images ([#19052](https://github.com/aws/aws-cdk/issues/19052)) ([4eac4de](https://github.com/aws/aws-cdk/commit/4eac4deb98411e921e5a2e6477185207b8588f75)), closes [#18916](https://github.com/aws/aws-cdk/issues/18916) [#9817](https://github.com/aws/aws-cdk/issues/9817) +* **eks:** Service Account names validation ([#19251](https://github.com/aws/aws-cdk/issues/19251)) ([7c3099e](https://github.com/aws/aws-cdk/commit/7c3099e958d7bf0ddb5a7b08afb672a0c652b27d)), closes [#18189](https://github.com/aws/aws-cdk/issues/18189) +* **elasticsearch:** Decouple setting access policies from domain constructor ([#15876](https://github.com/aws/aws-cdk/issues/15876)) ([cefdfd3](https://github.com/aws/aws-cdk/commit/cefdfd384eeac1752567f672452296def68b1206)) +* **iotevents:** support actions ([#18869](https://github.com/aws/aws-cdk/issues/18869)) ([e01654e](https://github.com/aws/aws-cdk/commit/e01654e792708ee283d7a31e1370d0d1ae383171)) +* **iotevents:** support setting Events on input and exit for State ([#19249](https://github.com/aws/aws-cdk/issues/19249)) ([ffa9e0d](https://github.com/aws/aws-cdk/commit/ffa9e0d287d0a86e1e0eb7dc2dec16d9f3e84450)) +* **lambda-nodejs:** support esbuild inject ([#19221](https://github.com/aws/aws-cdk/issues/19221)) ([3432c45](https://github.com/aws/aws-cdk/commit/3432c457fe38a83743d7ce2a5cb6c36a6ec01b8f)), closes [#19133](https://github.com/aws/aws-cdk/issues/19133) +* **s3:** add `s3:ObjectRestore:Delete` to `EventType` for notification ([#19250](https://github.com/aws/aws-cdk/issues/19250)) ([e0f863a](https://github.com/aws/aws-cdk/commit/e0f863a4c56041860e14c75b9aa5a6d35860fae6)), closes [#19223](https://github.com/aws/aws-cdk/issues/19223) +* **servicecatalog:** Service Catalog is now in Developer Preview ([#19204](https://github.com/aws/aws-cdk/issues/19204)) ([6dfc254](https://github.com/aws/aws-cdk/commit/6dfc254e1925597b4ef2ece9c132b1a0e580dd6d)) + + +### Bug Fixes + +* **apigatewayv2-integrations:** in case of multiple routes, only one execute permission is created ([#18716](https://github.com/aws/aws-cdk/issues/18716)) ([1e352ca](https://github.com/aws/aws-cdk/commit/1e352ca2ab458bfe4e1de6cf431166654ce9aa58)) +* **aws-apigateway:** missing comma to make failure response payload valid json ([#19253](https://github.com/aws/aws-cdk/issues/19253)) ([b1fce4f](https://github.com/aws/aws-cdk/commit/b1fce4f1641c90a4b7d1d33139453260b452d5cd)), closes [#19252](https://github.com/aws/aws-cdk/issues/19252) +* **aws-route53-targets:** add support for custom cname_prefix urls in elastic beanstalk environment endpoint target ([#18804](https://github.com/aws/aws-cdk/issues/18804)) ([289a794](https://github.com/aws/aws-cdk/commit/289a79467d9974ee3582c9e30843b0eb9e90b467)) +* **cli:** `watch` logs always end with the 'truncated' message ([#19241](https://github.com/aws/aws-cdk/issues/19241)) ([d3fdfe5](https://github.com/aws/aws-cdk/commit/d3fdfe5264e64cb333795b32edbad36cfaab3dc7)), closes [#18805](https://github.com/aws/aws-cdk/issues/18805) +* **cli:** deprecated stack ids printed at the end of synth ([#19216](https://github.com/aws/aws-cdk/issues/19216)) ([7d8a479](https://github.com/aws/aws-cdk/commit/7d8a4792a142f45109f35a51c6e1b3888d4111d3)), closes [#18599](https://github.com/aws/aws-cdk/issues/18599) +* **cli:** notices refresh doesn't respect the --no-notices flag ([#19226](https://github.com/aws/aws-cdk/issues/19226)) ([b3c5fe8](https://github.com/aws/aws-cdk/commit/b3c5fe8d0b695e06558bce23a6dd39b20265594f)) +* **efs:** fix bug when setting both lifecyclePolicy and outOfInfrequentAccessPolicy ([#19082](https://github.com/aws/aws-cdk/issues/19082)) ([d435ab6](https://github.com/aws/aws-cdk/commit/d435ab6120c47464427489d98bea9347983a2123)), closes [#19058](https://github.com/aws/aws-cdk/issues/19058) +* **lambda-nodejs:** local tsc detection with pre compilation ([#19266](https://github.com/aws/aws-cdk/issues/19266)) ([5de7b86](https://github.com/aws/aws-cdk/commit/5de7b86d916be6ab892e75e18c54a327fe1f65ff)), closes [#19242](https://github.com/aws/aws-cdk/issues/19242) +* **lambda-python:** asset bundling fails on windows ([#19270](https://github.com/aws/aws-cdk/issues/19270)) ([0da57da](https://github.com/aws/aws-cdk/commit/0da57da9606d982788350a6257f0f0ed6e9fd92a)), closes [#18861](https://github.com/aws/aws-cdk/issues/18861) +* **lambda-python:** docker image gets built even when we don't need to bundle assets ([#16192](https://github.com/aws/aws-cdk/issues/16192)) ([5dc61ea](https://github.com/aws/aws-cdk/commit/5dc61eabc0ea3e6294f83db5deb8528461a1d5bc)), closes [#14747](https://github.com/aws/aws-cdk/issues/14747) +* **rds:** allow cluster from snapshot to enable encrypted storage ([#19175](https://github.com/aws/aws-cdk/issues/19175)) ([bd4141d](https://github.com/aws/aws-cdk/commit/bd4141d864612974829c95d530085d4f18bdfeb8)), closes [#17241](https://github.com/aws/aws-cdk/issues/17241) +* **rds:** read replica instance cannot join domain ([#19202](https://github.com/aws/aws-cdk/issues/19202)) ([cef8fec](https://github.com/aws/aws-cdk/commit/cef8fec1b0410daa6b57c152e9bad73dcc034397)), closes [#18786](https://github.com/aws/aws-cdk/issues/18786) +* **rds:** subnet selection not respected for multi user secret rotation ([#19237](https://github.com/aws/aws-cdk/issues/19237)) ([dc7a17c](https://github.com/aws/aws-cdk/commit/dc7a17cd20198a6eb52c2ab25857e73bd7048d26)), closes [#19233](https://github.com/aws/aws-cdk/issues/19233) + +## [1.147.0](https://github.com/aws/aws-cdk/compare/v1.146.0...v1.147.0) (2022-03-01) + + +### Features + +* **cfnspec:** cloudformation spec v58.0.0 ([#19153](https://github.com/aws/aws-cdk/issues/19153)) ([a6b0a10](https://github.com/aws/aws-cdk/commit/a6b0a1018694a0696ed27635d4def5d1630b8f9a)) +* **cli:** hotswap support for resources in nested stacks ([#18950](https://github.com/aws/aws-cdk/issues/18950)) ([2ea9da1](https://github.com/aws/aws-cdk/commit/2ea9da118794809265d215e3d2f554bbcb91b271)) +* **ec2:** add c6a instances ([#19113](https://github.com/aws/aws-cdk/issues/19113)) ([427cdfd](https://github.com/aws/aws-cdk/commit/427cdfde5e8c48ed7c1f86b275ccb2516a901239)) + + +### Bug Fixes + +* **apigateway:** fix strange vtl template for cors preflight request ([#19104](https://github.com/aws/aws-cdk/issues/19104)) ([59ef06a](https://github.com/aws/aws-cdk/commit/59ef06ae2a70fcb1800fcc1f40eec671c77440f0)), closes [/datatracker.ietf.org/doc/html/rfc6454#section-7](https://github.com/aws//datatracker.ietf.org/doc/html/rfc6454/issues/section-7) +* **aws-apigateway:** api gateway usage plan ([#19023](https://github.com/aws/aws-cdk/issues/19023)) ([5b764cc](https://github.com/aws/aws-cdk/commit/5b764cc397de4f4b203f5c69fa0128c6dced49f9)), closes [#18994](https://github.com/aws/aws-cdk/issues/18994) +* **aws-lambda-python:** skip default docker build when image passed ([#19143](https://github.com/aws/aws-cdk/issues/19143)) ([7300f2e](https://github.com/aws/aws-cdk/commit/7300f2eee9e1593eef271d7a953edf80a8962e08)), closes [#18082](https://github.com/aws/aws-cdk/issues/18082) +* **cli:** cdk version displays notices ([#19181](https://github.com/aws/aws-cdk/issues/19181)) ([fa16f7a](https://github.com/aws/aws-cdk/commit/fa16f7a9c11981da75e44ffc83adcdc6edad94fc)) +* **cli:** long connection timeout slows the CLI down ([#19187](https://github.com/aws/aws-cdk/issues/19187)) ([6595d04](https://github.com/aws/aws-cdk/commit/6595d044e29fb262fb62430783ad08359e16bc30)) +* **custom-resources:** physical resource id must be determined before isComplete ([#18630](https://github.com/aws/aws-cdk/issues/18630)) ([c190367](https://github.com/aws/aws-cdk/commit/c1903678aba31ca5b23a3bebb84249921e15dd5c)) +* **dynamodb:** `grant*Data()` methods are missing the `dynamodb:DescribeTable` permission ([#19129](https://github.com/aws/aws-cdk/issues/19129)) ([4a44a65](https://github.com/aws/aws-cdk/commit/4a44a65bb4634081e04811966d5f4e2fd49bc7c6)), closes [#18773](https://github.com/aws/aws-cdk/issues/18773) +* **dynamodb:** `Table.grantWriteData()` doesn't include enough KMS permissions ([#19102](https://github.com/aws/aws-cdk/issues/19102)) ([77f1e0b](https://github.com/aws/aws-cdk/commit/77f1e0b57bd4508ade86be7733e71e94a47d7f4c)), closes [#10010](https://github.com/aws/aws-cdk/issues/10010) +* **ec2:** invalid volume type check for iops ([#19073](https://github.com/aws/aws-cdk/issues/19073)) ([3f49f02](https://github.com/aws/aws-cdk/commit/3f49f020090142c77feb892894c54e62dc4de7ae)) +* **eks:** Helm charts fail to install when provided as an asset ([#19180](https://github.com/aws/aws-cdk/issues/19180)) ([9961257](https://github.com/aws/aws-cdk/commit/99612574bbaf97379482e9e424e1d1115809d74b)) +* **lambda-nodejs:** `logLevel` property of `BundlingOptions` is ignored when `nodeModules` are defined ([#18456](https://github.com/aws/aws-cdk/issues/18456)) ([5c40b90](https://github.com/aws/aws-cdk/commit/5c40b90707b869f62e59613d50d5deaafbaa52f1)), closes [#18383](https://github.com/aws/aws-cdk/issues/18383) +* **stepfunctions-tasks:** RUN_JOB integration pattern not supported for CallAwsService ([#19186](https://github.com/aws/aws-cdk/issues/19186)) ([4b134b7](https://github.com/aws/aws-cdk/commit/4b134b785115f026a0eaa37b699cd32c85ff8e73)), closes [#19174](https://github.com/aws/aws-cdk/issues/19174) +* apply tags to nested stack ([#19128](https://github.com/aws/aws-cdk/issues/19128)) ([3af329b](https://github.com/aws/aws-cdk/commit/3af329bcb66b9dffce0c03f0816b33e91e901808)), closes [#17463](https://github.com/aws/aws-cdk/issues/17463) +* **triggers:** not published as part of v2 ([#19168](https://github.com/aws/aws-cdk/issues/19168)) ([8f727d1](https://github.com/aws/aws-cdk/commit/8f727d15f8f87d4ca323fee449826908db7971a4)), closes [#19164](https://github.com/aws/aws-cdk/issues/19164) +* construct paths are not printed for nested stacks in CLI output ([#18725](https://github.com/aws/aws-cdk/issues/18725)) ([b0e0155](https://github.com/aws/aws-cdk/commit/b0e0155f87a65c34a75e11776f98d55b83d2b220)) +* **rds:** MySQL Cluster version 8.0 uses wrong Parameter for S3 import ([#19145](https://github.com/aws/aws-cdk/issues/19145)) ([96b2034](https://github.com/aws/aws-cdk/commit/96b2034c44b441a96cfe19855d343b0f983c8772)), closes [#19126](https://github.com/aws/aws-cdk/issues/19126) + +## [1.146.0](https://github.com/aws/aws-cdk/compare/v1.145.0...v1.146.0) (2022-02-24) + + +### Features + +* **apigatewayv2:** Import existing WebSocketApi from attributes ([#18958](https://github.com/aws/aws-cdk/issues/18958)) ([f203845](https://github.com/aws/aws-cdk/commit/f203845d26ae8333f467f1cb91ad965697087d85)) +* **cli:** bundle dependencies ([#18667](https://github.com/aws/aws-cdk/issues/18667)) ([31d135f](https://github.com/aws/aws-cdk/commit/31d135fb51d3cd4e26fbdc132e03815a1416da75)) +* **cli:** support for matching notices with arbitrary module names ([#19088](https://github.com/aws/aws-cdk/issues/19088)) ([a87dee7](https://github.com/aws/aws-cdk/commit/a87dee756057e554909207237b70f80af185b110)) +* **cli:** support for notices ([#18936](https://github.com/aws/aws-cdk/issues/18936)) ([d37fbbb](https://github.com/aws/aws-cdk/commit/d37fbbbb31003d69da88b9340a6a9c9e1e927ac5)) +* **cloudfront-origins:** extend max keepaliveTimeout of HttpOrigin to 180 ([#18837](https://github.com/aws/aws-cdk/issues/18837)) ([171fdcd](https://github.com/aws/aws-cdk/commit/171fdcdf595fcff5b2567b17e6fa73bf0d42e1bc)), closes [#18697](https://github.com/aws/aws-cdk/issues/18697) +* **eks:** Allow helm pull from OCI repositories ([#18547](https://github.com/aws/aws-cdk/issues/18547)) ([7e624d9](https://github.com/aws/aws-cdk/commit/7e624d994c94dbd584643c4cb6e9f8df53dabc18)) +* **lambda:** add a fromFunctionName() method ([#19076](https://github.com/aws/aws-cdk/issues/19076)) ([5b92cc3](https://github.com/aws/aws-cdk/commit/5b92cc3a31eea29b40814498fca614eb1c7c8724)), closes [#18255](https://github.com/aws/aws-cdk/issues/18255) [#19031](https://github.com/aws/aws-cdk/issues/19031) +* **pipelines:** ECR source action ([#16385](https://github.com/aws/aws-cdk/issues/16385)) ([fc11ae2](https://github.com/aws/aws-cdk/commit/fc11ae2c4ec3bd9dfe3ff813aa831c744d8ac444)), closes [#16378](https://github.com/aws/aws-cdk/issues/16378) +* **pipelines:** step outputs ([#19024](https://github.com/aws/aws-cdk/issues/19024)) ([0dec2ee](https://github.com/aws/aws-cdk/commit/0dec2ee78a70832c3a697be26c67498460a587dd)), closes [#17189](https://github.com/aws/aws-cdk/issues/17189) [#18893](https://github.com/aws/aws-cdk/issues/18893) [#15943](https://github.com/aws/aws-cdk/issues/15943) [#16407](https://github.com/aws/aws-cdk/issues/16407) +* **rds:** make VPC optional for serverless Clusters ([#17413](https://github.com/aws/aws-cdk/issues/17413)) ([4f7818d](https://github.com/aws/aws-cdk/commit/4f7818dd76bd48ed652407f4852cc97ba57d7395)), closes [#17401](https://github.com/aws/aws-cdk/issues/17401) +* triggers ([#19011](https://github.com/aws/aws-cdk/issues/19011)) ([11d6c69](https://github.com/aws/aws-cdk/commit/11d6c69a8b1ee70cbea025d134be7702dd804444)) + + +### Bug Fixes + +* **cli:** hotswapping is slow for many resources deployed at once ([#19081](https://github.com/aws/aws-cdk/issues/19081)) ([040238e](https://github.com/aws/aws-cdk/commit/040238e9285945d1c48ef79474e527b871e7824c)), closes [#19021](https://github.com/aws/aws-cdk/issues/19021) +* **s3-notifications:** notifications allowed with imported kms keys ([#18989](https://github.com/aws/aws-cdk/issues/18989)) ([7441418](https://github.com/aws/aws-cdk/commit/7441418fbf9ffdf8d85a573e3c81c45c5648fe8a)) +* API compatibility check fails in CI pipeline ([#19069](https://github.com/aws/aws-cdk/issues/19069)) ([6ec1005](https://github.com/aws/aws-cdk/commit/6ec1005c9cfa9723520885748d759b00be5cd2fa)), closes [#19070](https://github.com/aws/aws-cdk/issues/19070) +* **cloudfront:** trim autogenerated cache policy name ([#18953](https://github.com/aws/aws-cdk/issues/18953)) ([c7394c9](https://github.com/aws/aws-cdk/commit/c7394c96c42cb6a5af1e309bee2a5f11eb3ad35c)), closes [#18918](https://github.com/aws/aws-cdk/issues/18918) +* **elasticloadbalancingv2:** validate port/protocol are not provided for lambda targets ([#19043](https://github.com/aws/aws-cdk/issues/19043)) ([64d26cc](https://github.com/aws/aws-cdk/commit/64d26cc22b1fe456777c3367769ddbe860f26cf3)), closes [#12514](https://github.com/aws/aws-cdk/issues/12514) +* **route53:** fix cross account delegation deployment dependency ([#19047](https://github.com/aws/aws-cdk/issues/19047)) ([692a0d0](https://github.com/aws/aws-cdk/commit/692a0d06f2865503d1d88b0ba8af38ecceaec871)), closes [#19041](https://github.com/aws/aws-cdk/issues/19041) + +## [1.145.0](https://github.com/aws/aws-cdk/compare/v1.144.0...v1.145.0) (2022-02-18) + + +### Features + +* **aws-stepfunctions-tasks:** add environment property for SageMakerCreateTrainingJob ([#18976](https://github.com/aws/aws-cdk/issues/18976)) ([60d6e66](https://github.com/aws/aws-cdk/commit/60d6e66baef9d30db23e93b16f7c6d159ddf58c4)), closes [#18919](https://github.com/aws/aws-cdk/issues/18919) +* **cfnspec:** cloudformation spec v56.0.0 ([#18930](https://github.com/aws/aws-cdk/issues/18930)) ([24a52ae](https://github.com/aws/aws-cdk/commit/24a52ae1c250ec1875e64d6fc4ef8bec2f47399a)) +* **cfnspec:** cloudformation spec v57.0.0 ([#19030](https://github.com/aws/aws-cdk/issues/19030)) ([f0acbc4](https://github.com/aws/aws-cdk/commit/f0acbc469d835ad8808f4176eed53bf2af7c66e2)) +* **cli:** hotswap for appsync vtl mapping template changes ([#18881](https://github.com/aws/aws-cdk/issues/18881)) ([9858002](https://github.com/aws/aws-cdk/commit/985800228d04b9c2f3ac117e3b41c7f089547d38)) +* **codepipeline:** add support for CloudFormation StackSet actions ([#14225](https://github.com/aws/aws-cdk/issues/14225)) ([d8bc0d0](https://github.com/aws/aws-cdk/commit/d8bc0d08a9796724bb31cc5d7552cf99297678d9)) +* **config:** S3_BUCKET_LEVEL_PUBLIC_ACCESS_PROHIBITED managed rule ([#18890](https://github.com/aws/aws-cdk/issues/18890)) ([1a7e3e2](https://github.com/aws/aws-cdk/commit/1a7e3e20e005b4165a27506615c7245b88ce998b)), closes [#18888](https://github.com/aws/aws-cdk/issues/18888) +* **core:** stack synthesizer that uses CLI credentials ([#18963](https://github.com/aws/aws-cdk/issues/18963)) ([a36b72b](https://github.com/aws/aws-cdk/commit/a36b72b5045fceada7c96d00770d8c48f2ca1415)), closes [#16888](https://github.com/aws/aws-cdk/issues/16888) +* **ec2:** allow imdsv2 usage on bastion host ([#18955](https://github.com/aws/aws-cdk/issues/18955)) ([8c6777c](https://github.com/aws/aws-cdk/commit/8c6777c904588f9b911d8b8a5d63a65ae1c7aad9)) +* **ecs:** support version stages and ids for Secrets ([#18174](https://github.com/aws/aws-cdk/issues/18174)) ([6d091c2](https://github.com/aws/aws-cdk/commit/6d091c2da7749a81c3752953d0bc7db65ab48f45)), closes [#18123](https://github.com/aws/aws-cdk/issues/18123) +* **events:** API Destinations ([#13729](https://github.com/aws/aws-cdk/issues/13729)) ([2adbc14](https://github.com/aws/aws-cdk/commit/2adbc14bae8266a6bd357e752185133a32e4ca87)) +* **iot-actions:** add SNS publish action ([#18839](https://github.com/aws/aws-cdk/issues/18839)) ([3a39f6b](https://github.com/aws/aws-cdk/commit/3a39f6bf34eb428c527db1c614ed682c582821fb)), closes [#17700](https://github.com/aws/aws-cdk/issues/17700) +* **iotevents:** create new module for IoT Events actions ([#18956](https://github.com/aws/aws-cdk/issues/18956)) ([3533ea9](https://github.com/aws/aws-cdk/commit/3533ea9cb7ec7fd9e230abd27556a87d3559bdb8)), closes [/github.com/aws/aws-cdk/pull/18869#discussion_r802719713](https://github.com/aws//github.com/aws/aws-cdk/pull/18869/issues/discussion_r802719713) +* **lambda:** allow Topic to be dlq for Lambda ([#18546](https://github.com/aws/aws-cdk/issues/18546)) ([f8d8fe4](https://github.com/aws/aws-cdk/commit/f8d8fe4e1397e3d8da91a3a44f025475c8b7f592)), closes [#16246](https://github.com/aws/aws-cdk/issues/16246) +* **logs:** custom Role for Kinesis destination ([#13553](https://github.com/aws/aws-cdk/issues/13553)) ([bb96621](https://github.com/aws/aws-cdk/commit/bb96621d642fedcf1e22086a249034ca1ab63f73)), closes [#7661](https://github.com/aws/aws-cdk/issues/7661) +* **rds:** simpler way to configure parameters for instance and cluster ([#18126](https://github.com/aws/aws-cdk/issues/18126)) ([3ba9088](https://github.com/aws/aws-cdk/commit/3ba90881dab49f47220872e6e5afef3a7732ef13)), closes [#18124](https://github.com/aws/aws-cdk/issues/18124) +* **s3-deployment:** add `deployedBucket` attribute for sequencing ([#15384](https://github.com/aws/aws-cdk/issues/15384)) ([edac101](https://github.com/aws/aws-cdk/commit/edac1011574f3cf38bb0ac39400bf41c66337ffd)) + + +### Bug Fixes + +* **assertions:** 'pattern.indexOf' is not a function ([#19009](https://github.com/aws/aws-cdk/issues/19009)) ([6df26e7](https://github.com/aws/aws-cdk/commit/6df26e7ed73455b77b07707debef5bb26ae78909)) +* **assertions:** incorrect assertions when >1 messages on a resource ([#18948](https://github.com/aws/aws-cdk/issues/18948)) ([072e1b9](https://github.com/aws/aws-cdk/commit/072e1b990a43768b88a05dd436dd6d6d9649c13a)), closes [#18840](https://github.com/aws/aws-cdk/issues/18840) +* **aws-cdk:** include nested stacks when building changesets ([#17396](https://github.com/aws/aws-cdk/issues/17396)) ([a7dbeef](https://github.com/aws/aws-cdk/commit/a7dbeef9eae3e00e209d06f5cc5bb3bf3d084d18)), closes [#5722](https://github.com/aws/aws-cdk/issues/5722) +* **cli:** handle attributes of AWS::Events::EventBus when hotswapping ([#18834](https://github.com/aws/aws-cdk/issues/18834)) ([a30a32a](https://github.com/aws/aws-cdk/commit/a30a32aaa5dfb764022370fe7867564d57640bfb)), closes [#18831](https://github.com/aws/aws-cdk/issues/18831) +* **core:** undeployable due to invalid mapping ([#18922](https://github.com/aws/aws-cdk/issues/18922)) ([db28485](https://github.com/aws/aws-cdk/commit/db28485f4d2ea243e4184dd06b52395b4980beba)), closes [#18789](https://github.com/aws/aws-cdk/issues/18789) [#18789](https://github.com/aws/aws-cdk/issues/18789) +* **lambda:** unlock use case for cross-account functions w/ preconfigured permissions ([#18979](https://github.com/aws/aws-cdk/issues/18979)) ([023108a](https://github.com/aws/aws-cdk/commit/023108ac080ba34c82ef0b60fee20014c4a78428)), closes [#18228](https://github.com/aws/aws-cdk/issues/18228) [#18781](https://github.com/aws/aws-cdk/issues/18781) [#18967](https://github.com/aws/aws-cdk/issues/18967) [#18781](https://github.com/aws/aws-cdk/issues/18781) +* **lambda:** Validate Lambda "functionName" parameter ([#17970](https://github.com/aws/aws-cdk/issues/17970)) ([a416a2d](https://github.com/aws/aws-cdk/commit/a416a2d68f14c0711d42b38e81b0091d160dfd6f)), closes [#13264](https://github.com/aws/aws-cdk/issues/13264) +* **pipelines:** self-mutate always adds analytics ([#19010](https://github.com/aws/aws-cdk/issues/19010)) ([bc47b29](https://github.com/aws/aws-cdk/commit/bc47b2937a806d6522a4d9106976200bf6810024)), closes [#18933](https://github.com/aws/aws-cdk/issues/18933) +* **stepfunctions:** imported State Machine sill has region and account from its Stack, instead of its ARN ([#19026](https://github.com/aws/aws-cdk/issues/19026)) ([23329b4](https://github.com/aws/aws-cdk/commit/23329b4ac7c845efe7d0e0d7ce03499e7dd723ac)), closes [#17982](https://github.com/aws/aws-cdk/issues/17982) +* python3 version check with Python 3.10 ([#18754](https://github.com/aws/aws-cdk/issues/18754)) ([0ef6527](https://github.com/aws/aws-cdk/commit/0ef65279cc5f2269046e0bae05d44f5aabc43eb9)) +* **stepfunctions-tasks:** EMR Create Cluster does not support dynamic allocation of step concurrency level ([#18972](https://github.com/aws/aws-cdk/issues/18972)) ([d19e538](https://github.com/aws/aws-cdk/commit/d19e5386f737aa58f27c7ac2082306006dcd6d95)) +* **synthetics:** generated role has incorrect permissions for cloudwatch logs ([#18946](https://github.com/aws/aws-cdk/issues/18946)) ([f8bb85f](https://github.com/aws/aws-cdk/commit/f8bb85fad8f659a2b72d5d05d7a94c97765a76f8)), closes [#18910](https://github.com/aws/aws-cdk/issues/18910) + +## [1.144.0](https://github.com/aws/aws-cdk/compare/v1.143.0...v1.144.0) (2022-02-08) + + +### Features + +* **assets:** support networking mode for DockerImageAsset ([#18114](https://github.com/aws/aws-cdk/issues/18114)) ([a7b39f5](https://github.com/aws/aws-cdk/commit/a7b39f527976e29a7f39c1ba1813efba2e0aa209)), closes [#15516](https://github.com/aws/aws-cdk/issues/15516) +* **cfnspec:** cloudformation spec v55.0.0 ([#18827](https://github.com/aws/aws-cdk/issues/18827)) ([a1d94b3](https://github.com/aws/aws-cdk/commit/a1d94b3624eb1b6b543d8ce209ec85af8e85beda)) +* **cli:** `cdk diff` works for Nested Stacks ([#18207](https://github.com/aws/aws-cdk/issues/18207)) ([1337b24](https://github.com/aws/aws-cdk/commit/1337b247e82d9462074416623e665cf9526d2cc0)), closes [#5722](https://github.com/aws/aws-cdk/issues/5722) +* **iotevents:** add grant method to Input class ([#18617](https://github.com/aws/aws-cdk/issues/18617)) ([e89688e](https://github.com/aws/aws-cdk/commit/e89688ec1dd7a3b072d23287cddcb73bccc16fd4)) +* **iotevents:** support transition events ([#18768](https://github.com/aws/aws-cdk/issues/18768)) ([ccc1988](https://github.com/aws/aws-cdk/commit/ccc198864f92620857da09c68013123e9cd3f01d)), closes [#17711](https://github.com/aws/aws-cdk/issues/17711) +* **s3-deployment:** deploy data with deploy-time values ([#18659](https://github.com/aws/aws-cdk/issues/18659)) ([d40e332](https://github.com/aws/aws-cdk/commit/d40e332578f7590a0c949fdd01622a644cf9359b)), closes [#12903](https://github.com/aws/aws-cdk/issues/12903) + + +### Bug Fixes + +* **aws-appsync:** Strip unsupported characters from Lambda DataSource ([#18765](https://github.com/aws/aws-cdk/issues/18765)) ([bb8d6f6](https://github.com/aws/aws-cdk/commit/bb8d6f6bf5941b76ef0590c99fe8e26440e09c18)) +* **tooling:** update vscode devcontainer image ([#18455](https://github.com/aws/aws-cdk/issues/18455)) ([28647f7](https://github.com/aws/aws-cdk/commit/28647f7105da6bd02975aa7d90300d77fe85d0e6)) + ## [1.143.0](https://github.com/aws/aws-cdk/compare/v1.142.0...v1.143.0) (2022-02-02) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 25ed091ee83e4..c769e0f191e1c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -89,7 +89,7 @@ specific to the CDK. ### Build -The full build of the CDK takes a long time complete; 1-2 hours depending on the performance of the build machine. +The full build of the CDK takes a long time to complete; 1-2 hours depending on the performance of the build machine. However, most first time contributions will require changing only one CDK module, sometimes two. A full build of the CDK is not required in these cases. @@ -234,9 +234,17 @@ Integration tests perform a few functions in the CDK code base - 3. (Optionally) Acts as a way to validate that constructs set up the CloudFormation resources as expected. A successful CloudFormation deployment does not mean that the resources are set up correctly. -If you are working on a new feature that is using previously unused CloudFormation resource types, or involves -configuring resource types across services, you need to write integration tests that use these resource types or -features. +**When are integration tests required?** + +The following list contains common scenarios where we _know_ that integration tests are required. +This is not an exhaustive list and we will, by default, require integration tests for all +new features unless there is a good reason why one is not needed. + +1. Adding a new feature that is using previously unused CloudFormation resource types +2. Adding a new feature that is using previously unused (or untested) CloudFormation properties +3. Involves configuring resource types across services (i.e. integrations) +4. Adding a new supported version (e.g. a new [AuroraMysqlEngineVersion](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_rds.AuroraMysqlEngineVersion.html)) +5. Adding any functionality via a [Custom Resource](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.custom_resources-readme.html) To the extent possible, include a section (like below) in the integration test file that specifies how the successfully deployed stack can be verified for correctness. Correctness here implies that the resources have been set up correctly. @@ -254,6 +262,16 @@ Examples: * [integ.destinations.ts](https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-lambda-destinations/test/integ.destinations.ts#L7) * [integ.token-authorizer.lit.ts](https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer.lit.ts#L7-L12) +**What do do if you cannot run integration tests** + +If you are working on a PR that requires an update to an integration test and you are unable +to run the `cdk-integ` tool to perform a real deployment, please call this out on the pull request +so a maintainer can run the tests for you. Please **do not** run the `cdk-integ` tool with `--dry-run` +or manually update the snapshot. + +See the [integration test guide](./INTEGRATION_TESTS.md) for a more complete guide on running +CDK integration tests. + #### yarn watch (Optional) We've added a watch feature to the CDK that builds your code as you type it. Start this by running `yarn watch` for @@ -292,6 +310,8 @@ $ yarn watch & # runs in the background * Shout out to collaborators. +* Call out any new [unconventional dependencies](#adding-new-unconventional-dependencies) that are created as part of your PR. + * If not obvious (i.e. from unit tests), describe how you verified that your change works. * If this PR includes breaking changes, they must be listed at the end in the following format @@ -312,6 +332,30 @@ $ yarn watch & # runs in the background * Make sure to update the PR title/description if things change. The PR title/description are going to be used as the commit title/message and will appear in the CHANGELOG, so maintain them all the way throughout the process. +#### Adding new unconventional dependencies + +**For the aws-cdk an unconventional dependency is defined as any dependency that is not managed via the module's +`package.json` file.** + +Sometimes constructs introduce new unconventional dependencies. Any new unconventional dependency that is introduced needs to have +an auto upgrade process in place. The recommended way to update dependencies is through [dependabot](https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates). +You can find the dependabot config file [here](./.github/dependabot.yml). + +An example of this is the [@aws-cdk/lambda-layer-awscli](packages/@aws-cdk/lambda-layer-awscli) module. +This module creates a lambda layer that bundles the AWS CLI. This is considered an unconventional +dependency because the AWS CLI is bundled into the CDK as part of the build, and the version +of the AWS CLI that is bundled is not managed by the `package.json` file. + +In order to automatically update the version of the AWS CLI, a custom build process was +created that takes upgrades into consideration. You can take a look at the files in +[packages/@aws-cdk/lambda-layer-awscli/layer](packages/@aws-cdk/lambda-layer-awscli/layer) +to see how the build works, but at a high level a [requirements.txt](packages/@aws-cdk/lambda-layer-awscli/layer/requirements.txt) +file was created to manage the version. This file was then added to [dependabot.yml](https://github.com/aws/aws-cdk/blob/ab57eb6d1ed69b40ed6ec774853c275785acace8/.github/dependabot.yml#L14-L20) +so that dependabot will automatically upgrade the version as new versions are released. + +**If you think your PR introduces a new unconventional dependency, make sure to call it +out in the description so that we can discuss the best way to manage that dependency.** + ### Step 5: Merge * Make sure your PR builds successfully (we have CodeBuild setup to automatically build all PRs). @@ -343,6 +387,7 @@ Breaking changes come in two flavors: * API surface changes * Behavior changes + ### API surface changes This encompasses any changes that affect the shape of the API. Changes that @@ -481,7 +526,7 @@ grantAwesomePowerBeta1(); ``` Times goes by, we get feedback that this method will actually be much better -if it accept a `Principal`. Since adding a required property is a breaking +if it accepts a `Principal`. Since adding a required property is a breaking change, we will add `grantAwesomePowerBeta2()` and deprecate `grantAwesomePowerBeta1`: diff --git a/INTEGRATION_TESTS.md b/INTEGRATION_TESTS.md new file mode 100644 index 0000000000000..3f21037d95aa2 --- /dev/null +++ b/INTEGRATION_TESTS.md @@ -0,0 +1,225 @@ +# Integration Tests + +This document describes the purpose of integration tests as well as acting as a guide +on what type of changes require integrations tests and how you should write integration tests. + +- [What are CDK Integration Tests](#what-are-cdk-integration-tests) +- [When are integration tests required](#when-are-integration-tests-required) +- [How to write Integration Tests](#how-to-write-integration-tests) + - [Creating a test](#creating-a-test) + - [New L2 Constructs](#new-l2-constructs) + - [Existing L2 Constructs](#existing-l2-constructs) + - [Assertions](#assertions) + +## What are CDK Integration Tests + +All Construct libraries in the CDK code base have integration tests that serve to - + +1. Acts as a regression detector. It does this by running `cdk synth` on the integration test and comparing it against + the `*.expected.json` file. This highlights how a change affects the synthesized stacks. +2. Allows for a way to verify if the stacks are still valid CloudFormation templates, as part of an intrusive change. + This is done by running `yarn integ` which will run `cdk deploy` across all of the integration tests in that package. + If you are developing a new integration test or for some other reason want to work on a single integration test + over and over again without running through all the integration tests you can do so using + `yarn integ integ.test-name.js` .Remember to set up AWS credentials before doing this. +3. (Optionally) Acts as a way to validate that constructs set up the CloudFormation resources as expected. + A successful CloudFormation deployment does not mean that the resources are set up correctly. + + +## When are Integration Tests Required + +The following list contains common scenarios where we _know_ that integration tests are required. +This is not an exhaustive list and we will, by default, require integration tests for all +new features unless there is a good reason why one is not needed. + +**1. Adding a new feature that is using previously unused CloudFormation resource types** +For example, adding a new L2 construct for an L1 resource. There should be a new integration test +to test that the new L2 successfully creates the resources in AWS. + +**2. Adding a new feature that is using previously unused (or untested) CloudFormation properties** +For example, there is an existing L2 construct for a CloudFormation resource and you are adding +support for a new property. This could be either a new property that has been added to CloudFormation +or an existing property that the CDK did not have coverage for. You should either update and existing +integration test to cover this new property or create a new test. + +Sometimes the CloudFormation documentation is incorrect or unclear on the correct way to configure +a property. This can lead to introducing new features that don't actually work. Creating +an integration test for the new feature can ensure that it works and avoid unnecessary bugs. + +**3. Involves configuring resource types across services (i.e. integrations)** +For example, you are adding functionality that allows for service x to integrate with service y. +A good example of this is the [aws-stepfunctions-tasks](./packages/@aws-cdk/aws-stepfunctions-tasks) or +[aws-apigatewayv2-integrations](./packages/@aws-cdk/aws-apigatewayv2-integrations) modules. Both of these +have L2 constructs that provide functionality to integrate services. + +Sometimes these integrations involve configuring/formatting json/vtl or some other type of data. +For these types of features it is important to create an integration test that not only validates +that the infrastructure deploys successfully, but that the intended functionality works. This could +mean deploying the integration test and then manually making an HTTP request or invoking a Lambda function. + +**4. Adding a new supported version (e.g. a new [AuroraMysqlEngineVersion](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_rds.AuroraMysqlEngineVersion.html))** +Sometimes new versions introduce new CloudFormation properties or new required configuration. +For example Aurora MySQL version 8 introduced a new parameter and was not compatible with the +existing parameter (see [#19145](https://github.com/aws/aws-cdk/pull/19145)). + +**5. Adding any functionality via a [Custom Resource](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.custom_resources-readme.html)** +Custom resources involve non-standard functionality and are at a higher risk of introducing bugs. + +## How to write Integration Tests + +This section will detail how to write integration tests, how they are executed and how to ensure +you have good test coverage. + +### Creating a Test + +An integration tests is any file located in the `test/` directory that has a name that starts with `integ.` +(e.g. `integ.*.ts`). + +To create a new integration test, first create a new file, for example `integ.my-new-construct.ts`. +The contents of this file should be a CDK app. For example, a very simple integration test for a +Lambda Function would look like this: + +_integ.lambda.ts_ +```ts +import * as iam from '@aws-cdk/aws-iam'; +import * as cdk from '@aws-cdk/core'; +import * as lambda from '../lib'; + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'aws-cdk-lambda-1'); + +const fn = new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, +}); + +app.synth(); +``` + +To run the test you would run: + +*Note - filename must be `*.js`* +``` +npm run cdk-integ integ.lambda.js +``` + +This will: +1. Synthesize the CDK app +2. `cdk deploy` to your AWS account +3. `cdk destroy` to delete the stack +4. Save a snapshot of the synthed CloudFormation template to `integ.lambda.expected.json` + +Now when you run `npm test` it will synth the integ app and compare the result with the snapshot. +If the snapshot has changed the same process must be followed to update the snapshot. + +### New L2 Constructs + +When creating a new L2 construct (or new construct library) it is important to ensure you have a good +coverage base from which future contributions can build on. + +Some general rules to follow are: + +- **1 test with all default values** +One test for each L2 that only populates the required properties. For a Lambda Function this would look like: + +```ts +new lambda.Function(this, 'Handler', { + code, + handler, + runtime, +}); +``` + +- **1 test with all values provided** +One test for each L2 that populates non-default properties. Some of this will come down to judgement, but this should +be based on major functionality. For example, when testing a Lambda Function there are 37 (*at the time of this writing) different +input parameters. Some of these can be tested together and don't represent large pieces of functionality, +while others do. + +For example, the test for a Lambda Function might look like this. For most of these properties we are probably fine +testing them together and just testing one of their values. For example we don't gain much by testing a bunch of +different `memorySize` settings, as long as we test that we can `set` the memorySize then we should be good. + +```ts +new lambda.Function(this, 'Handler', { + code, + handler, + runtime, + architecture, + description, + environment, + environmentEncryption, + functionName, + initialPolicy, + insightsVersion, + layers, + maxEventAge, + memorySize, + reservedConcurrentExecutions, + retryAttempts, + role, + timeout, + tracing, +}); +``` + +Other parameters might represent larger pieces of functionality and might create other resources for us or configure +integrations with other services. For these it might make sense to split them out into separate tests so it is easier +to reason about them. + +A couple of examples would be +(you could also mix in different configurations of the above parameters with each of these): + +_testing filesystems_ +```ts +new lambda.Function(this, 'Handler', { + filesystem, +}); +``` + +_testing event sources_ +```ts +new lambda.Function(this, 'Handler', { + events, +}); +``` + +_testing VPCs_ +```ts +new lambda.Function(this, 'Handler', { + securityGroups, + vpc, + vpcSubnets, +}); +``` + +### Existing L2 Constructs + +Updating an existing L2 Construct could consist of: + +1. **Adding coverage for a new (or previously uncovered) CloudFormation property.** +In this case you would want to either add this new property to an existing integration test or create a new +integration test. A new integration test is preferred for larger update (e.g. adding VPC connectivity, etc). + +2. **Updating functionality for an existing property.** +In this case you should first check if you are already covered by an existing integration test. If not, then you would follow the +same process as adding new coverage. + +3. **Changing functionality that affects asset bundling** +Some constructs deal with asset bundling (i.e. `aws-lambda-nodejs`, `aws-lambda-python`, etc). There are some updates that may not +touch any CloudFormation property, but instead change the way that code is bundled. While these types of changes may not require +a change to an integration test, you need to make sure that the integration tests and assertions are rerun. + +An example of this would be making a change to the way `aws-lambda-nodejs` bundles Lambda code. A couple of things could go wrong that would +only be caught by rerunning the integration tests. + +1. The bundling commands are only running when performing a real synth (not part of unit tests). Running the integration test confirms +that the actual bundling was not broken. +2. When deploying Lambda Functions, CloudFormation will only update the Function configuration with the new code, +but it will not validate that the Lambda function can be invoked. Because of this, it is important to rerun the integration test +to deploy the Lambda Function _and_ then rerun the assertions to ensure that the function can still be invoked. + +### Assertions +...Coming soon... diff --git a/package.json b/package.json index 59b528b4f7d46..7680a471da635 100644 --- a/package.json +++ b/package.json @@ -16,17 +16,18 @@ }, "devDependencies": { "@yarnpkg/lockfile": "^1.1.0", - "cdk-generate-synthetic-examples": "^0.1.5", + "cdk-generate-synthetic-examples": "^0.1.8", "conventional-changelog-cli": "^2.2.2", "fs-extra": "^9.1.0", "graceful-fs": "^4.2.9", "jest-junit": "^13.0.0", - "jsii-diff": "^1.52.1", - "jsii-pacmak": "^1.52.1", - "jsii-reflect": "^1.52.1", - "jsii-rosetta": "^1.52.1", + "jsii-diff": "^1.55.1", + "jsii-pacmak": "^1.55.1", + "jsii-reflect": "^1.55.1", + "jsii-rosetta": "^1.55.1", "lerna": "^4.0.0", "patch-package": "^6.4.7", + "semver": "^6.3.0", "standard-version": "^9.3.2", "typescript": "~3.9.10" }, diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/package.json b/packages/@aws-cdk-containers/ecs-service-extensions/package.json index 016a3d84b427a..3587f60c10eda 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/package.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/package.json @@ -37,12 +37,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/aws-autoscaling": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", - "jest": "^27.4.7", + "jest": "^27.5.1", "@aws-cdk/pkglint": "0.0.0", "@aws-cdk/assertions": "0.0.0" }, diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.all-service-addons.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.all-service-addons.expected.json index 04e3fb87689fa..4f51a31f422dd 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.all-service-addons.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.all-service-addons.expected.json @@ -941,8 +941,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { @@ -972,30 +972,12 @@ ] } }, - { - "Action": "ecr:GetAuthorizationToken", - "Effect": "Allow", - "Resource": "*" - }, { "Action": [ - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "nametaskdefinitionenvoyLogGroup258B673B", - "Arn" - ] - } - }, - { - "Action": [ - "ecr:GetAuthorizationToken", "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetAuthorizationToken", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": "*" @@ -1006,38 +988,32 @@ "logs:PutLogEvents" ], "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "nametaskdefinitionfirelensLogGroup80DDA60F", - "Arn" - ] - } - }, - { - "Action": [ - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "nametaskdefinitionxrayLogGroup4AF4CA37", - "Arn" - ] - } - }, - { - "Action": [ - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "nametaskdefinitioncloudwatchagentLogGroup78DDC685", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "nametaskdefinitioncloudwatchagentLogGroup78DDC685", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "nametaskdefinitionenvoyLogGroup258B673B", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "nametaskdefinitionfirelensLogGroup80DDA60F", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "nametaskdefinitionxrayLogGroup4AF4CA37", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -1814,8 +1790,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { @@ -1845,30 +1821,12 @@ ] } }, - { - "Action": "ecr:GetAuthorizationToken", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "greetingtaskdefinitionenvoyLogGroup6556AC35", - "Arn" - ] - } - }, { "Action": [ - "ecr:GetAuthorizationToken", "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetAuthorizationToken", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": "*" @@ -1879,38 +1837,32 @@ "logs:PutLogEvents" ], "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "greetingtaskdefinitionfirelensLogGroupD7A398A7", - "Arn" - ] - } - }, - { - "Action": [ - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "greetingtaskdefinitionxrayLogGroupD25C072D", - "Arn" - ] - } - }, - { - "Action": [ - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "greetingtaskdefinitioncloudwatchagentLogGroupCEF72742", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "greetingtaskdefinitioncloudwatchagentLogGroupCEF72742", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "greetingtaskdefinitionenvoyLogGroup6556AC35", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "greetingtaskdefinitionfirelensLogGroupD7A398A7", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "greetingtaskdefinitionxrayLogGroupD25C072D", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -2810,8 +2762,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { @@ -2841,30 +2793,12 @@ ] } }, - { - "Action": "ecr:GetAuthorizationToken", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "greetertaskdefinitionenvoyLogGroup6E10B93E", - "Arn" - ] - } - }, { "Action": [ - "ecr:GetAuthorizationToken", "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetAuthorizationToken", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": "*" @@ -2875,38 +2809,32 @@ "logs:PutLogEvents" ], "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "greetertaskdefinitionfirelensLogGroupD5BAAC35", - "Arn" - ] - } - }, - { - "Action": [ - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "greetertaskdefinitionxrayLogGroupBC1558B6", - "Arn" - ] - } - }, - { - "Action": [ - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "greetertaskdefinitioncloudwatchagentLogGroupE7EAF327", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "greetertaskdefinitioncloudwatchagentLogGroupE7EAF327", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "greetertaskdefinitionenvoyLogGroup6E10B93E", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "greetertaskdefinitionfirelensLogGroupD5BAAC35", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "greetertaskdefinitionxrayLogGroupBC1558B6", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json index 556524b695267..dd7f3d375b03a 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json @@ -511,9 +511,9 @@ "Statement": [ { "Action": [ - "sqs:SendMessage", "sqs:GetQueueAttributes", - "sqs:GetQueueUrl" + "sqs:GetQueueUrl", + "sqs:SendMessage" ], "Condition": { "ArnEquals": { @@ -538,9 +538,9 @@ }, { "Action": [ - "sqs:SendMessage", "sqs:GetQueueAttributes", - "sqs:GetQueueUrl" + "sqs:GetQueueUrl", + "sqs:SendMessage" ], "Condition": { "ArnEquals": { @@ -740,11 +740,11 @@ }, { "Action": [ - "sqs:ReceiveMessage", "sqs:ChangeMessageVisibility", - "sqs:GetQueueUrl", "sqs:DeleteMessage", - "sqs:GetQueueAttributes" + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + "sqs:ReceiveMessage" ], "Effect": "Allow", "Resource": { @@ -757,16 +757,17 @@ { "Action": [ "dynamodb:BatchGetItem", + "dynamodb:BatchWriteItem", + "dynamodb:ConditionCheckItem", + "dynamodb:DeleteItem", + "dynamodb:DescribeTable", + "dynamodb:GetItem", "dynamodb:GetRecords", "dynamodb:GetShardIterator", + "dynamodb:PutItem", "dynamodb:Query", - "dynamodb:GetItem", "dynamodb:Scan", - "dynamodb:ConditionCheckItem", - "dynamodb:BatchWriteItem", - "dynamodb:PutItem", - "dynamodb:UpdateItem", - "dynamodb:DeleteItem" + "dynamodb:UpdateItem" ], "Effect": "Allow", "Resource": [ @@ -1050,12 +1051,28 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "nameserviceTaskRecordManagerCleanupResourceProviderHandler08068F99", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "nameserviceTaskRecordManagerCleanupResourceProviderHandler08068F99", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "nameserviceTaskRecordManagerCleanupResourceProviderHandler08068F99", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -1073,7 +1090,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, "S3Key": { "Fn::Join": [ @@ -1086,7 +1103,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -1099,7 +1116,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -1337,17 +1354,17 @@ "Type": "String", "Description": "Artifact hash for asset \"8f06a3db22794ebc7ff89b4745fd706afd46e17816fe46da72e5125cabae725d\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { "Type": "String", - "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { "Type": "String", - "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { "Type": "String", - "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16": { "Type": "String", diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.multiple-environments.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.multiple-environments.expected.json index fa97c69cefc1c..ecee47c85b2a4 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.multiple-environments.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.multiple-environments.expected.json @@ -1306,18 +1306,26 @@ "logs:PutLogEvents" ], "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "nameproductionlogsD0BFFE8C", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "nameproductionlogsD0BFFE8C", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "nameproductiontaskdefinitionenvoyLogGroupF79A2732", + "Arn" + ] + } + ] }, { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { @@ -1351,19 +1359,6 @@ "Action": "ecr:GetAuthorizationToken", "Effect": "Allow", "Resource": "*" - }, - { - "Action": [ - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "nameproductiontaskdefinitionenvoyLogGroupF79A2732", - "Arn" - ] - } } ], "Version": "2012-10-17" @@ -1868,18 +1863,26 @@ "logs:PutLogEvents" ], "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "namedevelopmentlogs108670CC", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "namedevelopmentlogs108670CC", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "namedevelopmenttaskdefinitionenvoyLogGroupF8FCAFD6", + "Arn" + ] + } + ] }, { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { @@ -1913,19 +1916,6 @@ "Action": "ecr:GetAuthorizationToken", "Effect": "Allow", "Resource": "*" - }, - { - "Action": [ - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "namedevelopmenttaskdefinitionenvoyLogGroupF8FCAFD6", - "Arn" - ] - } } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.publish-subscribe.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.publish-subscribe.expected.json index 24cd1d0a4e434..34ffb8672f890 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.publish-subscribe.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.publish-subscribe.expected.json @@ -548,16 +548,14 @@ { "Action": "sns:Publish", "Effect": "Allow", - "Resource": { - "Ref": "signupD2AAA171" - } - }, - { - "Action": "sns:Publish", - "Effect": "Allow", - "Resource": { - "Ref": "delete1CCE71FF" - } + "Resource": [ + { + "Ref": "delete1CCE71FF" + }, + { + "Ref": "signupD2AAA171" + } + ] } ], "Version": "2012-10-17" @@ -913,35 +911,27 @@ "Statement": [ { "Action": [ - "sqs:ReceiveMessage", "sqs:ChangeMessageVisibility", - "sqs:GetQueueUrl", "sqs:DeleteMessage", - "sqs:GetQueueAttributes" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "EventsQueueB96EB0D2", - "Arn" - ] - } - }, - { - "Action": [ - "sqs:ReceiveMessage", - "sqs:ChangeMessageVisibility", + "sqs:GetQueueAttributes", "sqs:GetQueueUrl", - "sqs:DeleteMessage", - "sqs:GetQueueAttributes" + "sqs:ReceiveMessage" ], "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "signupqueue33AFF2E6", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "EventsQueueB96EB0D2", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "signupqueue33AFF2E6", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/alexa-ask/package.json b/packages/@aws-cdk/alexa-ask/package.json index ece5934f1136a..2d533773cdc92 100644 --- a/packages/@aws-cdk/alexa-ask/package.json +++ b/packages/@aws-cdk/alexa-ask/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/app-delivery/package.json b/packages/@aws-cdk/app-delivery/package.json index 8d3da28ad60ba..89760784513ef 100644 --- a/packages/@aws-cdk/app-delivery/package.json +++ b/packages/@aws-cdk/app-delivery/package.json @@ -72,9 +72,9 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "fast-check": "^2.21.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "fast-check": "^2.23.2", + "jest": "^27.5.1" }, "repository": { "type": "git", diff --git a/packages/@aws-cdk/app-delivery/test/integ.cicd.expected.json b/packages/@aws-cdk/app-delivery/test/integ.cicd.expected.json index 9d53a0d8b915c..fa3888cc26741 100644 --- a/packages/@aws-cdk/app-delivery/test/integ.cicd.expected.json +++ b/packages/@aws-cdk/app-delivery/test/integ.cicd.expected.json @@ -29,16 +29,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -67,22 +67,20 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "CodePipelineDeployExecuteCodePipelineActionRoleAE36AF49", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "CodePipelineDeployChangeSetCodePipelineActionRoleB3BCDD8A", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "CodePipelineDeployChangeSetCodePipelineActionRoleB3BCDD8A", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "CodePipelineDeployExecuteCodePipelineActionRoleAE36AF49", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -334,8 +332,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -431,8 +429,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -471,4 +469,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/assert-internal/package.json b/packages/@aws-cdk/assert-internal/package.json index c263b915edd4f..26857b92b9f77 100644 --- a/packages/@aws-cdk/assert-internal/package.json +++ b/packages/@aws-cdk/assert-internal/package.json @@ -26,9 +26,9 @@ "devDependencies": { "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7", - "ts-jest": "^27.1.3" + "@types/jest": "^27.4.1", + "jest": "^27.5.1", + "ts-jest": "^27.1.4" }, "dependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0", @@ -40,7 +40,7 @@ "peerDependencies": { "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69", - "jest": "^27.4.7" + "jest": "^27.5.1" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", diff --git a/packages/@aws-cdk/assert/package.json b/packages/@aws-cdk/assert/package.json index b462bcbbab2db..153f87b7f98cb 100644 --- a/packages/@aws-cdk/assert/package.json +++ b/packages/@aws-cdk/assert/package.json @@ -37,11 +37,11 @@ "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "aws-cdk-migration": "0.0.0", "constructs": "^3.3.69", "jest": "^27.3.1", - "ts-jest": "^27.1.3" + "ts-jest": "^27.1.4" }, "dependencies": { "@aws-cdk/cloudformation-diff": "0.0.0", diff --git a/packages/@aws-cdk/assertions/README.md b/packages/@aws-cdk/assertions/README.md index d23c37a08b099..8692ecc7d66ce 100644 --- a/packages/@aws-cdk/assertions/README.md +++ b/packages/@aws-cdk/assertions/README.md @@ -550,9 +550,9 @@ Annotations.fromStack(stack).hasError( Here are the available APIs for `Annotations`: -- `hasError()` and `findError()` -- `hasWarning()` and `findWarning()` -- `hasInfo()` and `findInfo()` +- `hasError()`, `hasNoError()`, and `findError()` +- `hasWarning()`, `hasNoWarning()`, and `findWarning()` +- `hasInfo()`, `hasNoInfo()`, and `findInfo()` The corresponding `findXxx()` API is complementary to the `hasXxx()` API, except instead of asserting its presence, it returns the set of matching messages. diff --git a/packages/@aws-cdk/assertions/lib/annotations.ts b/packages/@aws-cdk/assertions/lib/annotations.ts index c656b15d6bab8..2068b58ccb480 100644 --- a/packages/@aws-cdk/assertions/lib/annotations.ts +++ b/packages/@aws-cdk/assertions/lib/annotations.ts @@ -1,7 +1,7 @@ import { Stack, Stage } from '@aws-cdk/core'; import { SynthesisMessage } from '@aws-cdk/cx-api'; import { Messages } from './private/message'; -import { findMessage, hasMessage } from './private/messages'; +import { findMessage, hasMessage, hasNoMessage } from './private/messages'; /** * Suite of assertions that can be run on a CDK Stack. @@ -35,6 +35,19 @@ export class Annotations { } } + /** + * Assert that an error with the given message does not exist in the synthesized CDK `Stack`. + * + * @param constructPath the construct path to the error. Provide `'*'` to match all errors in the template. + * @param message the error message as should be expected. This should be a string or Matcher object. + */ + public hasNoError(constructPath: string, message: any): void { + const matchError = hasNoMessage(this._messages, constructPath, constructMessage('error', message)); + if (matchError) { + throw new Error(matchError); + } + } + /** * Get the set of matching errors of a given construct path and message. * @@ -58,6 +71,19 @@ export class Annotations { } } + /** + * Assert that an warning with the given message does not exist in the synthesized CDK `Stack`. + * + * @param constructPath the construct path to the warning. Provide `'*'` to match all warnings in the template. + * @param message the warning message as should be expected. This should be a string or Matcher object. + */ + public hasNoWarning(constructPath: string, message: any): void { + const matchError = hasNoMessage(this._messages, constructPath, constructMessage('warning', message)); + if (matchError) { + throw new Error(matchError); + } + } + /** * Get the set of matching warning of a given construct path and message. * @@ -81,6 +107,19 @@ export class Annotations { } } + /** + * Assert that an info with the given message does not exist in the synthesized CDK `Stack`. + * + * @param constructPath the construct path to the info. Provide `'*'` to match all info in the template. + * @param message the info message as should be expected. This should be a string or Matcher object. + */ + public hasNoInfo(constructPath: string, message: any): void { + const matchError = hasNoMessage(this._messages, constructPath, constructMessage('info', message)); + if (matchError) { + throw new Error(matchError); + } + } + /** * Get the set of matching infos of a given construct path and message. * @@ -102,10 +141,10 @@ function constructMessage(type: 'info' | 'warning' | 'error', message: any): {[k } function convertArrayToMessagesType(messages: SynthesisMessage[]): Messages { - return messages.reduce((obj, item) => { + return messages.reduce((obj, item, index) => { return { ...obj, - [item.id]: item, + [index]: item, }; }, {}) as Messages; } diff --git a/packages/@aws-cdk/assertions/lib/private/cyclic.ts b/packages/@aws-cdk/assertions/lib/private/cyclic.ts index 07451a126ad28..85aa0cbf07147 100644 --- a/packages/@aws-cdk/assertions/lib/private/cyclic.ts +++ b/packages/@aws-cdk/assertions/lib/private/cyclic.ts @@ -70,11 +70,16 @@ function findExpressionDependencies(obj: any): Set { } else if (keys.length === 1 && keys[0] === 'Fn::Sub') { const argument = x[keys[0]]; const pattern = Array.isArray(argument) ? argument[0] : argument; - for (const logId of logicalIdsInSubString(pattern)) { - ret.add(logId); + + // pattern should always be a string, but we've encountered some cases in which + // it isn't. Better safeguard. + if (typeof pattern === 'string') { + for (const logId of logicalIdsInSubString(pattern)) { + ret.add(logId); + } } const contextDict = Array.isArray(argument) ? argument[1] : undefined; - if (contextDict) { + if (contextDict && typeof contextDict === 'object') { Object.values(contextDict).forEach(recurse); } } else { diff --git a/packages/@aws-cdk/assertions/lib/private/message.ts b/packages/@aws-cdk/assertions/lib/private/message.ts index 9657a5d90ad99..1a14fe6be1b00 100644 --- a/packages/@aws-cdk/assertions/lib/private/message.ts +++ b/packages/@aws-cdk/assertions/lib/private/message.ts @@ -1,5 +1,5 @@ import { SynthesisMessage } from '@aws-cdk/cx-api'; export type Messages = { - [logicalId: string]: SynthesisMessage; + [key: string]: SynthesisMessage; } diff --git a/packages/@aws-cdk/assertions/lib/private/messages.ts b/packages/@aws-cdk/assertions/lib/private/messages.ts index 75c6fe3ae50b1..f152ebcefb0e5 100644 --- a/packages/@aws-cdk/assertions/lib/private/messages.ts +++ b/packages/@aws-cdk/assertions/lib/private/messages.ts @@ -1,10 +1,10 @@ -import { MatchResult } from '../matcher'; +import { SynthesisMessage } from '@aws-cdk/cx-api'; import { Messages } from './message'; -import { filterLogicalId, formatFailure, matchSection } from './section'; +import { formatAllMatches, formatFailure, matchSection } from './section'; -export function findMessage(messages: Messages, logicalId: string, props: any = {}): { [key: string]: { [key: string]: any } } { - const section: { [key: string]: {} } = messages; - const result = matchSection(filterLogicalId(section, logicalId), props); +export function findMessage(messages: Messages, constructPath: string, props: any = {}): { [key: string]: { [key: string]: any } } { + const section: { [key: string]: SynthesisMessage } = messages; + const result = matchSection(filterPath(section, constructPath), props); if (!result.match) { return {}; @@ -13,9 +13,9 @@ export function findMessage(messages: Messages, logicalId: string, props: any = return result.matches; } -export function hasMessage(messages: Messages, logicalId: string, props: any): string | void { - const section: { [key: string]: {} } = messages; - const result = matchSection(filterLogicalId(section, logicalId), props); +export function hasMessage(messages: Messages, constructPath: string, props: any): string | void { + const section: { [key: string]: SynthesisMessage } = messages; + const result = matchSection(filterPath(section, constructPath), props); if (result.match) { return; @@ -25,17 +25,40 @@ export function hasMessage(messages: Messages, logicalId: string, props: any): s return 'No messages found in the stack'; } + handleTrace(result.closestResult.target); return [ `Stack has ${result.analyzedCount} messages, but none match as expected.`, - formatFailure(formatMessage(result.closestResult)), + formatFailure(result.closestResult), + ].join('\n'); +} + +export function hasNoMessage(messages: Messages, constructPath: string, props: any): string | void { + const section: { [key: string]: SynthesisMessage } = messages; + const result = matchSection(filterPath(section, constructPath), props); + + if (!result.match) { + return; + } + + return [ + `Expected no matches, but stack has ${Object.keys(result.matches).length} messages as follows:`, + formatAllMatches(result.matches), ].join('\n'); } // We redact the stack trace by default because it is unnecessarily long and unintelligible. // If there is a use case for rendering the trace, we can add it later. -function formatMessage(match: MatchResult, renderTrace: boolean = false): MatchResult { - if (!renderTrace) { - match.target.entry.trace = 'redacted'; - } - return match; +function handleTrace(match: any, redact: boolean = true): void { + if (redact && match.entry?.trace !== undefined) { + match.entry.trace = 'redacted'; + }; +} + +function filterPath(section: { [key: string]: SynthesisMessage }, path: string): { [key: string]: SynthesisMessage } { + // default signal for all paths is '*' + if (path === '*') return section; + + return Object.entries(section ?? {}) + .filter(([_, v]) => v.id === path) + .reduce((agg, [k, v]) => { return { ...agg, [k]: v }; }, {}); } diff --git a/packages/@aws-cdk/assertions/lib/private/section.ts b/packages/@aws-cdk/assertions/lib/private/section.ts index d2dd96800da08..2468e47f33c1c 100644 --- a/packages/@aws-cdk/assertions/lib/private/section.ts +++ b/packages/@aws-cdk/assertions/lib/private/section.ts @@ -43,6 +43,12 @@ function eachEntryInSection( } } +export function formatAllMatches(matches: {[key: string]: any}): string { + return [ + leftPad(JSON.stringify(matches, undefined, 2)), + ].join('\n'); +} + export function formatFailure(closestResult: MatchResult): string { return [ 'The closest result is:', diff --git a/packages/@aws-cdk/assertions/package.json b/packages/@aws-cdk/assertions/package.json index 31bcf0b7d0067..f93da67271e60 100644 --- a/packages/@aws-cdk/assertions/package.json +++ b/packages/@aws-cdk/assertions/package.json @@ -65,10 +65,10 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/fs-extra": "^9.0.13", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "constructs": "^3.3.69", - "jest": "^27.4.7", - "ts-jest": "^27.1.3" + "jest": "^27.5.1", + "ts-jest": "^27.1.4" }, "dependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0", diff --git a/packages/@aws-cdk/assertions/test/annotations.test.ts b/packages/@aws-cdk/assertions/test/annotations.test.ts index 8275e52d39dff..ebc1ca081d868 100644 --- a/packages/@aws-cdk/assertions/test/annotations.test.ts +++ b/packages/@aws-cdk/assertions/test/annotations.test.ts @@ -50,15 +50,26 @@ describe('Messages', () => { }); }); + describe('hasNoError', () => { + test('match', () => { + annotations.hasNoError('/Default/Fred', Match.anyValue()); + }); + + test('no match', () => { + expect(() => annotations.hasNoError('/Default/Foo', 'this is an error')) + .toThrowError(/Expected no matches, but stack has 1 messages as follows:/); + }); + }); + describe('findError', () => { test('match', () => { const result = annotations.findError('*', Match.anyValue()); - expect(Object.keys(result).length).toEqual(2); + expect(result.length).toEqual(2); }); test('no match', () => { const result = annotations.findError('*', 'no message looks like this'); - expect(Object.keys(result).length).toEqual(0); + expect(result.length).toEqual(0); }); }); @@ -72,15 +83,26 @@ describe('Messages', () => { }); }); + describe('hasNoWarning', () => { + test('match', () => { + annotations.hasNoWarning('/Default/Foo', Match.anyValue()); + }); + + test('no match', () => { + expect(() => annotations.hasNoWarning('/Default/Fred', 'this is a warning')) + .toThrowError(/Expected no matches, but stack has 1 messages as follows:/); + }); + }); + describe('findWarning', () => { test('match', () => { const result = annotations.findWarning('*', Match.anyValue()); - expect(Object.keys(result).length).toEqual(1); + expect(result.length).toEqual(1); }); test('no match', () => { const result = annotations.findWarning('*', 'no message looks like this'); - expect(Object.keys(result).length).toEqual(0); + expect(result.length).toEqual(0); }); }); @@ -94,22 +116,33 @@ describe('Messages', () => { }); }); + describe('hasNoInfo', () => { + test('match', () => { + annotations.hasNoInfo('/Default/Qux', 'this info is incorrect'); + }); + + test('no match', () => { + expect(() => annotations.hasNoInfo('/Default/Qux', 'this is an info')) + .toThrowError(/Expected no matches, but stack has 1 messages as follows:/); + }); + }); + describe('findInfo', () => { test('match', () => { const result = annotations.findInfo('/Default/Qux', 'this is an info'); - expect(Object.keys(result).length).toEqual(1); + expect(result.length).toEqual(1); }); test('no match', () => { const result = annotations.findInfo('*', 'no message looks like this'); - expect(Object.keys(result).length).toEqual(0); + expect(result.length).toEqual(0); }); }); describe('with matchers', () => { test('anyValue', () => { const result = annotations.findError('*', Match.anyValue()); - expect(Object.keys(result).length).toEqual(2); + expect(result.length).toEqual(2); }); test('not', () => { @@ -123,6 +156,45 @@ describe('Messages', () => { }); }); +describe('Multiple Messages on the Resource', () => { + let stack: Stack; + let annotations: _Annotations; + beforeAll(() => { + stack = new Stack(); + new CfnResource(stack, 'Foo', { + type: 'Foo::Bar', + properties: { + Fred: 'Thud', + }, + }); + + const bar = new CfnResource(stack, 'Bar', { + type: 'Foo::Bar', + properties: { + Baz: 'Qux', + }, + }); + bar.node.setContext('disable-stack-trace', false); + + Aspects.of(stack).add(new MultipleAspectsPerNode()); + annotations = _Annotations.fromStack(stack); + }); + + test('succeeds on hasXxx APIs', () => { + annotations.hasError('/Default/Foo', 'error: this is an error'); + annotations.hasError('/Default/Foo', 'error: unsupported type Foo::Bar'); + annotations.hasWarning('/Default/Foo', 'warning: Foo::Bar is deprecated'); + }); + + test('succeeds on findXxx APIs', () => { + const result1 = annotations.findError('*', Match.stringLikeRegexp('error:.*')); + expect(result1.length).toEqual(4); + const result2 = annotations.findError('/Default/Bar', Match.stringLikeRegexp('error:.*')); + expect(result2.length).toEqual(2); + const result3 = annotations.findWarning('/Default/Bar', 'warning: Foo::Bar is deprecated'); + expect(result3[0].entry.data).toEqual('warning: Foo::Bar is deprecated'); + }); +}); class MyAspect implements IAspect { public visit(node: IConstruct): void { if (node instanceof CfnResource) { @@ -147,4 +219,22 @@ class MyAspect implements IAspect { protected info(node: IConstruct, message: string): void { Annotations.of(node).addInfo(message); } +} + +class MultipleAspectsPerNode implements IAspect { + public visit(node: IConstruct): void { + if (node instanceof CfnResource) { + this.error(node, 'error: this is an error'); + this.error(node, `error: unsupported type ${node.cfnResourceType}`); + this.warn(node, `warning: ${node.cfnResourceType} is deprecated`); + } + } + + protected warn(node: IConstruct, message: string): void { + Annotations.of(node).addWarning(message); + } + + protected error(node: IConstruct, message: string): void { + Annotations.of(node).addError(message); + } } \ No newline at end of file diff --git a/packages/@aws-cdk/assets/package.json b/packages/@aws-cdk/assets/package.json index 13efc124c74d0..30adc5c82cfcb 100644 --- a/packages/@aws-cdk/assets/package.json +++ b/packages/@aws-cdk/assets/package.json @@ -80,10 +80,10 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "@types/sinon": "^9.0.11", "aws-cdk": "0.0.0", - "jest": "^27.4.7", + "jest": "^27.5.1", "sinon": "^9.2.4", "ts-mock-imports": "^1.3.8" }, diff --git a/packages/@aws-cdk/aws-accessanalyzer/package.json b/packages/@aws-cdk/aws-accessanalyzer/package.json index faf809becc93b..ed8871901f393 100644 --- a/packages/@aws-cdk/aws-accessanalyzer/package.json +++ b/packages/@aws-cdk/aws-accessanalyzer/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-acmpca/package.json b/packages/@aws-cdk/aws-acmpca/package.json index a4a7a79a1e8e6..8522c051e20b0 100644 --- a/packages/@aws-cdk/aws-acmpca/package.json +++ b/packages/@aws-cdk/aws-acmpca/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-amazonmq/package.json b/packages/@aws-cdk/aws-amazonmq/package.json index c7050a78a44e4..56d6e296c4ed0 100644 --- a/packages/@aws-cdk/aws-amazonmq/package.json +++ b/packages/@aws-cdk/aws-amazonmq/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-amplify/package.json b/packages/@aws-cdk/aws-amplify/package.json index e546c68ed28c4..7a221bfd747f5 100644 --- a/packages/@aws-cdk/aws-amplify/package.json +++ b/packages/@aws-cdk/aws-amplify/package.json @@ -86,7 +86,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "@types/yaml": "1.9.6", "aws-sdk": "^2.848.0" }, diff --git a/packages/@aws-cdk/aws-amplify/test/integ.app-asset-deployment.expected.json b/packages/@aws-cdk/aws-amplify/test/integ.app-asset-deployment.expected.json index 47b29583b6a21..2bd04571ffc91 100644 --- a/packages/@aws-cdk/aws-amplify/test/integ.app-asset-deployment.expected.json +++ b/packages/@aws-cdk/aws-amplify/test/integ.app-asset-deployment.expected.json @@ -1,52 +1,52 @@ { "Parameters": { - "AssetParameters76c74dffba7c3eb9a040dc95633eac403472969bf8a18831ac1cf243971c5bf7S3Bucket3C55BA0F": { + "AssetParameters8c89eadc6be22019c81ed6b9c7d9929ae10de55679fd8e0e9fd4c00f8edc1cdaS3Bucket83484C89": { "Type": "String", - "Description": "S3 bucket for asset \"76c74dffba7c3eb9a040dc95633eac403472969bf8a18831ac1cf243971c5bf7\"" + "Description": "S3 bucket for asset \"8c89eadc6be22019c81ed6b9c7d9929ae10de55679fd8e0e9fd4c00f8edc1cda\"" }, - "AssetParameters76c74dffba7c3eb9a040dc95633eac403472969bf8a18831ac1cf243971c5bf7S3VersionKeyE1E2D7D6": { + "AssetParameters8c89eadc6be22019c81ed6b9c7d9929ae10de55679fd8e0e9fd4c00f8edc1cdaS3VersionKey70C0B407": { "Type": "String", - "Description": "S3 key for asset version \"76c74dffba7c3eb9a040dc95633eac403472969bf8a18831ac1cf243971c5bf7\"" + "Description": "S3 key for asset version \"8c89eadc6be22019c81ed6b9c7d9929ae10de55679fd8e0e9fd4c00f8edc1cda\"" }, - "AssetParameters76c74dffba7c3eb9a040dc95633eac403472969bf8a18831ac1cf243971c5bf7ArtifactHashB1665559": { + "AssetParameters8c89eadc6be22019c81ed6b9c7d9929ae10de55679fd8e0e9fd4c00f8edc1cdaArtifactHash3A9285DE": { "Type": "String", - "Description": "Artifact hash for asset \"76c74dffba7c3eb9a040dc95633eac403472969bf8a18831ac1cf243971c5bf7\"" + "Description": "Artifact hash for asset \"8c89eadc6be22019c81ed6b9c7d9929ae10de55679fd8e0e9fd4c00f8edc1cda\"" }, - "AssetParametersff9527128e3cc60cee11deb3d533504348f62709c853288178d757494fd92c56S3Bucket7A871D89": { + "AssetParametersf4c3be09f3fcdd17ab851339f091bc78984d15e3f83e6883a31e2e034ad4cce6S3Bucket3E112CA5": { "Type": "String", - "Description": "S3 bucket for asset \"ff9527128e3cc60cee11deb3d533504348f62709c853288178d757494fd92c56\"" + "Description": "S3 bucket for asset \"f4c3be09f3fcdd17ab851339f091bc78984d15e3f83e6883a31e2e034ad4cce6\"" }, - "AssetParametersff9527128e3cc60cee11deb3d533504348f62709c853288178d757494fd92c56S3VersionKeyAACF81DD": { + "AssetParametersf4c3be09f3fcdd17ab851339f091bc78984d15e3f83e6883a31e2e034ad4cce6S3VersionKeyE9CF14C0": { "Type": "String", - "Description": "S3 key for asset version \"ff9527128e3cc60cee11deb3d533504348f62709c853288178d757494fd92c56\"" + "Description": "S3 key for asset version \"f4c3be09f3fcdd17ab851339f091bc78984d15e3f83e6883a31e2e034ad4cce6\"" }, - "AssetParametersff9527128e3cc60cee11deb3d533504348f62709c853288178d757494fd92c56ArtifactHash2A4E644A": { + "AssetParametersf4c3be09f3fcdd17ab851339f091bc78984d15e3f83e6883a31e2e034ad4cce6ArtifactHash3B9A157C": { "Type": "String", - "Description": "Artifact hash for asset \"ff9527128e3cc60cee11deb3d533504348f62709c853288178d757494fd92c56\"" + "Description": "Artifact hash for asset \"f4c3be09f3fcdd17ab851339f091bc78984d15e3f83e6883a31e2e034ad4cce6\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { "Type": "String", - "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { "Type": "String", - "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { "Type": "String", - "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersa1ec2b3c34d7ba5b1816474781916bb1c8a8086a266e6d7cf88a0720b114d2ddS3Bucket456FC783": { + "AssetParameterse3304a59a46a1ac955511f11bdfe439a31c567da6faab8390ac987e9c9edff8aS3Bucket0A5FA7C6": { "Type": "String", - "Description": "S3 bucket for asset \"a1ec2b3c34d7ba5b1816474781916bb1c8a8086a266e6d7cf88a0720b114d2dd\"" + "Description": "S3 bucket for asset \"e3304a59a46a1ac955511f11bdfe439a31c567da6faab8390ac987e9c9edff8a\"" }, - "AssetParametersa1ec2b3c34d7ba5b1816474781916bb1c8a8086a266e6d7cf88a0720b114d2ddS3VersionKey4A933266": { + "AssetParameterse3304a59a46a1ac955511f11bdfe439a31c567da6faab8390ac987e9c9edff8aS3VersionKey657A1204": { "Type": "String", - "Description": "S3 key for asset version \"a1ec2b3c34d7ba5b1816474781916bb1c8a8086a266e6d7cf88a0720b114d2dd\"" + "Description": "S3 key for asset version \"e3304a59a46a1ac955511f11bdfe439a31c567da6faab8390ac987e9c9edff8a\"" }, - "AssetParametersa1ec2b3c34d7ba5b1816474781916bb1c8a8086a266e6d7cf88a0720b114d2ddArtifactHash7857C55E": { + "AssetParameterse3304a59a46a1ac955511f11bdfe439a31c567da6faab8390ac987e9c9edff8aArtifactHash065BBA17": { "Type": "String", - "Description": "Artifact hash for asset \"a1ec2b3c34d7ba5b1816474781916bb1c8a8086a266e6d7cf88a0720b114d2dd\"" + "Description": "Artifact hash for asset \"e3304a59a46a1ac955511f11bdfe439a31c567da6faab8390ac987e9c9edff8a\"" } }, "Resources": { @@ -123,7 +123,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters76c74dffba7c3eb9a040dc95633eac403472969bf8a18831ac1cf243971c5bf7S3VersionKeyE1E2D7D6" + "Ref": "AssetParameters8c89eadc6be22019c81ed6b9c7d9929ae10de55679fd8e0e9fd4c00f8edc1cdaS3VersionKey70C0B407" } ] } @@ -136,7 +136,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters76c74dffba7c3eb9a040dc95633eac403472969bf8a18831ac1cf243971c5bf7S3VersionKeyE1E2D7D6" + "Ref": "AssetParameters8c89eadc6be22019c81ed6b9c7d9929ae10de55679fd8e0e9fd4c00f8edc1cdaS3VersionKey70C0B407" } ] } @@ -146,7 +146,7 @@ ] }, "S3BucketName": { - "Ref": "AssetParameters76c74dffba7c3eb9a040dc95633eac403472969bf8a18831ac1cf243971c5bf7S3Bucket3C55BA0F" + "Ref": "AssetParameters8c89eadc6be22019c81ed6b9c7d9929ae10de55679fd8e0e9fd4c00f8edc1cdaS3Bucket83484C89" } }, "UpdateReplacePolicy": "Delete", @@ -169,7 +169,7 @@ }, "/", { - "Ref": "AssetParametersa1ec2b3c34d7ba5b1816474781916bb1c8a8086a266e6d7cf88a0720b114d2ddS3Bucket456FC783" + "Ref": "AssetParameterse3304a59a46a1ac955511f11bdfe439a31c567da6faab8390ac987e9c9edff8aS3Bucket0A5FA7C6" }, "/", { @@ -179,7 +179,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa1ec2b3c34d7ba5b1816474781916bb1c8a8086a266e6d7cf88a0720b114d2ddS3VersionKey4A933266" + "Ref": "AssetParameterse3304a59a46a1ac955511f11bdfe439a31c567da6faab8390ac987e9c9edff8aS3VersionKey657A1204" } ] } @@ -192,7 +192,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa1ec2b3c34d7ba5b1816474781916bb1c8a8086a266e6d7cf88a0720b114d2ddS3VersionKey4A933266" + "Ref": "AssetParameterse3304a59a46a1ac955511f11bdfe439a31c567da6faab8390ac987e9c9edff8aS3VersionKey657A1204" } ] } @@ -202,17 +202,17 @@ ] }, "Parameters": { - "referencetocdkamplifyappassetdeploymentAssetParametersff9527128e3cc60cee11deb3d533504348f62709c853288178d757494fd92c56S3BucketA0EDA7B5Ref": { - "Ref": "AssetParametersff9527128e3cc60cee11deb3d533504348f62709c853288178d757494fd92c56S3Bucket7A871D89" + "referencetocdkamplifyappassetdeploymentAssetParametersf4c3be09f3fcdd17ab851339f091bc78984d15e3f83e6883a31e2e034ad4cce6S3Bucket3462E0F4Ref": { + "Ref": "AssetParametersf4c3be09f3fcdd17ab851339f091bc78984d15e3f83e6883a31e2e034ad4cce6S3Bucket3E112CA5" }, - "referencetocdkamplifyappassetdeploymentAssetParametersff9527128e3cc60cee11deb3d533504348f62709c853288178d757494fd92c56S3VersionKeyD32C918ARef": { - "Ref": "AssetParametersff9527128e3cc60cee11deb3d533504348f62709c853288178d757494fd92c56S3VersionKeyAACF81DD" + "referencetocdkamplifyappassetdeploymentAssetParametersf4c3be09f3fcdd17ab851339f091bc78984d15e3f83e6883a31e2e034ad4cce6S3VersionKey4934CDF2Ref": { + "Ref": "AssetParametersf4c3be09f3fcdd17ab851339f091bc78984d15e3f83e6883a31e2e034ad4cce6S3VersionKeyE9CF14C0" }, - "referencetocdkamplifyappassetdeploymentAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketA5B3B03BRef": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetocdkamplifyappassetdeploymentAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket2F32F802Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetocdkamplifyappassetdeploymentAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey61CE3542Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetocdkamplifyappassetdeploymentAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKey3B80829BRef": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, diff --git a/packages/@aws-cdk/aws-apigateway/README.md b/packages/@aws-cdk/aws-apigateway/README.md index 83e9d04cd31c6..8dae2d1cf9165 100644 --- a/packages/@aws-cdk/aws-apigateway/README.md +++ b/packages/@aws-cdk/aws-apigateway/README.md @@ -126,7 +126,7 @@ Other metadata such as billing details, AWS account ID and resource ARNs are not By default, a `prod` stage is provisioned. -In order to reduce the payload size sent to AWS Step Functions, `headers` are not forwarded to the Step Functions execution input. It is possible to choose whether `headers`, `requestContext`, `path` and `querystring` are included or not. By default, `headers` are excluded in all requests. +In order to reduce the payload size sent to AWS Step Functions, `headers` are not forwarded to the Step Functions execution input. It is possible to choose whether `headers`, `requestContext`, `path`, `querystring`, and `authorizer` are included or not. By default, `headers` are excluded in all requests. More details about AWS Step Functions payload limit can be found at https://docs.aws.amazon.com/step-functions/latest/dg/limits-overview.html#service-limits-task-executions. @@ -184,7 +184,7 @@ AWS Step Functions will receive the following execution input: } ``` -Additional information around the request such as the request context and headers can be included as part of the input +Additional information around the request such as the request context, authorizer context, and headers can be included as part of the input forwarded to the state machine. The following example enables headers to be included in the input but not query string. ```ts fixture=stepfunctions @@ -193,6 +193,7 @@ new apigateway.StepFunctionsRestApi(this, 'StepFunctionsRestApi', { headers: true, path: false, querystring: false, + authorizer: false, requestContext: { caller: true, user: true, diff --git a/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts b/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts index f7be4f954d7e8..85ac3c901f3a5 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts @@ -105,7 +105,7 @@ abstract class LambdaAuthorizer extends Authorizer implements IAuthorizer { this.role.attachInlinePolicy(new iam.Policy(this, 'authorizerInvokePolicy', { statements: [ new iam.PolicyStatement({ - resources: [this.handler.functionArn], + resources: this.handler.resourceArnsForGrantInvoke, actions: ['lambda:InvokeFunction'], }), ], diff --git a/packages/@aws-cdk/aws-apigateway/lib/integrations/stepfunctions.ts b/packages/@aws-cdk/aws-apigateway/lib/integrations/stepfunctions.ts index 339e7b2949198..335c87fd22d9d 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/integrations/stepfunctions.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/integrations/stepfunctions.ts @@ -6,6 +6,7 @@ import { Token } from '@aws-cdk/core'; import { RequestContext } from '.'; import { IntegrationConfig, IntegrationOptions, PassthroughBehavior } from '../integration'; import { Method } from '../method'; +import { Model } from '../model'; import { AwsIntegration } from './aws'; /** * Options when configuring Step Functions synchronous integration with Rest API @@ -68,6 +69,20 @@ export interface StepFunctionsExecutionIntegrationOptions extends IntegrationOpt * @default false */ readonly headers?: boolean; + + /** + * If the whole authorizer object, including custom context values should be in the execution input. The execution input will include a new key `authorizer`: + * + * { + * "body": {}, + * "authorizer": { + * "key": "value" + * } + * } + * + * @default false + */ + readonly authorizer?: boolean; } /** @@ -80,6 +95,7 @@ export class StepFunctionsIntegration { * @example * * const stateMachine = new stepfunctions.StateMachine(this, 'MyStateMachine', { + * stateMachineType: stepfunctions.StateMachineType.EXPRESS, * definition: stepfunctions.Chain.start(new stepfunctions.Pass(this, 'Pass')), * }); * @@ -113,9 +129,11 @@ class StepFunctionsExecutionIntegration extends AwsIntegration { public bind(method: Method): IntegrationConfig { const bindResult = super.bind(method); - const principal = new iam.ServicePrincipal('apigateway.amazonaws.com'); - this.stateMachine.grantExecution(principal, 'states:StartSyncExecution'); + const credentialsRole = bindResult.options?.credentialsRole ?? new iam.Role(method, 'StartSyncExecutionRole', { + assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), + }); + this.stateMachine.grantStartSyncExecution(credentialsRole); let stateMachineName; @@ -138,8 +156,17 @@ class StepFunctionsExecutionIntegration extends AwsIntegration { if (stateMachineName !== undefined && !Token.isUnresolved(stateMachineName)) { deploymentToken = JSON.stringify({ stateMachineName }); } + + for (const methodResponse of METHOD_RESPONSES) { + method.addMethodResponse(methodResponse); + } + return { ...bindResult, + options: { + ...bindResult.options, + credentialsRole, + }, deploymentToken, }; } @@ -186,10 +213,10 @@ function integrationResponse() { /* eslint-disable */ 'application/json': [ '#set($inputRoot = $input.path(\'$\'))', - '#if($input.path(\'$.status\').toString().equals("FAILED"))', - '#set($context.responseOverride.status = 500)', + '#if($input.path(\'$.status\').toString().equals("FAILED"))', + '#set($context.responseOverride.status = 500)', '{', - '"error": "$input.path(\'$.error\')"', + '"error": "$input.path(\'$.error\')",', '"cause": "$input.path(\'$.cause\')"', '}', '#else', @@ -241,6 +268,7 @@ function templateString( const includeHeader = options.headers?? false; const includeQueryString = options.querystring?? true; const includePath = options.path?? true; + const includeAuthorizer = options.authorizer ?? false; if (options.requestContext && Object.keys(options.requestContext).length > 0) { requestContextStr = requestContext(options.requestContext); @@ -251,6 +279,7 @@ function templateString( templateStr = templateStr.replace('%INCLUDE_HEADERS%', String(includeHeader)); templateStr = templateStr.replace('%INCLUDE_QUERYSTRING%', String(includeQueryString)); templateStr = templateStr.replace('%INCLUDE_PATH%', String(includePath)); + templateStr = templateStr.replace('%INCLUDE_AUTHORIZER%', String(includeAuthorizer)); templateStr = templateStr.replace('%REQUESTCONTEXT%', requestContextStr); return templateStr; @@ -285,4 +314,28 @@ function requestContext(requestContextObj: RequestContext | undefined): string { const doublequotes = '"'; const replaceWith = '@@'; return contextAsString.split(doublequotes).join(replaceWith); -} \ No newline at end of file +} + +/** + * Method response model for each HTTP code response + */ +const METHOD_RESPONSES = [ + { + statusCode: '200', + responseModels: { + 'application/json': Model.EMPTY_MODEL, + }, + }, + { + statusCode: '400', + responseModels: { + 'application/json': Model.ERROR_MODEL, + }, + }, + { + statusCode: '500', + responseModels: { + 'application/json': Model.ERROR_MODEL, + }, + }, +]; diff --git a/packages/@aws-cdk/aws-apigateway/lib/integrations/stepfunctions.vtl b/packages/@aws-cdk/aws-apigateway/lib/integrations/stepfunctions.vtl index df4eda7c279d5..f389662efd6ed 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/integrations/stepfunctions.vtl +++ b/packages/@aws-cdk/aws-apigateway/lib/integrations/stepfunctions.vtl @@ -9,6 +9,7 @@ #set($includeHeaders = %INCLUDE_HEADERS%) #set($includeQueryString = %INCLUDE_QUERYSTRING%) #set($includePath = %INCLUDE_PATH%) +#set($includeAuthorizer = %INCLUDE_AUTHORIZER%) #set($allParams = $input.params()) { "stateMachineArn": "%STATEMACHINE%", @@ -49,6 +50,17 @@ #set($inputString = "$inputString }") #end + #if ($includeAuthorizer) + #set($inputString = "$inputString, @@authorizer@@:{") + #foreach($paramName in $context.authorizer.keySet()) + #set($inputString = "$inputString @@$paramName@@: @@$util.escapeJavaScript($context.authorizer.get($paramName))@@") + #if($foreach.hasNext) + #set($inputString = "$inputString,") + #end + #end + #set($inputString = "$inputString }") + #end + #set($requestContext = "%REQUESTCONTEXT%") ## Check if the request context should be included as part of the execution input #if($requestContext && !$requestContext.empty) diff --git a/packages/@aws-cdk/aws-apigateway/lib/method.ts b/packages/@aws-cdk/aws-apigateway/lib/method.ts index 5a99d03270f41..8746189f9bdaa 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/method.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/method.ts @@ -1,4 +1,4 @@ -import { ArnFormat, Resource, Stack } from '@aws-cdk/core'; +import { ArnFormat, Lazy, Resource, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnMethod, CfnMethodProps } from './apigateway.generated'; import { Authorizer, IAuthorizer } from './authorizer'; @@ -168,6 +168,8 @@ export class Method extends Resource { */ public readonly api: IRestApi; + private methodResponses: MethodResponse[]; + constructor(scope: Construct, id: string, props: MethodProps) { super(scope, id); @@ -196,6 +198,8 @@ export class Method extends Resource { authorizer._attachToApi(this.api); } + this.methodResponses = options.methodResponses ?? []; + const integration = props.integration ?? this.resource.defaultIntegration ?? new MockIntegration(); const bindResult = integration.bind(this); @@ -209,7 +213,7 @@ export class Method extends Resource { authorizerId, requestParameters: options.requestParameters || defaultMethodOptions.requestParameters, integration: this.renderIntegration(bindResult), - methodResponses: this.renderMethodResponses(options.methodResponses), + methodResponses: Lazy.any({ produce: () => this.renderMethodResponses(this.methodResponses) }, { omitEmptyArray: true }), requestModels: this.renderRequestModels(options.requestModels), requestValidatorId: this.requestValidatorId(options), authorizationScopes: options.authorizationScopes ?? defaultMethodOptions.authorizationScopes, @@ -267,6 +271,13 @@ export class Method extends Resource { return this.api.arnForExecuteApi(this.httpMethod, pathForArn(this.resource.path), 'test-invoke-stage'); } + /** + * Add a method response to this method + */ + public addMethodResponse(methodResponse: MethodResponse): void { + this.methodResponses.push(methodResponse); + } + private renderIntegration(bindResult: IntegrationConfig): CfnMethod.IntegrationProperty { const options = bindResult.options ?? {}; let credentials; diff --git a/packages/@aws-cdk/aws-apigateway/lib/resource.ts b/packages/@aws-cdk/aws-apigateway/lib/resource.ts index 714e99bce7a0b..f843ee1b5e25a 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/resource.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/resource.ts @@ -311,8 +311,8 @@ export abstract class ResourceBase extends ResourceConstruct implements IResourc const template = new Array(); - template.push('#set($origin = $input.params("Origin"))'); - template.push('#if($origin == "") #set($origin = $input.params("origin")) #end'); + template.push('#set($origin = $input.params().header.get("Origin"))'); + template.push('#if($origin == "") #set($origin = $input.params().header.get("origin")) #end'); const condition = origins.map(o => `$origin.matches("${o}")`).join(' || '); diff --git a/packages/@aws-cdk/aws-apigateway/lib/stepfunctions-api.ts b/packages/@aws-cdk/aws-apigateway/lib/stepfunctions-api.ts index 69addc0619383..c48b497160bd7 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/stepfunctions-api.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/stepfunctions-api.ts @@ -4,19 +4,18 @@ import { Construct } from 'constructs'; import { RestApi, RestApiProps } from '.'; import { RequestContext } from './integrations'; import { StepFunctionsIntegration } from './integrations/stepfunctions'; -import { Model } from './model'; /** * Properties for StepFunctionsRestApi * */ export interface StepFunctionsRestApiProps extends RestApiProps { -/** - * The default State Machine that handles all requests from this API. - * - * This stateMachine will be used as a the default integration for all methods in - * this API, unless specified otherwise in `addMethod`. - */ + /** + * The default State Machine that handles all requests from this API. + * + * This stateMachine will be used as a the default integration for all methods in + * this API, unless specified otherwise in `addMethod`. + */ readonly stateMachine: sfn.IStateMachine; /** @@ -75,6 +74,28 @@ export interface StepFunctionsRestApiProps extends RestApiProps { * @default false */ readonly headers?: boolean; + + /** + * If the whole authorizer object, including custom context values should be in the execution input. The execution input will include a new key `authorizer`: + * + * { + * "body": {}, + * "authorizer": { + * "key": "value" + * } + * } + * + * @default false + */ + readonly authorizer?: boolean; + + /** + * An IAM role that API Gateway will assume to start the execution of the + * state machine. + * + * @default - a new role is created + */ + readonly role?: iam.IRole; } /** @@ -91,63 +112,16 @@ export class StepFunctionsRestApi extends RestApi { } const stepfunctionsIntegration = StepFunctionsIntegration.startExecution(props.stateMachine, { - credentialsRole: role(scope, props), + credentialsRole: props.role, requestContext: props.requestContext, path: props.path?? true, querystring: props.querystring?? true, headers: props.headers, + authorizer: props.authorizer, }); super(scope, id, props); - this.root.addMethod('ANY', stepfunctionsIntegration, { - methodResponses: methodResponse(), - }); + this.root.addMethod('ANY', stepfunctionsIntegration); } } - -/** - * Defines the IAM Role for API Gateway with required permissions - * to invoke a synchronous execution for the provided state machine - * - * @param scope - * @param props - * @returns Role - IAM Role - */ -function role(scope: Construct, props: StepFunctionsRestApiProps): iam.Role { - const roleName: string = 'StartSyncExecutionRole'; - const apiRole = new iam.Role(scope, roleName, { - assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), - }); - - props.stateMachine.grantStartSyncExecution(apiRole); - - return apiRole; -} - -/** - * Defines the method response modelfor each HTTP code response - * @returns methodResponse - */ -function methodResponse() { - return [ - { - statusCode: '200', - responseModels: { - 'application/json': Model.EMPTY_MODEL, - }, - }, - { - statusCode: '400', - responseModels: { - 'application/json': Model.ERROR_MODEL, - }, - }, - { - statusCode: '500', - responseModels: { - 'application/json': Model.ERROR_MODEL, - }, - }, - ]; -} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts b/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts index 4db28eb936e80..2f10071259517 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts @@ -6,7 +6,7 @@ import { CfnUsagePlan, CfnUsagePlanKey } from './apigateway.generated'; import { Method } from './method'; import { IRestApi } from './restapi'; import { Stage } from './stage'; -import { validateInteger } from './util'; +import { validateDouble, validateInteger } from './util'; /** * Container for defining throttling parameters to API stages or methods. @@ -316,7 +316,7 @@ export class UsagePlan extends UsagePlanBase { const burstLimit = props.burstLimit; validateInteger(burstLimit, 'Throttle burst limit'); const rateLimit = props.rateLimit; - validateInteger(rateLimit, 'Throttle rate limit'); + validateDouble(rateLimit, 'Throttle rate limit'); ret = { burstLimit: burstLimit, diff --git a/packages/@aws-cdk/aws-apigateway/lib/util.ts b/packages/@aws-cdk/aws-apigateway/lib/util.ts index eb7566a56ae0c..a97f89882fe04 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/util.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/util.ts @@ -78,6 +78,12 @@ export function validateInteger(property: number | undefined, messagePrefix: str } } +export function validateDouble(property: number | undefined, messagePrefix: string) { + if (property && isNaN(property) && isNaN(parseFloat(property.toString()))) { + throw new Error(`${messagePrefix} should be an double`); + } +} + export class JsonSchemaMapper { /** * Transforms naming of some properties to prefix with a $, where needed diff --git a/packages/@aws-cdk/aws-apigateway/package.json b/packages/@aws-cdk/aws-apigateway/package.json index cff64a652688b..3243e168f0919 100644 --- a/packages/@aws-cdk/aws-apigateway/package.json +++ b/packages/@aws-cdk/aws-apigateway/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer-iam-role.expected.json b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer-iam-role.expected.json index eda922f948d66..d5cca0c564f32 100644 --- a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer-iam-role.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer-iam-role.expected.json @@ -176,12 +176,28 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyAuthorizerFunction70F1223E", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "MyAuthorizerFunction70F1223E", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "MyAuthorizerFunction70F1223E", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-apigateway/test/authorizers/lambda.test.ts b/packages/@aws-cdk/aws-apigateway/test/authorizers/lambda.test.ts index a4eea0f56892d..f215a5143b54b 100644 --- a/packages/@aws-cdk/aws-apigateway/test/authorizers/lambda.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/authorizers/lambda.test.ts @@ -393,7 +393,7 @@ describe('lambda authorizer', () => { PolicyDocument: { Statement: [ { - Resource: stack.resolve(func.functionArn), + Resource: stack.resolve(func.resourceArnsForGrantInvoke), Action: 'lambda:InvokeFunction', Effect: 'Allow', }, @@ -485,7 +485,7 @@ describe('lambda authorizer', () => { PolicyDocument: { Statement: [ { - Resource: stack.resolve(func.functionArn), + Resource: stack.resolve(func.resourceArnsForGrantInvoke), Action: 'lambda:InvokeFunction', Effect: 'Allow', }, diff --git a/packages/@aws-cdk/aws-apigateway/test/cors.test.ts b/packages/@aws-cdk/aws-apigateway/test/cors.test.ts index 581b8af3e6c53..c573e6302589e 100644 --- a/packages/@aws-cdk/aws-apigateway/test/cors.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/cors.test.ts @@ -290,7 +290,7 @@ describe('cors', () => { 'method.response.header.Access-Control-Allow-Methods': "'OPTIONS,GET,PUT,POST,DELETE,PATCH,HEAD'", }, ResponseTemplates: { - 'application/json': '#set($origin = $input.params("Origin"))\n#if($origin == "") #set($origin = $input.params("origin")) #end\n#if($origin.matches("https://amazon.com") || $origin.matches("https://aws.amazon.com"))\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end', + 'application/json': '#set($origin = $input.params().header.get("Origin"))\n#if($origin == "") #set($origin = $input.params().header.get("origin")) #end\n#if($origin.matches("https://amazon.com") || $origin.matches("https://aws.amazon.com"))\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end', }, StatusCode: '204', }, diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.cors.expected.json b/packages/@aws-cdk/aws-apigateway/test/integ.cors.expected.json index 22b5c45a87b53..02d757e898afe 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integ.cors.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/integ.cors.expected.json @@ -51,7 +51,7 @@ "corsapitest8682546E" ] }, - "corsapitestDeployment2BF1633A228079ea05e5799220dd4ca13512b92d": { + "corsapitestDeployment2BF1633A51392cbce1ac2785bd0e53063423e203": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { @@ -74,7 +74,7 @@ "Ref": "corsapitest8682546E" }, "DeploymentId": { - "Ref": "corsapitestDeployment2BF1633A228079ea05e5799220dd4ca13512b92d" + "Ref": "corsapitestDeployment2BF1633A51392cbce1ac2785bd0e53063423e203" }, "StageName": "prod" }, @@ -472,7 +472,7 @@ "method.response.header.Access-Control-Allow-Methods": "'OPTIONS,GET,PUT,POST,DELETE,PATCH,HEAD'" }, "ResponseTemplates": { - "application/json": "#set($origin = $input.params(\"Origin\"))\n#if($origin == \"\") #set($origin = $input.params(\"origin\")) #end\n#if($origin.matches(\"https://www.test-cors.org\"))\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end" + "application/json": "#set($origin = $input.params().header.get(\"Origin\"))\n#if($origin == \"\") #set($origin = $input.params().header.get(\"origin\")) #end\n#if($origin.matches(\"https://www.test-cors.org\"))\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end" }, "StatusCode": "204" } diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.stepfunctions-api.expected.json b/packages/@aws-cdk/aws-apigateway/test/integ.stepfunctions-api.expected.json index 33976c0937cf5..ce9b25be6ecbe 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integ.stepfunctions-api.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/integ.stepfunctions-api.expected.json @@ -44,7 +44,7 @@ "StateMachineRoleB840431D" ] }, - "StartSyncExecutionRoleDE73CB90": { + "StepFunctionsRestApiANYStartSyncExecutionRole425C03BB": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -61,7 +61,7 @@ } } }, - "StartSyncExecutionRoleDefaultPolicy5A5803F8": { + "StepFunctionsRestApiANYStartSyncExecutionRoleDefaultPolicy7B6D0CED": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { @@ -76,10 +76,10 @@ ], "Version": "2012-10-17" }, - "PolicyName": "StartSyncExecutionRoleDefaultPolicy5A5803F8", + "PolicyName": "StepFunctionsRestApiANYStartSyncExecutionRoleDefaultPolicy7B6D0CED", "Roles": [ { - "Ref": "StartSyncExecutionRoleDE73CB90" + "Ref": "StepFunctionsRestApiANYStartSyncExecutionRole425C03BB" } ] } @@ -152,7 +152,7 @@ "Integration": { "Credentials": { "Fn::GetAtt": [ - "StartSyncExecutionRoleDE73CB90", + "StepFunctionsRestApiANYStartSyncExecutionRole425C03BB", "Arn" ] }, @@ -160,7 +160,7 @@ "IntegrationResponses": [ { "ResponseTemplates": { - "application/json": "#set($inputRoot = $input.path('$'))\n#if($input.path('$.status').toString().equals(\"FAILED\"))\n#set($context.responseOverride.status = 500)\n{\n\"error\": \"$input.path('$.error')\"\n\"cause\": \"$input.path('$.cause')\"\n}\n#else\n$input.path('$.output')\n#end" + "application/json": "#set($inputRoot = $input.path('$'))\n#if($input.path('$.status').toString().equals(\"FAILED\"))\n#set($context.responseOverride.status = 500)\n{\n\"error\": \"$input.path('$.error')\",\n\"cause\": \"$input.path('$.cause')\"\n}\n#else\n$input.path('$.output')\n#end" }, "StatusCode": "200" }, @@ -185,11 +185,11 @@ "Fn::Join": [ "", [ - "## Velocity Template used for API Gateway request mapping template\n##\n## This template forwards the request body, header, path, and querystring\n## to the execution input of the state machine.\n##\n## \"@@\" is used here as a placeholder for '\"' to avoid using escape characters.\n\n#set($inputString = '')\n#set($includeHeaders = true)\n#set($includeQueryString = false)\n#set($includePath = false)\n#set($allParams = $input.params())\n{\n \"stateMachineArn\": \"", + "## Velocity Template used for API Gateway request mapping template\n##\n## This template forwards the request body, header, path, and querystring\n## to the execution input of the state machine.\n##\n## \"@@\" is used here as a placeholder for '\"' to avoid using escape characters.\n\n#set($inputString = '')\n#set($includeHeaders = true)\n#set($includeQueryString = false)\n#set($includePath = false)\n#set($includeAuthorizer = false)\n#set($allParams = $input.params())\n{\n \"stateMachineArn\": \"", { "Ref": "StateMachine2E01A3A5" }, - "\",\n\n #set($inputString = \"$inputString,@@body@@: $input.body\")\n\n #if ($includeHeaders)\n #set($inputString = \"$inputString, @@header@@:{\")\n #foreach($paramName in $allParams.header.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.header.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n \n #end\n\n #if ($includeQueryString)\n #set($inputString = \"$inputString, @@querystring@@:{\")\n #foreach($paramName in $allParams.querystring.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.querystring.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n\n #if ($includePath)\n #set($inputString = \"$inputString, @@path@@:{\")\n #foreach($paramName in $allParams.path.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.path.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n \n #set($requestContext = \"{@@accountId@@:@@$context.identity.accountId@@,@@userArn@@:@@$context.identity.userArn@@}\")\n ## Check if the request context should be included as part of the execution input\n #if($requestContext && !$requestContext.empty)\n #set($inputString = \"$inputString,\")\n #set($inputString = \"$inputString @@requestContext@@: $requestContext\")\n #end\n\n #set($inputString = \"$inputString}\")\n #set($inputString = $inputString.replaceAll(\"@@\",'\"'))\n #set($len = $inputString.length() - 1)\n \"input\": \"{$util.escapeJavaScript($inputString.substring(1,$len))}\"\n}\n" + "\",\n\n #set($inputString = \"$inputString,@@body@@: $input.body\")\n\n #if ($includeHeaders)\n #set($inputString = \"$inputString, @@header@@:{\")\n #foreach($paramName in $allParams.header.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.header.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n \n #end\n\n #if ($includeQueryString)\n #set($inputString = \"$inputString, @@querystring@@:{\")\n #foreach($paramName in $allParams.querystring.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.querystring.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n\n #if ($includePath)\n #set($inputString = \"$inputString, @@path@@:{\")\n #foreach($paramName in $allParams.path.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.path.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n \n #if ($includeAuthorizer)\n #set($inputString = \"$inputString, @@authorizer@@:{\")\n #foreach($paramName in $context.authorizer.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($context.authorizer.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n\n #set($requestContext = \"{@@accountId@@:@@$context.identity.accountId@@,@@userArn@@:@@$context.identity.userArn@@}\")\n ## Check if the request context should be included as part of the execution input\n #if($requestContext && !$requestContext.empty)\n #set($inputString = \"$inputString,\")\n #set($inputString = \"$inputString @@requestContext@@: $requestContext\")\n #end\n\n #set($inputString = \"$inputString}\")\n #set($inputString = $inputString.replaceAll(\"@@\",'\"'))\n #set($len = $inputString.length() - 1)\n \"input\": \"{$util.escapeJavaScript($inputString.substring(1,$len))}\"\n}\n" ] ] } @@ -289,4 +289,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-apigateway/test/integrations/stepfunctions.test.ts b/packages/@aws-cdk/aws-apigateway/test/integrations/stepfunctions.test.ts index 830ca2a8e2000..32fd13c5741c0 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integrations/stepfunctions.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/integrations/stepfunctions.test.ts @@ -52,11 +52,11 @@ describe('StepFunctionsIntegration', () => { 'Fn::Join': [ '', [ - "## Velocity Template used for API Gateway request mapping template\n##\n## This template forwards the request body, header, path, and querystring\n## to the execution input of the state machine.\n##\n## \"@@\" is used here as a placeholder for '\"' to avoid using escape characters.\n\n#set($inputString = '')\n#set($includeHeaders = false)\n#set($includeQueryString = true)\n#set($includePath = true)\n#set($allParams = $input.params())\n{\n \"stateMachineArn\": \"", + "## Velocity Template used for API Gateway request mapping template\n##\n## This template forwards the request body, header, path, and querystring\n## to the execution input of the state machine.\n##\n## \"@@\" is used here as a placeholder for '\"' to avoid using escape characters.\n\n#set($inputString = '')\n#set($includeHeaders = false)\n#set($includeQueryString = true)\n#set($includePath = true)\n#set($includeAuthorizer = false)\n#set($allParams = $input.params())\n{\n \"stateMachineArn\": \"", { Ref: 'StateMachine2E01A3A5', }, - "\",\n\n #set($inputString = \"$inputString,@@body@@: $input.body\")\n\n #if ($includeHeaders)\n #set($inputString = \"$inputString, @@header@@:{\")\n #foreach($paramName in $allParams.header.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.header.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n \n #end\n\n #if ($includeQueryString)\n #set($inputString = \"$inputString, @@querystring@@:{\")\n #foreach($paramName in $allParams.querystring.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.querystring.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n\n #if ($includePath)\n #set($inputString = \"$inputString, @@path@@:{\")\n #foreach($paramName in $allParams.path.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.path.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n \n #set($requestContext = \"\")\n ## Check if the request context should be included as part of the execution input\n #if($requestContext && !$requestContext.empty)\n #set($inputString = \"$inputString,\")\n #set($inputString = \"$inputString @@requestContext@@: $requestContext\")\n #end\n\n #set($inputString = \"$inputString}\")\n #set($inputString = $inputString.replaceAll(\"@@\",'\"'))\n #set($len = $inputString.length() - 1)\n \"input\": \"{$util.escapeJavaScript($inputString.substring(1,$len))}\"\n}\n", + "\",\n\n #set($inputString = \"$inputString,@@body@@: $input.body\")\n\n #if ($includeHeaders)\n #set($inputString = \"$inputString, @@header@@:{\")\n #foreach($paramName in $allParams.header.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.header.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n \n #end\n\n #if ($includeQueryString)\n #set($inputString = \"$inputString, @@querystring@@:{\")\n #foreach($paramName in $allParams.querystring.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.querystring.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n\n #if ($includePath)\n #set($inputString = \"$inputString, @@path@@:{\")\n #foreach($paramName in $allParams.path.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.path.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n \n #if ($includeAuthorizer)\n #set($inputString = \"$inputString, @@authorizer@@:{\")\n #foreach($paramName in $context.authorizer.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($context.authorizer.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n\n #set($requestContext = \"\")\n ## Check if the request context should be included as part of the execution input\n #if($requestContext && !$requestContext.empty)\n #set($inputString = \"$inputString,\")\n #set($inputString = \"$inputString @@requestContext@@: $requestContext\")\n #end\n\n #set($inputString = \"$inputString}\")\n #set($inputString = $inputString.replaceAll(\"@@\",'\"'))\n #set($len = $inputString.length() - 1)\n \"input\": \"{$util.escapeJavaScript($inputString.substring(1,$len))}\"\n}\n", ], ], }, @@ -264,6 +264,34 @@ describe('StepFunctionsIntegration', () => { }); }); + test('authorizer context is included when specified by the integration', () => { + //GIVEN + const { stack, api, stateMachine } = givenSetup(); + + //WHEN + const integ = apigw.StepFunctionsIntegration.startExecution(stateMachine, { + authorizer: true, + }); + api.root.addMethod('GET', integ); + + Template.fromStack(stack).hasResourceProperties('AWS::ApiGateway::Method', { + Integration: { + RequestTemplates: { + 'application/json': { + 'Fn::Join': [ + '', + [ + Match.stringLikeRegexp('#set\\(\\$includeAuthorizer = true\\)'), + { Ref: 'StateMachine2E01A3A5' }, + Match.anyValue(), + ], + ], + }, + }, + }, + }); + }); + test('works for imported RestApi', () => { const stack = new cdk.Stack(); const api = apigw.RestApi.fromRestApiAttributes(stack, 'RestApi', { @@ -390,7 +418,7 @@ function getIntegrationResponse() { '#if($input.path(\'$.status\').toString().equals("FAILED"))', '#set($context.responseOverride.status = 500)', '{', - '"error": "$input.path(\'$.error\')"', + '"error": "$input.path(\'$.error\')",', '"cause": "$input.path(\'$.cause\')"', '}', '#else', diff --git a/packages/@aws-cdk/aws-apigateway/test/stepfunctions-api.test.ts b/packages/@aws-cdk/aws-apigateway/test/stepfunctions-api.test.ts index 51426a4ffe6c3..44643ea0814ff 100644 --- a/packages/@aws-cdk/aws-apigateway/test/stepfunctions-api.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/stepfunctions-api.test.ts @@ -3,6 +3,7 @@ import * as sfn from '@aws-cdk/aws-stepfunctions'; import { StateMachine } from '@aws-cdk/aws-stepfunctions'; import * as cdk from '@aws-cdk/core'; import * as apigw from '../lib'; +import { StepFunctionsIntegration } from '../lib'; describe('Step Functions api', () => { test('StepFunctionsRestApi defines correct REST API resources', () => { @@ -33,7 +34,7 @@ describe('Step Functions api', () => { Integration: { Credentials: { 'Fn::GetAtt': [ - 'StartSyncExecutionRoleDE73CB90', + 'StepFunctionsRestApiANYStartSyncExecutionRole425C03BB', 'Arn', ], }, @@ -44,11 +45,11 @@ describe('Step Functions api', () => { 'Fn::Join': [ '', [ - "## Velocity Template used for API Gateway request mapping template\n##\n## This template forwards the request body, header, path, and querystring\n## to the execution input of the state machine.\n##\n## \"@@\" is used here as a placeholder for '\"' to avoid using escape characters.\n\n#set($inputString = '')\n#set($includeHeaders = false)\n#set($includeQueryString = true)\n#set($includePath = true)\n#set($allParams = $input.params())\n{\n \"stateMachineArn\": \"", + "## Velocity Template used for API Gateway request mapping template\n##\n## This template forwards the request body, header, path, and querystring\n## to the execution input of the state machine.\n##\n## \"@@\" is used here as a placeholder for '\"' to avoid using escape characters.\n\n#set($inputString = '')\n#set($includeHeaders = false)\n#set($includeQueryString = true)\n#set($includePath = true)\n#set($includeAuthorizer = false)\n#set($allParams = $input.params())\n{\n \"stateMachineArn\": \"", { Ref: 'StateMachine2E01A3A5', }, - "\",\n\n #set($inputString = \"$inputString,@@body@@: $input.body\")\n\n #if ($includeHeaders)\n #set($inputString = \"$inputString, @@header@@:{\")\n #foreach($paramName in $allParams.header.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.header.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n \n #end\n\n #if ($includeQueryString)\n #set($inputString = \"$inputString, @@querystring@@:{\")\n #foreach($paramName in $allParams.querystring.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.querystring.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n\n #if ($includePath)\n #set($inputString = \"$inputString, @@path@@:{\")\n #foreach($paramName in $allParams.path.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.path.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n \n #set($requestContext = \"\")\n ## Check if the request context should be included as part of the execution input\n #if($requestContext && !$requestContext.empty)\n #set($inputString = \"$inputString,\")\n #set($inputString = \"$inputString @@requestContext@@: $requestContext\")\n #end\n\n #set($inputString = \"$inputString}\")\n #set($inputString = $inputString.replaceAll(\"@@\",'\"'))\n #set($len = $inputString.length() - 1)\n \"input\": \"{$util.escapeJavaScript($inputString.substring(1,$len))}\"\n}\n", + "\",\n\n #set($inputString = \"$inputString,@@body@@: $input.body\")\n\n #if ($includeHeaders)\n #set($inputString = \"$inputString, @@header@@:{\")\n #foreach($paramName in $allParams.header.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.header.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n \n #end\n\n #if ($includeQueryString)\n #set($inputString = \"$inputString, @@querystring@@:{\")\n #foreach($paramName in $allParams.querystring.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.querystring.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n\n #if ($includePath)\n #set($inputString = \"$inputString, @@path@@:{\")\n #foreach($paramName in $allParams.path.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.path.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n \n #if ($includeAuthorizer)\n #set($inputString = \"$inputString, @@authorizer@@:{\")\n #foreach($paramName in $context.authorizer.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($context.authorizer.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n\n #set($requestContext = \"\")\n ## Check if the request context should be included as part of the execution input\n #if($requestContext && !$requestContext.empty)\n #set($inputString = \"$inputString,\")\n #set($inputString = \"$inputString @@requestContext@@: $requestContext\")\n #end\n\n #set($inputString = \"$inputString}\")\n #set($inputString = $inputString.replaceAll(\"@@\",'\"'))\n #set($len = $inputString.length() - 1)\n \"input\": \"{$util.escapeJavaScript($inputString.substring(1,$len))}\"\n}\n", ], ], }, @@ -75,6 +76,87 @@ describe('Step Functions api', () => { }); }); + test('StepFunctionsExecutionIntegration on a method', () => { + // GIVEN + const stack = new cdk.Stack(); + const api = new apigw.RestApi(stack, 'Api'); + const stateMachine = new sfn.StateMachine(stack, 'StateMachine', { + stateMachineType: sfn.StateMachineType.EXPRESS, + definition: new sfn.Pass(stack, 'Pass'), + }); + + // WHEN + api.root.addResource('sfn').addMethod('POST', StepFunctionsIntegration.startExecution(stateMachine)); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApiGateway::Method', { + HttpMethod: 'POST', + MethodResponses: getMethodResponse(), + Integration: { + Credentials: { + 'Fn::GetAtt': [ + 'ApisfnPOSTStartSyncExecutionRole8E8879B0', + 'Arn', + ], + }, + IntegrationHttpMethod: 'POST', + IntegrationResponses: getIntegrationResponse(), + RequestTemplates: { + 'application/json': { + 'Fn::Join': [ + '', + [ + "## Velocity Template used for API Gateway request mapping template\n##\n## This template forwards the request body, header, path, and querystring\n## to the execution input of the state machine.\n##\n## \"@@\" is used here as a placeholder for '\"' to avoid using escape characters.\n\n#set($inputString = '')\n#set($includeHeaders = false)\n#set($includeQueryString = true)\n#set($includePath = true)\n#set($includeAuthorizer = false)\n#set($allParams = $input.params())\n{\n \"stateMachineArn\": \"", + { + Ref: 'StateMachine2E01A3A5', + }, + "\",\n\n #set($inputString = \"$inputString,@@body@@: $input.body\")\n\n #if ($includeHeaders)\n #set($inputString = \"$inputString, @@header@@:{\")\n #foreach($paramName in $allParams.header.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.header.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n \n #end\n\n #if ($includeQueryString)\n #set($inputString = \"$inputString, @@querystring@@:{\")\n #foreach($paramName in $allParams.querystring.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.querystring.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n\n #if ($includePath)\n #set($inputString = \"$inputString, @@path@@:{\")\n #foreach($paramName in $allParams.path.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.path.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n \n #if ($includeAuthorizer)\n #set($inputString = \"$inputString, @@authorizer@@:{\")\n #foreach($paramName in $context.authorizer.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($context.authorizer.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n\n #set($requestContext = \"\")\n ## Check if the request context should be included as part of the execution input\n #if($requestContext && !$requestContext.empty)\n #set($inputString = \"$inputString,\")\n #set($inputString = \"$inputString @@requestContext@@: $requestContext\")\n #end\n\n #set($inputString = \"$inputString}\")\n #set($inputString = $inputString.replaceAll(\"@@\",'\"'))\n #set($len = $inputString.length() - 1)\n \"input\": \"{$util.escapeJavaScript($inputString.substring(1,$len))}\"\n}\n", + ], + ], + }, + }, + Type: 'AWS', + Uri: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':apigateway:', + { + Ref: 'AWS::Region', + }, + ':states:action/StartSyncExecution', + ], + ], + }, + PassthroughBehavior: 'NEVER', + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'states:StartSyncExecution', + Effect: 'Allow', + Resource: { + Ref: 'StateMachine2E01A3A5', + }, + }, + ], + Version: '2012-10-17', + }, + Roles: [ + { + Ref: 'ApisfnPOSTStartSyncExecutionRole8E8879B0', + }, + ], + }); + }); + test('fails if options.defaultIntegration is set', () => { //GIVEN const { stack, stateMachine } = givenSetup(); @@ -181,7 +263,7 @@ function getIntegrationResponse() { '#if($input.path(\'$.status\').toString().equals("FAILED"))', '#set($context.responseOverride.status = 500)', '{', - '"error": "$input.path(\'$.error\')"', + '"error": "$input.path(\'$.error\')",', '"cause": "$input.path(\'$.cause\')"', '}', '#else', diff --git a/packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts b/packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts index b31e3c90b256b..26a63641abc4e 100644 --- a/packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts @@ -27,13 +27,13 @@ describe('usage plan', () => { }); }); - test('usage plan with throttling limits', () => { + test('usage plan with integer throttling limits', () => { // GIVEN const stack = new cdk.Stack(); const api = new apigateway.RestApi(stack, 'my-api', { cloudWatchRole: false, deploy: true, deployOptions: { stageName: 'test' } }); const method: apigateway.Method = api.root.addMethod('GET'); // Need at least one method on the api const usagePlanName = 'Basic'; - const usagePlanDescription = 'Basic Usage Plan with throttling limits'; + const usagePlanDescription = 'Basic Usage Plan with integer throttling limits'; // WHEN new apigateway.UsagePlan(stack, 'my-usage-plan', { @@ -78,6 +78,57 @@ describe('usage plan', () => { }); }); + test('usage plan with integer and float throttling limits', () => { + // GIVEN + const stack = new cdk.Stack(); + const api = new apigateway.RestApi(stack, 'my-api', { cloudWatchRole: false, deploy: true, deployOptions: { stageName: 'test' } }); + const method: apigateway.Method = api.root.addMethod('GET'); // Need at least one method on the api + const usagePlanName = 'Basic'; + const usagePlanDescription = 'Basic Usage Plan with integer and float throttling limits'; + + // WHEN + new apigateway.UsagePlan(stack, 'my-usage-plan', { + name: usagePlanName, + description: usagePlanDescription, + apiStages: [ + { + stage: api.deploymentStage, + throttle: [ + { + method, + throttle: { + burstLimit: 20, + rateLimit: 10.5, + }, + }, + ], + }, + ], + }); + + // THEN + Template.fromStack(stack).hasResourceProperties(RESOURCE_TYPE, { + UsagePlanName: usagePlanName, + Description: usagePlanDescription, + ApiStages: [ + { + ApiId: { + Ref: 'myapi4C7BF186', + }, + Stage: { + Ref: 'myapiDeploymentStagetest4A4AB65E', + }, + Throttle: { + '//GET': { + BurstLimit: 20, + RateLimit: 10.5, + }, + }, + }, + ], + }); + }); + test('usage plan with blocked methods', () => { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json index 084eb7c3dd027..0f103f65f0baa 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json @@ -85,8 +85,8 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.92", - "@types/jest": "^27.4.0" + "@types/aws-lambda": "^8.10.93", + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-apigatewayv2": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.iam.expected.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.iam.expected.json index be1c18a7e49f7..4993cbdffad53 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.iam.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.iam.expected.json @@ -11,50 +11,48 @@ { "Action": "execute-api:Invoke", "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "HttpApiF5A9A8A7" - }, - "/*/*/foo" + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "HttpApiF5A9A8A7" + }, + "/*/*/books/*" + ] ] - ] - } - }, - { - "Action": "execute-api:Invoke", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "HttpApiF5A9A8A7" - }, - "/*/*/books/*" + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "HttpApiF5A9A8A7" + }, + "/*/*/foo" + ] ] - ] - } + } + ] } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.expected.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.expected.json index 921b4b1876d8f..1f4a0445f9243 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.expected.json @@ -209,7 +209,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters7f2fe4e4fa40a84f0f773203f5c5fdaac31c80ce42c5185ed2659a049db03043S3BucketC7E46972" + "Ref": "AssetParameters74589072567ba0ad5a12f277a47a8c3b7b5151e9290901fae0a4ce72fe7e3a3aS3Bucket7FA0095F" }, "S3Key": { "Fn::Join": [ @@ -222,7 +222,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters7f2fe4e4fa40a84f0f773203f5c5fdaac31c80ce42c5185ed2659a049db03043S3VersionKeyA8ECA032" + "Ref": "AssetParameters74589072567ba0ad5a12f277a47a8c3b7b5151e9290901fae0a4ce72fe7e3a3aS3VersionKeyC54BEE58" } ] } @@ -235,7 +235,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters7f2fe4e4fa40a84f0f773203f5c5fdaac31c80ce42c5185ed2659a049db03043S3VersionKeyA8ECA032" + "Ref": "AssetParameters74589072567ba0ad5a12f277a47a8c3b7b5151e9290901fae0a4ce72fe7e3a3aS3VersionKeyC54BEE58" } ] } @@ -345,17 +345,17 @@ } }, "Parameters": { - "AssetParameters7f2fe4e4fa40a84f0f773203f5c5fdaac31c80ce42c5185ed2659a049db03043S3BucketC7E46972": { + "AssetParameters74589072567ba0ad5a12f277a47a8c3b7b5151e9290901fae0a4ce72fe7e3a3aS3Bucket7FA0095F": { "Type": "String", - "Description": "S3 bucket for asset \"7f2fe4e4fa40a84f0f773203f5c5fdaac31c80ce42c5185ed2659a049db03043\"" + "Description": "S3 bucket for asset \"74589072567ba0ad5a12f277a47a8c3b7b5151e9290901fae0a4ce72fe7e3a3a\"" }, - "AssetParameters7f2fe4e4fa40a84f0f773203f5c5fdaac31c80ce42c5185ed2659a049db03043S3VersionKeyA8ECA032": { + "AssetParameters74589072567ba0ad5a12f277a47a8c3b7b5151e9290901fae0a4ce72fe7e3a3aS3VersionKeyC54BEE58": { "Type": "String", - "Description": "S3 key for asset version \"7f2fe4e4fa40a84f0f773203f5c5fdaac31c80ce42c5185ed2659a049db03043\"" + "Description": "S3 key for asset version \"74589072567ba0ad5a12f277a47a8c3b7b5151e9290901fae0a4ce72fe7e3a3a\"" }, - "AssetParameters7f2fe4e4fa40a84f0f773203f5c5fdaac31c80ce42c5185ed2659a049db03043ArtifactHashE679D99A": { + "AssetParameters74589072567ba0ad5a12f277a47a8c3b7b5151e9290901fae0a4ce72fe7e3a3aArtifactHash06752181": { "Type": "String", - "Description": "Artifact hash for asset \"7f2fe4e4fa40a84f0f773203f5c5fdaac31c80ce42c5185ed2659a049db03043\"" + "Description": "Artifact hash for asset \"74589072567ba0ad5a12f277a47a8c3b7b5151e9290901fae0a4ce72fe7e3a3a\"" }, "AssetParameters1fd1c15cb7d5e2e36a11745fd10b4b7c3ca8eb30642b41954630413d2b913cdaS3Bucket2E6D85D3": { "Type": "String", diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/lambda.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/lambda.ts index 2417fffe1610d..69019e0c2866a 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/lambda.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/lambda.ts @@ -50,7 +50,7 @@ export class HttpLambdaIntegration extends HttpRouteIntegration { this._id = id; } - public bind(options: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig { + protected completeBind(options: HttpRouteIntegrationBindOptions) { const route = options.route; this.handler.addPermission(`${this._id}-Permission`, { scope: options.scope, @@ -61,7 +61,9 @@ export class HttpLambdaIntegration extends HttpRouteIntegration { resourceName: `*/*${route.path ?? ''}`, // empty string in the case of the catch-all route $default }), }); + } + public bind(_: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig { return { type: HttpIntegrationType.AWS_PROXY, uri: this.handler.functionArn, diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json index 2adf4f6882119..749d5fb08b479 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json @@ -81,7 +81,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-apigatewayv2": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/lambda.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/lambda.test.ts index 5c318e1629842..f832921ad995b 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/lambda.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/lambda.test.ts @@ -1,4 +1,4 @@ -import { Template } from '@aws-cdk/assertions'; +import { Match, Template } from '@aws-cdk/assertions'; import { HttpApi, HttpRoute, HttpRouteKey, MappingValue, ParameterMapping, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; import { Code, Function, Runtime } from '@aws-cdk/aws-lambda'; import { App, Stack } from '@aws-cdk/core'; @@ -71,6 +71,41 @@ describe('LambdaProxyIntegration', () => { expect(() => app.synth()).not.toThrow(); }); + + test('multiple routes for the same lambda integration', () => { + const app = new App(); + const lambdaStack = new Stack(app, 'lambdaStack'); + const fooFn = fooFunction(lambdaStack, 'Fn'); + + const stack = new Stack(app, 'apigwStack'); + const api = new HttpApi(stack, 'httpApi'); + const integration = new HttpLambdaIntegration('Integration', fooFn); + + api.addRoutes({ + path: '/foo', + integration, + }); + + api.addRoutes({ + path: '/bar', + integration, + }); + + // Make sure we have two permissions -- one for each method -- but a single integration + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { + SourceArn: { + 'Fn::Join': ['', Match.arrayWith([':execute-api:', '/*/*/foo'])], + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { + SourceArn: { + 'Fn::Join': ['', Match.arrayWith([':execute-api:', '/*/*/bar'])], + }, + }); + + Template.fromStack(stack).resourceCountIs('AWS::ApiGatewayV2::Integration', 1); + }); }); function fooFunction(stack: Stack, id: string) { diff --git a/packages/@aws-cdk/aws-apigatewayv2/README.md b/packages/@aws-cdk/aws-apigatewayv2/README.md index 5e0a110082ab9..040ee20d0bf6a 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/README.md +++ b/packages/@aws-cdk/aws-apigatewayv2/README.md @@ -404,6 +404,12 @@ webSocketApi.addRoute('sendmessage', { }); ``` +To import an existing WebSocketApi: + +```ts +const webSocketApi = apigwv2.WebSocketApi.fromWebSocketApiAttributes(this, 'mywsapi', { webSocketId: 'api-1234' }); +``` + ### Manage Connections Permission Grant permission to use API Gateway Management API of a WebSocket API by calling the `grantManageConnections` API. diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/integration.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/integration.ts index 58e9c9a60879a..9667f072d9036 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/integration.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/integration.ts @@ -332,9 +332,22 @@ export abstract class HttpRouteIntegration { credentials: config.credentials, }); } + this.completeBind(options); return { integrationId: this.integration.integrationId }; } + /** + * Complete the binding of the integration to the route. In some cases, there is + * some additional work to do, such as adding permissions for the API to access + * the target. This work is necessary whether the integration has just been + * created for this route or it is an existing one, previously created for other + * routes. In most cases, however, concrete implementations do not need to + * override this method. + */ + protected completeBind(_options: HttpRouteIntegrationBindOptions): void { + // no-op by default + } + /** * Bind this integration to the route. */ diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/api.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/api.ts index da740d582bbad..f81eb7b899f1f 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/api.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/api.ts @@ -85,11 +85,47 @@ export interface WebSocketApiProps { readonly defaultRouteOptions?: WebSocketRouteOptions; } +/** + * Attributes for importing a WebSocketApi into the CDK + */ +export interface WebSocketApiAttributes { + /** + * The identifier of the WebSocketApi + */ + readonly webSocketId: string; + + /** + * The endpoint URL of the WebSocketApi + * @default - throw san error if apiEndpoint is accessed. + */ + readonly apiEndpoint?: string; +} + + /** * Create a new API Gateway WebSocket API endpoint. * @resource AWS::ApiGatewayV2::Api */ export class WebSocketApi extends ApiBase implements IWebSocketApi { + /** + * Import an existing WebSocket API into this CDK app. + */ + public static fromWebSocketApiAttributes(scope: Construct, id: string, attrs: WebSocketApiAttributes): IWebSocketApi { + class Import extends ApiBase { + public readonly apiId = attrs.webSocketId; + public readonly websocketApiId = attrs.webSocketId; + private readonly _apiEndpoint = attrs.apiEndpoint; + + public get apiEndpoint(): string { + if (!this._apiEndpoint) { + throw new Error('apiEndpoint is not configured on the imported WebSocketApi.'); + } + return this._apiEndpoint; + } + } + return new Import(scope, id); + } + public readonly apiId: string; public readonly apiEndpoint: string; diff --git a/packages/@aws-cdk/aws-apigatewayv2/package.json b/packages/@aws-cdk/aws-apigatewayv2/package.json index 31ec578d85b51..088009ce5a483 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2/package.json @@ -89,7 +89,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/websocket/api.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/websocket/api.test.ts index 1ac6cfbae315f..f9fb740c0e190 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/websocket/api.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/websocket/api.test.ts @@ -107,6 +107,25 @@ describe('WebSocketApi', () => { }); }); + test('import', () => { + // GIVEN + const stack = new Stack(); + const imported = WebSocketApi.fromWebSocketApiAttributes(stack, 'imported', { webSocketId: 'ws-1234', apiEndpoint: 'api-endpoint' }); + + // THEN + expect(imported.apiId).toEqual('ws-1234'); + expect(imported.apiEndpoint).toEqual('api-endpoint'); + }); + + test('apiEndpoint for imported', () => { + // GIVEN + const stack = new Stack(); + const api = WebSocketApi.fromWebSocketApiAttributes(stack, 'imported', { webSocketId: 'api-1234' }); + + // THEN + expect(() => api.apiEndpoint).toThrow(/apiEndpoint is not configured/); + }); + describe('grantManageConnections', () => { test('adds an IAM policy to the principal', () => { // GIVEN diff --git a/packages/@aws-cdk/aws-appconfig/package.json b/packages/@aws-cdk/aws-appconfig/package.json index 4f4abaaf6dc40..59a35b9f2f241 100644 --- a/packages/@aws-cdk/aws-appconfig/package.json +++ b/packages/@aws-cdk/aws-appconfig/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-appflow/package.json b/packages/@aws-cdk/aws-appflow/package.json index fd0648da5f582..e401c2c7c98de 100644 --- a/packages/@aws-cdk/aws-appflow/package.json +++ b/packages/@aws-cdk/aws-appflow/package.json @@ -82,7 +82,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-appintegrations/package.json b/packages/@aws-cdk/aws-appintegrations/package.json index cd4ecf81dd7c5..d0615ae38682c 100644 --- a/packages/@aws-cdk/aws-appintegrations/package.json +++ b/packages/@aws-cdk/aws-appintegrations/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-applicationautoscaling/README.md b/packages/@aws-cdk/aws-applicationautoscaling/README.md index 0870212d274a9..9697a9d27badc 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/README.md +++ b/packages/@aws-cdk/aws-applicationautoscaling/README.md @@ -222,7 +222,7 @@ const handler = new lambda.Function(this, 'MyFunction', { reservedConcurrentExecutions: 2, }); -const fnVer = handler.addVersion('CDKLambdaVersion', undefined, 'demo alias', 10); +const fnVer = handler.currentVersion; const target = new appscaling.ScalableTarget(this, 'ScalableTarget', { serviceNamespace: appscaling.ServiceNamespace.LAMBDA, diff --git a/packages/@aws-cdk/aws-applicationautoscaling/lib/scalable-target.ts b/packages/@aws-cdk/aws-applicationautoscaling/lib/scalable-target.ts index a81385e411a99..6b0f4ab30d7a9 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/lib/scalable-target.ts +++ b/packages/@aws-cdk/aws-applicationautoscaling/lib/scalable-target.ts @@ -148,6 +148,10 @@ export class ScalableTarget extends Resource implements IScalableTarget { if (action.minCapacity === undefined && action.maxCapacity === undefined) { throw new Error(`You must supply at least one of minCapacity or maxCapacity, got ${JSON.stringify(action)}`); } + + // add a warning on synth when minute is not defined in a cron schedule + action.schedule._bind(this); + this.actions.push({ scheduledActionName: id, schedule: action.schedule.expressionString, diff --git a/packages/@aws-cdk/aws-applicationautoscaling/lib/schedule.ts b/packages/@aws-cdk/aws-applicationautoscaling/lib/schedule.ts index 3bd74c1e4f681..ab51bb43452ee 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/lib/schedule.ts +++ b/packages/@aws-cdk/aws-applicationautoscaling/lib/schedule.ts @@ -1,4 +1,5 @@ -import { Duration } from '@aws-cdk/core'; +import { Annotations, Duration } from '@aws-cdk/core'; +import { Construct } from 'constructs'; /** * Schedule for scheduled scaling actions @@ -58,7 +59,15 @@ export abstract class Schedule { const day = fallback(options.day, options.weekDay !== undefined ? '?' : '*'); const weekDay = fallback(options.weekDay, '?'); - return new LiteralSchedule(`cron(${minute} ${hour} ${day} ${month} ${weekDay} ${year})`); + return new class extends Schedule { + public readonly expressionString: string = `cron(${minute} ${hour} ${day} ${month} ${weekDay} ${year})`; + public _bind(scope: Construct) { + if (!options.minute) { + Annotations.of(scope).addWarning('cron: If you don\'t pass \'minute\', by default the event runs every minute. Pass \'minute: \'*\'\' if that\'s what you intend, or \'minute: 0\' to run once per hour instead.'); + } + return new LiteralSchedule(this.expressionString); + } + }; } /** @@ -66,8 +75,13 @@ export abstract class Schedule { */ public abstract readonly expressionString: string; - protected constructor() { - } + protected constructor() {} + + /** + * + * @internal + */ + public abstract _bind(scope: Construct): void; } /** @@ -126,6 +140,8 @@ class LiteralSchedule extends Schedule { constructor(public readonly expressionString: string) { super(); } + + public _bind() {} } function fallback(x: T | undefined, def: T): T { diff --git a/packages/@aws-cdk/aws-applicationautoscaling/package.json b/packages/@aws-cdk/aws-applicationautoscaling/package.json index e9f6d2d248dc7..2f389484affc8 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/package.json +++ b/packages/@aws-cdk/aws-applicationautoscaling/package.json @@ -83,9 +83,9 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "fast-check": "^2.21.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "fast-check": "^2.23.2", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-autoscaling-common": "0.0.0", diff --git a/packages/@aws-cdk/aws-applicationautoscaling/test/scalable-target.test.ts b/packages/@aws-cdk/aws-applicationautoscaling/test/scalable-target.test.ts index bb66486113531..8cdf9051af1f5 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/test/scalable-target.test.ts +++ b/packages/@aws-cdk/aws-applicationautoscaling/test/scalable-target.test.ts @@ -1,4 +1,4 @@ -import { Match, Template } from '@aws-cdk/assertions'; +import { Annotations, Match, Template } from '@aws-cdk/assertions'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; @@ -79,6 +79,45 @@ describe('scalable target', () => { }); }); + test('scheduled scaling shows warning when minute is not defined in cron', () => { + // GIVEN + const stack = new cdk.Stack(); + const target = createScalableTarget(stack); + + // WHEN + target.scaleOnSchedule('ScaleUp', { + schedule: appscaling.Schedule.cron({ + hour: '8', + day: '1', + }), + maxCapacity: 50, + minCapacity: 1, + }); + + // THEN + Annotations.fromStack(stack).hasWarning('/Default/Target', Match.stringLikeRegexp("cron: If you don't pass 'minute', by default the event runs every minute.*")); + }); + + test('scheduled scaling shows no warning when minute is * in cron', () => { + // GIVEN + const stack = new cdk.Stack(); + const target = createScalableTarget(stack); + + // WHEN + target.scaleOnSchedule('ScaleUp', { + schedule: appscaling.Schedule.cron({ + hour: '8', + day: '1', + minute: '*', + }), + maxCapacity: 50, + minCapacity: 1, + }); + + // THEN + Annotations.fromStack(stack).hasNoWarning('/Default/Target', Match.stringLikeRegexp("cron: If you don't pass 'minute', by default the event runs every minute.*")); + }); + test('step scaling on MathExpression', () => { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-applicationinsights/package.json b/packages/@aws-cdk/aws-applicationinsights/package.json index 38d8d1d6311c1..70ecad632f81f 100644 --- a/packages/@aws-cdk/aws-applicationinsights/package.json +++ b/packages/@aws-cdk/aws-applicationinsights/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-appmesh/package.json b/packages/@aws-cdk/aws-appmesh/package.json index e2a885f180327..81b3eff008d13 100644 --- a/packages/@aws-cdk/aws-appmesh/package.json +++ b/packages/@aws-cdk/aws-appmesh/package.json @@ -89,8 +89,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-acmpca": "0.0.0", diff --git a/packages/@aws-cdk/aws-apprunner/package.json b/packages/@aws-cdk/aws-apprunner/package.json index 0627cfbcc38fa..be5b3afe4c9cc 100644 --- a/packages/@aws-cdk/aws-apprunner/package.json +++ b/packages/@aws-cdk/aws-apprunner/package.json @@ -88,7 +88,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-ecr": "0.0.0", diff --git a/packages/@aws-cdk/aws-apprunner/test/integ.service.expected.json b/packages/@aws-cdk/aws-apprunner/test/integ.service.expected.json index ed37fa7666d4c..9ca183c3ca56a 100644 --- a/packages/@aws-cdk/aws-apprunner/test/integ.service.expected.json +++ b/packages/@aws-cdk/aws-apprunner/test/integ.service.expected.json @@ -46,8 +46,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { @@ -153,8 +153,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-appstream/package.json b/packages/@aws-cdk/aws-appstream/package.json index 059821e8a6b4b..0069735f46906 100644 --- a/packages/@aws-cdk/aws-appstream/package.json +++ b/packages/@aws-cdk/aws-appstream/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-appsync/README.md b/packages/@aws-cdk/aws-appsync/README.md index 8e78c92bd4b7b..721fa10390784 100644 --- a/packages/@aws-cdk/aws-appsync/README.md +++ b/packages/@aws-cdk/aws-appsync/README.md @@ -240,18 +240,19 @@ httpDs.createResolver({ }); ``` -### Elasticsearch +### Amazon OpenSearch Service -AppSync has builtin support for Elasticsearch from domains that are provisioned -through your AWS account. You can use AppSync resolvers to perform GraphQL operations -such as queries, mutations, and subscriptions. +AppSync has builtin support for Amazon OpenSearch Service (successor to Amazon +Elasticsearch Service) from domains that are provisioned through your AWS account. You can +use AppSync resolvers to perform GraphQL operations such as queries, mutations, and +subscriptions. ```ts -import * as es from '@aws-cdk/aws-elasticsearch'; +import * as opensearch from '@aws-cdk/aws-opensearchservice'; const user = new iam.User(this, 'User'); -const domain = new es.Domain(this, 'Domain', { - version: es.ElasticsearchVersion.V7_1, +const domain = new opensearch.Domain(this, 'Domain', { + version: opensearch.EngineVersion.OPENSEARCH_1_1, removalPolicy: RemovalPolicy.DESTROY, fineGrainedAccessControl: { masterUserArn: user.userArn }, encryptionAtRest: { enabled: true }, @@ -260,7 +261,7 @@ const domain = new es.Domain(this, 'Domain', { }); declare const api: appsync.GraphqlApi; -const ds = api.addElasticsearchDataSource('ds', domain); +const ds = api.addOpenSearchDataSource('ds', domain); ds.createResolver({ typeName: 'Query', @@ -284,6 +285,43 @@ ds.createResolver({ }); ``` +## Custom Domain Names + +For many use cases you may want to associate a custom domain name with your +GraphQL API. This can be done during the API creation. + +```ts +import * as acm from '@aws-cdk/aws-certificatemanager'; +import * as route53 from '@aws-cdk/aws-route53'; + +const myDomainName = 'api.example.com'; +const certificate = new acm.Certificate(this, 'cert', { domainName: myDomainName }); +const api = new appsync.GraphqlApi(this, 'api', { + name: 'myApi', + domainName: { + certificate, + domainName: myDomainName, + }, +}); + +// hosted zone and route53 features +declare const hostedZoneId: string; +declare const zoneName = 'example.com'; + +// hosted zone for adding appsync domain +const zone = route53.HostedZone.fromHostedZoneAttributes(this, `HostedZone`, { + hostedZoneId, + zoneName, +}); + +// create a cname to the appsync domain. will map to something like xxxx.cloudfront.net +new route53.CnameRecord(this, `CnameApiRecord`, { + recordName: 'api', + zone, + domainName: myDomainName, +}); +``` + ## Schema Every GraphQL Api needs a schema to define the Api. CDK offers `appsync.Schema` diff --git a/packages/@aws-cdk/aws-appsync/lib/data-source.ts b/packages/@aws-cdk/aws-appsync/lib/data-source.ts index c89479c4ef69b..7781f0c57d0af 100644 --- a/packages/@aws-cdk/aws-appsync/lib/data-source.ts +++ b/packages/@aws-cdk/aws-appsync/lib/data-source.ts @@ -1,7 +1,8 @@ import { ITable } from '@aws-cdk/aws-dynamodb'; -import { IDomain } from '@aws-cdk/aws-elasticsearch'; +import { IDomain as IElasticsearchDomain } from '@aws-cdk/aws-elasticsearch'; import { Grant, IGrantable, IPrincipal, IRole, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import { IFunction } from '@aws-cdk/aws-lambda'; +import { IDomain as IOpenSearchDomain } from '@aws-cdk/aws-opensearchservice'; import { IServerlessCluster } from '@aws-cdk/aws-rds'; import { ISecret } from '@aws-cdk/aws-secretsmanager'; import { IResolvable, Lazy, Stack } from '@aws-cdk/core'; @@ -64,11 +65,18 @@ export interface ExtendedDataSourceProps { */ readonly dynamoDbConfig?: CfnDataSource.DynamoDBConfigProperty | IResolvable; /** - * configuration for Elasticsearch Datasource + * configuration for Elasticsearch data source * + * @deprecated - use `openSearchConfig` * @default - No config */ readonly elasticsearchConfig?: CfnDataSource.ElasticsearchConfigProperty | IResolvable; + /** + * configuration for OpenSearch data source + * + * @default - No config + */ + readonly openSearchServiceConfig?: CfnDataSource.OpenSearchServiceConfigProperty | IResolvable; /** * configuration for HTTP Datasource * @@ -370,17 +378,21 @@ export class RdsDataSource extends BackedDataSource { } /** - * Properities for the Elasticsearch Data Source + * Properties for the Elasticsearch Data Source + * + * @deprecated - use `OpenSearchDataSourceProps` with `OpenSearchDataSource` */ export interface ElasticsearchDataSourceProps extends BackedDataSourceProps { /** * The elasticsearch domain containing the endpoint for the data source */ - readonly domain: IDomain; + readonly domain: IElasticsearchDomain; } /** * An Appsync datasource backed by Elasticsearch + * + * @deprecated - use `OpenSearchDataSource` */ export class ElasticsearchDataSource extends BackedDataSource { constructor(scope: Construct, id: string, props: ElasticsearchDataSourceProps) { @@ -394,4 +406,31 @@ export class ElasticsearchDataSource extends BackedDataSource { props.domain.grantReadWrite(this); } -} \ No newline at end of file +} + +/** + * Properties for the OpenSearch Data Source + */ +export interface OpenSearchDataSourceProps extends BackedDataSourceProps { + /** + * The OpenSearch domain containing the endpoint for the data source + */ + readonly domain: IOpenSearchDomain; +} + +/** + * An Appsync datasource backed by OpenSearch + */ +export class OpenSearchDataSource extends BackedDataSource { + constructor(scope: Construct, id: string, props: OpenSearchDataSourceProps) { + super(scope, id, props, { + type: 'AMAZON_OPENSEARCH_SERVICE', + openSearchServiceConfig: { + awsRegion: props.domain.stack.region, + endpoint: `https://${props.domain.domainEndpoint}`, + }, + }); + + props.domain.grantReadWrite(this); + } +} diff --git a/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts b/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts index dfd596b929903..0737be10c8fc3 100644 --- a/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts +++ b/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts @@ -1,10 +1,11 @@ import { ITable } from '@aws-cdk/aws-dynamodb'; -import { IDomain } from '@aws-cdk/aws-elasticsearch'; +import { IDomain as IElasticsearchDomain } from '@aws-cdk/aws-elasticsearch'; import { IFunction } from '@aws-cdk/aws-lambda'; +import { IDomain as IOpenSearchDomain } from '@aws-cdk/aws-opensearchservice'; import { IServerlessCluster } from '@aws-cdk/aws-rds'; import { ISecret } from '@aws-cdk/aws-secretsmanager'; import { CfnResource, IResource, Resource } from '@aws-cdk/core'; -import { DynamoDbDataSource, HttpDataSource, LambdaDataSource, NoneDataSource, RdsDataSource, AwsIamConfig, ElasticsearchDataSource } from './data-source'; +import { DynamoDbDataSource, HttpDataSource, LambdaDataSource, NoneDataSource, RdsDataSource, AwsIamConfig, ElasticsearchDataSource, OpenSearchDataSource } from './data-source'; import { Resolver, ExtendedResolverProps } from './resolver'; /** @@ -114,11 +115,21 @@ export interface IGraphqlApi extends IResource { /** * add a new elasticsearch data source to this API * + * @deprecated - use `addOpenSearchDataSource` * @param id The data source's id * @param domain The elasticsearch domain for this data source * @param options The optional configuration for this data source */ - addElasticsearchDataSource(id: string, domain: IDomain, options?: DataSourceOptions): ElasticsearchDataSource; + addElasticsearchDataSource(id: string, domain: IElasticsearchDomain, options?: DataSourceOptions): ElasticsearchDataSource; + + /** + * Add a new OpenSearch data source to this API + * + * @param id The data source's id + * @param domain The OpenSearch domain for this data source + * @param options The optional configuration for this data source + */ + addOpenSearchDataSource(id: string, domain: IOpenSearchDomain, options?: DataSourceOptions): OpenSearchDataSource; /** * creates a new resolver for this datasource and API using the given properties @@ -241,11 +252,12 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi { /** * add a new elasticsearch data source to this API * + * @deprecated - use `addOpenSearchDataSource` * @param id The data source's id * @param domain The elasticsearch domain for this data source * @param options The optional configuration for this data source */ - public addElasticsearchDataSource(id: string, domain: IDomain, options?: DataSourceOptions): ElasticsearchDataSource { + public addElasticsearchDataSource(id: string, domain: IElasticsearchDomain, options?: DataSourceOptions): ElasticsearchDataSource { return new ElasticsearchDataSource(this, id, { api: this, name: options?.name, @@ -254,6 +266,22 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi { }); } + /** + * add a new OpenSearch data source to this API + * + * @param id The data source's id + * @param domain The OpenSearch domain for this data source + * @param options The optional configuration for this data source + */ + public addOpenSearchDataSource(id: string, domain: IOpenSearchDomain, options?: DataSourceOptions): OpenSearchDataSource { + return new OpenSearchDataSource(this, id, { + api: this, + name: options?.name, + description: options?.description, + domain, + }); + } + /** * creates a new resolver for this datasource and API using the given properties */ @@ -273,4 +301,4 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi { construct; return false; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-appsync/lib/graphqlapi.ts b/packages/@aws-cdk/aws-appsync/lib/graphqlapi.ts index a63b757ba6b0b..5d7cce7131cbb 100644 --- a/packages/@aws-cdk/aws-appsync/lib/graphqlapi.ts +++ b/packages/@aws-cdk/aws-appsync/lib/graphqlapi.ts @@ -1,9 +1,10 @@ +import { ICertificate } from '@aws-cdk/aws-certificatemanager'; import { IUserPool } from '@aws-cdk/aws-cognito'; import { ManagedPolicy, Role, IRole, ServicePrincipal, Grant, IGrantable } from '@aws-cdk/aws-iam'; import { IFunction } from '@aws-cdk/aws-lambda'; import { ArnFormat, CfnResource, Duration, Expiration, IResolvable, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; -import { CfnApiKey, CfnGraphQLApi, CfnGraphQLSchema } from './appsync.generated'; +import { CfnApiKey, CfnGraphQLApi, CfnGraphQLSchema, CfnDomainName, CfnDomainNameApiAssociation } from './appsync.generated'; import { IGraphqlApi, GraphqlApiBase } from './graphqlapi-base'; import { Schema } from './schema'; import { IIntermediateType } from './schema-base'; @@ -254,6 +255,21 @@ export interface LogConfig { readonly role?: IRole; } +/** + * Domain name configuration for AppSync + */ +export interface DomainOptions { + /** + * The certificate to use with the domain name. + */ + readonly certificate: ICertificate; + + /** + * The actual domain name. For example, `api.example.com`. + */ + readonly domainName: string; +} + /** * Properties for an AppSync GraphQL API */ @@ -292,6 +308,16 @@ export interface GraphqlApiProps { * @default - false */ readonly xrayEnabled?: boolean; + + /** + * The domain name configuration for the GraphQL API + * + * The Route 53 hosted zone and CName DNS record must be configured in addition to this setting to + * enable custom domain URL + * + * @default - no domain name + */ + readonly domainName?: DomainOptions; } /** @@ -391,7 +417,7 @@ export class GraphqlApi extends GraphqlApiBase { class Import extends GraphqlApiBase { public readonly apiId = attrs.graphqlApiId; public readonly arn = arn; - constructor (s: Construct, i: string) { + constructor(s: Construct, i: string) { super(s, i); } } @@ -450,7 +476,7 @@ export class GraphqlApi extends GraphqlApiBase { const additionalModes = props.authorizationConfig?.additionalAuthorizationModes ?? []; const modes = [defaultMode, ...additionalModes]; - this.modes = modes.map((mode) => mode.authorizationType ); + this.modes = modes.map((mode) => mode.authorizationType); this.validateAuthorizationProps(modes); @@ -472,6 +498,19 @@ export class GraphqlApi extends GraphqlApiBase { this.schema = props.schema ?? new Schema(); this.schemaResource = this.schema.bind(this); + if (props.domainName) { + new CfnDomainName(this, 'DomainName', { + domainName: props.domainName.domainName, + certificateArn: props.domainName.certificate.certificateArn, + description: `domain for ${this.name} at ${this.graphqlUrl}`, + }); + + new CfnDomainNameApiAssociation(this, 'DomainAssociation', { + domainName: props.domainName.domainName, + apiId: this.apiId, + }); + } + if (modes.some((mode) => mode.authorizationType === AuthorizationType.API_KEY)) { const config = modes.find((mode: AuthorizationMode) => { return mode.authorizationType === AuthorizationType.API_KEY && mode.apiKeyConfig; diff --git a/packages/@aws-cdk/aws-appsync/package.json b/packages/@aws-cdk/aws-appsync/package.json index b303333ffd1dc..f69c2d957e031 100644 --- a/packages/@aws-cdk/aws-appsync/package.json +++ b/packages/@aws-cdk/aws-appsync/package.json @@ -85,16 +85,18 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { + "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/aws-dynamodb": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticsearch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-opensearchservice": "0.0.0", "@aws-cdk/aws-rds": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", @@ -103,12 +105,14 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/aws-dynamodb": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticsearch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-opensearchservice": "0.0.0", "@aws-cdk/aws-rds": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-elasticsearch.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-elasticsearch.test.ts index 89199d65ca629..c6049ba4b3baa 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-elasticsearch.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-elasticsearch.test.ts @@ -1,6 +1,7 @@ import * as path from 'path'; import { Template } from '@aws-cdk/assertions'; import * as es from '@aws-cdk/aws-elasticsearch'; +import { describeDeprecated } from '@aws-cdk/cdk-build-tools'; import * as cdk from '@aws-cdk/core'; import * as appsync from '../lib'; @@ -8,143 +9,146 @@ import * as appsync from '../lib'; let stack: cdk.Stack; let api: appsync.GraphqlApi; let domain: es.Domain; -beforeEach(() => { - stack = new cdk.Stack(); - api = new appsync.GraphqlApi(stack, 'baseApi', { - name: 'api', - schema: appsync.Schema.fromAsset(path.join(__dirname, 'appsync.test.graphql')), - }); - domain = new es.Domain(stack, 'EsDomain', { - version: es.ElasticsearchVersion.V7_10, - }); -}); - -describe('Elasticsearch Data Source Configuration', () => { - test('Elasticsearch configure properly', () => { - // WHEN - api.addElasticsearchDataSource('ds', domain); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { - PolicyDocument: { - Version: '2012-10-17', - Statement: [{ - Action: [ - 'es:ESHttpGet', - 'es:ESHttpHead', - 'es:ESHttpDelete', - 'es:ESHttpPost', - 'es:ESHttpPut', - 'es:ESHttpPatch', - ], - Effect: 'Allow', - Resource: [{ - 'Fn::GetAtt': ['EsDomain1213C634', 'Arn'], - }, - { - 'Fn::Join': ['', [{ - 'Fn::GetAtt': ['EsDomain1213C634', 'Arn'], - }, '/*']], - }], - }], - }, + +describeDeprecated('Appsync Elasticsearch integration', () => { + beforeEach(() => { + stack = new cdk.Stack(); + api = new appsync.GraphqlApi(stack, 'baseApi', { + name: 'api', + schema: appsync.Schema.fromAsset(path.join(__dirname, 'appsync.test.graphql')), + }); + domain = new es.Domain(stack, 'EsDomain', { + version: es.ElasticsearchVersion.V7_10, }); }); - test('Elastic search configuration contains fully qualified url', () => { - // WHEN - api.addElasticsearchDataSource('ds', domain); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { - ElasticsearchConfig: { - Endpoint: { - 'Fn::Join': ['', ['https://', { - 'Fn::GetAtt': ['EsDomain1213C634', 'DomainEndpoint'], - }]], + describe('Elasticsearch Data Source Configuration', () => { + test('Elasticsearch configure properly', () => { + // WHEN + api.addElasticsearchDataSource('ds', domain); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Version: '2012-10-17', + Statement: [{ + Action: [ + 'es:ESHttpGet', + 'es:ESHttpHead', + 'es:ESHttpDelete', + 'es:ESHttpPost', + 'es:ESHttpPut', + 'es:ESHttpPatch', + ], + Effect: 'Allow', + Resource: [{ + 'Fn::GetAtt': ['EsDomain1213C634', 'Arn'], + }, + { + 'Fn::Join': ['', [{ + 'Fn::GetAtt': ['EsDomain1213C634', 'Arn'], + }, '/*']], + }], + }], }, - }, + }); }); - }); - test('default configuration produces name identical to the id', () => { - // WHEN - api.addElasticsearchDataSource('ds', domain); + test('Elastic search configuration contains fully qualified url', () => { + // WHEN + api.addElasticsearchDataSource('ds', domain); - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { - Type: 'AMAZON_ELASTICSEARCH', - Name: 'ds', + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + ElasticsearchConfig: { + Endpoint: { + 'Fn::Join': ['', ['https://', { + 'Fn::GetAtt': ['EsDomain1213C634', 'DomainEndpoint'], + }]], + }, + }, + }); }); - }); - test('appsync configures name correctly', () => { - // WHEN - api.addElasticsearchDataSource('ds', domain, { - name: 'custom', - }); + test('default configuration produces name identical to the id', () => { + // WHEN + api.addElasticsearchDataSource('ds', domain); - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { - Type: 'AMAZON_ELASTICSEARCH', - Name: 'custom', + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'AMAZON_ELASTICSEARCH', + Name: 'ds', + }); }); - }); - test('appsync configures name and description correctly', () => { - // WHEN - api.addElasticsearchDataSource('ds', domain, { - name: 'custom', - description: 'custom description', + test('appsync configures name correctly', () => { + // WHEN + api.addElasticsearchDataSource('ds', domain, { + name: 'custom', + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'AMAZON_ELASTICSEARCH', + Name: 'custom', + }); }); - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { - Type: 'AMAZON_ELASTICSEARCH', - Name: 'custom', - Description: 'custom description', + test('appsync configures name and description correctly', () => { + // WHEN + api.addElasticsearchDataSource('ds', domain, { + name: 'custom', + description: 'custom description', + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'AMAZON_ELASTICSEARCH', + Name: 'custom', + Description: 'custom description', + }); }); - }); - test('appsync errors when creating multiple elasticsearch data sources with no configuration', () => { - // WHEN - const when = () => { - api.addElasticsearchDataSource('ds', domain); - api.addElasticsearchDataSource('ds', domain); - }; - - // THEN - expect(when).toThrow('There is already a Construct with name \'ds\' in GraphqlApi [baseApi]'); - }); -}); - -describe('adding elasticsearch data source from imported api', () => { - test('imported api can add ElasticsearchDataSource from id', () => { - // WHEN - const importedApi = appsync.GraphqlApi.fromGraphqlApiAttributes(stack, 'importedApi', { - graphqlApiId: api.apiId, - }); - importedApi.addElasticsearchDataSource('ds', domain); + test('appsync errors when creating multiple elasticsearch data sources with no configuration', () => { + // WHEN + const when = () => { + api.addElasticsearchDataSource('ds', domain); + api.addElasticsearchDataSource('ds', domain); + }; - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { - Type: 'AMAZON_ELASTICSEARCH', - ApiId: { 'Fn::GetAtt': ['baseApiCDA4D43A', 'ApiId'] }, + // THEN + expect(when).toThrow('There is already a Construct with name \'ds\' in GraphqlApi [baseApi]'); }); }); - test('imported api can add ElasticsearchDataSource from attributes', () => { - // WHEN - const importedApi = appsync.GraphqlApi.fromGraphqlApiAttributes(stack, 'importedApi', { - graphqlApiId: api.apiId, - graphqlApiArn: api.arn, + describe('adding elasticsearch data source from imported api', () => { + test('imported api can add ElasticsearchDataSource from id', () => { + // WHEN + const importedApi = appsync.GraphqlApi.fromGraphqlApiAttributes(stack, 'importedApi', { + graphqlApiId: api.apiId, + }); + importedApi.addElasticsearchDataSource('ds', domain); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'AMAZON_ELASTICSEARCH', + ApiId: { 'Fn::GetAtt': ['baseApiCDA4D43A', 'ApiId'] }, + }); }); - importedApi.addElasticsearchDataSource('ds', domain); - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { - Type: 'AMAZON_ELASTICSEARCH', - ApiId: { 'Fn::GetAtt': ['baseApiCDA4D43A', 'ApiId'] }, + test('imported api can add ElasticsearchDataSource from attributes', () => { + // WHEN + const importedApi = appsync.GraphqlApi.fromGraphqlApiAttributes(stack, 'importedApi', { + graphqlApiId: api.apiId, + graphqlApiArn: api.arn, + }); + importedApi.addElasticsearchDataSource('ds', domain); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'AMAZON_ELASTICSEARCH', + ApiId: { 'Fn::GetAtt': ['baseApiCDA4D43A', 'ApiId'] }, + }); }); }); }); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-opensearch.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-opensearch.test.ts new file mode 100644 index 0000000000000..92cf5d26c0abf --- /dev/null +++ b/packages/@aws-cdk/aws-appsync/test/appsync-opensearch.test.ts @@ -0,0 +1,150 @@ +import * as path from 'path'; +import { Template } from '@aws-cdk/assertions'; +import * as opensearch from '@aws-cdk/aws-opensearchservice'; +import * as cdk from '@aws-cdk/core'; +import * as appsync from '../lib'; + +// GLOBAL GIVEN +let stack: cdk.Stack; +let api: appsync.GraphqlApi; +let domain: opensearch.Domain; +beforeEach(() => { + stack = new cdk.Stack(); + api = new appsync.GraphqlApi(stack, 'baseApi', { + name: 'api', + schema: appsync.Schema.fromAsset(path.join(__dirname, 'appsync.test.graphql')), + }); + domain = new opensearch.Domain(stack, 'OsDomain', { + version: opensearch.EngineVersion.OPENSEARCH_1_1, + }); +}); + +describe('OpenSearch Data Source Configuration', () => { + test('OpenSearch configure properly', () => { + // WHEN + api.addOpenSearchDataSource('ds', domain); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Version: '2012-10-17', + Statement: [{ + Action: [ + 'es:ESHttpGet', + 'es:ESHttpHead', + 'es:ESHttpDelete', + 'es:ESHttpPost', + 'es:ESHttpPut', + 'es:ESHttpPatch', + ], + Effect: 'Allow', + Resource: [{ + 'Fn::GetAtt': ['OsDomain5D09FC6A', 'Arn'], + }, + { + 'Fn::Join': ['', [{ + 'Fn::GetAtt': ['OsDomain5D09FC6A', 'Arn'], + }, '/*']], + }], + }], + }, + }); + }); + + test('OpenSearch configuration contains fully qualified url', () => { + // WHEN + api.addOpenSearchDataSource('ds', domain); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + OpenSearchServiceConfig: { + Endpoint: { + 'Fn::Join': ['', ['https://', { + 'Fn::GetAtt': ['OsDomain5D09FC6A', 'DomainEndpoint'], + }]], + }, + }, + }); + }); + + test('default configuration produces name identical to the id', () => { + // WHEN + api.addOpenSearchDataSource('ds', domain); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'AMAZON_OPENSEARCH_SERVICE', + Name: 'ds', + }); + }); + + test('appsync configures name correctly', () => { + // WHEN + api.addOpenSearchDataSource('ds', domain, { + name: 'custom', + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'AMAZON_OPENSEARCH_SERVICE', + Name: 'custom', + }); + }); + + test('appsync configures name and description correctly', () => { + // WHEN + api.addOpenSearchDataSource('ds', domain, { + name: 'custom', + description: 'custom description', + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'AMAZON_OPENSEARCH_SERVICE', + Name: 'custom', + Description: 'custom description', + }); + }); + + test('appsync errors when creating multiple openSearch data sources with no configuration', () => { + // WHEN + const when = () => { + api.addOpenSearchDataSource('ds', domain); + api.addOpenSearchDataSource('ds', domain); + }; + + // THEN + expect(when).toThrow('There is already a Construct with name \'ds\' in GraphqlApi [baseApi]'); + }); +}); + +describe('adding openSearch data source from imported api', () => { + test('imported api can add OpenSearchDataSource from id', () => { + // WHEN + const importedApi = appsync.GraphqlApi.fromGraphqlApiAttributes(stack, 'importedApi', { + graphqlApiId: api.apiId, + }); + importedApi.addOpenSearchDataSource('ds', domain); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'AMAZON_OPENSEARCH_SERVICE', + ApiId: { 'Fn::GetAtt': ['baseApiCDA4D43A', 'ApiId'] }, + }); + }); + + test('imported api can add OpenSearchDataSource from attributes', () => { + // WHEN + const importedApi = appsync.GraphqlApi.fromGraphqlApiAttributes(stack, 'importedApi', { + graphqlApiId: api.apiId, + graphqlApiArn: api.arn, + }); + importedApi.addOpenSearchDataSource('ds', domain); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', { + Type: 'AMAZON_OPENSEARCH_SERVICE', + ApiId: { 'Fn::GetAtt': ['baseApiCDA4D43A', 'ApiId'] }, + }); + }); +}); diff --git a/packages/@aws-cdk/aws-appsync/test/appsync.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync.test.ts index 9c75c0c7a28c9..350fbff6229db 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync.test.ts @@ -1,5 +1,6 @@ import * as path from 'path'; import { Template } from '@aws-cdk/assertions'; +import { Certificate } from '@aws-cdk/aws-certificatemanager'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import * as appsync from '../lib'; @@ -155,3 +156,38 @@ test('appsync GraphqlApi should not use custom role for CW Logs when not specifi }, }); }); + +test('appsync GraphqlApi should be configured with custom domain when specified', () => { + const domainName = 'api.example.com'; + // GIVEN + const certificate = new Certificate(stack, 'AcmCertificate', { + domainName, + }); + + // WHEN + new appsync.GraphqlApi(stack, 'api-custom-cw-logs-role', { + authorizationConfig: {}, + name: 'apiWithCustomRole', + schema: appsync.Schema.fromAsset(path.join(__dirname, 'appsync.test.graphql')), + domainName: { + domainName, + certificate, + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DomainNameApiAssociation', { + ApiId: { + 'Fn::GetAtt': [ + 'apicustomcwlogsrole508EAC74', + 'ApiId', + ], + }, + DomainName: domainName, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DomainName', { + CertificateArn: { Ref: 'AcmCertificate49D3B5AF' }, + DomainName: domainName, + }); +}); diff --git a/packages/@aws-cdk/aws-appsync/test/integ.api-import.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.api-import.expected.json index e4b54f04116fc..496d000a2d3b3 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.api-import.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.api-import.expected.json @@ -76,16 +76,17 @@ { "Action": [ "dynamodb:BatchGetItem", + "dynamodb:BatchWriteItem", + "dynamodb:ConditionCheckItem", + "dynamodb:DeleteItem", + "dynamodb:DescribeTable", + "dynamodb:GetItem", "dynamodb:GetRecords", "dynamodb:GetShardIterator", + "dynamodb:PutItem", "dynamodb:Query", - "dynamodb:GetItem", "dynamodb:Scan", - "dynamodb:ConditionCheckItem", - "dynamodb:BatchWriteItem", - "dynamodb:PutItem", - "dynamodb:UpdateItem", - "dynamodb:DeleteItem" + "dynamodb:UpdateItem" ], "Effect": "Allow", "Resource": [ diff --git a/packages/@aws-cdk/aws-appsync/test/integ.appsync-lambda.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.appsync-lambda.expected.json index f4bd20a97d90e..c3c4e3e186912 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.appsync-lambda.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.appsync-lambda.expected.json @@ -58,12 +58,28 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "funcC3A0C2E2", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "funcC3A0C2E2", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "funcC3A0C2E2", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.expected.json index ed0307de0e72f..5a00755f91307 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.expected.json @@ -59,16 +59,17 @@ { "Action": [ "dynamodb:BatchGetItem", + "dynamodb:BatchWriteItem", + "dynamodb:ConditionCheckItem", + "dynamodb:DeleteItem", + "dynamodb:DescribeTable", + "dynamodb:GetItem", "dynamodb:GetRecords", "dynamodb:GetShardIterator", + "dynamodb:PutItem", "dynamodb:Query", - "dynamodb:GetItem", "dynamodb:Scan", - "dynamodb:ConditionCheckItem", - "dynamodb:BatchWriteItem", - "dynamodb:PutItem", - "dynamodb:UpdateItem", - "dynamodb:DeleteItem" + "dynamodb:UpdateItem" ], "Effect": "Allow", "Resource": [ diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql-elasticsearch.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.graphql-elasticsearch.expected.json index 22e64957700e9..f425d5be9a287 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql-elasticsearch.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql-elasticsearch.expected.json @@ -105,12 +105,12 @@ "Statement": [ { "Action": [ + "es:ESHttpDelete", "es:ESHttpGet", "es:ESHttpHead", - "es:ESHttpDelete", + "es:ESHttpPatch", "es:ESHttpPost", - "es:ESHttpPut", - "es:ESHttpPatch" + "es:ESHttpPut" ], "Effect": "Allow", "Resource": [ diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json index 374a89dc33d14..2077eae3e3308 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json @@ -90,16 +90,17 @@ { "Action": [ "dynamodb:BatchGetItem", + "dynamodb:BatchWriteItem", + "dynamodb:ConditionCheckItem", + "dynamodb:DeleteItem", + "dynamodb:DescribeTable", + "dynamodb:GetItem", "dynamodb:GetRecords", "dynamodb:GetShardIterator", + "dynamodb:PutItem", "dynamodb:Query", - "dynamodb:GetItem", "dynamodb:Scan", - "dynamodb:ConditionCheckItem", - "dynamodb:BatchWriteItem", - "dynamodb:PutItem", - "dynamodb:UpdateItem", - "dynamodb:DeleteItem" + "dynamodb:UpdateItem" ], "Effect": "Allow", "Resource": [ @@ -291,64 +292,62 @@ { "Action": "appsync:GraphQL", "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":appsync:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":apis/", - { - "Fn::GetAtt": [ - "ApiF70053CD", - "ApiId" - ] - }, - "/types/test/*" + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":appsync:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":apis/", + { + "Fn::GetAtt": [ + "ApiF70053CD", + "ApiId" + ] + }, + "/types/Mutation/fields/addTest" + ] ] - ] - } - }, - { - "Action": "appsync:GraphQL", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":appsync:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":apis/", - { - "Fn::GetAtt": [ - "ApiF70053CD", - "ApiId" - ] - }, - "/types/Mutation/fields/addTest" + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":appsync:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":apis/", + { + "Fn::GetAtt": [ + "ApiF70053CD", + "ApiId" + ] + }, + "/types/test/*" + ] ] - ] - } + } + ] } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql-opensearch.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.graphql-opensearch.expected.json new file mode 100644 index 0000000000000..1977b2d346896 --- /dev/null +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql-opensearch.expected.json @@ -0,0 +1,210 @@ +{ + "Resources": { + "User00B015A1": { + "Type": "AWS::IAM::User" + }, + "Domain66AC69E0": { + "Type": "AWS::OpenSearchService::Domain", + "Properties": { + "AdvancedSecurityOptions": { + "Enabled": true, + "InternalUserDatabaseEnabled": false, + "MasterUserOptions": { + "MasterUserARN": { + "Fn::GetAtt": [ + "User00B015A1", + "Arn" + ] + } + } + }, + "ClusterConfig": { + "DedicatedMasterEnabled": false, + "InstanceCount": 1, + "InstanceType": "r5.large.search", + "ZoneAwarenessEnabled": false + }, + "CognitoOptions": { + "Enabled": false + }, + "DomainEndpointOptions": { + "EnforceHTTPS": true, + "TLSSecurityPolicy": "Policy-Min-TLS-1-0-2019-07" + }, + "EBSOptions": { + "EBSEnabled": true, + "VolumeSize": 10, + "VolumeType": "gp2" + }, + "EncryptionAtRestOptions": { + "Enabled": true + }, + "EngineVersion": "OpenSearch_1.1", + "LogPublishingOptions": {}, + "NodeToNodeEncryptionOptions": { + "Enabled": true + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "apiC8550315": { + "Type": "AWS::AppSync::GraphQLApi", + "Properties": { + "AuthenticationType": "API_KEY", + "Name": "api" + } + }, + "apiSchema0EA92056": { + "Type": "AWS::AppSync::GraphQLSchema", + "Properties": { + "ApiId": { + "Fn::GetAtt": [ + "apiC8550315", + "ApiId" + ] + }, + "Definition": "type test {\n version: String!\n}\ntype Query {\n getTests: [test]!\n}\ntype Mutation {\n addTest(version: String!): test\n}\n" + } + }, + "apiDefaultApiKey6AB8D7C4": { + "Type": "AWS::AppSync::ApiKey", + "Properties": { + "ApiId": { + "Fn::GetAtt": [ + "apiC8550315", + "ApiId" + ] + } + }, + "DependsOn": [ + "apiSchema0EA92056" + ] + }, + "apidsServiceRoleBDB08107": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "appsync.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "apidsServiceRoleDefaultPolicy5634EFD0": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "es:ESHttpDelete", + "es:ESHttpGet", + "es:ESHttpHead", + "es:ESHttpPatch", + "es:ESHttpPost", + "es:ESHttpPut" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "Domain66AC69E0", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Domain66AC69E0", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "apidsServiceRoleDefaultPolicy5634EFD0", + "Roles": [ + { + "Ref": "apidsServiceRoleBDB08107" + } + ] + } + }, + "apids4328272F": { + "Type": "AWS::AppSync::DataSource", + "Properties": { + "ApiId": { + "Fn::GetAtt": [ + "apiC8550315", + "ApiId" + ] + }, + "Name": "ds", + "Type": "AMAZON_OPENSEARCH_SERVICE", + "OpenSearchServiceConfig": { + "AwsRegion": { + "Ref": "AWS::Region" + }, + "Endpoint": { + "Fn::Join": [ + "", + [ + "https://", + { + "Fn::GetAtt": [ + "Domain66AC69E0", + "DomainEndpoint" + ] + } + ] + ] + } + }, + "ServiceRoleArn": { + "Fn::GetAtt": [ + "apidsServiceRoleBDB08107", + "Arn" + ] + } + } + }, + "apidsQuerygetTestsResolver5C6FBB59": { + "Type": "AWS::AppSync::Resolver", + "Properties": { + "ApiId": { + "Fn::GetAtt": [ + "apiC8550315", + "ApiId" + ] + }, + "FieldName": "getTests", + "TypeName": "Query", + "DataSourceName": "ds", + "Kind": "UNIT", + "RequestMappingTemplate": "{\"version\":\"2017-02-28\",\"operation\":\"GET\",\"path\":\"/id/post/_search\",\"params\":{\"headers\":{},\"queryString\":{},\"body\":{\"from\":0,\"size\":50}}}", + "ResponseMappingTemplate": "{\"version\":\"2017-02-28\",\"operation\":\"GET\",\"path\":\"/id/post/_search\",\"params\":{\"headers\":{},\"queryString\":{},\"body\":{\"from\":0,\"size\":50,\"query\":{\"term\":{\"author\":\"$util.toJson($context.arguments.author)\"}}}}}" + }, + "DependsOn": [ + "apids4328272F", + "apiSchema0EA92056" + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql-opensearch.ts b/packages/@aws-cdk/aws-appsync/test/integ.graphql-opensearch.ts new file mode 100644 index 0000000000000..e055bfe15c83b --- /dev/null +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql-opensearch.ts @@ -0,0 +1,66 @@ +import * as path from 'path'; +import { User } from '@aws-cdk/aws-iam'; +import * as opensearch from '@aws-cdk/aws-opensearchservice'; +import * as cdk from '@aws-cdk/core'; +import * as appsync from '../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'appsync-opensearch'); +const user = new User(stack, 'User'); +const domain = new opensearch.Domain(stack, 'Domain', { + version: opensearch.EngineVersion.OPENSEARCH_1_1, + removalPolicy: cdk.RemovalPolicy.DESTROY, + fineGrainedAccessControl: { + masterUserArn: user.userArn, + }, + encryptionAtRest: { + enabled: true, + }, + nodeToNodeEncryption: true, + enforceHttps: true, +}); + +const api = new appsync.GraphqlApi(stack, 'api', { + name: 'api', + schema: appsync.Schema.fromAsset(path.join(__dirname, 'appsync.test.graphql')), +}); + +const ds = api.addOpenSearchDataSource('ds', domain); + +ds.createResolver({ + typeName: 'Query', + fieldName: 'getTests', + requestMappingTemplate: appsync.MappingTemplate.fromString(JSON.stringify({ + version: '2017-02-28', + operation: 'GET', + path: '/id/post/_search', + params: { + headers: {}, + queryString: {}, + body: { + from: 0, + size: 50, + }, + }, + })), + responseMappingTemplate: appsync.MappingTemplate.fromString(JSON.stringify({ + version: '2017-02-28', + operation: 'GET', + path: '/id/post/_search', + params: { + headers: {}, + queryString: {}, + body: { + from: 0, + size: 50, + query: { + term: { + author: '$util.toJson($context.arguments.author)', + }, + }, + }, + }, + })), +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql-schema.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.graphql-schema.expected.json index a6e5ff5764331..37f1d635fd1a0 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql-schema.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql-schema.expected.json @@ -58,16 +58,17 @@ { "Action": [ "dynamodb:BatchGetItem", + "dynamodb:BatchWriteItem", + "dynamodb:ConditionCheckItem", + "dynamodb:DeleteItem", + "dynamodb:DescribeTable", + "dynamodb:GetItem", "dynamodb:GetRecords", "dynamodb:GetShardIterator", + "dynamodb:PutItem", "dynamodb:Query", - "dynamodb:GetItem", "dynamodb:Scan", - "dynamodb:ConditionCheckItem", - "dynamodb:BatchWriteItem", - "dynamodb:PutItem", - "dynamodb:UpdateItem", - "dynamodb:DeleteItem" + "dynamodb:UpdateItem" ], "Effect": "Allow", "Resource": [ diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json index e14c0af7a5450..ac78e134f2fd7 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json @@ -138,16 +138,17 @@ { "Action": [ "dynamodb:BatchGetItem", + "dynamodb:BatchWriteItem", + "dynamodb:ConditionCheckItem", + "dynamodb:DeleteItem", + "dynamodb:DescribeTable", + "dynamodb:GetItem", "dynamodb:GetRecords", "dynamodb:GetShardIterator", + "dynamodb:PutItem", "dynamodb:Query", - "dynamodb:GetItem", "dynamodb:Scan", - "dynamodb:ConditionCheckItem", - "dynamodb:BatchWriteItem", - "dynamodb:PutItem", - "dynamodb:UpdateItem", - "dynamodb:DeleteItem" + "dynamodb:UpdateItem" ], "Effect": "Allow", "Resource": [ @@ -351,16 +352,17 @@ { "Action": [ "dynamodb:BatchGetItem", + "dynamodb:BatchWriteItem", + "dynamodb:ConditionCheckItem", + "dynamodb:DeleteItem", + "dynamodb:DescribeTable", + "dynamodb:GetItem", "dynamodb:GetRecords", "dynamodb:GetShardIterator", + "dynamodb:PutItem", "dynamodb:Query", - "dynamodb:GetItem", "dynamodb:Scan", - "dynamodb:ConditionCheckItem", - "dynamodb:BatchWriteItem", - "dynamodb:PutItem", - "dynamodb:UpdateItem", - "dynamodb:DeleteItem" + "dynamodb:UpdateItem" ], "Effect": "Allow", "Resource": [ @@ -743,16 +745,17 @@ { "Action": [ "dynamodb:BatchGetItem", + "dynamodb:BatchWriteItem", + "dynamodb:ConditionCheckItem", + "dynamodb:DeleteItem", + "dynamodb:DescribeTable", + "dynamodb:GetItem", "dynamodb:GetRecords", "dynamodb:GetShardIterator", + "dynamodb:PutItem", "dynamodb:Query", - "dynamodb:GetItem", "dynamodb:Scan", - "dynamodb:ConditionCheckItem", - "dynamodb:BatchWriteItem", - "dynamodb:PutItem", - "dynamodb:UpdateItem", - "dynamodb:DeleteItem" + "dynamodb:UpdateItem" ], "Effect": "Allow", "Resource": [ diff --git a/packages/@aws-cdk/aws-aps/package.json b/packages/@aws-cdk/aws-aps/package.json index a63226c0a8148..7fbef265f7a3b 100644 --- a/packages/@aws-cdk/aws-aps/package.json +++ b/packages/@aws-cdk/aws-aps/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-athena/package.json b/packages/@aws-cdk/aws-athena/package.json index 343d9eb7f34eb..134a9cdbe2bdf 100644 --- a/packages/@aws-cdk/aws-athena/package.json +++ b/packages/@aws-cdk/aws-athena/package.json @@ -84,8 +84,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-auditmanager/package.json b/packages/@aws-cdk/aws-auditmanager/package.json index a9a3738209a4d..16fe6cc71fd69 100644 --- a/packages/@aws-cdk/aws-auditmanager/package.json +++ b/packages/@aws-cdk/aws-auditmanager/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-autoscaling-common/package.json b/packages/@aws-cdk/aws-autoscaling-common/package.json index 64b399fd336ba..e8107108376f5 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/package.json +++ b/packages/@aws-cdk/aws-autoscaling-common/package.json @@ -74,9 +74,9 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "fast-check": "^2.21.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "fast-check": "^2.23.2", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json index eb1dab85bfe70..164d2d933695c 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json @@ -77,8 +77,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", diff --git a/packages/@aws-cdk/aws-autoscaling/README.md b/packages/@aws-cdk/aws-autoscaling/README.md index a939ddac4a182..d889ce254e437 100644 --- a/packages/@aws-cdk/aws-autoscaling/README.md +++ b/packages/@aws-cdk/aws-autoscaling/README.md @@ -488,6 +488,27 @@ const aspect = new autoscaling.AutoScalingGroupRequireImdsv2Aspect(); Aspects.of(this).add(aspect); ``` +## Warm Pool + +Auto Scaling offers [a warm pool](https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-warm-pools.html) which gives an ability to decrease latency for applications that have exceptionally long boot times. You can create a warm pool with default parameters as below: + +```ts +declare const autoScalingGroup: autoscaling.AutoScalingGroup; + +autoScalingGroup.addWarmPool(); +``` + +You can also customize a warm pool by configuring parameters: + +```ts +declare const autoScalingGroup: autoscaling.AutoScalingGroup; + +autoScalingGroup.addWarmPool({ + minSize: 1, + reuseOnScaleIn: true, +}); +``` + ## Future work * [ ] CloudWatch Events (impossible to add currently as the AutoScalingGroup ARN is diff --git a/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts b/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts index e2ec8ed39f3b6..b4960ea780593 100644 --- a/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts +++ b/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts @@ -23,6 +23,7 @@ import { BasicStepScalingPolicyProps, StepScalingPolicy } from './step-scaling-p import { BaseTargetTrackingProps, PredefinedMetric, TargetTrackingScalingPolicy } from './target-tracking-scaling-policy'; import { TerminationPolicy } from './termination-policy'; import { BlockDevice, BlockDeviceVolume, EbsDeviceVolumeType } from './volume'; +import { WarmPool, WarmPoolOptions } from './warm-pool'; /** * Name tag constant @@ -744,6 +745,16 @@ abstract class AutoScalingGroupBase extends Resource implements IAutoScalingGrou }); } + /** + * Add a pool of pre-initialized EC2 instances that sits alongside an Auto Scaling group + */ + public addWarmPool(options?: WarmPoolOptions): WarmPool { + return new WarmPool(this, 'WarmPool', { + autoScalingGroup: this, + ...options, + }); + } + /** * Scale out or in based on time */ @@ -1630,6 +1641,11 @@ export interface IAutoScalingGroup extends IResource, iam.IGrantable { */ addLifecycleHook(id: string, props: BasicLifecycleHookProps): LifecycleHook; + /** + * Add a pool of pre-initialized EC2 instances that sits alongside an Auto Scaling group + */ + addWarmPool(options?: WarmPoolOptions): WarmPool; + /** * Scale out or in based on time */ diff --git a/packages/@aws-cdk/aws-autoscaling/lib/index.ts b/packages/@aws-cdk/aws-autoscaling/lib/index.ts index 8cfcb36d42497..98d1bf94e7933 100644 --- a/packages/@aws-cdk/aws-autoscaling/lib/index.ts +++ b/packages/@aws-cdk/aws-autoscaling/lib/index.ts @@ -9,6 +9,7 @@ export * from './step-scaling-policy'; export * from './target-tracking-scaling-policy'; export * from './termination-policy'; export * from './volume'; +export * from './warm-pool'; // AWS::AutoScaling CloudFormation Resources: export * from './autoscaling.generated'; diff --git a/packages/@aws-cdk/aws-autoscaling/lib/schedule.ts b/packages/@aws-cdk/aws-autoscaling/lib/schedule.ts index 3525d9b6dee0e..48b6553639319 100644 --- a/packages/@aws-cdk/aws-autoscaling/lib/schedule.ts +++ b/packages/@aws-cdk/aws-autoscaling/lib/schedule.ts @@ -1,3 +1,6 @@ +import { Annotations } from '@aws-cdk/core'; +import { Construct } from 'constructs'; + /** * Schedule for scheduled scaling actions */ @@ -26,7 +29,15 @@ export abstract class Schedule { const day = fallback(options.day, '*'); const weekDay = fallback(options.weekDay, '*'); - return new LiteralSchedule(`${minute} ${hour} ${day} ${month} ${weekDay}`); + return new class extends Schedule { + public readonly expressionString: string = `${minute} ${hour} ${day} ${month} ${weekDay}`; + public _bind(scope: Construct) { + if (!options.minute) { + Annotations.of(scope).addWarning('cron: If you don\'t pass \'minute\', by default the event runs every minute. Pass \'minute: \'*\'\' if that\'s what you intend, or \'minute: 0\' to run once per hour instead.'); + } + return new LiteralSchedule(this.expressionString); + } + }; } /** @@ -34,8 +45,13 @@ export abstract class Schedule { */ public abstract readonly expressionString: string; - protected constructor() { - } + protected constructor() {} + + /** + * + * @internal + */ + public abstract _bind(scope: Construct): void; } /** @@ -87,6 +103,8 @@ class LiteralSchedule extends Schedule { constructor(public readonly expressionString: string) { super(); } + + public _bind(): void {} } function fallback(x: T | undefined, def: T): T { diff --git a/packages/@aws-cdk/aws-autoscaling/lib/scheduled-action.ts b/packages/@aws-cdk/aws-autoscaling/lib/scheduled-action.ts index fa5d431bcf47b..83aae38fc281c 100644 --- a/packages/@aws-cdk/aws-autoscaling/lib/scheduled-action.ts +++ b/packages/@aws-cdk/aws-autoscaling/lib/scheduled-action.ts @@ -97,6 +97,9 @@ export class ScheduledAction extends Resource { throw new Error('At least one of minCapacity, maxCapacity, or desiredCapacity is required'); } + // add a warning on synth when minute is not defined in a cron schedule + props.schedule._bind(this); + new CfnScheduledAction(this, 'Resource', { autoScalingGroupName: props.autoScalingGroup.autoScalingGroupName, startTime: formatISO(props.startTime), diff --git a/packages/@aws-cdk/aws-autoscaling/lib/warm-pool.ts b/packages/@aws-cdk/aws-autoscaling/lib/warm-pool.ts new file mode 100644 index 0000000000000..c08b0fa45c38c --- /dev/null +++ b/packages/@aws-cdk/aws-autoscaling/lib/warm-pool.ts @@ -0,0 +1,104 @@ +import { Lazy, Names, Resource } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { IAutoScalingGroup } from './auto-scaling-group'; +import { CfnWarmPool } from './autoscaling.generated'; + +/** + * Options for a warm pool + */ +export interface WarmPoolOptions { + /** + * Indicates whether instances in the Auto Scaling group can be returned to the warm pool on scale in. + * + * If the value is not specified, instances in the Auto Scaling group will be terminated + * when the group scales in. + * + * @default false + */ + readonly reuseOnScaleIn?: boolean; + + /** + * The maximum number of instances that are allowed to be in the warm pool + * or in any state except Terminated for the Auto Scaling group. + * + * If the value is not specified, Amazon EC2 Auto Scaling launches and maintains + * the difference between the group's maximum capacity and its desired capacity. + * + * @default - max size of the Auto Scaling group + */ + readonly maxGroupPreparedCapacity?: number; + /** + * The minimum number of instances to maintain in the warm pool. + * + * @default 0 + */ + readonly minSize?: number; + /** + * The instance state to transition to after the lifecycle actions are complete. + * + * @default PoolState.STOPPED + */ + readonly poolState?: PoolState; +} + +/** + * Properties for a warm pool + */ +export interface WarmPoolProps extends WarmPoolOptions { + /** + * The Auto Scaling group to add the warm pool to. + */ + readonly autoScalingGroup: IAutoScalingGroup; +} + +/** + * Define a warm pool + */ +export class WarmPool extends Resource { + constructor(scope: Construct, id: string, props: WarmPoolProps) { + super(scope, id, { + physicalName: Lazy.string({ produce: () => Names.uniqueId(this) }), + }); + + if (props.maxGroupPreparedCapacity && props.maxGroupPreparedCapacity < -1) { + throw new Error('\'maxGroupPreparedCapacity\' parameter should be greater than or equal to -1'); + } + + if (props.minSize && props.minSize < 0) { + throw new Error('\'minSize\' parameter should be greater than or equal to 0'); + } + + new CfnWarmPool(this, 'Resource', { + autoScalingGroupName: props.autoScalingGroup.autoScalingGroupName, + instanceReusePolicy: props.reuseOnScaleIn !== undefined ? { + reuseOnScaleIn: props.reuseOnScaleIn, + } : undefined, + maxGroupPreparedCapacity: props.maxGroupPreparedCapacity, + minSize: props.minSize, + poolState: props.poolState, + }); + } +} + +/** + * The instance state in the warm pool + */ +export enum PoolState { + /** + * Hibernated + * + * To use this state, prerequisites must be in place. + * @see https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/hibernating-prerequisites.html + */ + HIBERNATED = 'Hibernated', + + /** + * Running + */ + RUNNING = 'Running', + + /** + * Stopped + */ + STOPPED = 'Stopped', +} diff --git a/packages/@aws-cdk/aws-autoscaling/package.json b/packages/@aws-cdk/aws-autoscaling/package.json index cc9037521f731..46b688d3ae6ec 100644 --- a/packages/@aws-cdk/aws-autoscaling/package.json +++ b/packages/@aws-cdk/aws-autoscaling/package.json @@ -86,8 +86,8 @@ "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-autoscaling-common": "0.0.0", @@ -122,6 +122,7 @@ "export:@aws-cdk/aws-autoscaling.IAutoScalingGroup", "props-physical-name:@aws-cdk/aws-autoscaling.AutoScalingGroupProps", "props-physical-name:@aws-cdk/aws-autoscaling.ScheduledActionProps", + "props-physical-name:@aws-cdk/aws-autoscaling.WarmPoolProps", "props-default-doc:@aws-cdk/aws-autoscaling.EbsDeviceOptionsBase.iops", "docs-public-apis:@aws-cdk/aws-autoscaling.ScalingProcess.ADD_TO_LOAD_BALANCER", "docs-public-apis:@aws-cdk/aws-autoscaling.ScalingProcess.SCHEDULED_ACTIONS", diff --git a/packages/@aws-cdk/aws-autoscaling/test/aspects/require-imdsv2-aspect.test.ts b/packages/@aws-cdk/aws-autoscaling/test/aspects/require-imdsv2-aspect.test.ts index 5fa4210d2a6f5..51c3cf01d165e 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/aspects/require-imdsv2-aspect.test.ts +++ b/packages/@aws-cdk/aws-autoscaling/test/aspects/require-imdsv2-aspect.test.ts @@ -1,4 +1,4 @@ -import { Match, Template } from '@aws-cdk/assertions'; +import { Annotations, Match, Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import { @@ -39,11 +39,7 @@ describe('AutoScalingGroupRequireImdsv2Aspect', () => { }, })); - expect(asg.node.metadataEntry).toContainEqual({ - data: expect.stringContaining('CfnLaunchConfiguration.MetadataOptions field is a CDK token.'), - type: 'aws:cdk:warning', - trace: undefined, - }); + Annotations.fromStack(stack).hasWarning('/Stack/AutoScalingGroup', Match.stringLikeRegexp('.*CfnLaunchConfiguration.MetadataOptions field is a CDK token.')); }); test('requires IMDSv2', () => { diff --git a/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts b/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts index 945339ca86f5b..d1234b3aa29cd 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts +++ b/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts @@ -1,10 +1,9 @@ -import { Match, Template } from '@aws-cdk/assertions'; +import { Annotations, Match, Template } from '@aws-cdk/assertions'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as sns from '@aws-cdk/aws-sns'; import { testDeprecated } from '@aws-cdk/cdk-build-tools'; -import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import * as cdk from '@aws-cdk/core'; import * as autoscaling from '../lib'; @@ -875,7 +874,7 @@ describe('auto scaling group', () => { const stack = new cdk.Stack(); const vpc = mockVpc(stack); - const asg = new autoscaling.AutoScalingGroup(stack, 'MyStack', { + new autoscaling.AutoScalingGroup(stack, 'MyStack', { instanceType: ec2.InstanceType.of(ec2.InstanceClass.M4, ec2.InstanceSize.MICRO), machineImage: new ec2.AmazonLinuxImage(), vpc, @@ -890,8 +889,7 @@ describe('auto scaling group', () => { }); // THEN - expect(asg.node.metadataEntry[0].type).toEqual(cxschema.ArtifactMetadataEntryType.WARN); - expect(asg.node.metadataEntry[0].data).toEqual('iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); + Annotations.fromStack(stack).hasWarning('/Default/MyStack', 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); }); test('warning if iops and volumeType !== IO1', () => { @@ -899,7 +897,7 @@ describe('auto scaling group', () => { const stack = new cdk.Stack(); const vpc = mockVpc(stack); - const asg = new autoscaling.AutoScalingGroup(stack, 'MyStack', { + new autoscaling.AutoScalingGroup(stack, 'MyStack', { instanceType: ec2.InstanceType.of(ec2.InstanceClass.M4, ec2.InstanceSize.MICRO), machineImage: new ec2.AmazonLinuxImage(), vpc, @@ -915,8 +913,7 @@ describe('auto scaling group', () => { }); // THEN - expect(asg.node.metadataEntry[0].type).toEqual(cxschema.ArtifactMetadataEntryType.WARN); - expect(asg.node.metadataEntry[0].data).toEqual('iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); + Annotations.fromStack(stack).hasWarning('/Default/MyStack', 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); }); test('step scaling on metric', () => { diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.warm-pool.expected.json b/packages/@aws-cdk/aws-autoscaling/test/integ.warm-pool.expected.json new file mode 100644 index 0000000000000..67ee9bf5bebd7 --- /dev/null +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.warm-pool.expected.json @@ -0,0 +1,495 @@ +{ + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC" + } + ] + } + }, + "VPCPublicSubnet1SubnetB4246D30": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableAssociation0B0896DC": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "VPCPublicSubnet1DefaultRoute91CEF279": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet1EIP6AD938E8": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1NATGatewayE0556630": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet2Subnet74179F39": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTableAssociation5A808732": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "VPCPublicSubnet2DefaultRouteB7481BBA": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet2EIP4947BC00": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2NATGateway3C070193": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPrivateSubnet1Subnet8BCA10E0": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableBE8A6027": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableAssociation347902D1": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + } + } + }, + "VPCPrivateSubnet1DefaultRouteAE1D6490": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet1NATGatewayE0556630" + } + } + }, + "VPCPrivateSubnet2SubnetCFCDAA7A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTable0A19E10E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTableAssociation0C73D413": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + } + }, + "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet2NATGateway3C070193" + } + } + }, + "VPCIGWB7E252D3": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, + "FleetInstanceSecurityGroupA8C3D7AD": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-cdk-autoscaling-integ/Fleet/InstanceSecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/Fleet" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "FleetInstanceRoleA605DB82": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/Fleet" + } + ] + } + }, + "FleetInstanceProfileC6192A66": { + "Type": "AWS::IAM::InstanceProfile", + "Properties": { + "Roles": [ + { + "Ref": "FleetInstanceRoleA605DB82" + } + ] + } + }, + "FleetLaunchConfig59F79D36": { + "Type": "AWS::AutoScaling::LaunchConfiguration", + "Properties": { + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, + "InstanceType": "t2.micro", + "IamInstanceProfile": { + "Ref": "FleetInstanceProfileC6192A66" + }, + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "FleetInstanceSecurityGroupA8C3D7AD", + "GroupId" + ] + } + ], + "UserData": { + "Fn::Base64": "#!/bin/bash" + } + }, + "DependsOn": [ + "FleetInstanceRoleA605DB82" + ] + }, + "FleetASG3971DFE5": { + "Type": "AWS::AutoScaling::AutoScalingGroup", + "Properties": { + "MaxSize": "1", + "MinSize": "1", + "AutoScalingGroupName": "ASG", + "LaunchConfigurationName": { + "Ref": "FleetLaunchConfig59F79D36" + }, + "Tags": [ + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "aws-cdk-autoscaling-integ/Fleet" + } + ], + "VPCZoneIdentifier": [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + ] + }, + "UpdatePolicy": { + "AutoScalingScheduledAction": { + "IgnoreUnmodifiedGroupSizeProperties": true + } + } + }, + "FleetWarmPoolB57F9BC1": { + "Type": "AWS::AutoScaling::WarmPool", + "Properties": { + "AutoScalingGroupName": { + "Ref": "FleetASG3971DFE5" + } + } + } + }, + "Parameters": { + "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.warm-pool.ts b/packages/@aws-cdk/aws-autoscaling/test/integ.warm-pool.ts new file mode 100644 index 0000000000000..29c30f8401eb5 --- /dev/null +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.warm-pool.ts @@ -0,0 +1,27 @@ +#!/usr/bin/env node +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import * as autoscaling from '../lib'; + +/** + * Stack verification steps: + * + * -- aws autoscaling describe-warm-pool --auto-scaling-group-name ASG has 0 and 'Stopped' as MinSize and PoolState, respectively. + */ +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-cdk-autoscaling-integ'); + +const vpc = new ec2.Vpc(stack, 'VPC', { + maxAzs: 2, +}); + +const asg = new autoscaling.AutoScalingGroup(stack, 'Fleet', { + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.MICRO), + machineImage: new ec2.AmazonLinuxImage({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 }), + autoScalingGroupName: 'ASG', +}); + +asg.addWarmPool(); + +app.synth(); diff --git a/packages/@aws-cdk/aws-autoscaling/test/scheduled-action.test.ts b/packages/@aws-cdk/aws-autoscaling/test/scheduled-action.test.ts index 8579099ffd6cf..4c76ce3a11d08 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/scheduled-action.test.ts +++ b/packages/@aws-cdk/aws-autoscaling/test/scheduled-action.test.ts @@ -1,4 +1,4 @@ -import { Template } from '@aws-cdk/assertions'; +import { Annotations, Match, Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import { describeDeprecated } from '@aws-cdk/cdk-build-tools'; import * as cdk from '@aws-cdk/core'; @@ -120,6 +120,40 @@ describeDeprecated('scheduled action', () => { }, }); }); + + test('scheduled scaling shows warning when minute is not defined in cron', () => { + // GIVEN + const stack = new cdk.Stack(); + const asg = makeAutoScalingGroup(stack); + + // WHEN + asg.scaleOnSchedule('ScaleOutInTheMorning', { + schedule: autoscaling.Schedule.cron({ hour: '8' }), + minCapacity: 10, + }); + + // THEN + Annotations.fromStack(stack).hasWarning('/Default/ASG/ScheduledActionScaleOutInTheMorning', "cron: If you don't pass 'minute', by default the event runs every minute. Pass 'minute: '*'' if that's what you intend, or 'minute: 0' to run once per hour instead."); + }); + + test('scheduled scaling shows no warning when minute is * in cron', () => { + // GIVEN + const stack = new cdk.Stack(); + const asg = makeAutoScalingGroup(stack); + + // WHEN + asg.scaleOnSchedule('ScaleOutInTheMorning', { + schedule: autoscaling.Schedule.cron({ + hour: '8', + minute: '*', + }), + minCapacity: 10, + }); + + // THEN + const annotations = Annotations.fromStack(stack).findWarning('*', Match.anyValue()); + expect(annotations.length).toBe(0); + }); }); function makeAutoScalingGroup(scope: constructs.Construct) { diff --git a/packages/@aws-cdk/aws-autoscaling/test/warm-pool.test.ts b/packages/@aws-cdk/aws-autoscaling/test/warm-pool.test.ts new file mode 100644 index 0000000000000..041feac6ce30b --- /dev/null +++ b/packages/@aws-cdk/aws-autoscaling/test/warm-pool.test.ts @@ -0,0 +1,85 @@ +import { Template } from '@aws-cdk/assertions'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import * as autoscaling from '../lib'; + +describe('warm pool', () => { + test('we can add a warm pool without properties', () => { + // GIVEN + const stack = new cdk.Stack(); + const asg = newASG(stack); + + // WHEN + asg.addWarmPool(); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AutoScaling::WarmPool', { + AutoScalingGroupName: { + Ref: 'ASG46ED3070', + }, + }); + }); + + test('we can add a warm pool with all optional properties', () => { + // GIVEN + const stack = new cdk.Stack(); + const asg = newASG(stack); + + // WHEN + asg.addWarmPool({ + reuseOnScaleIn: true, + maxGroupPreparedCapacity: 5, + minSize: 2, + poolState: autoscaling.PoolState.HIBERNATED, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AutoScaling::WarmPool', { + AutoScalingGroupName: { + Ref: 'ASG46ED3070', + }, + InstanceReusePolicy: { + ReuseOnScaleIn: true, + }, + MaxGroupPreparedCapacity: 5, + MinSize: 2, + PoolState: 'Hibernated', + }); + }); +}); + +test('adding a warm pool with maxGroupPreparedCapacity smaller than -1 throws an error', () => { + // GIVEN + const stack = new cdk.Stack(); + const asg = newASG(stack); + + // WHEN + expect(() => { + asg.addWarmPool({ + maxGroupPreparedCapacity: -42, + }); + }).toThrow(/'maxGroupPreparedCapacity' parameter should be greater than or equal to -1/); +}); + +test('adding a warm pool with negative minSize throws an error', () => { + // GIVEN + const stack = new cdk.Stack(); + const asg = newASG(stack); + + // WHEN + expect(() => { + asg.addWarmPool({ + minSize: -1, + }); + }).toThrow(/'minSize' parameter should be greater than or equal to 0/); +}); + +function newASG(stack: cdk.Stack) { + const vpc = new ec2.Vpc(stack, 'VPC'); + + return new autoscaling.AutoScalingGroup(stack, 'ASG', { + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M4, ec2.InstanceSize.MICRO), + machineImage: new ec2.AmazonLinuxImage(), + }); +} diff --git a/packages/@aws-cdk/aws-autoscalingplans/package.json b/packages/@aws-cdk/aws-autoscalingplans/package.json index 6de1130ba56bb..26c9be8cc368f 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/package.json +++ b/packages/@aws-cdk/aws-autoscalingplans/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-backup/package.json b/packages/@aws-cdk/aws-backup/package.json index 5f0d0088cff3e..5462be05a3813 100644 --- a/packages/@aws-cdk/aws-backup/package.json +++ b/packages/@aws-cdk/aws-backup/package.json @@ -86,7 +86,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-dynamodb": "0.0.0", diff --git a/packages/@aws-cdk/aws-batch/package.json b/packages/@aws-cdk/aws-batch/package.json index 9065dc802171a..0c405c1a720f5 100644 --- a/packages/@aws-cdk/aws-batch/package.json +++ b/packages/@aws-cdk/aws-batch/package.json @@ -84,8 +84,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-batch/test/integ.batch.expected.json b/packages/@aws-cdk/aws-batch/test/integ.batch.expected.json index 7624200d45321..299b04e3f66db 100644 --- a/packages/@aws-cdk/aws-batch/test/integ.batch.expected.json +++ b/packages/@aws-cdk/aws-batch/test/integ.batch.expected.json @@ -1665,6 +1665,11 @@ }, "batchjobrepo4C508C51": { "Type": "AWS::ECR::Repository", + "Properties": { + "ImageScanningConfiguration": { + "ScanOnPush": false + } + }, "UpdateReplacePolicy": "Retain", "DeletionPolicy": "Retain" }, @@ -1725,8 +1730,14 @@ "Privileged": false, "ReadonlyRootFilesystem": false, "ResourceRequirements": [ - { "Type": "VCPU", "Value": "1" }, - { "Type": "MEMORY", "Value": "4" } + { + "Type": "VCPU", + "Value": "1" + }, + { + "Type": "MEMORY", + "Value": "4" + } ] }, "PlatformCapabilities": [ diff --git a/packages/@aws-cdk/aws-billingconductor/.eslintrc.js b/packages/@aws-cdk/aws-billingconductor/.eslintrc.js new file mode 100644 index 0000000000000..2658ee8727166 --- /dev/null +++ b/packages/@aws-cdk/aws-billingconductor/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-billingconductor/.gitignore b/packages/@aws-cdk/aws-billingconductor/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-billingconductor/.gitignore @@ -0,0 +1,19 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk +nyc.config.js +!.eslintrc.js +!jest.config.js +junit.xml diff --git a/packages/@aws-cdk/aws-billingconductor/.npmignore b/packages/@aws-cdk/aws-billingconductor/.npmignore new file mode 100644 index 0000000000000..f931fede67c44 --- /dev/null +++ b/packages/@aws-cdk/aws-billingconductor/.npmignore @@ -0,0 +1,29 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json + +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml +test/ +!*.lit.ts diff --git a/packages/@aws-cdk/aws-billingconductor/LICENSE b/packages/@aws-cdk/aws-billingconductor/LICENSE new file mode 100644 index 0000000000000..82ad00bb02d0b --- /dev/null +++ b/packages/@aws-cdk/aws-billingconductor/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/aws-billingconductor/NOTICE b/packages/@aws-cdk/aws-billingconductor/NOTICE new file mode 100644 index 0000000000000..1b7adbb891265 --- /dev/null +++ b/packages/@aws-cdk/aws-billingconductor/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-billingconductor/README.md b/packages/@aws-cdk/aws-billingconductor/README.md new file mode 100644 index 0000000000000..ef26512903834 --- /dev/null +++ b/packages/@aws-cdk/aws-billingconductor/README.md @@ -0,0 +1,31 @@ +# AWS::BillingConductor Construct Library + + +--- + +![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge) + +> All classes with the `Cfn` prefix in this module ([CFN Resources]) are always stable and safe to use. +> +> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib + +--- + + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as billingconductor from '@aws-cdk/aws-billingconductor'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::BillingConductor](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_BillingConductor.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-billingconductor/jest.config.js b/packages/@aws-cdk/aws-billingconductor/jest.config.js new file mode 100644 index 0000000000000..3a2fd93a1228a --- /dev/null +++ b/packages/@aws-cdk/aws-billingconductor/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-billingconductor/lib/index.ts b/packages/@aws-cdk/aws-billingconductor/lib/index.ts new file mode 100644 index 0000000000000..f8d5221b7fe42 --- /dev/null +++ b/packages/@aws-cdk/aws-billingconductor/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::BillingConductor CloudFormation Resources: +export * from './billingconductor.generated'; diff --git a/packages/@aws-cdk/aws-billingconductor/package.json b/packages/@aws-cdk/aws-billingconductor/package.json new file mode 100644 index 0000000000000..c3dafc9781d87 --- /dev/null +++ b/packages/@aws-cdk/aws-billingconductor/package.json @@ -0,0 +1,110 @@ +{ + "name": "@aws-cdk/aws-billingconductor", + "version": "0.0.0", + "description": "AWS::BillingConductor Construct Library", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.BillingConductor", + "packageId": "Amazon.CDK.AWS.BillingConductor", + "signAssembly": true, + "assemblyOriginatorKeyFile": "../../key.snk", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "java": { + "package": "software.amazon.awscdk.services.billingconductor", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "billingconductor" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-billingconductor", + "module": "aws_cdk.aws_billingconductor" + } + }, + "metadata": { + "jsii": { + "rosetta": { + "strict": true + } + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-billingconductor" + }, + "homepage": "https://github.com/aws/aws-cdk", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "cfn2ts": "cfn2ts", + "build+test": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "gen": "cfn2ts", + "rosetta:extract": "yarn --silent jsii-rosetta extract", + "build+extract": "yarn build && yarn rosetta:extract", + "build+test+extract": "yarn build+test && yarn rosetta:extract" + }, + "cdk-build": { + "cloudformation": "AWS::BillingConductor", + "jest": true, + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::BillingConductor", + "aws-billingconductor" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^27.4.1" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "experimental", + "maturity": "cfn-only", + "awscdkio": { + "announce": false + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-billingconductor/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-billingconductor/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..e208762bca03c --- /dev/null +++ b/packages/@aws-cdk/aws-billingconductor/rosetta/default.ts-fixture @@ -0,0 +1,8 @@ +import { Construct } from 'constructs'; +import { Stack } from '@aws-cdk/core'; + +class MyStack extends Stack { + constructor(scope: Construct, id: string) { + /// here + } +} diff --git a/packages/@aws-cdk/aws-billingconductor/test/billingconductor.test.ts b/packages/@aws-cdk/aws-billingconductor/test/billingconductor.test.ts new file mode 100644 index 0000000000000..465c7bdea0693 --- /dev/null +++ b/packages/@aws-cdk/aws-billingconductor/test/billingconductor.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assertions'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-budgets/package.json b/packages/@aws-cdk/aws-budgets/package.json index 7b0506935bdb3..3da84da4dcca0 100644 --- a/packages/@aws-cdk/aws-budgets/package.json +++ b/packages/@aws-cdk/aws-budgets/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-cassandra/package.json b/packages/@aws-cdk/aws-cassandra/package.json index 70e21b61df3e3..5325bf8bfe1bf 100644 --- a/packages/@aws-cdk/aws-cassandra/package.json +++ b/packages/@aws-cdk/aws-cassandra/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-ce/package.json b/packages/@aws-cdk/aws-ce/package.json index 6332fc8cffd14..ff751b12bb50d 100644 --- a/packages/@aws-cdk/aws-ce/package.json +++ b/packages/@aws-cdk/aws-ce/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json index 97a986405b3e5..75c89369c8199 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json @@ -29,7 +29,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.92", + "@types/aws-lambda": "^8.10.93", "@types/sinon": "^9.0.11", "@aws-cdk/cdk-build-tools": "0.0.0", "aws-sdk": "^2.596.0", @@ -40,10 +40,10 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^4.3.1", "eslint-plugin-standard": "^4.1.0", - "jest": "^27.4.7", + "jest": "^27.5.1", "lambda-tester": "^3.6.0", "sinon": "^9.2.4", "nock": "^13.2.4", - "ts-jest": "^27.1.3" + "ts-jest": "^27.1.4" } } diff --git a/packages/@aws-cdk/aws-certificatemanager/package.json b/packages/@aws-cdk/aws-certificatemanager/package.json index 86685caaf49ff..b2dcdedca636d 100644 --- a/packages/@aws-cdk/aws-certificatemanager/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-acmpca": "0.0.0", diff --git a/packages/@aws-cdk/aws-chatbot/package.json b/packages/@aws-cdk/aws-chatbot/package.json index 35a6887f3b5cb..259cf25fb4985 100644 --- a/packages/@aws-cdk/aws-chatbot/package.json +++ b/packages/@aws-cdk/aws-chatbot/package.json @@ -86,7 +86,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-chatbot/test/integ.chatbot-logretention.expected.json b/packages/@aws-cdk/aws-chatbot/test/integ.chatbot-logretention.expected.json index c6d56914ef5a3..894a8938f900f 100644 --- a/packages/@aws-cdk/aws-chatbot/test/integ.chatbot-logretention.expected.json +++ b/packages/@aws-cdk/aws-chatbot/test/integ.chatbot-logretention.expected.json @@ -63,8 +63,8 @@ ] }, "LogGroupName": "/aws/chatbot/test-channel", - "RetentionInDays": 30, - "LogGroupRegion": "us-east-1" + "LogGroupRegion": "us-east-1", + "RetentionInDays": 30 } }, "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRole9741ECFB": { @@ -105,8 +105,8 @@ "Statement": [ { "Action": [ - "logs:PutRetentionPolicy", - "logs:DeleteRetentionPolicy" + "logs:DeleteRetentionPolicy", + "logs:PutRetentionPolicy" ], "Effect": "Allow", "Resource": "*" @@ -125,9 +125,11 @@ "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aFD4BFC8A": { "Type": "AWS::Lambda::Function", "Properties": { + "Handler": "index.handler", + "Runtime": "nodejs14.x", "Code": { "S3Bucket": { - "Ref": "AssetParameters884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147S3BucketAE1150B3" + "Ref": "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665S3Bucket0D8A173B" }, "S3Key": { "Fn::Join": [ @@ -140,7 +142,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147S3VersionKeyC76660C1" + "Ref": "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665S3VersionKeyE95BF332" } ] } @@ -153,7 +155,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147S3VersionKeyC76660C1" + "Ref": "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665S3VersionKeyE95BF332" } ] } @@ -163,14 +165,12 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRole9741ECFB", "Arn" ] - }, - "Runtime": "nodejs14.x" + } }, "DependsOn": [ "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB", @@ -179,17 +179,17 @@ } }, "Parameters": { - "AssetParameters884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147S3BucketAE1150B3": { + "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665S3Bucket0D8A173B": { "Type": "String", - "Description": "S3 bucket for asset \"884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147\"" + "Description": "S3 bucket for asset \"22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665\"" }, - "AssetParameters884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147S3VersionKeyC76660C1": { + "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665S3VersionKeyE95BF332": { "Type": "String", - "Description": "S3 key for asset version \"884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147\"" + "Description": "S3 key for asset version \"22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665\"" }, - "AssetParameters884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147ArtifactHash717FC602": { + "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665ArtifactHashF4A1E70E": { "Type": "String", - "Description": "Artifact hash for asset \"884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147\"" + "Description": "Artifact hash for asset \"22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665\"" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloud9/package.json b/packages/@aws-cdk/aws-cloud9/package.json index 7078ef97f408e..2fd6aab3799e2 100644 --- a/packages/@aws-cdk/aws-cloud9/package.json +++ b/packages/@aws-cdk/aws-cloud9/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-codecommit": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudformation/package.json b/packages/@aws-cdk/aws-cloudformation/package.json index 0b15fd01bfe35..3f3b7106f9943 100644 --- a/packages/@aws-cdk/aws-cloudformation/package.json +++ b/packages/@aws-cdk/aws-cloudformation/package.json @@ -86,9 +86,9 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.92", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/aws-lambda": "^8.10.93", + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.core-custom-resources.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.core-custom-resources.expected.json index e5db15d48809b..8c3fc43456cb2 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.core-custom-resources.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.core-custom-resources.expected.json @@ -27,7 +27,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters925e7fbbec7bdbf0136ef5a07b8a0fbe0b1f1bb4ea50ae2154163df78aa9f226S3Bucket8B4D0E9E" + "Ref": "AssetParametersf668ac061a3c96c2a1ff8d441720965e8a44caf19c1c7efb7e648e51d0f742b2S3Bucket583D2319" }, "S3Key": { "Fn::Join": [ @@ -40,7 +40,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters925e7fbbec7bdbf0136ef5a07b8a0fbe0b1f1bb4ea50ae2154163df78aa9f226S3VersionKeyDECB34FE" + "Ref": "AssetParametersf668ac061a3c96c2a1ff8d441720965e8a44caf19c1c7efb7e648e51d0f742b2S3VersionKey9E55A55A" } ] } @@ -53,7 +53,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters925e7fbbec7bdbf0136ef5a07b8a0fbe0b1f1bb4ea50ae2154163df78aa9f226S3VersionKeyDECB34FE" + "Ref": "AssetParametersf668ac061a3c96c2a1ff8d441720965e8a44caf19c1c7efb7e648e51d0f742b2S3VersionKey9E55A55A" } ] } @@ -99,17 +99,17 @@ } }, "Parameters": { - "AssetParameters925e7fbbec7bdbf0136ef5a07b8a0fbe0b1f1bb4ea50ae2154163df78aa9f226S3Bucket8B4D0E9E": { + "AssetParametersf668ac061a3c96c2a1ff8d441720965e8a44caf19c1c7efb7e648e51d0f742b2S3Bucket583D2319": { "Type": "String", - "Description": "S3 bucket for asset \"925e7fbbec7bdbf0136ef5a07b8a0fbe0b1f1bb4ea50ae2154163df78aa9f226\"" + "Description": "S3 bucket for asset \"f668ac061a3c96c2a1ff8d441720965e8a44caf19c1c7efb7e648e51d0f742b2\"" }, - "AssetParameters925e7fbbec7bdbf0136ef5a07b8a0fbe0b1f1bb4ea50ae2154163df78aa9f226S3VersionKeyDECB34FE": { + "AssetParametersf668ac061a3c96c2a1ff8d441720965e8a44caf19c1c7efb7e648e51d0f742b2S3VersionKey9E55A55A": { "Type": "String", - "Description": "S3 key for asset version \"925e7fbbec7bdbf0136ef5a07b8a0fbe0b1f1bb4ea50ae2154163df78aa9f226\"" + "Description": "S3 key for asset version \"f668ac061a3c96c2a1ff8d441720965e8a44caf19c1c7efb7e648e51d0f742b2\"" }, - "AssetParameters925e7fbbec7bdbf0136ef5a07b8a0fbe0b1f1bb4ea50ae2154163df78aa9f226ArtifactHashEEC400F2": { + "AssetParametersf668ac061a3c96c2a1ff8d441720965e8a44caf19c1c7efb7e648e51d0f742b2ArtifactHashD6C9265F": { "Type": "String", - "Description": "Artifact hash for asset \"925e7fbbec7bdbf0136ef5a07b8a0fbe0b1f1bb4ea50ae2154163df78aa9f226\"" + "Description": "Artifact hash for asset \"f668ac061a3c96c2a1ff8d441720965e8a44caf19c1c7efb7e648e51d0f742b2\"" } }, "Outputs": { @@ -135,4 +135,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudformation/test/nested-stack.test.ts b/packages/@aws-cdk/aws-cloudformation/test/nested-stack.test.ts index a625012eba58a..2b0445fb34d3b 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/nested-stack.test.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/nested-stack.test.ts @@ -4,7 +4,7 @@ import { Template } from '@aws-cdk/assertions'; import * as s3_assets from '@aws-cdk/aws-s3-assets'; import * as sns from '@aws-cdk/aws-sns'; import { describeDeprecated } from '@aws-cdk/cdk-build-tools'; -import { App, CfnParameter, CfnResource, ContextProvider, LegacyStackSynthesizer, Names, Stack } from '@aws-cdk/core'; +import { App, CfnParameter, CfnResource, ContextProvider, LegacyStackSynthesizer, Names, Stack, Tags } from '@aws-cdk/core'; import { NestedStack } from '../lib/nested-stack'; // keep this import separate from other imports to reduce chance for merge conflicts with v2-main @@ -1085,4 +1085,49 @@ describeDeprecated('NestedStack', () => { }); }); + test('nested stack should get the tags added in root stack', () =>{ + const app = new App(); + const parentStack = new Stack(app, 'parent-stack'); + const nestedStack = new NestedStack(parentStack, 'MyNestedStack'); + + // add tags + Tags.of(nestedStack).add('tag-1', '22'); + Tags.of(nestedStack).add('tag-2', '33'); + + new sns.Topic(nestedStack, 'MyTopic'); + + // THEN + Template.fromStack(parentStack).hasResourceProperties( + 'AWS::CloudFormation::Stack', + { + Tags: [ + { + Key: 'tag-1', + Value: '22', + }, + { + Key: 'tag-2', + Value: '33', + }, + ], + }, + ); + + Template.fromStack(nestedStack).hasResourceProperties( + 'AWS::SNS::Topic', + { + Tags: [ + { + Key: 'tag-1', + Value: '22', + }, + { + Key: 'tag-2', + Value: '33', + }, + ], + }, + ); + }); + }); diff --git a/packages/@aws-cdk/aws-cloudfront-origins/README.md b/packages/@aws-cdk/aws-cloudfront-origins/README.md index f88a7e7111b1b..d4e948b1e887e 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/README.md +++ b/packages/@aws-cdk/aws-cloudfront-origins/README.md @@ -76,11 +76,12 @@ const origin = new origins.LoadBalancerV2Origin(loadBalancer, { connectionAttempts: 3, connectionTimeout: Duration.seconds(5), readTimeout: Duration.seconds(45), + keepaliveTimeout: Duration.seconds(45), protocolPolicy: cloudfront.OriginProtocolPolicy.MATCH_VIEWER, }); ``` -Note that the `readTimeout` property can extend its value over 60 seconds only if a limit increase request for CloudFront origin response timeout +Note that the `readTimeout` and `keepaliveTimeout` properties can extend their values over 60 seconds only if a limit increase request for CloudFront origin response timeout quota has been approved in the target account; otherwise, values over 60 seconds will produce an error at deploy time. Consider that this value is still limited to a maximum value of 180 seconds, which is a hard limit for that quota. diff --git a/packages/@aws-cdk/aws-cloudfront-origins/lib/http-origin.ts b/packages/@aws-cdk/aws-cloudfront-origins/lib/http-origin.ts index 50b94b0c52191..e4d6ac190dcff 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/lib/http-origin.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/lib/http-origin.ts @@ -46,7 +46,10 @@ export interface HttpOriginProps extends cloudfront.OriginProps { /** * Specifies how long, in seconds, CloudFront persists its connection to the origin. - * The valid range is from 1 to 60 seconds, inclusive. + * The valid range is from 1 to 180 seconds, inclusive. + * + * Note that values over 60 seconds are possible only after a limit increase request for the origin response timeout quota + * has been approved in the target account; otherwise, values over 60 seconds will produce an error at deploy time. * * @default Duration.seconds(5) */ @@ -62,7 +65,7 @@ export class HttpOrigin extends cloudfront.OriginBase { super(domainName, props); validateSecondsInRangeOrUndefined('readTimeout', 1, 180, props.readTimeout); - validateSecondsInRangeOrUndefined('keepaliveTimeout', 1, 60, props.keepaliveTimeout); + validateSecondsInRangeOrUndefined('keepaliveTimeout', 1, 180, props.keepaliveTimeout); } protected renderCustomOriginConfig(): cloudfront.CfnDistribution.CustomOriginConfigProperty | undefined { diff --git a/packages/@aws-cdk/aws-cloudfront-origins/package.json b/packages/@aws-cdk/aws-cloudfront-origins/package.json index a7fd2e966e6fd..d7bea5cd1ecca 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/package.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/package.json @@ -82,7 +82,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "aws-sdk": "^2.848.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/http-origin.test.ts b/packages/@aws-cdk/aws-cloudfront-origins/test/http-origin.test.ts index df149f56753b2..f1109a7f8c7db 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/http-origin.test.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/http-origin.test.ts @@ -84,12 +84,12 @@ test.each([ Duration.seconds(0), Duration.seconds(0.5), Duration.seconds(60.5), - Duration.seconds(61), + Duration.seconds(181), Duration.minutes(5), -])('validates keepaliveTimeout is an integer between 1 and 60 seconds', (keepaliveTimeout) => { +])('validates keepaliveTimeout is an integer between 1 and 180 seconds', (keepaliveTimeout) => { expect(() => { new HttpOrigin('www.example.com', { keepaliveTimeout, }); - }).toThrow(`keepaliveTimeout: Must be an int between 1 and 60 seconds (inclusive); received ${keepaliveTimeout.toSeconds()}.`); + }).toThrow(`keepaliveTimeout: Must be an int between 1 and 180 seconds (inclusive); received ${keepaliveTimeout.toSeconds()}.`); }); diff --git a/packages/@aws-cdk/aws-cloudfront/README.md b/packages/@aws-cdk/aws-cloudfront/README.md index e87a4f9b56617..3a727d6c1763f 100644 --- a/packages/@aws-cdk/aws-cloudfront/README.md +++ b/packages/@aws-cdk/aws-cloudfront/README.md @@ -91,7 +91,7 @@ your domain name, and provide one (or more) domain names from the certificate fo The certificate must be present in the AWS Certificate Manager (ACM) service in the US East (N. Virginia) region; the certificate may either be created by ACM, or created elsewhere and imported into ACM. When a certificate is used, the distribution will support HTTPS connections -from SNI only and a minimum protocol version of TLSv1.2_2021 if the '@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021' feature flag is set, and TLSv1.2_2019 otherwise. +from SNI only and a minimum protocol version of TLSv1.2_2021 if the `@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021` feature flag is set, and TLSv1.2_2019 otherwise. ```ts // To use your own domain name in a Distribution, you must associate a certificate @@ -539,6 +539,203 @@ const distribution = cloudfront.Distribution.fromDistributionAttributes(this, 'I }); ``` +## Migrating from the original CloudFrontWebDistribution to the newer Distribution construct + +It's possible to migrate a distribution from the original to the modern API. +The changes necessary are the following: + +### The Distribution + +Replace `new CloudFrontWebDistribution` with `new Distribution`. Some +configuration properties have been changed: + +| Old API | New API | +|--------------------------------|------------------------------------------------------------------------------------------------| +| `originConfigs` | `defaultBehavior`; use `additionalBehaviors` if necessary | +| `viewerCertificate` | `certificate`; use `domainNames` for aliases | +| `errorConfigurations` | `errorResponses` | +| `loggingConfig` | `enableLogging`; configure with `logBucket` `logFilePrefix` and `logIncludesCookies` | +| `viewerProtocolPolicy` | removed; set on each behavior instead. default changed from `REDIRECT_TO_HTTPS` to `ALLOW_ALL` | + +After switching constructs, you need to maintain the same logical ID for the underlying [CfnDistribution](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-cloudfront.CfnDistribution.html) if you wish to avoid the deletion and recreation of your distribution. +To do this, use [escape hatches](https://docs.aws.amazon.com/cdk/v2/guide/cfn_layer.html) to override the logical ID created by the new Distribution construct with the logical ID created by the old construct. + +Example: + +```ts +declare const sourceBucket: s3.Bucket; + +const myDistribution = new cloudfront.Distribution(this, 'MyCfWebDistribution', { + defaultBehavior: { + origin: new origins.S3Origin(sourceBucket), + }, +}); +const cfnDistribution = myDistribution.node.defaultChild as cloudfront.CfnDistribution; +cfnDistribution.overrideLogicalId('MyDistributionCFDistribution3H55TI9Q'); +``` + +### Behaviors + +The modern API makes use of the [CloudFront Origins](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudfront_origins-readme.html) module to easily configure your origin. Replace your origin configuration with the relevant CloudFront Origins class. For example, here's a behavior with an S3 origin: + +```ts +declare const sourceBucket: s3.Bucket; +declare const oai: cloudfront.OriginAccessIdentity; + +new cloudfront.CloudFrontWebDistribution(this, 'MyCfWebDistribution', { + originConfigs: [ + { + s3OriginSource: { + s3BucketSource: sourceBucket, + originAccessIdentity: oai, + }, + behaviors : [ {isDefaultBehavior: true}], + }, + ], +}); +``` + +Becomes: + +```ts +declare const sourceBucket: s3.Bucket; + +const distribution = new cloudfront.Distribution(this, 'MyCfWebDistribution', { + defaultBehavior: { + origin: new origins.S3Origin(sourceBucket) // This class automatically creates an Origin Access Identity + }, +}); +``` + +In the original API all behaviors are defined in the `originConfigs` property. The new API is optimized for a single origin and behavior, so the default behavior and additional behaviors will be defined separately. + +```ts +declare const sourceBucket: s3.Bucket; +declare const oai: cloudfront.OriginAccessIdentity; + +new cloudfront.CloudFrontWebDistribution(this, 'MyCfWebDistribution', { + originConfigs: [ + { + s3OriginSource: { + s3BucketSource: sourceBucket, + originAccessIdentity: oai, + }, + behaviors: [ {isDefaultBehavior: true}], + }, + { + customOriginSource: { + domainName: 'MYALIAS', + }, + behaviors: [{ pathPattern: '/somewhere' }] + } + ], +}); +``` + +Becomes: + +```ts +declare const sourceBucket: s3.Bucket; + +const distribution = new cloudfront.Distribution(this, 'MyCfWebDistribution', { + defaultBehavior: { + origin: new origins.S3Origin(sourceBucket) // This class automatically creates an Origin Access Identity + }, + additionalBehaviors: { + '/somewhere': { + origin: new origins.HttpOrigin('MYALIAS'), + } + } +}); +``` + +### Certificates + +If you are using an ACM certificate, you can pass the certificate directly to the `certificate` prop. +Any aliases used before in the `ViewerCertificate` class should be passed in to the `domainNames` prop in the modern API. + +```ts +import * as acm from '@aws-cdk/aws-certificatemanager'; +declare const certificate: acm.Certificate; +declare const sourceBucket: s3.Bucket; + +const viewerCertificate = cloudfront.ViewerCertificate.fromAcmCertificate(certificate, { + aliases: ['MYALIAS'], +}); + +new cloudfront.CloudFrontWebDistribution(this, 'MyCfWebDistribution', { + originConfigs: [ + { + s3OriginSource: { + s3BucketSource: sourceBucket, + }, + behaviors : [ {isDefaultBehavior: true} ], + }, + ], + viewerCertificate: viewerCertificate, +}); +``` + +Becomes: + +```ts +import * as acm from '@aws-cdk/aws-certificatemanager'; +declare const certificate: acm.Certificate; +declare const sourceBucket: s3.Bucket; + +const distribution = new cloudfront.Distribution(this, 'MyCfWebDistribution', { + defaultBehavior: { + origin: new origins.S3Origin(sourceBucket), + }, + domainNames: ['MYALIAS'], + certificate: certificate, +}); +``` + +IAM certificates aren't directly supported by the new API, but can be easily configured through [escape hatches](https://docs.aws.amazon.com/cdk/v2/guide/cfn_layer.html) + +```ts +declare const sourceBucket: s3.Bucket; +const viewerCertificate = cloudfront.ViewerCertificate.fromIamCertificate('MYIAMROLEIDENTIFIER', { + aliases: ['MYALIAS'], +}); + +new cloudfront.CloudFrontWebDistribution(this, 'MyCfWebDistribution', { + originConfigs: [ + { + s3OriginSource: { + s3BucketSource: sourceBucket, + }, + behaviors : [ {isDefaultBehavior: true} ], + }, + ], + viewerCertificate: viewerCertificate, +}); +``` + +Becomes: + +```ts +declare const sourceBucket: s3.Bucket; +const distribution = new cloudfront.Distribution(this, 'MyCfWebDistribution', { + defaultBehavior: { + origin: new origins.S3Origin(sourceBucket), + }, + domainNames: ['MYALIAS'], +}); + +const cfnDistribution = distribution.node.defaultChild as cloudfront.CfnDistribution; + +cfnDistribution.addPropertyOverride('ViewerCertificate.IamCertificateId', 'MYIAMROLEIDENTIFIER'); +cfnDistribution.addPropertyOverride('ViewerCertificate.SslSupportMethod', 'sni-only'); +``` + +### Other changes + +A number of default settings have changed on the new API when creating a new distribution, behavior, and origin. +After making the major changes needed for the migration, run `cdk diff` to see what settings have changed. +If no changes are desired during migration, you will at the least be able to use [escape hatches](https://docs.aws.amazon.com/cdk/v2/guide/cfn_layer.html) to override what the CDK synthesizes, if you can't change the properties directly. + ## CloudFrontWebDistribution API > The `CloudFrontWebDistribution` construct is the original construct written for working with CloudFront distributions. @@ -662,7 +859,7 @@ new cloudfront.CloudFrontWebDistribution(this, 'MyDistribution', { behaviors : [ {isDefaultBehavior: true}], }, ], - geoRestriction: cloudfront.GeoRestriction.whitelist('US', 'UK'), + geoRestriction: cloudfront.GeoRestriction.allowlist('US', 'GB'), }); ``` diff --git a/packages/@aws-cdk/aws-cloudfront/lib/cache-policy.ts b/packages/@aws-cdk/aws-cloudfront/lib/cache-policy.ts index 533ccbd5d78b9..e870a538fc887 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/cache-policy.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/cache-policy.ts @@ -129,9 +129,14 @@ export class CachePolicy extends Resource implements ICachePolicy { physicalName: props.cachePolicyName, }); - const cachePolicyName = props.cachePolicyName ?? `${Names.uniqueId(this)}-${Stack.of(this).region}`; + const cachePolicyName = props.cachePolicyName ?? `${Names.uniqueId(this).slice(0, 110)}-${Stack.of(this).region}`; + if (!Token.isUnresolved(cachePolicyName) && !cachePolicyName.match(/^[\w-]+$/i)) { - throw new Error(`'cachePolicyName' can only include '-', '_', and alphanumeric characters, got: '${props.cachePolicyName}'`); + throw new Error(`'cachePolicyName' can only include '-', '_', and alphanumeric characters, got: '${cachePolicyName}'`); + } + + if (cachePolicyName.length > 128) { + throw new Error(`'cachePolicyName' cannot be longer than 128 characters, got: '${cachePolicyName.length}'`); } const minTtl = (props.minTtl ?? Duration.seconds(0)).toSeconds(); diff --git a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts index c593edd9efec7..b88144d0a7c54 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts @@ -285,7 +285,7 @@ export class Distribution extends Resource implements IDistribution { // Comments have an undocumented limit of 128 characters const trimmedComment = props.comment && props.comment.length > 128 - ? `${props.comment.substr(0, 128 - 3)}...` + ? `${props.comment.slice(0, 128 - 3)}...` : props.comment; const distribution = new CfnDistribution(this, 'Resource', { @@ -430,7 +430,9 @@ export class Distribution extends Resource implements IDistribution { throw new Error('Explicitly disabled logging but provided a logging bucket.'); } - const bucket = props.logBucket ?? new s3.Bucket(this, 'LoggingBucket'); + const bucket = props.logBucket ?? new s3.Bucket(this, 'LoggingBucket', { + encryption: s3.BucketEncryption.S3_MANAGED, + }); return { bucket: bucket.bucketRegionalDomainName, includeCookies: props.logIncludesCookies, diff --git a/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts b/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts index e095984ed2081..126db00ecc323 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts @@ -47,6 +47,7 @@ export class EdgeFunction extends Resource implements lambda.IVersion { public readonly role?: iam.IRole; public readonly version: string; public readonly architecture: lambda.Architecture; + public readonly resourceArnsForGrantInvoke: string[]; private readonly _edgeFunction: lambda.Function; @@ -68,6 +69,7 @@ export class EdgeFunction extends Resource implements lambda.IVersion { this.permissionsNode = this._edgeFunction.permissionsNode; this.version = lambda.extractQualifierFromArn(this.functionArn); this.architecture = this._edgeFunction.architecture; + this.resourceArnsForGrantInvoke = this._edgeFunction.resourceArnsForGrantInvoke; this.node.defaultChild = this._edgeFunction; } diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts index c0a332a2e1b89..5b4e785cc21a7 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts @@ -954,7 +954,9 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu } if (props.loggingConfig) { - this.loggingBucket = props.loggingConfig.bucket || new s3.Bucket(this, 'LoggingBucket'); + this.loggingBucket = props.loggingConfig.bucket || new s3.Bucket(this, 'LoggingBucket', { + encryption: s3.BucketEncryption.S3_MANAGED, + }); distributionConfig = { ...distributionConfig, logging: { diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index b803454912cec..37ee6edb996a2 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -84,9 +84,9 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "aws-sdk": "^2.848.0", - "jest": "^27.4.7" + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudfront/test/cache-policy.test.ts b/packages/@aws-cdk/aws-cloudfront/test/cache-policy.test.ts index 47e9b0ee46fb9..2abeffd3cc39b 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/cache-policy.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/cache-policy.test.ts @@ -85,7 +85,12 @@ describe('CachePolicy', () => { }); }); - test('throws if given a cachePolicyName with invalid characters', () => { + test('throws on long policy names over 128 characters', () => { + const errorMessage = /'cachePolicyName' cannot be longer than 128 characters/; + expect(() => new CachePolicy(stack, 'CachePolicy1', { cachePolicyName: 'FooBarBaz'.repeat(15) })).toThrow(errorMessage); + }); + + test('throws if cachePolicyName contains invalid characters', () => { const errorMessage = /'cachePolicyName' can only include '-', '_', and alphanumeric characters/; expect(() => new CachePolicy(stack, 'CachePolicy1', { cachePolicyName: 'My Policy' })).toThrow(errorMessage); expect(() => new CachePolicy(stack, 'CachePolicy2', { cachePolicyName: 'MyPolicy!' })).toThrow(errorMessage); diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-bucket-logging.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-bucket-logging.expected.json index 36a334898a57f..5bdfba44e3ae1 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-bucket-logging.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-bucket-logging.expected.json @@ -75,6 +75,17 @@ }, "AnAmazingWebsiteProbably2LoggingBucket222F7CE9": { "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256" + } + } + ] + } + }, "UpdateReplacePolicy": "Retain", "DeletionPolicy": "Retain" }, diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-lambda-association.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-lambda-association.expected.json index eb45a5dd3192d..8759a3b629e14 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-lambda-association.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-lambda-association.expected.json @@ -14,14 +14,10 @@ "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { - "Service": "lambda.amazonaws.com" - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "edgelambda.amazonaws.com" + "Service": [ + "edgelambda.amazonaws.com", + "lambda.amazonaws.com" + ] } } ], @@ -49,13 +45,13 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "LambdaServiceRoleA8ED4D3B", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.expected.json index 4ddd5ddb8d373..fb0c6b3543bd0 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.expected.json @@ -2,6 +2,17 @@ "Resources": { "MyDistLoggingBucket9B8976BC": { "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256" + } + } + ] + } + }, "UpdateReplacePolicy": "Retain", "DeletionPolicy": "Retain" }, diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda-cross-region.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda-cross-region.expected.json index bc5f2284b77ca..6558d75227882 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda-cross-region.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda-cross-region.expected.json @@ -76,7 +76,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters45b7ed524ce2b119dd4f2b8642ae8bfaf0df45bc6bd705072ae4ee6d1a999241S3BucketF1BC72A7" + "Ref": "AssetParameterse718f39096261b3e336dd6d896baabf1049bb1938cb1865de1b5e576cb57376aS3BucketA88C096E" }, "S3Key": { "Fn::Join": [ @@ -89,7 +89,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters45b7ed524ce2b119dd4f2b8642ae8bfaf0df45bc6bd705072ae4ee6d1a999241S3VersionKey7AD83AC7" + "Ref": "AssetParameterse718f39096261b3e336dd6d896baabf1049bb1938cb1865de1b5e576cb57376aS3VersionKeyF63BD825" } ] } @@ -102,7 +102,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters45b7ed524ce2b119dd4f2b8642ae8bfaf0df45bc6bd705072ae4ee6d1a999241S3VersionKey7AD83AC7" + "Ref": "AssetParameterse718f39096261b3e336dd6d896baabf1049bb1938cb1865de1b5e576cb57376aS3VersionKeyF63BD825" } ] } @@ -190,17 +190,17 @@ } }, "Parameters": { - "AssetParameters45b7ed524ce2b119dd4f2b8642ae8bfaf0df45bc6bd705072ae4ee6d1a999241S3BucketF1BC72A7": { + "AssetParameterse718f39096261b3e336dd6d896baabf1049bb1938cb1865de1b5e576cb57376aS3BucketA88C096E": { "Type": "String", - "Description": "S3 bucket for asset \"45b7ed524ce2b119dd4f2b8642ae8bfaf0df45bc6bd705072ae4ee6d1a999241\"" + "Description": "S3 bucket for asset \"e718f39096261b3e336dd6d896baabf1049bb1938cb1865de1b5e576cb57376a\"" }, - "AssetParameters45b7ed524ce2b119dd4f2b8642ae8bfaf0df45bc6bd705072ae4ee6d1a999241S3VersionKey7AD83AC7": { + "AssetParameterse718f39096261b3e336dd6d896baabf1049bb1938cb1865de1b5e576cb57376aS3VersionKeyF63BD825": { "Type": "String", - "Description": "S3 key for asset version \"45b7ed524ce2b119dd4f2b8642ae8bfaf0df45bc6bd705072ae4ee6d1a999241\"" + "Description": "S3 key for asset version \"e718f39096261b3e336dd6d896baabf1049bb1938cb1865de1b5e576cb57376a\"" }, - "AssetParameters45b7ed524ce2b119dd4f2b8642ae8bfaf0df45bc6bd705072ae4ee6d1a999241ArtifactHash1B3D1B80": { + "AssetParameterse718f39096261b3e336dd6d896baabf1049bb1938cb1865de1b5e576cb57376aArtifactHashE4754D11": { "Type": "String", - "Description": "Artifact hash for asset \"45b7ed524ce2b119dd4f2b8642ae8bfaf0df45bc6bd705072ae4ee6d1a999241\"" + "Description": "Artifact hash for asset \"e718f39096261b3e336dd6d896baabf1049bb1938cb1865de1b5e576cb57376a\"" } } }, @@ -215,14 +215,10 @@ "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { - "Service": "lambda.amazonaws.com" - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "edgelambda.amazonaws.com" + "Service": [ + "edgelambda.amazonaws.com", + "lambda.amazonaws.com" + ] } } ], @@ -309,14 +305,10 @@ "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { - "Service": "lambda.amazonaws.com" - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "edgelambda.amazonaws.com" + "Service": [ + "edgelambda.amazonaws.com", + "lambda.amazonaws.com" + ] } } ], diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda.expected.json index 44ad319c62a4b..d87415745eed9 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda.expected.json @@ -9,14 +9,10 @@ "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { - "Service": "lambda.amazonaws.com" - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "edgelambda.amazonaws.com" + "Service": [ + "edgelambda.amazonaws.com", + "lambda.amazonaws.com" + ] } } ], @@ -44,13 +40,13 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "LambdaServiceRoleA8ED4D3B", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -99,4 +95,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index 1d28c67dd7c28..d5b30cb2c16c8 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -84,9 +84,9 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "aws-sdk": "^2.848.0", - "jest": "^27.4.7" + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudtrail/test/integ.cloudtrail-supplied-bucket.lit.expected.json b/packages/@aws-cdk/aws-cloudtrail/test/integ.cloudtrail-supplied-bucket.lit.expected.json index 86773e090a9fe..e115d5360fee6 100644 --- a/packages/@aws-cdk/aws-cloudtrail/test/integ.cloudtrail-supplied-bucket.lit.expected.json +++ b/packages/@aws-cdk/aws-cloudtrail/test/integ.cloudtrail-supplied-bucket.lit.expected.json @@ -42,13 +42,13 @@ "Code": { "ZipFile": "exports.handler = {}" }, - "Handler": "hello.handler", "Role": { "Fn::GetAtt": [ "LambdaFunctionServiceRoleC555A460", "Arn" ] }, + "Handler": "hello.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/package.json b/packages/@aws-cdk/aws-cloudwatch-actions/package.json index 2a37790862f9b..a54a582f66548 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/package.json +++ b/packages/@aws-cdk/aws-cloudwatch-actions/package.json @@ -77,8 +77,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudwatch/README.md b/packages/@aws-cdk/aws-cloudwatch/README.md index 37a31f636b3ad..8404c6ce9ad7a 100644 --- a/packages/@aws-cdk/aws-cloudwatch/README.md +++ b/packages/@aws-cdk/aws-cloudwatch/README.md @@ -436,6 +436,20 @@ dashboard.addWidgets( ); ``` +An alarm status widget only showing firing alarms, sorted by state and timestamp: + +```ts +declare const dashboard: cloudwatch.Dashboard; +declare const errorAlarm: cloudwatch.Alarm; + +dashboard.addWidgets(new cloudwatch.AlarmStatusWidget({ + title: "Errors", + alarms: [errorAlarm], + sortBy: cloudwatch.AlarmStatusWidgetSortBy.STATE_UPDATED_TIMESTAMP, + states: [cloudwatch.AlarmState.ALARM], +})); +``` + ### Query results widget A `LogQueryWidget` shows the results of a query from Logs Insights: diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/alarm-status-widget.ts b/packages/@aws-cdk/aws-cloudwatch/lib/alarm-status-widget.ts index 3562a0b9cba6b..852fe4051ac5f 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/alarm-status-widget.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/alarm-status-widget.ts @@ -1,6 +1,33 @@ import { IAlarm } from './alarm-base'; +import { AlarmState } from './alarm-rule'; import { ConcreteWidget } from './widget'; + +/** + * The sort possibilities for AlarmStatusWidgets + */ +export enum AlarmStatusWidgetSortBy { + + /** + * Choose DEFAULT to sort them in alphabetical order by alarm name. + */ + DEFAULT = 'default', + + /** + * Choose STATE_UPDATED_TIMESTAMP to sort them first by alarm state, with alarms in ALARM state first, + * INSUFFICIENT_DATA alarms next, and OK alarms last. + * Within each group, the alarms are sorted by when they last changed state, with more recent state changes listed first. + */ + STATE_UPDATED_TIMESTAMP = 'stateUpdatedTimestamp', + + /** + * Choose TIMESTAMP to sort them by the time when the alarms most recently changed state, + * no matter the current alarm state. + * The alarm that changed state most recently is listed first. + */ + TIMESTAMP = 'timestamp', +} + /** * Properties for an Alarm Status Widget */ @@ -27,6 +54,24 @@ export interface AlarmStatusWidgetProps { * @default 3 */ readonly height?: number; + + /** + * Specifies how to sort the alarms in the widget. + * + * @default - alphabetical order + */ + readonly sortBy?: AlarmStatusWidgetSortBy; + + /** + * Use this field to filter the list of alarms displayed in the widget to only those alarms currently in the specified states. + * You can specify one or more alarm states in the value for this field. + * The alarm states that you can specify are ALARM, INSUFFICIENT_DATA, and OK. + * + * If you omit this field or specify an empty array, all the alarms specifed in alarms are displayed. + * + * @default - all the alarms specified in alarms are displayed. + */ + readonly states?: AlarmState[]; } /** @@ -56,6 +101,8 @@ export class AlarmStatusWidget extends ConcreteWidget { properties: { title: this.props.title ? this.props.title : 'Alarm Status', alarms: this.props.alarms.map((alarm) => alarm.alarmArn), + states: this.props.states, + sortBy: this.props.sortBy, }, }, ]; diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/graph.ts b/packages/@aws-cdk/aws-cloudwatch/lib/graph.ts index 709baba719109..af23010e166c8 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/graph.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/graph.ts @@ -450,6 +450,8 @@ export class Color { /** red - hex #d62728 */ public static readonly RED = '#d62728'; + + private constructor() {} } /** diff --git a/packages/@aws-cdk/aws-cloudwatch/package.json b/packages/@aws-cdk/aws-cloudwatch/package.json index 61c877e59737f..f263def7dfcd2 100644 --- a/packages/@aws-cdk/aws-cloudwatch/package.json +++ b/packages/@aws-cdk/aws-cloudwatch/package.json @@ -84,8 +84,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudwatch/test/alarm-status-widget.test.ts b/packages/@aws-cdk/aws-cloudwatch/test/alarm-status-widget.test.ts index 3c771ba47ea05..31cb33c724237 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/alarm-status-widget.test.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/alarm-status-widget.test.ts @@ -1,5 +1,5 @@ import { Stack } from '@aws-cdk/core'; -import { Metric, Alarm, AlarmStatusWidget } from '../lib'; +import { Metric, Alarm, AlarmStatusWidget, AlarmStatusWidgetSortBy, AlarmState } from '../lib'; describe('Alarm Status Widget', () => { test('alarm status widget', () => { // GIVEN @@ -28,7 +28,38 @@ describe('Alarm Status Widget', () => { }, }, ]); + }); + test('alarm status widget custom props', () => { + // GIVEN + const stack = new Stack(); + const metric = new Metric({ namespace: 'CDK', metricName: 'Test' }); + const alarm = new Alarm(stack, 'Alarm', { + metric, + threshold: 1, + evaluationPeriods: 1, + }); + + // WHEN + const widget = new AlarmStatusWidget({ + alarms: [alarm], + sortBy: AlarmStatusWidgetSortBy.STATE_UPDATED_TIMESTAMP, + states: [AlarmState.ALARM], + }); + // THEN + expect(stack.resolve(widget.toJson())).toEqual([ + { + type: 'alarm', + width: 6, + height: 3, + properties: { + title: 'Alarm Status', + alarms: [{ 'Fn::GetAtt': ['Alarm7103F465', 'Arn'] }], + sortBy: 'stateUpdatedTimestamp', + states: ['ALARM'], + }, + }, + ]); }); }); diff --git a/packages/@aws-cdk/aws-cloudwatch/test/integ.alarm-and-dashboard.expected.json b/packages/@aws-cdk/aws-cloudwatch/test/integ.alarm-and-dashboard.expected.json index cdd7382b40f17..ab719f5952e61 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/integ.alarm-and-dashboard.expected.json +++ b/packages/@aws-cdk/aws-cloudwatch/test/integ.alarm-and-dashboard.expected.json @@ -45,7 +45,14 @@ "Arn" ] }, - "\"]},\"yAxis\":{}}},{\"type\":\"metric\",\"width\":6,\"height\":6,\"x\":0,\"y\":8,\"properties\":{\"view\":\"timeSeries\",\"title\":\"More messages in queue with alarm annotation\",\"region\":\"", + "\"]},\"yAxis\":{}}},{\"type\":\"alarm\",\"width\":6,\"height\":3,\"x\":0,\"y\":8,\"properties\":{\"title\":\"Firing alarms\",\"alarms\":[\"", + { + "Fn::GetAtt": [ + "Alarm7103F465", + "Arn" + ] + }, + "\"]}},{\"type\":\"metric\",\"width\":6,\"height\":6,\"x\":0,\"y\":11,\"properties\":{\"view\":\"timeSeries\",\"title\":\"More messages in queue with alarm annotation\",\"region\":\"", { "Ref": "AWS::Region" }, @@ -56,7 +63,7 @@ "QueueName" ] }, - "\"]],\"annotations\":{\"horizontal\":[{\"label\":\"ApproximateNumberOfMessagesVisible >= 100 for 2 datapoints within 15 minutes\",\"value\":100,\"yAxis\":\"left\"}]},\"yAxis\":{}}},{\"type\":\"metric\",\"width\":6,\"height\":3,\"x\":0,\"y\":14,\"properties\":{\"view\":\"singleValue\",\"title\":\"Current messages in queue\",\"region\":\"", + "\"]],\"annotations\":{\"horizontal\":[{\"label\":\"ApproximateNumberOfMessagesVisible >= 100 for 2 datapoints within 15 minutes\",\"value\":100,\"yAxis\":\"left\"}]},\"yAxis\":{}}},{\"type\":\"metric\",\"width\":6,\"height\":3,\"x\":0,\"y\":17,\"properties\":{\"view\":\"singleValue\",\"title\":\"Current messages in queue\",\"region\":\"", { "Ref": "AWS::Region" }, @@ -67,27 +74,27 @@ "QueueName" ] }, - "\"]]}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":17,\"properties\":{\"view\":\"table\",\"title\":\"Errors in my log group\",\"region\":\"", + "\"]]}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":20,\"properties\":{\"view\":\"table\",\"title\":\"Errors in my log group\",\"region\":\"", { "Ref": "AWS::Region" }, - "\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\"}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":23,\"properties\":{\"view\":\"bar\",\"title\":\"Errors in my log group - bar\",\"region\":\"", + "\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\"}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":26,\"properties\":{\"view\":\"bar\",\"title\":\"Errors in my log group - bar\",\"region\":\"", { "Ref": "AWS::Region" }, - "\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\"}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":29,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Errors in my log group - line\",\"region\":\"", + "\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\"}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":32,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Errors in my log group - line\",\"region\":\"", { "Ref": "AWS::Region" }, - "\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\",\"stacked\":false}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":35,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Errors in my log group - stacked\",\"region\":\"", + "\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\",\"stacked\":false}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":38,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Errors in my log group - stacked\",\"region\":\"", { "Ref": "AWS::Region" }, - "\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\",\"stacked\":true}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":41,\"properties\":{\"view\":\"pie\",\"title\":\"Errors in my log group - pie\",\"region\":\"", + "\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\",\"stacked\":true}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":44,\"properties\":{\"view\":\"pie\",\"title\":\"Errors in my log group - pie\",\"region\":\"", { "Ref": "AWS::Region" }, - "\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\"}},{\"type\":\"metric\",\"width\":6,\"height\":3,\"x\":0,\"y\":47,\"properties\":{\"view\":\"singleValue\",\"title\":\"Sent message size\",\"region\":\"", + "\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\"}},{\"type\":\"metric\",\"width\":6,\"height\":3,\"x\":0,\"y\":50,\"properties\":{\"view\":\"singleValue\",\"title\":\"Sent message size\",\"region\":\"", { "Ref": "AWS::Region" }, @@ -98,7 +105,7 @@ "QueueName" ] }, - "\"]],\"singleValueFullPrecision\":false}},{\"type\":\"metric\",\"width\":6,\"height\":3,\"x\":0,\"y\":50,\"properties\":{\"view\":\"singleValue\",\"title\":\"Sent message size with full precision\",\"region\":\"", + "\"]],\"singleValueFullPrecision\":false}},{\"type\":\"metric\",\"width\":6,\"height\":3,\"x\":0,\"y\":53,\"properties\":{\"view\":\"singleValue\",\"title\":\"Sent message size with full precision\",\"region\":\"", { "Ref": "AWS::Region" }, diff --git a/packages/@aws-cdk/aws-cloudwatch/test/integ.alarm-and-dashboard.ts b/packages/@aws-cdk/aws-cloudwatch/test/integ.alarm-and-dashboard.ts index 799dad893e227..d76f441d3c28c 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/integ.alarm-and-dashboard.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/integ.alarm-and-dashboard.ts @@ -45,6 +45,10 @@ dashboard.addWidgets(new cloudwatch.AlarmWidget({ title: 'Messages in queue', alarm, })); +dashboard.addWidgets(new cloudwatch.AlarmStatusWidget({ + title: 'Firing alarms', + alarms: [alarm], +})); dashboard.addWidgets(new cloudwatch.GraphWidget({ title: 'More messages in queue with alarm annotation', left: [numberOfMessagesVisibleMetric], diff --git a/packages/@aws-cdk/aws-codeartifact/package.json b/packages/@aws-cdk/aws-codeartifact/package.json index 943a1e3a421a7..9303cee955029 100644 --- a/packages/@aws-cdk/aws-codeartifact/package.json +++ b/packages/@aws-cdk/aws-codeartifact/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-codebuild/README.md b/packages/@aws-cdk/aws-codebuild/README.md index 4bccbbc68cfa1..3be027de2404c 100644 --- a/packages/@aws-cdk/aws-codebuild/README.md +++ b/packages/@aws-cdk/aws-codebuild/README.md @@ -280,11 +280,12 @@ can use the `environment` property to customize the build environment: ## Images The CodeBuild library supports both Linux and Windows images via the -`LinuxBuildImage` and `WindowsBuildImage` classes, respectively. +`LinuxBuildImage` (or `LinuxArmBuildImage`), and `WindowsBuildImage` classes, respectively. You can specify one of the predefined Windows/Linux images by using one of the constants such as `WindowsBuildImage.WIN_SERVER_CORE_2019_BASE`, -`WindowsBuildImage.WINDOWS_BASE_2_0` or `LinuxBuildImage.STANDARD_2_0`. +`WindowsBuildImage.WINDOWS_BASE_2_0`, `LinuxBuildImage.STANDARD_2_0`, or +`LinuxArmBuildImage.AMAZON_LINUX_2_ARM`. Alternatively, you can specify a custom image using one of the static methods on `LinuxBuildImage`: @@ -302,6 +303,10 @@ or one of the corresponding methods on `WindowsBuildImage`: * `WindowsBuildImage.fromEcrRepository(repo[, tag, imageType])` * `WindowsBuildImage.fromAsset(parent, id, props, [, imageType])` +or one of the corresponding methods on `LinuxArmBuildImage`: + +* `LinuxArmBuildImage.fromEcrRepository(repo[, tag])` + Note that the `WindowsBuildImage` version of the static methods accepts an optional parameter of type `WindowsImageType`, which can be either `WindowsImageType.STANDARD`, the default, or `WindowsImageType.SERVER_2019`: diff --git a/packages/@aws-cdk/aws-codebuild/lib/index.ts b/packages/@aws-cdk/aws-codebuild/lib/index.ts index 5c2de5f3119c2..e2abd2da98db8 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/index.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/index.ts @@ -11,6 +11,7 @@ export * from './build-spec'; export * from './file-location'; export * from './linux-gpu-build-image'; export * from './untrusted-code-boundary-policy'; +export * from './linux-arm-build-image'; // AWS::CodeBuild CloudFormation Resources: export * from './codebuild.generated'; diff --git a/packages/@aws-cdk/aws-codebuild/lib/linux-arm-build-image.ts b/packages/@aws-cdk/aws-codebuild/lib/linux-arm-build-image.ts new file mode 100644 index 0000000000000..12a7d2e54daf6 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/lib/linux-arm-build-image.ts @@ -0,0 +1,105 @@ +import * as ecr from '@aws-cdk/aws-ecr'; +import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; +import { BuildSpec } from './build-spec'; +import { runScriptLinuxBuildSpec } from './private/run-script-linux-build-spec'; +import { BuildEnvironment, ComputeType, IBuildImage, ImagePullPrincipalType } from './project'; + +/** + * Construction properties of {@link LinuxArmBuildImage}. + * Module-private, as the constructor of {@link LinuxArmBuildImage} is private. + */ +interface LinuxArmBuildImageProps { + readonly imageId: string; + readonly imagePullPrincipalType?: ImagePullPrincipalType; + readonly secretsManagerCredentials?: secretsmanager.ISecret; + readonly repository?: ecr.IRepository; +} + +/** + * A CodeBuild image running aarch64 Linux. + * + * This class has a bunch of public constants that represent the CodeBuild ARM images. + * + * You can also specify a custom image using the static method: + * + * - LinuxBuildImage.fromEcrRepository(repo[, tag]) + * + * + * @see https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-available.html + */ +export class LinuxArmBuildImage implements IBuildImage { + /** Image "aws/codebuild/amazonlinux2-aarch64-standard:1.0". */ + public static readonly AMAZON_LINUX_2_STANDARD_1_0 = LinuxArmBuildImage.fromCodeBuildImageId('aws/codebuild/amazonlinux2-aarch64-standard:1.0'); + /** Image "aws/codebuild/amazonlinux2-aarch64-standard:2.0". */ + public static readonly AMAZON_LINUX_2_STANDARD_2_0 = LinuxArmBuildImage.fromCodeBuildImageId('aws/codebuild/amazonlinux2-aarch64-standard:2.0'); + + /** + * Returns an ARM image running Linux from an ECR repository. + * + * NOTE: if the repository is external (i.e. imported), then we won't be able to add + * a resource policy statement for it so CodeBuild can pull the image. + * + * @see https://docs.aws.amazon.com/codebuild/latest/userguide/sample-ecr.html + * + * @param repository The ECR repository + * @param tag Image tag (default "latest") + * @returns An aarch64 Linux build image from an ECR repository. + */ + public static fromEcrRepository(repository: ecr.IRepository, tag: string = 'latest'): IBuildImage { + return new LinuxArmBuildImage({ + imageId: repository.repositoryUriForTag(tag), + imagePullPrincipalType: ImagePullPrincipalType.SERVICE_ROLE, + repository, + }); + } + + /** + * Uses a Docker image provided by CodeBuild. + * + * @see https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-available.html + * + * @param id The image identifier + * @example 'aws/codebuild/amazonlinux2-aarch64-standard:1.0' + * @returns A Docker image provided by CodeBuild. + */ + public static fromCodeBuildImageId(id: string): IBuildImage { + return new LinuxArmBuildImage({ + imageId: id, + imagePullPrincipalType: ImagePullPrincipalType.CODEBUILD, + }); + } + + public readonly type = 'ARM_CONTAINER'; + public readonly defaultComputeType = ComputeType.LARGE; + public readonly imageId: string; + public readonly imagePullPrincipalType?: ImagePullPrincipalType; + public readonly secretsManagerCredentials?: secretsmanager.ISecret; + public readonly repository?: ecr.IRepository; + + private constructor(props: LinuxArmBuildImageProps) { + this.imageId = props.imageId; + this.imagePullPrincipalType = props.imagePullPrincipalType; + this.secretsManagerCredentials = props.secretsManagerCredentials; + this.repository = props.repository; + } + + /** + * Validates by checking the BuildEnvironment computeType as aarch64 images only support ComputeType.SMALL and + * ComputeType.LARGE + * @param buildEnvironment BuildEnvironment + */ + public validate(buildEnvironment: BuildEnvironment): string[] { + const ret = []; + if (buildEnvironment.computeType && + buildEnvironment.computeType !== ComputeType.SMALL && + buildEnvironment.computeType !== ComputeType.LARGE) { + ret.push(`ARM images only support ComputeTypes '${ComputeType.SMALL}' and '${ComputeType.LARGE}' - ` + + `'${buildEnvironment.computeType}' was given`); + } + return ret; + } + + public runScriptBuildspec(entrypoint: string): BuildSpec { + return runScriptLinuxBuildSpec(entrypoint); + } +} diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index c6a816e3aedd2..e3ea5ac394f4c 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -1642,32 +1642,6 @@ export interface IBindableBuildImage extends IBuildImage { bind(scope: CoreConstruct, project: IProject, options: BuildImageBindOptions): BuildImageConfig; } -class ArmBuildImage implements IBuildImage { - public readonly type = 'ARM_CONTAINER'; - public readonly defaultComputeType = ComputeType.LARGE; - public readonly imagePullPrincipalType = ImagePullPrincipalType.CODEBUILD; - public readonly imageId: string; - - constructor(imageId: string) { - this.imageId = imageId; - } - - public validate(buildEnvironment: BuildEnvironment): string[] { - const ret = []; - if (buildEnvironment.computeType && - buildEnvironment.computeType !== ComputeType.SMALL && - buildEnvironment.computeType !== ComputeType.LARGE) { - ret.push(`ARM images only support ComputeTypes '${ComputeType.SMALL}' and '${ComputeType.LARGE}' - ` + - `'${buildEnvironment.computeType}' was given`); - } - return ret; - } - - public runScriptBuildspec(entrypoint: string): BuildSpec { - return runScriptLinuxBuildSpec(entrypoint); - } -} - /** * The options when creating a CodeBuild Docker build image * using {@link LinuxBuildImage.fromDockerRegistry} @@ -1695,8 +1669,12 @@ interface LinuxBuildImageProps { readonly repository?: ecr.IRepository; } +// Keep around to resolve a circular dependency until removing deprecated ARM image constants from LinuxBuildImage +// eslint-disable-next-line no-duplicate-imports, import/order +import { LinuxArmBuildImage } from './linux-arm-build-image'; + /** - * A CodeBuild image running Linux. + * A CodeBuild image running x86-64 Linux. * * This class has a bunch of public constants that represent the most popular images. * @@ -1723,9 +1701,13 @@ export class LinuxBuildImage implements IBuildImage { /** The Amazon Linux 2 x86_64 standard image, version `3.0`. */ public static readonly AMAZON_LINUX_2_3 = LinuxBuildImage.codeBuildImage('aws/codebuild/amazonlinux2-x86_64-standard:3.0'); - public static readonly AMAZON_LINUX_2_ARM: IBuildImage = new ArmBuildImage('aws/codebuild/amazonlinux2-aarch64-standard:1.0'); - /** Image "aws/codebuild/amazonlinux2-aarch64-standard:2.0". */ - public static readonly AMAZON_LINUX_2_ARM_2: IBuildImage = new ArmBuildImage('aws/codebuild/amazonlinux2-aarch64-standard:2.0'); + /** @deprecated Use LinuxArmBuildImage.AMAZON_LINUX_2_STANDARD_1_0 instead. */ + public static readonly AMAZON_LINUX_2_ARM = LinuxArmBuildImage.AMAZON_LINUX_2_STANDARD_1_0; + /** + * Image "aws/codebuild/amazonlinux2-aarch64-standard:2.0". + * @deprecated Use LinuxArmBuildImage.AMAZON_LINUX_2_STANDARD_2_0 instead. + * */ + public static readonly AMAZON_LINUX_2_ARM_2 = LinuxArmBuildImage.AMAZON_LINUX_2_STANDARD_2_0; /** @deprecated Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section */ public static readonly UBUNTU_14_04_BASE = LinuxBuildImage.codeBuildImage('aws/codebuild/ubuntu-base:14.04'); @@ -1789,7 +1771,7 @@ export class LinuxBuildImage implements IBuildImage { public static readonly UBUNTU_14_04_DOTNET_CORE_2_1 = LinuxBuildImage.codeBuildImage('aws/codebuild/dot-net:core-2.1'); /** - * @returns a Linux build image from a Docker Hub image. + * @returns a x86-64 Linux build image from a Docker Hub image. */ public static fromDockerRegistry(name: string, options: DockerImageOptions = {}): IBuildImage { return new LinuxBuildImage({ @@ -1800,7 +1782,7 @@ export class LinuxBuildImage implements IBuildImage { } /** - * @returns A Linux build image from an ECR repository. + * @returns A x86-64 Linux build image from an ECR repository. * * NOTE: if the repository is external (i.e. imported), then we won't be able to add * a resource policy statement for it so CodeBuild can pull the image. @@ -1819,7 +1801,7 @@ export class LinuxBuildImage implements IBuildImage { } /** - * Uses an Docker image asset as a Linux build image. + * Uses an Docker image asset as a x86-64 Linux build image. */ public static fromAsset(scope: Construct, id: string, props: DockerImageAssetProps): IBuildImage { const asset = new DockerImageAsset(scope, id, props); @@ -1961,7 +1943,7 @@ export class WindowsBuildImage implements IBuildImage { } /** - * @returns A Linux build image from an ECR repository. + * @returns A Windows build image from an ECR repository. * * NOTE: if the repository is external (i.e. imported), then we won't be able to add * a resource policy statement for it so CodeBuild can pull the image. @@ -2125,4 +2107,4 @@ export enum ProjectNotificationEvents { function isBindableBuildImage(x: unknown): x is IBindableBuildImage { return typeof x === 'object' && !!x && !!(x as any).bind; -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index 0f16ed23d8b1d..5f43a603aaa62 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -90,9 +90,9 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "aws-sdk": "^2.848.0", - "jest": "^27.4.7" + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/assets": "0.0.0", diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json index 745a6588da5fb..64a8873d3f1d4 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json @@ -49,7 +49,8 @@ ":log-group:/aws/codebuild/", { "Ref": "ProjectC78D97AD" - } + }, + ":*" ] ] }, @@ -72,8 +73,7 @@ ":log-group:/aws/codebuild/", { "Ref": "ProjectC78D97AD" - }, - ":*" + } ] ] } @@ -81,11 +81,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -116,8 +116,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.caching.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.caching.expected.json index d98388270cec6..7190b590998a0 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.caching.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.caching.expected.json @@ -29,16 +29,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -91,7 +91,8 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - } + }, + ":*" ] ] }, @@ -114,8 +115,7 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - }, - ":*" + } ] ] } diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.defaults.lit.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.defaults.lit.expected.json index ff9f8df2fb326..efa59865ec87f 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.defaults.lit.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.defaults.lit.expected.json @@ -49,7 +49,8 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - } + }, + ":*" ] ] }, @@ -72,8 +73,7 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - }, - ":*" + } ] ] } @@ -81,11 +81,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.docker-asset.lit.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.docker-asset.lit.expected.json index 66b816d4191af..d3c45a9bee054 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.docker-asset.lit.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.docker-asset.lit.expected.json @@ -25,8 +25,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { @@ -82,7 +82,8 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - } + }, + ":*" ] ] }, @@ -105,8 +106,7 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - }, - ":*" + } ] ] } @@ -171,4 +171,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.docker-registry.lit.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.docker-registry.lit.expected.json index 43cdce11f042f..1a5332128c23a 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.docker-registry.lit.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.docker-registry.lit.expected.json @@ -24,8 +24,8 @@ "Statement": [ { "Action": [ - "secretsmanager:GetSecretValue", - "secretsmanager:DescribeSecret" + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue" ], "Effect": "Allow", "Resource": { @@ -72,7 +72,8 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - } + }, + ":*" ] ] }, @@ -95,8 +96,7 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - }, - ":*" + } ] ] } diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.ecr.lit.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.ecr.lit.expected.json index fdae4323ed9cd..b4596c6b80c9c 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.ecr.lit.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.ecr.lit.expected.json @@ -2,6 +2,11 @@ "Resources": { "MyRepoF4F48043": { "Type": "AWS::ECR::Repository", + "Properties": { + "ImageScanningConfiguration": { + "ScanOnPush": false + } + }, "UpdateReplacePolicy": "Retain", "DeletionPolicy": "Retain" }, @@ -30,8 +35,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { @@ -73,7 +78,8 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - } + }, + ":*" ] ] }, @@ -96,8 +102,7 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - }, - ":*" + } ] ] } diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.github-webhook-batch.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.github-webhook-batch.expected.json index 4cedce9c2a951..81549a1ec5147 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.github-webhook-batch.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.github-webhook-batch.expected.json @@ -49,7 +49,8 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - } + }, + ":*" ] ] }, @@ -72,8 +73,7 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - }, - ":*" + } ] ] } @@ -114,9 +114,9 @@ "Statement": [ { "Action": [ + "codebuild:RetryBuild", "codebuild:StartBuild", - "codebuild:StopBuild", - "codebuild:RetryBuild" + "codebuild:StopBuild" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.github.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.github.expected.json index 1fe01cff9c7b4..162a000a260a3 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.github.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.github.expected.json @@ -49,7 +49,8 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - } + }, + ":*" ] ] }, @@ -72,8 +73,7 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - }, - ":*" + } ] ] } diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-bucket.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.project-bucket.expected.json index 77cc168a3e0d5..026dd626f1f23 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-bucket.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.project-bucket.expected.json @@ -29,8 +29,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -84,7 +84,8 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - } + }, + ":*" ] ] }, @@ -107,8 +108,7 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - }, - ":*" + } ] ] } diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-buildspec-artifacts.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.project-buildspec-artifacts.expected.json index 011e192831fb9..5183f984b8274 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-buildspec-artifacts.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.project-buildspec-artifacts.expected.json @@ -29,16 +29,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -91,7 +91,8 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - } + }, + ":*" ] ] }, @@ -114,8 +115,7 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - }, - ":*" + } ] ] } diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-file-system-location.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.project-file-system-location.expected.json index fc1f6cffd67c6..c34c157a0999a 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-file-system-location.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.project-file-system-location.expected.json @@ -95,15 +95,15 @@ "MyVPCPublicSubnet1NATGateway838228A5": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "MyVPCPublicSubnet1Subnet0C75866A" + }, "AllocationId": { "Fn::GetAtt": [ "MyVPCPublicSubnet1EIP5EB6147D", "AllocationId" ] }, - "SubnetId": { - "Ref": "MyVPCPublicSubnet1Subnet0C75866A" - }, "Tags": [ { "Key": "Name", @@ -316,7 +316,8 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - } + }, + ":*" ] ] }, @@ -339,8 +340,7 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - }, - ":*" + } ] ] } @@ -435,11 +435,11 @@ { "Action": [ "ec2:CreateNetworkInterface", - "ec2:DescribeNetworkInterfaces", "ec2:DeleteNetworkInterface", - "ec2:DescribeSubnets", - "ec2:DescribeSecurityGroups", "ec2:DescribeDhcpOptions", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", "ec2:DescribeVpcs" ], "Effect": "Allow", diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-logging.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.project-logging.expected.json index 03ffa27190981..0f90560191381 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-logging.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.project-logging.expected.json @@ -37,13 +37,13 @@ "Statement": [ { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -109,7 +109,8 @@ ":log-group:/aws/codebuild/", { "Ref": "ProjectC78D97AD" - } + }, + ":*" ] ] }, @@ -132,8 +133,7 @@ ":log-group:/aws/codebuild/", { "Ref": "ProjectC78D97AD" - }, - ":*" + } ] ] } @@ -141,11 +141,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-notification.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.project-notification.expected.json index 829263818ad5f..5a75c6e491764 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-notification.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.project-notification.expected.json @@ -49,7 +49,8 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - } + }, + ":*" ] ] }, @@ -72,8 +73,7 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - }, - ":*" + } ] ] } @@ -81,11 +81,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-secondary-sources-artifacts.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.project-secondary-sources-artifacts.expected.json index f8c74e1af60e6..9b8aff476278c 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-secondary-sources-artifacts.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.project-secondary-sources-artifacts.expected.json @@ -29,8 +29,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -59,16 +59,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -121,7 +121,8 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - } + }, + ":*" ] ] }, @@ -144,8 +145,7 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - }, - ":*" + } ] ] } diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-vpc.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.project-vpc.expected.json index 1d9e5d8d8959f..1ce67e3c882e0 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-vpc.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.project-vpc.expected.json @@ -95,15 +95,15 @@ "MyVPCPublicSubnet1NATGateway838228A5": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "MyVPCPublicSubnet1Subnet0C75866A" + }, "AllocationId": { "Fn::GetAtt": [ "MyVPCPublicSubnet1EIP5EB6147D", "AllocationId" ] }, - "SubnetId": { - "Ref": "MyVPCPublicSubnet1Subnet0C75866A" - }, "Tags": [ { "Key": "Name", @@ -316,7 +316,8 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - } + }, + ":*" ] ] }, @@ -339,8 +340,7 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - }, - ":*" + } ] ] } @@ -415,11 +415,11 @@ { "Action": [ "ec2:CreateNetworkInterface", - "ec2:DescribeNetworkInterfaces", "ec2:DeleteNetworkInterface", - "ec2:DescribeSubnets", - "ec2:DescribeSecurityGroups", "ec2:DescribeDhcpOptions", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", "ec2:DescribeVpcs" ], "Effect": "Allow", diff --git a/packages/@aws-cdk/aws-codebuild/test/linux-arm-build-image.test.ts b/packages/@aws-cdk/aws-codebuild/test/linux-arm-build-image.test.ts new file mode 100644 index 0000000000000..389fbc0529b22 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/linux-arm-build-image.test.ts @@ -0,0 +1,328 @@ +import { Match, Template } from '@aws-cdk/assertions'; +import * as ecr from '@aws-cdk/aws-ecr'; +import * as cdk from '@aws-cdk/core'; +import * as codebuild from '../lib'; + +describe('Linux ARM build image', () => { + describe('AMAZON_LINUX_2_STANDARD_1_0', () => { + test('has type ARM_CONTAINER and default ComputeType LARGE', () => { + const stack = new cdk.Stack(); + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.LinuxArmBuildImage.AMAZON_LINUX_2_STANDARD_1_0, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CodeBuild::Project', { + Environment: { + Type: 'ARM_CONTAINER', + ComputeType: 'BUILD_GENERAL1_LARGE', + }, + }); + }); + + test('can be used with ComputeType SMALL', () => { + const stack = new cdk.Stack(); + new codebuild.PipelineProject(stack, 'Project', { + environment: { + computeType: codebuild.ComputeType.SMALL, + buildImage: codebuild.LinuxArmBuildImage.AMAZON_LINUX_2_STANDARD_1_0, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CodeBuild::Project', { + Environment: { + Type: 'ARM_CONTAINER', + ComputeType: 'BUILD_GENERAL1_SMALL', + }, + }); + }); + + test('cannot be used in conjunction with ComputeType MEDIUM', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.LinuxArmBuildImage.AMAZON_LINUX_2_STANDARD_1_0, + computeType: codebuild.ComputeType.MEDIUM, + }, + }); + }).toThrow(/ARM images only support ComputeTypes 'BUILD_GENERAL1_SMALL' and 'BUILD_GENERAL1_LARGE' - 'BUILD_GENERAL1_MEDIUM' was given/); + }); + + test('can be used with ComputeType LARGE', () => { + const stack = new cdk.Stack(); + new codebuild.PipelineProject(stack, 'Project', { + environment: { + computeType: codebuild.ComputeType.LARGE, + buildImage: codebuild.LinuxArmBuildImage.AMAZON_LINUX_2_STANDARD_1_0, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CodeBuild::Project', { + Environment: { + Type: 'ARM_CONTAINER', + ComputeType: 'BUILD_GENERAL1_LARGE', + }, + }); + }); + + test('cannot be used in conjunction with ComputeType X2_LARGE', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.LinuxArmBuildImage.AMAZON_LINUX_2_STANDARD_1_0, + computeType: codebuild.ComputeType.X2_LARGE, + }, + }); + }).toThrow(/ARM images only support ComputeTypes 'BUILD_GENERAL1_SMALL' and 'BUILD_GENERAL1_LARGE' - 'BUILD_GENERAL1_2XLARGE' was given/); + }); + }); + + describe('AMAZON_LINUX_2_STANDARD_2_0', () => { + test('has type ARM_CONTAINER and default ComputeType LARGE', () => { + const stack = new cdk.Stack(); + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.LinuxArmBuildImage.AMAZON_LINUX_2_STANDARD_2_0, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CodeBuild::Project', { + Environment: { + Type: 'ARM_CONTAINER', + ComputeType: 'BUILD_GENERAL1_LARGE', + }, + }); + }); + + test('can be used with ComputeType SMALL', () => { + const stack = new cdk.Stack(); + new codebuild.PipelineProject(stack, 'Project', { + environment: { + computeType: codebuild.ComputeType.SMALL, + buildImage: codebuild.LinuxArmBuildImage.AMAZON_LINUX_2_STANDARD_2_0, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CodeBuild::Project', { + Environment: { + Type: 'ARM_CONTAINER', + ComputeType: 'BUILD_GENERAL1_SMALL', + }, + }); + }); + + test('cannot be used in conjunction with ComputeType MEDIUM', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.LinuxArmBuildImage.AMAZON_LINUX_2_STANDARD_2_0, + computeType: codebuild.ComputeType.MEDIUM, + }, + }); + }).toThrow(/ARM images only support ComputeTypes 'BUILD_GENERAL1_SMALL' and 'BUILD_GENERAL1_LARGE' - 'BUILD_GENERAL1_MEDIUM' was given/); + }); + + test('can be used with ComputeType LARGE', () => { + const stack = new cdk.Stack(); + new codebuild.PipelineProject(stack, 'Project', { + environment: { + computeType: codebuild.ComputeType.LARGE, + buildImage: codebuild.LinuxArmBuildImage.AMAZON_LINUX_2_STANDARD_2_0, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CodeBuild::Project', { + Environment: { + Type: 'ARM_CONTAINER', + ComputeType: 'BUILD_GENERAL1_LARGE', + }, + }); + }); + + test('cannot be used in conjunction with ComputeType X2_LARGE', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.LinuxArmBuildImage.AMAZON_LINUX_2_STANDARD_2_0, + computeType: codebuild.ComputeType.X2_LARGE, + }, + }); + }).toThrow(/ARM images only support ComputeTypes 'BUILD_GENERAL1_SMALL' and 'BUILD_GENERAL1_LARGE' - 'BUILD_GENERAL1_2XLARGE' was given/); + }); + }); + + describe('ECR Repository', () => { + test('allows creating a build image from a new ECR repository', () => { + const stack = new cdk.Stack(); + + const repository = new ecr.Repository(stack, 'my-repo'); + + new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + phases: { + build: { commands: ['ls'] }, + }, + }), + environment: { + buildImage: codebuild.LinuxArmBuildImage.fromEcrRepository(repository, 'v1'), + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CodeBuild::Project', { + Environment: { + ComputeType: 'BUILD_GENERAL1_LARGE', + Image: { + 'Fn::Join': ['', [ + { + 'Fn::Select': [4, { + 'Fn::Split': [':', { + 'Fn::GetAtt': ['myrepo5DFA62E5', 'Arn'], + }], + }], + }, + '.dkr.ecr.', + { + 'Fn::Select': [3, { + 'Fn::Split': [':', { + 'Fn::GetAtt': ['myrepo5DFA62E5', 'Arn'], + }], + }], + }, + '.', + { Ref: 'AWS::URLSuffix' }, + '/', + { Ref: 'myrepo5DFA62E5' }, + ':v1', + ]], + }, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: Match.arrayWith([Match.objectLike({ + Action: [ + 'ecr:BatchCheckLayerAvailability', + 'ecr:GetDownloadUrlForLayer', + 'ecr:BatchGetImage', + ], + Resource: { + 'Fn::GetAtt': ['myrepo5DFA62E5', 'Arn'], + }, + })]), + }, + }); + }); + + test('allows creating a build image from an existing ECR repository', () => { + const stack = new cdk.Stack(); + + const repository = ecr.Repository.fromRepositoryName(stack, 'my-imported-repo', 'test-repo'); + + new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + phases: { + build: { commands: ['ls'] }, + }, + }), + environment: { + buildImage: codebuild.LinuxArmBuildImage.fromEcrRepository(repository), + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CodeBuild::Project', { + Environment: { + ComputeType: 'BUILD_GENERAL1_LARGE', + Image: { + 'Fn::Join': ['', [ + { Ref: 'AWS::AccountId' }, + '.dkr.ecr.', + { Ref: 'AWS::Region' }, + '.', + { Ref: 'AWS::URLSuffix' }, + '/test-repo:latest', + ]], + }, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: Match.arrayWith([Match.objectLike({ + Action: [ + 'ecr:BatchCheckLayerAvailability', + 'ecr:GetDownloadUrlForLayer', + 'ecr:BatchGetImage', + ], + Resource: { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':ecr:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':repository/test-repo', + ]], + }, + })]), + }, + }); + }); + + test('allows creating a build image from an existing cross-account ECR repository', () => { + const stack = new cdk.Stack(); + + const repository = ecr.Repository.fromRepositoryArn(stack, 'my-cross-acount-repo', 'arn:aws:ecr:us-east-1:585695036304:repository/foo/bar/foo/fooo'); + + new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + phases: { + build: { commands: ['ls'] }, + }, + }), + environment: { + buildImage: codebuild.LinuxArmBuildImage.fromEcrRepository(repository), + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CodeBuild::Project', { + Environment: { + ComputeType: 'BUILD_GENERAL1_LARGE', + Image: { + 'Fn::Join': ['', [ + '585695036304.dkr.ecr.us-east-1.', + { Ref: 'AWS::URLSuffix' }, + '/foo/bar/foo/fooo:latest', + ]], + }, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: Match.arrayWith([Match.objectLike({ + Action: [ + 'ecr:BatchCheckLayerAvailability', + 'ecr:GetDownloadUrlForLayer', + 'ecr:BatchGetImage', + ], + Resource: 'arn:aws:ecr:us-east-1:585695036304:repository/foo/bar/foo/fooo', + })]), + }, + }); + }); + }); +}); diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index 2374b358d9194..108604988db31 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -91,9 +91,9 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "aws-sdk": "^2.848.0", - "jest": "^27.4.7" + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-codestarnotifications": "0.0.0", diff --git a/packages/@aws-cdk/aws-codedeploy/README.md b/packages/@aws-cdk/aws-codedeploy/README.md index 9b6aa5cda5d8d..2608c706022ea 100644 --- a/packages/@aws-cdk/aws-codedeploy/README.md +++ b/packages/@aws-cdk/aws-codedeploy/README.md @@ -207,7 +207,7 @@ To create a new CodeDeploy Deployment Group that deploys to a Lambda function: ```ts declare const myApplication: codedeploy.LambdaApplication; declare const func: lambda.Function; -const version = func.addVersion('1'); +const version = func.currentVersion; const version1Alias = new lambda.Alias(this, 'alias', { aliasName: 'prod', version, @@ -222,7 +222,7 @@ const deploymentGroup = new codedeploy.LambdaDeploymentGroup(this, 'BlueGreenDep In order to deploy a new version of this function: -1. Increment the version, e.g. `const version = func.addVersion('2')`. +1. Reference the version with the latest changes `const version = func.currentVersion`. 2. Re-deploy the stack (this will trigger a deployment). 3. Monitor the CodeDeploy deployment as traffic shifts between the versions. diff --git a/packages/@aws-cdk/aws-codedeploy/package.json b/packages/@aws-cdk/aws-codedeploy/package.json index c251e138255da..ff289e51bbe4c 100644 --- a/packages/@aws-cdk/aws-codedeploy/package.json +++ b/packages/@aws-cdk/aws-codedeploy/package.json @@ -87,8 +87,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", diff --git a/packages/@aws-cdk/aws-codedeploy/test/lambda/deployment-group.test.ts b/packages/@aws-cdk/aws-codedeploy/test/lambda/deployment-group.test.ts index 365a03c4d5d30..c6ecfde1ae2de 100644 --- a/packages/@aws-cdk/aws-codedeploy/test/lambda/deployment-group.test.ts +++ b/packages/@aws-cdk/aws-codedeploy/test/lambda/deployment-group.test.ts @@ -299,12 +299,10 @@ describe('CodeDeploy Lambda DeploymentGroup', () => { PolicyDocument: { Statement: [{ Action: 'lambda:InvokeFunction', - Resource: { - 'Fn::GetAtt': [ - 'PreHook8B53F672', - 'Arn', - ], - }, + Resource: [ + { 'Fn::GetAtt': ['PreHook8B53F672', 'Arn'] }, + { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['PreHook8B53F672', 'Arn'] }, ':*']] }, + ], Effect: 'Allow', }], Version: '2012-10-17', @@ -347,12 +345,10 @@ describe('CodeDeploy Lambda DeploymentGroup', () => { PolicyDocument: { Statement: [{ Action: 'lambda:InvokeFunction', - Resource: { - 'Fn::GetAtt': [ - 'PreHook8B53F672', - 'Arn', - ], - }, + Resource: [ + { 'Fn::GetAtt': ['PreHook8B53F672', 'Arn'] }, + { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['PreHook8B53F672', 'Arn'] }, ':*']] }, + ], Effect: 'Allow', }], Version: '2012-10-17', @@ -395,12 +391,10 @@ describe('CodeDeploy Lambda DeploymentGroup', () => { PolicyDocument: { Statement: [{ Action: 'lambda:InvokeFunction', - Resource: { - 'Fn::GetAtt': [ - 'PostHookF2E49B30', - 'Arn', - ], - }, + Resource: [ + { 'Fn::GetAtt': ['PostHookF2E49B30', 'Arn'] }, + { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['PostHookF2E49B30', 'Arn'] }, ':*']] }, + ], Effect: 'Allow', }], Version: '2012-10-17', @@ -443,12 +437,10 @@ describe('CodeDeploy Lambda DeploymentGroup', () => { PolicyDocument: { Statement: [{ Action: 'lambda:InvokeFunction', - Resource: { - 'Fn::GetAtt': [ - 'PostHookF2E49B30', - 'Arn', - ], - }, + Resource: [ + { 'Fn::GetAtt': ['PostHookF2E49B30', 'Arn'] }, + { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['PostHookF2E49B30', 'Arn'] }, ':*']] }, + ], Effect: 'Allow', }], Version: '2012-10-17', diff --git a/packages/@aws-cdk/aws-codedeploy/test/lambda/integ.deployment-group.expected.json b/packages/@aws-cdk/aws-codedeploy/test/lambda/integ.deployment-group.expected.json index 2d9262dcf3212..e9b096abe09f9 100644 --- a/packages/@aws-cdk/aws-codedeploy/test/lambda/integ.deployment-group.expected.json +++ b/packages/@aws-cdk/aws-codedeploy/test/lambda/integ.deployment-group.expected.json @@ -72,13 +72,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "HandlerServiceRoleFCDC14AE", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -243,13 +243,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "PreHookServiceRoleC724B9BA", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -376,13 +376,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "PostHookServiceRoleE8A6AAC2", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -483,22 +483,48 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PreHook8B53F672", - "Arn" - ] - } - }, - { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PostHookF2E49B30", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "PostHookF2E49B30", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PreHook8B53F672", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PostHookF2E49B30", + "Arn" + ] + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PreHook8B53F672", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -586,4 +612,4 @@ "Description": "Artifact hash for asset \"93dbd8c02dbfca9077c9d83cb6d3a94659988c7d143988da4a554033a58f963c\"" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codedeploy/test/server/integ.deployment-group.expected.json b/packages/@aws-cdk/aws-codedeploy/test/server/integ.deployment-group.expected.json index c5ae20b9ac145..fc56b0069796a 100644 --- a/packages/@aws-cdk/aws-codedeploy/test/server/integ.deployment-group.expected.json +++ b/packages/@aws-cdk/aws-codedeploy/test/server/integ.deployment-group.expected.json @@ -95,15 +95,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VPCPublicSubnet2NATGateway3C070193": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "Tags": [ { "Key": "Name", @@ -289,15 +289,15 @@ "VPCPublicSubnet3NATGatewayD3048F5C": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet3EIPAD4BC883", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - }, "Tags": [ { "Key": "Name", @@ -576,8 +576,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -593,7 +593,8 @@ ":s3:::aws-codedeploy-", { "Ref": "AWS::Region" - } + }, + "/latest/*" ] ] }, @@ -608,8 +609,7 @@ ":s3:::aws-codedeploy-", { "Ref": "AWS::Region" - }, - "/latest/*" + } ] ] } diff --git a/packages/@aws-cdk/aws-codeguruprofiler/package.json b/packages/@aws-cdk/aws-codeguruprofiler/package.json index e0ca94e657487..65ab5a7d206dc 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/package.json +++ b/packages/@aws-cdk/aws-codeguruprofiler/package.json @@ -86,7 +86,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-codeguruprofiler/test/integ.profiler-group.expected.json b/packages/@aws-cdk/aws-codeguruprofiler/test/integ.profiler-group.expected.json index 8ea1221f6bbe8..3fed466911a4f 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/test/integ.profiler-group.expected.json +++ b/packages/@aws-cdk/aws-codeguruprofiler/test/integ.profiler-group.expected.json @@ -106,8 +106,8 @@ "Statement": [ { "Action": [ - "codeguru-profiler:GetProfile", - "codeguru-profiler:DescribeProfilingGroup" + "codeguru-profiler:DescribeProfilingGroup", + "codeguru-profiler:GetProfile" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-codegurureviewer/package.json b/packages/@aws-cdk/aws-codegurureviewer/package.json index 6c72bd475e6ed..e0e2d1748e1ae 100644 --- a/packages/@aws-cdk/aws-codegurureviewer/package.json +++ b/packages/@aws-cdk/aws-codegurureviewer/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-codepipeline-actions/README.md b/packages/@aws-cdk/aws-codepipeline-actions/README.md index ff43850561651..c616cecd2302e 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/README.md +++ b/packages/@aws-cdk/aws-codepipeline-actions/README.md @@ -607,7 +607,7 @@ directly from a CodeCommit repository, with a manual approval step in between to See [the AWS documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline.html) for more details about using CloudFormation in CodePipeline. -#### Actions defined by this package +#### Actions for updating individual CloudFormation Stacks This package contains the following CloudFormation actions: @@ -620,6 +620,57 @@ This package contains the following CloudFormation actions: changes from the people (or system) applying the changes. * **CloudFormationExecuteChangeSetAction** - Execute a change set prepared previously. +#### Actions for deploying CloudFormation StackSets to multiple accounts + +You can use CloudFormation StackSets to deploy the same CloudFormation template to multiple +accounts in a managed way. If you use AWS Organizations, StackSets can be deployed to +all accounts in a particular Organizational Unit (OU), and even automatically to new +accounts as soon as they are added to a particular OU. For more information, see +the [Working with StackSets](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/what-is-cfnstacksets.html) +section of the CloudFormation developer guide. + +The actions available for updating StackSets are: + +* **CloudFormationDeployStackSetAction** - Create or update a CloudFormation StackSet directly from the pipeline, optionally + immediately create and update Stack Instances as well. +* **CloudFormationDeployStackInstancesAction** - Update outdated Stack Instaces using the current version of the StackSet. + +Here's an example of using both of these actions: + +```ts +declare const pipeline: codepipeline.Pipeline; +declare const sourceOutput: codepipeline.Artifact; + +pipeline.addStage({ + stageName: 'DeployStackSets', + actions: [ + // First, update the StackSet itself with the newest template + new codepipeline_actions.CloudFormationDeployStackSetAction({ + actionName: 'UpdateStackSet', + runOrder: 1, + stackSetName: 'MyStackSet', + template: codepipeline_actions.StackSetTemplate.fromArtifactPath(sourceOutput.atPath('template.yaml')), + + // Change this to 'StackSetDeploymentModel.organizations()' if you want to deploy to OUs + deploymentModel: codepipeline_actions.StackSetDeploymentModel.selfManaged(), + // This deploys to a set of accounts + stackInstances: codepipeline_actions.StackInstances.inAccounts(['111111111111'], ['us-east-1', 'eu-west-1']), + }), + + // Afterwards, update/create additional instances in other accounts + new codepipeline_actions.CloudFormationDeployStackInstancesAction({ + actionName: 'AddMoreInstances', + runOrder: 2, + stackSetName: 'MyStackSet', + stackInstances: codepipeline_actions.StackInstances.inAccounts( + ['222222222222', '333333333333'], + ['us-east-1', 'eu-west-1'] + ), + }), + ], +}); +``` + #### Lambda deployed through CodePipeline If you want to deploy your Lambda through CodePipeline, @@ -714,7 +765,7 @@ const func = new lambda.Function(this, 'Lambda', { runtime: lambda.Runtime.NODEJS_12_X, }); // used to make sure each CDK synthesis produces a different Version -const version = func.addVersion('NewVersion'); +const version = func.currentVersion; const alias = new lambda.Alias(this, 'LambdaAlias', { aliasName: 'Prod', version, @@ -792,7 +843,7 @@ const deployStage = pipeline.addStage({ ``` When deploying across accounts, especially in a CDK Pipelines self-mutating pipeline, -it is recommended to provide the `role` property to the `EcsDeployAction`. +it is recommended to provide the `role` property to the `EcsDeployAction`. The Role will need to have permissions assigned to it for ECS deployment. See [the CodePipeline documentation](https://docs.aws.amazon.com/codepipeline/latest/userguide/how-to-custom-role.html#how-to-update-role-new-services) for the permissions needed. diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/index.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/index.ts new file mode 100644 index 0000000000000..413b0eccf60f5 --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/index.ts @@ -0,0 +1,4 @@ +export * from './pipeline-actions'; +export * from './stackset-action'; +export * from './stackinstances-action'; +export * from './stackset-types'; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts index 63618e086ed91..23f8185cd9c3b 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts @@ -3,6 +3,7 @@ import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import { Action } from '../action'; +import { parseCapabilities, SingletonPolicy } from './private/singleton-policy'; // keep this import separate from other imports to reduce chance for merge conflicts with v2-main // eslint-disable-next-line no-duplicate-imports, import/order @@ -512,148 +513,3 @@ export class CloudFormationDeleteStackAction extends CloudFormationDeployAction }; } } - -/** - * Manages a bunch of singleton-y statements on the policy of an IAM Role. - * Dedicated methods can be used to add specific permissions to the role policy - * using as few statements as possible (adding resources to existing compatible - * statements instead of adding new statements whenever possible). - * - * Statements created outside of this class are not considered when adding new - * permissions. - */ -class SingletonPolicy extends Construct implements iam.IGrantable { - /** - * Obtain a SingletonPolicy for a given role. - * @param role the Role this policy is bound to. - * @returns the SingletonPolicy for this role. - */ - public static forRole(role: iam.IRole): SingletonPolicy { - const found = role.node.tryFindChild(SingletonPolicy.UUID); - return (found as SingletonPolicy) || new SingletonPolicy(role); - } - - private static readonly UUID = '8389e75f-0810-4838-bf64-d6f85a95cf83'; - - public readonly grantPrincipal: iam.IPrincipal; - - private statements: { [key: string]: iam.PolicyStatement } = {}; - - private constructor(private readonly role: iam.IRole) { - super(role as unknown as cdk.Construct, SingletonPolicy.UUID); - this.grantPrincipal = role; - } - - public grantExecuteChangeSet(props: { stackName: string, changeSetName: string, region?: string }): void { - this.statementFor({ - actions: [ - 'cloudformation:DescribeStacks', - 'cloudformation:DescribeChangeSet', - 'cloudformation:ExecuteChangeSet', - ], - conditions: { StringEqualsIfExists: { 'cloudformation:ChangeSetName': props.changeSetName } }, - }).addResources(this.stackArnFromProps(props)); - } - - public grantCreateReplaceChangeSet(props: { stackName: string, changeSetName: string, region?: string }): void { - this.statementFor({ - actions: [ - 'cloudformation:CreateChangeSet', - 'cloudformation:DeleteChangeSet', - 'cloudformation:DescribeChangeSet', - 'cloudformation:DescribeStacks', - ], - conditions: { StringEqualsIfExists: { 'cloudformation:ChangeSetName': props.changeSetName } }, - }).addResources(this.stackArnFromProps(props)); - } - - public grantCreateUpdateStack(props: { stackName: string, replaceOnFailure?: boolean, region?: string }): void { - const actions = [ - 'cloudformation:DescribeStack*', - 'cloudformation:CreateStack', - 'cloudformation:UpdateStack', - 'cloudformation:GetTemplate*', - 'cloudformation:ValidateTemplate', - 'cloudformation:GetStackPolicy', - 'cloudformation:SetStackPolicy', - ]; - if (props.replaceOnFailure) { - actions.push('cloudformation:DeleteStack'); - } - this.statementFor({ actions }).addResources(this.stackArnFromProps(props)); - } - - public grantDeleteStack(props: { stackName: string, region?: string }): void { - this.statementFor({ - actions: [ - 'cloudformation:DescribeStack*', - 'cloudformation:DeleteStack', - ], - }).addResources(this.stackArnFromProps(props)); - } - - public grantPassRole(role: iam.IRole): void { - this.statementFor({ actions: ['iam:PassRole'] }).addResources(role.roleArn); - } - - private statementFor(template: StatementTemplate): iam.PolicyStatement { - const key = keyFor(template); - if (!(key in this.statements)) { - this.statements[key] = new iam.PolicyStatement({ actions: template.actions }); - if (template.conditions) { - this.statements[key].addConditions(template.conditions); - } - this.role.addToPolicy(this.statements[key]); - } - return this.statements[key]; - - function keyFor(props: StatementTemplate): string { - const actions = `${props.actions.sort().join('\x1F')}`; - const conditions = formatConditions(props.conditions); - return `${actions}\x1D${conditions}`; - - function formatConditions(cond?: StatementCondition): string { - if (cond == null) { return ''; } - let result = ''; - for (const op of Object.keys(cond).sort()) { - result += `${op}\x1E`; - const condition = cond[op]; - for (const attribute of Object.keys(condition).sort()) { - const value = condition[attribute]; - result += `${value}\x1F`; - } - } - return result; - } - } - } - - private stackArnFromProps(props: { stackName: string, region?: string }): string { - return cdk.Stack.of(this).formatArn({ - region: props.region, - service: 'cloudformation', - resource: 'stack', - resourceName: `${props.stackName}/*`, - }); - } -} - -interface StatementTemplate { - actions: string[]; - conditions?: StatementCondition; -} - -type StatementCondition = { [op: string]: { [attribute: string]: string } }; - -function parseCapabilities(capabilities: cdk.CfnCapabilities[] | undefined): string | undefined { - if (capabilities === undefined) { - return undefined; - } else if (capabilities.length === 1) { - const capability = capabilities.toString(); - return (capability === '') ? undefined : capability; - } else if (capabilities.length > 1) { - return capabilities.join(','); - } - - return undefined; -} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/private/singleton-policy.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/private/singleton-policy.ts new file mode 100644 index 0000000000000..7a9a3efdde784 --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/private/singleton-policy.ts @@ -0,0 +1,172 @@ +import * as iam from '@aws-cdk/aws-iam'; +import * as cdk from '@aws-cdk/core'; + +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order +import { Construct } from '@aws-cdk/core'; + +/** + * Manages a bunch of singleton-y statements on the policy of an IAM Role. + * Dedicated methods can be used to add specific permissions to the role policy + * using as few statements as possible (adding resources to existing compatible + * statements instead of adding new statements whenever possible). + * + * Statements created outside of this class are not considered when adding new + * permissions. + */ +export class SingletonPolicy extends Construct implements iam.IGrantable { + /** + * Obtain a SingletonPolicy for a given role. + * @param role the Role this policy is bound to. + * @returns the SingletonPolicy for this role. + */ + public static forRole(role: iam.IRole): SingletonPolicy { + const found = role.node.tryFindChild(SingletonPolicy.UUID); + return (found as SingletonPolicy) || new SingletonPolicy(role); + } + + private static readonly UUID = '8389e75f-0810-4838-bf64-d6f85a95cf83'; + + public readonly grantPrincipal: iam.IPrincipal; + + private statements: { [key: string]: iam.PolicyStatement } = {}; + + private constructor(private readonly role: iam.IRole) { + super(role as unknown as Construct, SingletonPolicy.UUID); + this.grantPrincipal = role; + } + + public grantExecuteChangeSet(props: { stackName: string, changeSetName: string, region?: string }): void { + this.statementFor({ + actions: [ + 'cloudformation:DescribeStacks', + 'cloudformation:DescribeChangeSet', + 'cloudformation:ExecuteChangeSet', + ], + conditions: { StringEqualsIfExists: { 'cloudformation:ChangeSetName': props.changeSetName } }, + }).addResources(this.stackArnFromProps(props)); + } + + public grantCreateReplaceChangeSet(props: { stackName: string, changeSetName: string, region?: string }): void { + this.statementFor({ + actions: [ + 'cloudformation:CreateChangeSet', + 'cloudformation:DeleteChangeSet', + 'cloudformation:DescribeChangeSet', + 'cloudformation:DescribeStacks', + ], + conditions: { StringEqualsIfExists: { 'cloudformation:ChangeSetName': props.changeSetName } }, + }).addResources(this.stackArnFromProps(props)); + } + + public grantCreateUpdateStack(props: { stackName: string, replaceOnFailure?: boolean, region?: string }): void { + const actions = [ + 'cloudformation:DescribeStack*', + 'cloudformation:CreateStack', + 'cloudformation:UpdateStack', + 'cloudformation:GetTemplate*', + 'cloudformation:ValidateTemplate', + 'cloudformation:GetStackPolicy', + 'cloudformation:SetStackPolicy', + ]; + if (props.replaceOnFailure) { + actions.push('cloudformation:DeleteStack'); + } + this.statementFor({ actions }).addResources(this.stackArnFromProps(props)); + } + + public grantCreateUpdateStackSet(props: { stackSetName: string, region?: string }): void { + const actions = [ + 'cloudformation:CreateStackSet', + 'cloudformation:UpdateStackSet', + 'cloudformation:DescribeStackSet', + 'cloudformation:DescribeStackSetOperation', + 'cloudformation:ListStackInstances', + 'cloudformation:CreateStackInstances', + ]; + this.statementFor({ actions }).addResources(this.stackSetArnFromProps(props)); + } + + public grantDeleteStack(props: { stackName: string, region?: string }): void { + this.statementFor({ + actions: [ + 'cloudformation:DescribeStack*', + 'cloudformation:DeleteStack', + ], + }).addResources(this.stackArnFromProps(props)); + } + + public grantPassRole(role: iam.IRole | string): void { + this.statementFor({ actions: ['iam:PassRole'] }).addResources(typeof role === 'string' ? role : role.roleArn); + } + + private statementFor(template: StatementTemplate): iam.PolicyStatement { + const key = keyFor(template); + if (!(key in this.statements)) { + this.statements[key] = new iam.PolicyStatement({ actions: template.actions }); + if (template.conditions) { + this.statements[key].addConditions(template.conditions); + } + this.role.addToPolicy(this.statements[key]); + } + return this.statements[key]; + + function keyFor(props: StatementTemplate): string { + const actions = `${props.actions.sort().join('\x1F')}`; + const conditions = formatConditions(props.conditions); + return `${actions}\x1D${conditions}`; + + function formatConditions(cond?: StatementCondition): string { + if (cond == null) { return ''; } + let result = ''; + for (const op of Object.keys(cond).sort()) { + result += `${op}\x1E`; + const condition = cond[op]; + for (const attribute of Object.keys(condition).sort()) { + const value = condition[attribute]; + result += `${value}\x1F`; + } + } + return result; + } + } + } + + private stackArnFromProps(props: { stackName: string, region?: string }): string { + return cdk.Stack.of(this).formatArn({ + region: props.region, + service: 'cloudformation', + resource: 'stack', + resourceName: `${props.stackName}/*`, + }); + } + + private stackSetArnFromProps(props: { stackSetName: string, region?: string }): string { + return cdk.Stack.of(this).formatArn({ + region: props.region, + service: 'cloudformation', + resource: 'stackset', + resourceName: `${props.stackSetName}:*`, + }); + } +} + +export interface StatementTemplate { + actions: string[]; + conditions?: StatementCondition; +} + +export type StatementCondition = { [op: string]: { [attribute: string]: string } }; + +export function parseCapabilities(capabilities: cdk.CfnCapabilities[] | undefined): string | undefined { + if (capabilities === undefined) { + return undefined; + } else if (capabilities.length === 1) { + const capability = capabilities.toString(); + return (capability === '') ? undefined : capability; + } else if (capabilities.length > 1) { + return capabilities.join(','); + } + + return undefined; +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/stackinstances-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/stackinstances-action.ts new file mode 100644 index 0000000000000..e0ddf6c9c1cb6 --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/stackinstances-action.ts @@ -0,0 +1,97 @@ +import * as codepipeline from '@aws-cdk/aws-codepipeline'; +import { Action } from '../action'; +import { validatePercentage } from '../common'; +import { SingletonPolicy } from './private/singleton-policy'; +import { CommonCloudFormationStackSetOptions, StackInstances, StackSetParameters } from './stackset-types'; + +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order +import { Construct as CoreConstruct } from '@aws-cdk/core'; + +/** + * Properties for the CloudFormationDeployStackInstancesAction + */ +export interface CloudFormationDeployStackInstancesActionProps extends codepipeline.CommonAwsActionProps, CommonCloudFormationStackSetOptions { + /** + * The name of the StackSet we are adding instances to + */ + readonly stackSetName: string; + + /** + * Specify where to create or update Stack Instances + * + * You can specify either AWS Accounts Ids or AWS Organizations Organizational Units. + */ + readonly stackInstances: StackInstances; + + /** + * Parameter values that only apply to the current Stack Instances + * + * These parameters are shared between all instances added by this action. + * + * @default - no parameters will be overridden + */ + readonly parameterOverrides?: StackSetParameters; +} + +/** + * CodePipeline action to create/update Stack Instances of a StackSet + * + * After the initial creation of a stack set, you can add new stack instances by + * using CloudFormationStackInstances. Template parameter values can be + * overridden at the stack instance level during create or update stack set + * instance operations. + * + * Each stack set has one template and set of template parameters. When you + * update the template or template parameters, you update them for the entire + * set. Then all instance statuses are set to OUTDATED until the changes are + * deployed to that instance. + */ +export class CloudFormationDeployStackInstancesAction extends Action { + private readonly props: CloudFormationDeployStackInstancesActionProps; + + constructor(props: CloudFormationDeployStackInstancesActionProps) { + super({ + ...props, + region: props.stackSetRegion, + provider: 'CloudFormationStackInstances', + category: codepipeline.ActionCategory.DEPLOY, + artifactBounds: { + minInputs: 0, + maxInputs: 3, + minOutputs: 0, + maxOutputs: 0, + }, + inputs: [ + ...props.parameterOverrides?._artifactsReferenced ?? [], + ...props.stackInstances?._artifactsReferenced ?? [], + ], + }); + + this.props = props; + + validatePercentage('failureTolerancePercentage', props.failureTolerancePercentage); + validatePercentage('maxAccountConcurrencyPercentage', props.maxAccountConcurrencyPercentage); + } + + protected bound(scope: CoreConstruct, _stage: codepipeline.IStage, options: codepipeline.ActionBindOptions): codepipeline.ActionConfig { + const singletonPolicy = SingletonPolicy.forRole(options.role); + singletonPolicy.grantCreateUpdateStackSet(this.props); + + const instancesResult = this.props.stackInstances?._bind(scope); + + if ((this.actionProperties.inputs || []).length > 0) { + options.bucket.grantRead(singletonPolicy); + } + + return { + configuration: { + StackSetName: this.props.stackSetName, + ParameterOverrides: this.props.parameterOverrides?._render(), + FailureTolerancePercentage: this.props.failureTolerancePercentage, + MaxConcurrentPercentage: this.props.maxAccountConcurrencyPercentage, + ...instancesResult?.stackSetConfiguration, + }, + }; + } +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/stackset-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/stackset-action.ts new file mode 100644 index 0000000000000..574e69f86a96c --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/stackset-action.ts @@ -0,0 +1,174 @@ +import * as codepipeline from '@aws-cdk/aws-codepipeline'; +import * as cdk from '@aws-cdk/core'; +import { Action } from '../action'; +import { validatePercentage } from '../common'; +import { parseCapabilities, SingletonPolicy } from './private/singleton-policy'; +import { CommonCloudFormationStackSetOptions, StackInstances, StackSetDeploymentModel, StackSetParameters, StackSetTemplate } from './stackset-types'; + +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order +import { Construct as CoreConstruct } from '@aws-cdk/core'; + +/** + * Properties for the CloudFormationDeployStackSetAction + */ +export interface CloudFormationDeployStackSetActionProps extends codepipeline.CommonAwsActionProps, CommonCloudFormationStackSetOptions { + /** + * The name to associate with the stack set. This name must be unique in the Region where it is created. + * + * The name may only contain alphanumeric and hyphen characters. It must begin with an alphabetic character and be 128 characters or fewer. + */ + readonly stackSetName: string; + + /** + * The location of the template that defines the resources in the stack set. + * This must point to a template with a maximum size of 460,800 bytes. + * + * Enter the path to the source artifact name and template file. + */ + readonly template: StackSetTemplate; + + /** + * A description of the stack set. You can use this to describe the stack set’s purpose or other relevant information. + * + * @default - no description + */ + readonly description?: string; + + /** + * Specify where to create or update Stack Instances + * + * You can specify either AWS Accounts Ids or AWS Organizations Organizational Units. + * + * @default - don't create or update any Stack Instances + */ + readonly stackInstances?: StackInstances; + + /** + * Determines how IAM roles are created and managed. + * + * The choices are: + * + * - Self Managed: you create IAM roles with the required permissions + * in the administration account and all target accounts. + * - Service Managed: only available if the account and target accounts + * are part of an AWS Organization. The necessary roles will be created + * for you. + * + * If you want to deploy to all accounts that are a member of AWS + * Organizations Organizational Units (OUs), you must select Service Managed + * permissions. + * + * Note: This parameter can only be changed when no stack instances exist in + * the stack set. + * + * @default StackSetDeploymentModel.selfManaged() + */ + readonly deploymentModel?: StackSetDeploymentModel; + + /** + * The template parameters for your stack set + * + * These parameters are shared between all instances of the stack set. + * + * @default - no parameters will be used + */ + readonly parameters?: StackSetParameters; + + /** + * Indicates that the template can create and update resources, depending on the types of resources in the template. + * + * You must use this property if you have IAM resources in your stack template or you create a stack directly from a template containing macros. + * + * @default - the StackSet will have no IAM capabilities + */ + readonly cfnCapabilities?: cdk.CfnCapabilities[]; +} + +/** + * CodePipeline action to deploy a stackset. + * + * CodePipeline offers the ability to perform AWS CloudFormation StackSets + * operations as part of your CI/CD process. You use a stack set to create + * stacks in AWS accounts across AWS Regions by using a single AWS + * CloudFormation template. All the resources included in each stack are defined + * by the stack set’s AWS CloudFormation template. When you create the stack + * set, you specify the template to use, as well as any parameters and + * capabilities that the template requires. + * + * For more information about concepts for AWS CloudFormation StackSets, see + * [StackSets + * concepts](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-concepts.html) + * in the AWS CloudFormation User Guide. + * + * If you use this action to make an update that includes adding stack + * instances, the new instances are deployed first and the update is completed + * last. The new instances first receive the old version, and then the update is + * applied to all instances. + * + * As a best practice, you should construct your pipeline so that the stack set + * is created and initially deploys to a subset or a single instance. After you + * test your deployment and view the generated stack set, then add the + * CloudFormationStackInstances action so that the remaining instances are + * created and updated. + */ +export class CloudFormationDeployStackSetAction extends Action { + private readonly props: CloudFormationDeployStackSetActionProps; + private readonly deploymentModel: StackSetDeploymentModel; + + constructor(props: CloudFormationDeployStackSetActionProps) { + super({ + ...props, + region: props.stackSetRegion, + provider: 'CloudFormationStackSet', + category: codepipeline.ActionCategory.DEPLOY, + artifactBounds: { + minInputs: 1, + maxInputs: 3, + minOutputs: 0, + maxOutputs: 0, + }, + inputs: [ + ...props.template._artifactsReferenced ?? [], + ...props.parameters?._artifactsReferenced ?? [], + ...props.stackInstances?._artifactsReferenced ?? [], + ], + }); + + this.props = props; + this.deploymentModel = props.deploymentModel ?? StackSetDeploymentModel.selfManaged(); + + validatePercentage('failureTolerancePercentage', props.failureTolerancePercentage); + validatePercentage('maxAccountConcurrencyPercentage', props.maxAccountConcurrencyPercentage); + } + + protected bound(scope: CoreConstruct, _stage: codepipeline.IStage, options: codepipeline.ActionBindOptions): codepipeline.ActionConfig { + const singletonPolicy = SingletonPolicy.forRole(options.role); + singletonPolicy.grantCreateUpdateStackSet(this.props); + + const instancesResult = this.props.stackInstances?._bind(scope); + const permissionModelBind = this.deploymentModel?._bind(scope); + + for (const role of permissionModelBind?.passedRoles ?? []) { + singletonPolicy.grantPassRole(role); + } + + if ((this.actionProperties.inputs || []).length > 0) { + options.bucket.grantRead(singletonPolicy); + } + + return { + configuration: { + StackSetName: this.props.stackSetName, + Description: this.props.description, + TemplatePath: this.props.template._render(), + Parameters: this.props.parameters?._render(), + Capabilities: parseCapabilities(this.props.cfnCapabilities), + FailureTolerancePercentage: this.props.failureTolerancePercentage, + MaxConcurrentPercentage: this.props.maxAccountConcurrencyPercentage, + ...instancesResult?.stackSetConfiguration, + ...permissionModelBind?.stackSetConfiguration, + }, + }; + } +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/stackset-types.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/stackset-types.ts new file mode 100644 index 0000000000000..319d96d732997 --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/stackset-types.ts @@ -0,0 +1,511 @@ +import * as codepipeline from '@aws-cdk/aws-codepipeline'; +import * as iam from '@aws-cdk/aws-iam'; +import * as cdk from '@aws-cdk/core'; +import { Construct } from 'constructs'; + +/** + * Options in common between both StackSet actions + */ +export interface CommonCloudFormationStackSetOptions { + + /** + * The percentage of accounts per Region for which this stack operation can fail before AWS CloudFormation stops the operation in that Region. If + * the operation is stopped in a Region, AWS CloudFormation doesn't attempt the operation in subsequent Regions. When calculating the number + * of accounts based on the specified percentage, AWS CloudFormation rounds down to the next whole number. + * + * @default 0% + */ + readonly failureTolerancePercentage?: number; + + /** + * The maximum percentage of accounts in which to perform this operation at one time. When calculating the number of accounts based on the specified + * percentage, AWS CloudFormation rounds down to the next whole number. If rounding down would result in zero, AWS CloudFormation sets the number as + * one instead. Although you use this setting to specify the maximum, for large deployments the actual number of accounts acted upon concurrently + * may be lower due to service throttling. + * + * @default 1% + */ + readonly maxAccountConcurrencyPercentage?: number; + + /** + * The AWS Region the StackSet is in. + * + * Note that a cross-region Pipeline requires replication buckets to function correctly. + * You can provide their names with the `PipelineProps.crossRegionReplicationBuckets` property. + * If you don't, the CodePipeline Construct will create new Stacks in your CDK app containing those buckets, + * that you will need to `cdk deploy` before deploying the main, Pipeline-containing Stack. + * + * @default - same region as the Pipeline + */ + readonly stackSetRegion?: string; +} + +/** + * The source of a StackSet template + */ +export abstract class StackSetTemplate { + /** + * Use a file in an artifact as Stack Template. + */ + public static fromArtifactPath(artifactPath: codepipeline.ArtifactPath): StackSetTemplate { + return new class extends StackSetTemplate { + public readonly _artifactsReferenced?: codepipeline.Artifact[] | undefined = [artifactPath.artifact]; + + public _render() { + return artifactPath.location; + } + }(); + } + + /** + * Which artifacts are referenced by this template + * + * Does not need to be called by app builders. + * + * @internal + */ + public abstract readonly _artifactsReferenced?: codepipeline.Artifact[] | undefined; + + /** + * Render the template to the pipeline + * + * Does not need to be called by app builders. + * + * @internal + */ + public abstract _render(): any; +} + +/** + * Where Stack Instances will be created from the StackSet + */ +export abstract class StackInstances { + /** + * Create stack instances in a set of accounts and regions passed as literal lists + * + * Stack Instances will be created in every combination of region and account. + * + * > NOTE: `StackInstances.inAccounts()` and `StackInstances.inOrganizationalUnits()` + * > have exactly the same behavior, and you can use them interchangeably if you want. + * > The only difference between them is that your code clearly indicates what entity + * > it's working with. + */ + public static inAccounts(accounts: string[], regions: string[]): StackInstances { + return StackInstances.fromList(accounts, regions); + } + + /** + * Create stack instances in all accounts in a set of Organizational Units (OUs) and regions passed as literal lists + * + * If you want to deploy to Organization Units, you must choose have created the StackSet + * with `deploymentModel: DeploymentModel.organizations()`. + * + * Stack Instances will be created in every combination of region and account. + * + * > NOTE: `StackInstances.inAccounts()` and `StackInstances.inOrganizationalUnits()` + * > have exactly the same behavior, and you can use them interchangeably if you want. + * > The only difference between them is that your code clearly indicates what entity + * > it's working with. + */ + public static inOrganizationalUnits(ous: string[], regions: string[]): StackInstances { + return StackInstances.fromList(ous, regions); + } + + /** + * Create stack instances in a set of accounts or organizational units taken from the pipeline artifacts, and a set of regions + * + * The file must be a JSON file containing a list of strings. For example: + * + * ```json + * [ + * "111111111111", + * "222222222222", + * "333333333333" + * ] + * ``` + * + * Stack Instances will be created in every combination of region and account, or region and + * Organizational Units (OUs). + * + * If this is set of Organizational Units, you must have selected `StackSetDeploymentModel.organizations()` + * as deployment model. + */ + public static fromArtifactPath(artifactPath: codepipeline.ArtifactPath, regions: string[]): StackInstances { + if (regions.length === 0) { + throw new Error("'regions' may not be an empty list"); + } + + return new class extends StackInstances { + public readonly _artifactsReferenced?: codepipeline.Artifact[] | undefined = [artifactPath.artifact]; + public _bind(_scope: Construct): StackInstancesBindResult { + return { + stackSetConfiguration: { + DeploymentTargets: artifactPath.location, + Regions: regions.join(','), + }, + }; + } + }(); + } + + /** + * Create stack instances in a literal set of accounts or organizational units, and a set of regions + * + * Stack Instances will be created in every combination of region and account, or region and + * Organizational Units (OUs). + * + * If this is set of Organizational Units, you must have selected `StackSetDeploymentModel.organizations()` + * as deployment model. + */ + private static fromList(targets: string[], regions: string[]): StackInstances { + if (targets.length === 0) { + throw new Error("'targets' may not be an empty list"); + } + + if (regions.length === 0) { + throw new Error("'regions' may not be an empty list"); + } + + return new class extends StackInstances { + public _bind(_scope: Construct): StackInstancesBindResult { + return { + stackSetConfiguration: { + DeploymentTargets: targets.join(','), + Regions: regions.join(','), + }, + }; + } + }(); + } + + + /** + * The artifacts referenced by the properties of this deployment target + * + * Does not need to be called by app builders. + * + * @internal + */ + readonly _artifactsReferenced?: codepipeline.Artifact[]; + + /** + * Called to attach the stack set instances to a stackset action + * + * Does not need to be called by app builders. + * + * @internal + */ + public abstract _bind(scope: Construct): StackInstancesBindResult; +} + +/** + * Returned by the StackInstances.bind() function + * + * Does not need to be used by app builders. + * + * @internal + */ +export interface StackInstancesBindResult { + /** + * Properties to mix into the Action configuration + */ + readonly stackSetConfiguration: any; +} + +/** + * Base parameters for the StackSet + */ +export abstract class StackSetParameters { + /** + * A list of template parameters for your stack set. + * + * You must specify all template parameters. Parameters you don't specify will revert + * to their `Default` values as specified in the template. + * + * Specify the names of parameters you want to retain their existing values, + * without specifying what those values are, in an array in the second + * argument to this function. Use of this feature is discouraged. CDK is for + * specifying desired-state infrastructure, and use of this feature makes the + * parameter values unmanaged. + * + * @example + * + * const parameters = codepipeline_actions.StackSetParameters.fromLiteral({ + * BucketName: 'my-bucket', + * Asset1: 'true', + * }); + */ + public static fromLiteral(parameters: Record, usePreviousValues?: string[]): StackSetParameters { + return new class extends StackSetParameters { + public readonly _artifactsReferenced: codepipeline.Artifact[] = []; + + _render(): string { + return [ + ...Object.entries(parameters).map(([key, value]) => + `ParameterKey=${key},ParameterValue=${value}`), + ...(usePreviousValues ?? []).map((key) => + `ParameterKey=${key},UsePreviousValue=true`), + ].join(' '); + } + }(); + } + + /** + * Read the parameters from a JSON file from one of the pipeline's artifacts + * + * The file needs to contain a list of `{ ParameterKey, ParameterValue, UsePreviousValue }` objects, like + * this: + * + * ``` + * [ + * { + * "ParameterKey": "BucketName", + * "ParameterValue": "my-bucket" + * }, + * { + * "ParameterKey": "Asset1", + * "ParameterValue": "true" + * }, + * { + * "ParameterKey": "Asset2", + * "UsePreviousValue": true + * } + * ] + * ``` + * + * You must specify all template parameters. Parameters you don't specify will revert + * to their `Default` values as specified in the template. + * + * For of parameters you want to retain their existing values + * without specifying what those values are, set `UsePreviousValue: true`. + * Use of this feature is discouraged. CDK is for + * specifying desired-state infrastructure, and use of this feature makes the + * parameter values unmanaged. + */ + public static fromArtifactPath(artifactPath: codepipeline.ArtifactPath): StackSetParameters { + return new class extends StackSetParameters { + public _artifactsReferenced: codepipeline.Artifact[] = [artifactPath.artifact]; + + public _render(): string { + return artifactPath.location; + } + }(); + } + + /** + * Artifacts referenced by this parameter set + * + * @internal + */ + public abstract readonly _artifactsReferenced: codepipeline.Artifact[]; + + /** + * Converts Parameters to a string. + * + * @internal + */ + public abstract _render(): string; +} + +/** + * Determines how IAM roles are created and managed. + */ +export abstract class StackSetDeploymentModel { + /** + * Deploy to AWS Organizations accounts. + * + * AWS CloudFormation StackSets automatically creates the IAM roles required + * to deploy to accounts managed by AWS Organizations. This requires an + * account to be a member of an Organization. + * + * Using this deployment model, you can specify either AWS Account Ids or + * Organization Unit Ids in the `stackInstances` parameter. + */ + public static organizations(props: OrganizationsDeploymentProps = {}): StackSetDeploymentModel { + return new class extends StackSetDeploymentModel { + _bind() { + return { + stackSetConfiguration: { + PermissionModel: 'SERVICE_MANAGED', + OrganizationsAutoDeployment: props.autoDeployment, + }, + }; + } + }(); + } + + /** + * Deploy to AWS Accounts not managed by AWS Organizations + * + * You are responsible for creating Execution Roles in every account you will + * be deploying to in advance to create the actual stack instances. Unless you + * specify overrides, StackSets expects the execution roles you create to have + * the default name `AWSCloudFormationStackSetExecutionRole`. See the [Grant + * self-managed + * permissions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-prereqs-self-managed.html) + * section of the CloudFormation documentation. + * + * The CDK will automatically create the central Administration Role in the + * Pipeline account which will be used to assume the Execution Role in each of + * the target accounts. + * + * If you wish to use a pre-created Administration Role, use `Role.fromRoleName()` + * or `Role.fromRoleArn()` to import it, and pass it to this function: + * + * ```ts + * const existingAdminRole = iam.Role.fromRoleName(this, 'AdminRole', 'AWSCloudFormationStackSetAdministrationRole'); + * + * const deploymentModel = codepipeline_actions.StackSetDeploymentModel.selfManaged({ + * // Use an existing Role. Leave this out to create a new Role. + * administrationRole: existingAdminRole, + * }); + * ``` + * + * Using this deployment model, you can only specify AWS Account Ids in the + * `stackInstances` parameter. + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-prereqs-self-managed.html + */ + public static selfManaged(props: SelfManagedDeploymentProps = {}): StackSetDeploymentModel { + return new class extends StackSetDeploymentModel { + _bind(scope: Construct) { + let administrationRole = props.administrationRole; + if (!administrationRole) { + administrationRole = new iam.Role(scope, 'StackSetAdministrationRole', { + assumedBy: new iam.ServicePrincipal('cloudformation.amazonaws.com', { + conditions: { + // Confused deputy protection + StringLike: { + 'aws:SourceArn': `arn:${cdk.Aws.PARTITION}:cloudformation:*:${cdk.Aws.ACCOUNT_ID}:stackset/*`, + }, + }, + }), + }); + administrationRole.addToPrincipalPolicy(new iam.PolicyStatement({ + actions: ['sts:AssumeRole'], + resources: [`arn:${cdk.Aws.PARTITION}:iam::*:role/${props.executionRoleName ?? 'AWSCloudFormationStackSetExecutionRole'}`], + })); + } + + return { + stackSetConfiguration: { + PermissionModel: 'SELF_MANAGED', + AdministrationRoleArn: administrationRole.roleArn, + ExecutionRoleName: props.executionRoleName, + }, + passedRoles: [administrationRole], + } as StackSetDeploymentModelBindResult; + } + }(); + } + + /** + * Bind to the Stack Set action and return the Action configuration + * + * Does not need to be called by app builders. + * + * @internal + */ + public abstract _bind(scope: Construct): StackSetDeploymentModelBindResult; +} + +/** + * Returned by the StackSetDeploymentModel.bind() function + * + * Does not need to be used by app builders. + * + * @internal + */ +export interface StackSetDeploymentModelBindResult { + /** + * Properties to mix into the Action configuration + */ + readonly stackSetConfiguration: any; + + /** + * Roles that need to be passed by the pipeline action + * + * @default - No roles + */ + readonly passedRoles?: iam.IRole[]; +} + +/** + * Properties for configuring service-managed (Organizations) permissions + */ +export interface OrganizationsDeploymentProps { + /** + * Automatically deploy to new accounts added to Organizational Units + * + * Whether AWS CloudFormation StackSets automatically deploys to AWS + * Organizations accounts that are added to a target organization or + * organizational unit (OU). + * + * @default Disabled + */ + readonly autoDeployment?: StackSetOrganizationsAutoDeployment; +} + +/** + * Describes whether AWS CloudFormation StackSets automatically deploys to AWS Organizations accounts that are added to a target organization or + * organizational unit (OU). + */ +export enum StackSetOrganizationsAutoDeployment { + /** + * StackSets automatically deploys additional stack instances to AWS Organizations accounts that are added to a target organization or + * organizational unit (OU) in the specified Regions. If an account is removed from a target organization or OU, AWS CloudFormation StackSets + * deletes stack instances from the account in the specified Regions. + */ + ENABLED = 'Enabled', + + /** + * StackSets does not automatically deploy additional stack instances to AWS Organizations accounts that are added to a target organization or + * organizational unit (OU) in the specified Regions. + */ + DISABLED = 'Disabled', + + /** + * Stack resources are retained when an account is removed from a target organization or OU. + */ + ENABLED_WITH_STACK_RETENTION = 'EnabledWithStackRetention' +} + + +/** + * Properties for configuring self-managed permissions + */ +export interface SelfManagedDeploymentProps { + /** + * The IAM role in the administrator account used to assume execution roles in the target accounts + * + * You must create this role before using the StackSet action. + * + * The role needs to be assumable by CloudFormation, and it needs to be able + * to `sts:AssumeRole` each of the execution roles (whose names are specified + * in the `executionRoleName` parameter) in each of the target accounts. + * + * If you do not specify the role, we assume you have created a role named + * `AWSCloudFormationStackSetAdministrationRole`. + * + * @default - Assume an existing role named `AWSCloudFormationStackSetAdministrationRole` in the same account as the pipeline. + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-prereqs-self-managed.html + */ + readonly administrationRole?: iam.IRole; + + /** + * The name of the IAM role in the target accounts used to perform stack set operations. + * + * You must create these roles in each of the target accounts before using the + * StackSet action. + * + * The roles need to be assumable by by the `administrationRole`, and need to + * have the permissions necessary to successfully create and modify the + * resources that the subsequent CloudFormation deployments need. + * Administrator permissions would be commonly granted to these, but if you can + * scope the permissions down frome there you would be safer. + * + * @default AWSCloudFormationStackSetExecutionRole + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-prereqs-self-managed.html + */ + readonly executionRoleName?: string; +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/common.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/common.ts index 7e3aade895ce8..c534661e469da 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/common.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/common.ts @@ -1,4 +1,5 @@ import * as codepipeline from '@aws-cdk/aws-codepipeline'; +import { Token } from '@aws-cdk/core'; /** * The ArtifactBounds that make sense for source Actions - @@ -25,3 +26,13 @@ export function deployArtifactBounds(): codepipeline.ActionArtifactBounds { maxOutputs: 0, }; } + +export function validatePercentage(name: string, value?: number) { + if (value === undefined || Token.isUnresolved(value)) { + return; + } + + if (value < 0 || value > 100 || !Number.isInteger(value)) { + throw new Error(`'${name}': must be a whole number between 0 and 100, got: ${value}`); + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/index.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/index.ts index e861161ab39c1..a0d665eddd886 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/index.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/index.ts @@ -1,7 +1,7 @@ export * from './alexa-ask/deploy-action'; export * from './bitbucket/source-action'; export * from './codestar-connections/source-action'; -export * from './cloudformation/pipeline-actions'; +export * from './cloudformation'; export * from './codebuild/build-action'; export * from './codecommit/source-action'; export * from './codedeploy/ecs-deploy-action'; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/lambda/invoke-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/lambda/invoke-action.ts index 8740d8fafb9ff..79029a95641fa 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/lambda/invoke-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/lambda/invoke-action.ts @@ -115,10 +115,7 @@ export class LambdaInvokeAction extends Action { })); // allow pipeline to invoke this lambda functionn - options.role.addToPolicy(new iam.PolicyStatement({ - actions: ['lambda:InvokeFunction'], - resources: [this.props.lambda.functionArn], - })); + this.props.lambda.grantInvoke(options.role); // allow the Role access to the Bucket, if there are any inputs/outputs if ((this.actionProperties.inputs || []).length > 0) { diff --git a/packages/@aws-cdk/aws-codepipeline-actions/package.json b/packages/@aws-cdk/aws-codepipeline-actions/package.json index b3b06d2306188..b9d312c04ae38 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/package.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/package.json @@ -78,13 +78,14 @@ "@aws-cdk/assertions": "0.0.0", "@aws-cdk/aws-cloudtrail": "0.0.0", "@aws-cdk/aws-codestarnotifications": "0.0.0", + "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "@types/lodash": "^4.14.178", - "jest": "^27.4.7", + "@types/jest": "^27.4.1", + "@types/lodash": "^4.14.181", + "jest": "^27.5.1", "lodash": "^4.17.21" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-pipeline-actions.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-pipeline-actions.test.ts index 5ed83cd1f6711..c34fde11237ab 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-pipeline-actions.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-pipeline-actions.test.ts @@ -5,6 +5,7 @@ import * as codepipeline from '@aws-cdk/aws-codepipeline'; import { PolicyStatement, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import * as cpactions from '../../lib'; +import { TestFixture } from './test-fixture'; /* eslint-disable quote-props */ @@ -723,32 +724,3 @@ describe('CloudFormation Pipeline Actions', () => { }); }); }); - -/** - * A test stack with a half-prepared pipeline ready to add CloudFormation actions to - */ -class TestFixture extends cdk.Stack { - public readonly pipeline: codepipeline.Pipeline; - public readonly sourceStage: codepipeline.IStage; - public readonly deployStage: codepipeline.IStage; - public readonly repo: codecommit.Repository; - public readonly sourceOutput: codepipeline.Artifact; - - constructor() { - super(); - - this.pipeline = new codepipeline.Pipeline(this, 'Pipeline'); - this.sourceStage = this.pipeline.addStage({ stageName: 'Source' }); - this.deployStage = this.pipeline.addStage({ stageName: 'Deploy' }); - this.repo = new codecommit.Repository(this, 'MyVeryImportantRepo', { - repositoryName: 'my-very-important-repo', - }); - this.sourceOutput = new codepipeline.Artifact('SourceArtifact'); - const source = new cpactions.CodeCommitSourceAction({ - actionName: 'Source', - output: this.sourceOutput, - repository: this.repo, - }); - this.sourceStage.addAction(source); - } -} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-stackset-pipeline-actions.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-stackset-pipeline-actions.test.ts new file mode 100644 index 0000000000000..80638dc219add --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-stackset-pipeline-actions.test.ts @@ -0,0 +1,419 @@ +import { Match, Template } from '@aws-cdk/assertions'; +import * as iam from '@aws-cdk/aws-iam'; +import * as cdk from '@aws-cdk/core'; +import * as cpactions from '../../lib'; +import { TestFixture } from './test-fixture'; +/* eslint-disable quote-props */ + +let stack: TestFixture; +let importedAdminRole: iam.IRole; +beforeEach(() => { + stack = new TestFixture({ + env: { + account: '111111111111', + region: 'us-east-1', + }, + }); + importedAdminRole = iam.Role.fromRoleArn(stack, 'ChangeSetRole', 'arn:aws:iam::1234:role/ImportedAdminRole'); +}); + +describe('StackSetAction', () => { + function defaultOpts() { + return { + actionName: 'StackSetUpdate', + description: 'desc', + stackSetName: 'MyStack', + cfnCapabilities: [cdk.CfnCapabilities.NAMED_IAM], + failureTolerancePercentage: 50, + maxAccountConcurrencyPercentage: 25, + template: cpactions.StackSetTemplate.fromArtifactPath(stack.sourceOutput.atPath('template.yaml')), + parameters: cpactions.StackSetParameters.fromArtifactPath(stack.sourceOutput.atPath('parameters.json')), + }; + }; + + describe('self-managed mode', () => { + test('creates admin role if not specified', () => { + stack.deployStage.addAction(new cpactions.CloudFormationDeployStackSetAction({ + ...defaultOpts(), + stackInstances: cpactions.StackInstances.fromArtifactPath( + stack.sourceOutput.atPath('accounts.json'), + ['us-east-1', 'us-west-1', 'ca-central-1'], + ), + deploymentModel: cpactions.StackSetDeploymentModel.selfManaged({ + executionRoleName: 'Exec', + }), + })); + + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': Match.arrayWith([ + { + 'Action': [ + 'cloudformation:CreateStackInstances', + 'cloudformation:CreateStackSet', + 'cloudformation:DescribeStackSet', + 'cloudformation:DescribeStackSetOperation', + 'cloudformation:ListStackInstances', + 'cloudformation:UpdateStackSet', + ], + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':cloudformation:us-east-1:111111111111:stackset/MyStack:*', + ]], + }, + }, + { + 'Action': 'iam:PassRole', + 'Effect': 'Allow', + 'Resource': { 'Fn::GetAtt': ['PipelineDeployStackSetUpdateStackSetAdministrationRole183434B0', 'Arn'] }, + }, + ]), + }, + 'Roles': [ + { 'Ref': 'PipelineDeployStackSetUpdateCodePipelineActionRole3EDBB32C' }, + ], + }); + + template.hasResourceProperties('AWS::CodePipeline::Pipeline', { + 'Stages': [ + { 'Name': 'Source' /* don't care about the rest */ }, + { + 'Name': 'Deploy', + 'Actions': [ + { + 'Configuration': { + 'StackSetName': 'MyStack', + 'Description': 'desc', + 'TemplatePath': 'SourceArtifact::template.yaml', + 'Parameters': 'SourceArtifact::parameters.json', + 'PermissionModel': 'SELF_MANAGED', + 'AdministrationRoleArn': { 'Fn::GetAtt': ['PipelineDeployStackSetUpdateStackSetAdministrationRole183434B0', 'Arn'] }, + 'ExecutionRoleName': 'Exec', + 'Capabilities': 'CAPABILITY_NAMED_IAM', + 'DeploymentTargets': 'SourceArtifact::accounts.json', + 'FailureTolerancePercentage': 50, + 'MaxConcurrentPercentage': 25, + 'Regions': 'us-east-1,us-west-1,ca-central-1', + }, + 'Name': 'StackSetUpdate', + }, + ], + }, + ], + }); + + template.hasResourceProperties('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': [ + { + 'Effect': 'Allow', + 'Action': 'sts:AssumeRole', + 'Resource': { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::*:role/Exec']] }, + }, + ], + }, + }); + }); + + test('passes admin role if specified', () => { + stack.deployStage.addAction(new cpactions.CloudFormationDeployStackSetAction({ + ...defaultOpts(), + stackInstances: cpactions.StackInstances.fromArtifactPath( + stack.sourceOutput.atPath('accounts.json'), + ['us-east-1', 'us-west-1', 'ca-central-1'], + ), + deploymentModel: cpactions.StackSetDeploymentModel.selfManaged({ + executionRoleName: 'Exec', + administrationRole: importedAdminRole, + }), + })); + + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': [ + 'cloudformation:CreateStackInstances', + 'cloudformation:CreateStackSet', + 'cloudformation:DescribeStackSet', + 'cloudformation:DescribeStackSetOperation', + 'cloudformation:ListStackInstances', + 'cloudformation:UpdateStackSet', + ], + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': [ + '', + [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':cloudformation:us-east-1:111111111111:stackset/MyStack:*', + ], + ], + }, + }, + { + 'Action': 'iam:PassRole', + 'Effect': 'Allow', + 'Resource': 'arn:aws:iam::1234:role/ImportedAdminRole', + }, + { + 'Action': [ + 's3:GetObject*', + 's3:GetBucket*', + 's3:List*', + ], + 'Effect': 'Allow', + 'Resource': [ + { 'Fn::GetAtt': ['PipelineArtifactsBucket22248F97', 'Arn'] }, + { + 'Fn::Join': ['', [ + { 'Fn::GetAtt': ['PipelineArtifactsBucket22248F97', 'Arn'] }, + '/*', + ]], + }, + ], + }, + { + 'Action': [ + 'kms:Decrypt', + 'kms:DescribeKey', + ], + 'Effect': 'Allow', + 'Resource': { 'Fn::GetAtt': ['PipelineArtifactsBucketEncryptionKey01D58D69', 'Arn'] }, + }, + ], + }, + 'Roles': [{ 'Ref': 'PipelineDeployStackSetUpdateCodePipelineActionRole3EDBB32C' }], + }); + }); + }); + + test('creates correct resources in organizations mode', () => { + stack.deployStage.addAction(new cpactions.CloudFormationDeployStackSetAction({ + ...defaultOpts(), + deploymentModel: cpactions.StackSetDeploymentModel.organizations(), + stackInstances: cpactions.StackInstances.fromArtifactPath( + stack.sourceOutput.atPath('accounts.json'), + ['us-east-1', 'us-west-1', 'ca-central-1'], + ), + })); + + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': Match.arrayWith([ + { + 'Action': [ + 'cloudformation:CreateStackInstances', + 'cloudformation:CreateStackSet', + 'cloudformation:DescribeStackSet', + 'cloudformation:DescribeStackSetOperation', + 'cloudformation:ListStackInstances', + 'cloudformation:UpdateStackSet', + ], + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': [ + '', + [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':cloudformation:us-east-1:111111111111:stackset/MyStack:*', + ], + ], + }, + }, + ]), + }, + 'Roles': [ + { 'Ref': 'PipelineDeployStackSetUpdateCodePipelineActionRole3EDBB32C' }, + ], + }); + }); + + test('creates correct pipeline resource with target list', () => { + stack.deployStage.addAction(new cpactions.CloudFormationDeployStackSetAction({ + ...defaultOpts(), + stackInstances: cpactions.StackInstances.inAccounts( + ['11111111111', '22222222222'], + ['us-east-1', 'us-west-1', 'ca-central-1'], + ), + deploymentModel: cpactions.StackSetDeploymentModel.selfManaged({ + administrationRole: importedAdminRole, + executionRoleName: 'Exec', + }), + })); + + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::CodePipeline::Pipeline', { + 'Stages': [ + { 'Name': 'Source' /* don't care about the rest */ }, + { + 'Name': 'Deploy', + 'Actions': [ + { + 'Configuration': { + 'StackSetName': 'MyStack', + 'Description': 'desc', + 'TemplatePath': 'SourceArtifact::template.yaml', + 'Parameters': 'SourceArtifact::parameters.json', + 'Capabilities': 'CAPABILITY_NAMED_IAM', + 'DeploymentTargets': '11111111111,22222222222', + 'FailureTolerancePercentage': 50, + 'MaxConcurrentPercentage': 25, + 'Regions': 'us-east-1,us-west-1,ca-central-1', + }, + 'InputArtifacts': [{ 'Name': 'SourceArtifact' }], + 'Name': 'StackSetUpdate', + }, + ], + }, + ], + }); + }); + + test('creates correct pipeline resource with parameter list', () => { + stack.deployStage.addAction(new cpactions.CloudFormationDeployStackSetAction({ + ...defaultOpts(), + parameters: cpactions.StackSetParameters.fromLiteral({ + key0: 'val0', + key1: 'val1', + }, ['key2', 'key3']), + stackInstances: cpactions.StackInstances.fromArtifactPath( + stack.sourceOutput.atPath('accounts.json'), + ['us-east-1', 'us-west-1', 'ca-central-1'], + ), + deploymentModel: cpactions.StackSetDeploymentModel.selfManaged({ + administrationRole: importedAdminRole, + executionRoleName: 'Exec', + }), + })); + + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::CodePipeline::Pipeline', { + 'Stages': [ + { 'Name': 'Source' /* don't care about the rest */ }, + { + 'Name': 'Deploy', + 'Actions': [ + { + 'Configuration': { + 'StackSetName': 'MyStack', + 'Description': 'desc', + 'TemplatePath': 'SourceArtifact::template.yaml', + 'Parameters': 'ParameterKey=key0,ParameterValue=val0 ParameterKey=key1,ParameterValue=val1 ParameterKey=key2,UsePreviousValue=true ParameterKey=key3,UsePreviousValue=true', + 'Capabilities': 'CAPABILITY_NAMED_IAM', + 'DeploymentTargets': 'SourceArtifact::accounts.json', + 'FailureTolerancePercentage': 50, + 'MaxConcurrentPercentage': 25, + 'Regions': 'us-east-1,us-west-1,ca-central-1', + }, + 'InputArtifacts': [{ 'Name': 'SourceArtifact' }], + 'Name': 'StackSetUpdate', + }, + ], + }, + ], + }); + }); + + test('correctly passes region', () => { + stack.deployStage.addAction(new cpactions.CloudFormationDeployStackSetAction({ + ...defaultOpts(), + stackSetRegion: 'us-banana-2', + })); + + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::CodePipeline::Pipeline', { + 'Stages': [ + { 'Name': 'Source' /* don't care about the rest */ }, + { + 'Name': 'Deploy', + 'Actions': [ + { + 'Region': 'us-banana-2', + }, + ], + }, + ], + }); + }); +}); + +describe('StackInstancesAction', () => { + function defaultOpts() { + return { + actionName: 'StackInstances', + stackSetName: 'MyStack', + failureTolerancePercentage: 50, + maxAccountConcurrencyPercentage: 25, + }; + }; + + test('simple', () => { + stack.deployStage.addAction(new cpactions.CloudFormationDeployStackInstancesAction({ + ...defaultOpts(), + stackInstances: cpactions.StackInstances.inAccounts( + ['1234', '5678'], + ['us-east-1', 'us-west-1'], + ), + })); + + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::CodePipeline::Pipeline', { + 'Stages': [ + { 'Name': 'Source' /* don't care about the rest */ }, + { + 'Name': 'Deploy', + 'Actions': [ + { + 'ActionTypeId': { + 'Category': 'Deploy', + 'Owner': 'AWS', + 'Provider': 'CloudFormationStackInstances', + 'Version': '1', + }, + 'Configuration': { + 'StackSetName': 'MyStack', + 'FailureTolerancePercentage': 50, + 'MaxConcurrentPercentage': 25, + 'DeploymentTargets': '1234,5678', + 'Regions': 'us-east-1,us-west-1', + }, + 'Name': 'StackInstances', + }, + ], + }, + ], + }); + }); + + test('correctly passes region', () => { + stack.deployStage.addAction(new cpactions.CloudFormationDeployStackInstancesAction({ + ...defaultOpts(), + stackSetRegion: 'us-banana-2', + stackInstances: cpactions.StackInstances.inAccounts(['1'], ['us-east-1']), + })); + + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::CodePipeline::Pipeline', { + 'Stages': [ + { 'Name': 'Source' /* don't care about the rest */ }, + { + 'Name': 'Deploy', + 'Actions': [ + { + 'Region': 'us-banana-2', + }, + ], + }, + ], + }); + }); +}); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/integ.stacksets.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/integ.stacksets.expected.json new file mode 100644 index 0000000000000..e57101d8a4892 --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/integ.stacksets.expected.json @@ -0,0 +1,652 @@ +{ + "Resources": { + "ArtifactBucket7410C9EF": { + "Type": "AWS::S3::Bucket", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "PipelineRoleD68726F7": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "codepipeline.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineRoleDefaultPolicyC7A05455": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:Abort*", + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*", + "s3:PutObject", + "s3:PutObjectLegalHold", + "s3:PutObjectRetention", + "s3:PutObjectTagging", + "s3:PutObjectVersionTagging" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "ArtifactBucket7410C9EF", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "ArtifactBucket7410C9EF", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineCfnInstancesCodePipelineActionRole289FD062", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineCfnStackSetCodePipelineActionRole9EA256DB", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineSourceCodePipelineActionRoleC6F9E7F5", + "Arn" + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineRoleDefaultPolicyC7A05455", + "Roles": [ + { + "Ref": "PipelineRoleD68726F7" + } + ] + } + }, + "PipelineC660917D": { + "Type": "AWS::CodePipeline::Pipeline", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "PipelineRoleD68726F7", + "Arn" + ] + }, + "Stages": [ + { + "Actions": [ + { + "ActionTypeId": { + "Category": "Source", + "Owner": "AWS", + "Provider": "S3", + "Version": "1" + }, + "Configuration": { + "S3Bucket": { + "Ref": "AssetParameters5bcf205623ea5b34a1944fea4c9982e835555e710235ae6f60172097737302e2S3Bucket3C8B9651" + }, + "S3ObjectKey": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters5bcf205623ea5b34a1944fea4c9982e835555e710235ae6f60172097737302e2S3VersionKeyD144071F" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters5bcf205623ea5b34a1944fea4c9982e835555e710235ae6f60172097737302e2S3VersionKeyD144071F" + } + ] + } + ] + } + ] + ] + } + }, + "Name": "Source", + "OutputArtifacts": [ + { + "Name": "SourceArtifact" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "PipelineSourceCodePipelineActionRoleC6F9E7F5", + "Arn" + ] + }, + "RunOrder": 1 + } + ], + "Name": "Source" + }, + { + "Actions": [ + { + "ActionTypeId": { + "Category": "Deploy", + "Owner": "AWS", + "Provider": "CloudFormationStackSet", + "Version": "1" + }, + "Configuration": { + "StackSetName": "TestStackSet", + "TemplatePath": "SourceArtifact::template.yaml", + "DeploymentTargets": "1111,2222", + "Regions": "us-east-1,eu-west-1", + "PermissionModel": "SELF_MANAGED", + "AdministrationRoleArn": { + "Fn::GetAtt": [ + "PipelineCfnStackSetStackSetAdministrationRoleAE2E9C50", + "Arn" + ] + } + }, + "InputArtifacts": [ + { + "Name": "SourceArtifact" + } + ], + "Name": "StackSet", + "RoleArn": { + "Fn::GetAtt": [ + "PipelineCfnStackSetCodePipelineActionRole9EA256DB", + "Arn" + ] + }, + "RunOrder": 1 + }, + { + "ActionTypeId": { + "Category": "Deploy", + "Owner": "AWS", + "Provider": "CloudFormationStackInstances", + "Version": "1" + }, + "Configuration": { + "StackSetName": "TestStackSet", + "DeploymentTargets": "1111,2222", + "Regions": "us-east-1,eu-west-1" + }, + "Name": "Instances", + "RoleArn": { + "Fn::GetAtt": [ + "PipelineCfnInstancesCodePipelineActionRole289FD062", + "Arn" + ] + }, + "RunOrder": 2 + } + ], + "Name": "Cfn" + } + ], + "ArtifactStore": { + "Location": { + "Ref": "ArtifactBucket7410C9EF" + }, + "Type": "S3" + } + }, + "DependsOn": [ + "PipelineRoleDefaultPolicyC7A05455", + "PipelineRoleD68726F7" + ] + }, + "PipelineSourceCodePipelineActionRoleC6F9E7F5": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::12345678:root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineSourceCodePipelineActionRoleDefaultPolicy2D565925": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "AssetParameters5bcf205623ea5b34a1944fea4c9982e835555e710235ae6f60172097737302e2S3Bucket3C8B9651" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters5bcf205623ea5b34a1944fea4c9982e835555e710235ae6f60172097737302e2S3VersionKeyD144071F" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters5bcf205623ea5b34a1944fea4c9982e835555e710235ae6f60172097737302e2S3VersionKeyD144071F" + } + ] + } + ] + } + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "AssetParameters5bcf205623ea5b34a1944fea4c9982e835555e710235ae6f60172097737302e2S3Bucket3C8B9651" + } + ] + ] + } + ] + }, + { + "Action": [ + "s3:Abort*", + "s3:DeleteObject*", + "s3:PutObject", + "s3:PutObjectLegalHold", + "s3:PutObjectRetention", + "s3:PutObjectTagging", + "s3:PutObjectVersionTagging" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "ArtifactBucket7410C9EF", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "ArtifactBucket7410C9EF", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineSourceCodePipelineActionRoleDefaultPolicy2D565925", + "Roles": [ + { + "Ref": "PipelineSourceCodePipelineActionRoleC6F9E7F5" + } + ] + } + }, + "PipelineCfnStackSetCodePipelineActionRole9EA256DB": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::12345678:root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineCfnStackSetCodePipelineActionRoleDefaultPolicyE5B66E2C": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "cloudformation:CreateStackInstances", + "cloudformation:CreateStackSet", + "cloudformation:DescribeStackSet", + "cloudformation:DescribeStackSetOperation", + "cloudformation:ListStackInstances", + "cloudformation:UpdateStackSet" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":cloudformation:test-region:12345678:stackset/TestStackSet:*" + ] + ] + } + }, + { + "Action": "iam:PassRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineCfnStackSetStackSetAdministrationRoleAE2E9C50", + "Arn" + ] + } + }, + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "ArtifactBucket7410C9EF", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "ArtifactBucket7410C9EF", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineCfnStackSetCodePipelineActionRoleDefaultPolicyE5B66E2C", + "Roles": [ + { + "Ref": "PipelineCfnStackSetCodePipelineActionRole9EA256DB" + } + ] + } + }, + "PipelineCfnStackSetStackSetAdministrationRoleAE2E9C50": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "StringLike": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":cloudformation:*:", + { + "Ref": "AWS::AccountId" + }, + ":stackset/*" + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "cloudformation.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineCfnStackSetStackSetAdministrationRoleDefaultPolicy55145C4E": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::*:role/AWSCloudFormationStackSetExecutionRole" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineCfnStackSetStackSetAdministrationRoleDefaultPolicy55145C4E", + "Roles": [ + { + "Ref": "PipelineCfnStackSetStackSetAdministrationRoleAE2E9C50" + } + ] + } + }, + "PipelineCfnInstancesCodePipelineActionRole289FD062": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::12345678:root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineCfnInstancesCodePipelineActionRoleDefaultPolicy38A9673E": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "cloudformation:CreateStackInstances", + "cloudformation:CreateStackSet", + "cloudformation:DescribeStackSet", + "cloudformation:DescribeStackSetOperation", + "cloudformation:ListStackInstances", + "cloudformation:UpdateStackSet" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":cloudformation:test-region:12345678:stackset/TestStackSet:*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineCfnInstancesCodePipelineActionRoleDefaultPolicy38A9673E", + "Roles": [ + { + "Ref": "PipelineCfnInstancesCodePipelineActionRole289FD062" + } + ] + } + } + }, + "Parameters": { + "AssetParameters5bcf205623ea5b34a1944fea4c9982e835555e710235ae6f60172097737302e2S3Bucket3C8B9651": { + "Type": "String", + "Description": "S3 bucket for asset \"5bcf205623ea5b34a1944fea4c9982e835555e710235ae6f60172097737302e2\"" + }, + "AssetParameters5bcf205623ea5b34a1944fea4c9982e835555e710235ae6f60172097737302e2S3VersionKeyD144071F": { + "Type": "String", + "Description": "S3 key for asset version \"5bcf205623ea5b34a1944fea4c9982e835555e710235ae6f60172097737302e2\"" + }, + "AssetParameters5bcf205623ea5b34a1944fea4c9982e835555e710235ae6f60172097737302e2ArtifactHashA83BA1E9": { + "Type": "String", + "Description": "Artifact hash for asset \"5bcf205623ea5b34a1944fea4c9982e835555e710235ae6f60172097737302e2\"" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/integ.stacksets.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/integ.stacksets.ts new file mode 100644 index 0000000000000..bc41e86474584 --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/integ.stacksets.ts @@ -0,0 +1,83 @@ +/** + * This integration test needs 2 accounts properly configured beforehand to properly test, + * and so is tested by hand. + * + * To test: + * + * ``` + * env AWS_REGION=eu-west-1 STACKSET_ACCOUNTS=11111111,22222222 cdk deploy -a test/cloudformation/integ.stacksets.js + * ``` + * + * Then make the pipeline in your account run. + * + * To update the snapshot: + * + * ``` + * yarn integ --dry-run cloudformation/integ.stacksets.js + * ``` + */ +import * as codepipeline from '@aws-cdk/aws-codepipeline'; +import * as s3 from '@aws-cdk/aws-s3'; +import { Asset } from '@aws-cdk/aws-s3-assets'; +import { App, RemovalPolicy, Stack, StackProps } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import * as cpactions from '../../lib'; + +export class StackSetPipelineStack extends Stack { + constructor(scope: Construct, id: string, props: StackProps) { + super(scope, id, props); + + const pipeline = new codepipeline.Pipeline(this, 'Pipeline', { + artifactBucket: new s3.Bucket(this, 'ArtifactBucket', { + removalPolicy: RemovalPolicy.DESTROY, + }), + }); + + const asset = new Asset(this, 'Asset', { + path: `${__dirname}/test-artifact`, + }); + + const sourceOutput = new codepipeline.Artifact('SourceArtifact'); + + pipeline.addStage({ + stageName: 'Source', + actions: [ + new cpactions.S3SourceAction({ + actionName: 'Source', + output: sourceOutput, + bucket: asset.bucket, + bucketKey: asset.s3ObjectKey, + }), + ], + }); + + const accounts = process.env.STACKSET_ACCOUNTS?.split(',') ?? ['1111', '2222']; + + pipeline.addStage({ + stageName: 'Cfn', + actions: [ + new cpactions.CloudFormationDeployStackSetAction({ + actionName: 'StackSet', + stackSetName: 'TestStackSet', + template: cpactions.StackSetTemplate.fromArtifactPath(sourceOutput.atPath('template.yaml')), + stackInstances: cpactions.StackInstances.inAccounts(accounts, ['us-east-1', 'eu-west-1']), + runOrder: 1, + }), + new cpactions.CloudFormationDeployStackInstancesAction({ + actionName: 'Instances', + stackSetName: 'TestStackSet', + stackInstances: cpactions.StackInstances.inAccounts(accounts, ['us-east-1', 'eu-west-1']), + runOrder: 2, + }), + ], + }); + } +} + +const app = new App(); +new StackSetPipelineStack(app, 'StackSetPipelineStack', { + env: { + region: process.env.CDK_DEFAULT_REGION, + account: process.env.CDK_DEFAULT_ACCOUNT, + }, +}); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test-artifact/template.yaml b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test-artifact/template.yaml new file mode 100644 index 0000000000000..c2c61591f6778 --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test-artifact/template.yaml @@ -0,0 +1,6 @@ +Resources: + Filler: + Type: AWS::CloudFormation::WaitConditionHandle +Outputs: + Great: + Value: It works! \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test-fixture.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test-fixture.ts new file mode 100644 index 0000000000000..f981d829c2a2d --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test-fixture.ts @@ -0,0 +1,33 @@ +import * as codecommit from '@aws-cdk/aws-codecommit'; +import * as codepipeline from '@aws-cdk/aws-codepipeline'; +import * as cdk from '@aws-cdk/core'; +import * as cpactions from '../../lib'; + +/** + * A test stack with a half-prepared pipeline ready to add CloudFormation actions to + */ +export class TestFixture extends cdk.Stack { + public readonly pipeline: codepipeline.Pipeline; + public readonly sourceStage: codepipeline.IStage; + public readonly deployStage: codepipeline.IStage; + public readonly repo: codecommit.Repository; + public readonly sourceOutput: codepipeline.Artifact; + + constructor(props: cdk.StackProps = {}) { + super(undefined, undefined, props); + + this.pipeline = new codepipeline.Pipeline(this, 'Pipeline'); + this.sourceStage = this.pipeline.addStage({ stageName: 'Source' }); + this.deployStage = this.pipeline.addStage({ stageName: 'Deploy' }); + this.repo = new codecommit.Repository(this, 'MyVeryImportantRepo', { + repositoryName: 'my-very-important-repo', + }); + this.sourceOutput = new codepipeline.Artifact('SourceArtifact'); + const source = new cpactions.CodeCommitSourceAction({ + actionName: 'Source', + output: this.sourceOutput, + repository: this.repo, + }); + this.sourceStage.addAction(source); + } +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json index 87d6594c254c4..bf53693d1bacc 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json @@ -154,16 +154,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -194,8 +194,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -208,42 +208,32 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineSourceCodePipelineActionRoleC6F9E7F5", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineDeployPrepareChangesCodePipelineActionRole41931444", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineDeployApproveChangesCodePipelineActionRole5AA6E21B", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineDeployExecuteChangesCodePipelineActionRole6AA2756F", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineDeployApproveChangesCodePipelineActionRole5AA6E21B", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineDeployExecuteChangesCodePipelineActionRole6AA2756F", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineDeployPrepareChangesCodePipelineActionRole41931444", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineSourceCodePipelineActionRoleC6F9E7F5", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -439,16 +429,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -479,8 +469,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -492,11 +482,11 @@ }, { "Action": [ + "codecommit:CancelUploadArchive", "codecommit:GetBranch", "codecommit:GetCommit", - "codecommit:UploadArchive", "codecommit:GetUploadArchiveStatus", - "codecommit:CancelUploadArchive" + "codecommit:UploadArchive" ], "Effect": "Allow", "Resource": { @@ -566,8 +556,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -676,8 +666,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json index 823b5af6c908b..d4ee615d4b1bf 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json @@ -148,16 +148,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -188,8 +188,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -202,52 +202,38 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineSourceCdkCodeSourceCodePipelineActionRole237947B8", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineSourceLambdaCodeSourceCodePipelineActionRole4E89EF60", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineBuildCDKBuildCodePipelineActionRole15F4B424", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineBuildLambdaBuildCodePipelineActionRole2DAE39E9", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineDeployLambdaCFNDeployCodePipelineActionRoleF8A74488", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineBuildCDKBuildCodePipelineActionRole15F4B424", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineBuildLambdaBuildCodePipelineActionRole2DAE39E9", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineDeployLambdaCFNDeployCodePipelineActionRoleF8A74488", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineSourceCdkCodeSourceCodePipelineActionRole237947B8", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineSourceLambdaCodeSourceCodePipelineActionRole4E89EF60", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -507,16 +493,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -547,8 +533,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -560,11 +546,11 @@ }, { "Action": [ + "codecommit:CancelUploadArchive", "codecommit:GetBranch", "codecommit:GetCommit", - "codecommit:UploadArchive", "codecommit:GetUploadArchiveStatus", - "codecommit:CancelUploadArchive" + "codecommit:UploadArchive" ], "Effect": "Allow", "Resource": { @@ -624,16 +610,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -664,8 +650,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -677,11 +663,11 @@ }, { "Action": [ + "codecommit:CancelUploadArchive", "codecommit:GetBranch", "codecommit:GetCommit", - "codecommit:UploadArchive", "codecommit:GetUploadArchiveStatus", - "codecommit:CancelUploadArchive" + "codecommit:UploadArchive" ], "Effect": "Allow", "Resource": { @@ -935,8 +921,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -1043,8 +1029,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -1291,7 +1277,8 @@ ":log-group:/aws/codebuild/", { "Ref": "CdkBuildProject9382C38D" - } + }, + ":*" ] ] }, @@ -1314,8 +1301,7 @@ ":log-group:/aws/codebuild/", { "Ref": "CdkBuildProject9382C38D" - }, - ":*" + } ] ] } @@ -1323,11 +1309,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -1357,16 +1343,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -1397,23 +1383,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineArtifactsBucketEncryptionKey01D58D69", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -1517,7 +1488,8 @@ ":log-group:/aws/codebuild/", { "Ref": "LambdaBuildProject7E2DAB11" - } + }, + ":*" ] ] }, @@ -1540,8 +1512,7 @@ ":log-group:/aws/codebuild/", { "Ref": "LambdaBuildProject7E2DAB11" - }, - ":*" + } ] ] } @@ -1549,11 +1520,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -1583,16 +1554,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -1623,23 +1594,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineArtifactsBucketEncryptionKey01D58D69", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-pipeline.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-pipeline.expected.json index 0990f457aae8f..ad6afd39fa570 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-pipeline.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-pipeline.expected.json @@ -148,16 +148,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -188,8 +188,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -202,22 +202,20 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineSourceCodePipelineActionRoleC6F9E7F5", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineLambdaCodePipelineActionRoleC6032822", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineLambdaCodePipelineActionRoleC6032822", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineSourceCodePipelineActionRoleC6F9E7F5", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -360,8 +358,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -390,13 +388,13 @@ }, { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -424,10 +422,10 @@ }, { "Action": [ + "kms:Decrypt", "kms:Encrypt", - "kms:ReEncrypt*", "kms:GenerateDataKey*", - "kms:Decrypt" + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -553,12 +551,28 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "LambdaFun98622869", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "LambdaFun98622869", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "LambdaFun98622869", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -839,8 +853,8 @@ "Statement": [ { "Action": [ - "codepipeline:PutJobSuccessResult", - "codepipeline:PutJobFailureResult" + "codepipeline:PutJobFailureResult", + "codepipeline:PutJobSuccessResult" ], "Effect": "Allow", "Resource": "*" @@ -862,13 +876,13 @@ "Code": { "ZipFile": "\n exports.handler = function () {\n console.log(\"Hello, world!\");\n };\n " }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "LambdaFunServiceRoleF0979767", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -877,4 +891,4 @@ ] } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-alexa-deploy.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-alexa-deploy.expected.json index c255275baa82b..8546b2ea0e96d 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-alexa-deploy.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-alexa-deploy.expected.json @@ -158,16 +158,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -198,8 +198,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -359,8 +359,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -389,13 +389,13 @@ }, { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -423,10 +423,10 @@ }, { "Action": [ + "kms:Decrypt", "kms:Encrypt", - "kms:ReEncrypt*", "kms:GenerateDataKey*", - "kms:Decrypt" + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-cross-region.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-cross-region.expected.json index 167b278084683..e84918465e0f5 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-cross-region.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-cross-region.expected.json @@ -34,16 +34,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -72,22 +72,20 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyPipelineSourceS3CodePipelineActionRole9F003087", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyPipelineCFNCFNDeployCodePipelineActionRole31B1904C", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "MyPipelineCFNCFNDeployCodePipelineActionRole31B1904C", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "MyPipelineSourceS3CodePipelineActionRole9F003087", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -237,8 +235,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -267,13 +265,13 @@ }, { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -359,8 +357,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -450,8 +448,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -490,4 +488,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-with-action-role.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-with-action-role.expected.json index b3d024a33f2a8..d1f15ddedf6f4 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-with-action-role.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-with-action-role.expected.json @@ -64,8 +64,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -159,16 +159,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -197,22 +197,20 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyPipelineSourceS3CodePipelineActionRole9F003087", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "ActionRole60B0EDF7", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "ActionRole60B0EDF7", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "MyPipelineSourceS3CodePipelineActionRole9F003087", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -356,8 +354,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -386,13 +384,13 @@ }, { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -453,8 +451,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -493,4 +491,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn.expected.json index 53189d1369dda..689aa0a10542c 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn.expected.json @@ -148,16 +148,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -188,8 +188,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -202,32 +202,26 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineSourceCodePipelineActionRoleC6F9E7F5", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineSourceAdditionalSourceCodePipelineActionRole0897461A", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineCFNDeployCFNCodePipelineActionRole444CF5DD", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineCFNDeployCFNCodePipelineActionRole444CF5DD", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineSourceAdditionalSourceCodePipelineActionRole0897461A", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineSourceCodePipelineActionRoleC6F9E7F5", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -412,8 +406,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -442,13 +436,13 @@ }, { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -476,10 +470,10 @@ }, { "Action": [ + "kms:Decrypt", "kms:Encrypt", - "kms:ReEncrypt*", "kms:GenerateDataKey*", - "kms:Decrypt" + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -539,8 +533,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -569,13 +563,13 @@ }, { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -603,10 +597,10 @@ }, { "Action": [ + "kms:Decrypt", "kms:Encrypt", - "kms:ReEncrypt*", "kms:GenerateDataKey*", - "kms:Decrypt" + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -676,8 +670,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-build-batch.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-build-batch.expected.json index 854b01ae12ac6..43d50d461ead0 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-build-batch.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-build-batch.expected.json @@ -105,16 +105,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -152,11 +152,11 @@ }, { "Action": [ + "codecommit:CancelUploadArchive", "codecommit:GetBranch", "codecommit:GetCommit", - "codecommit:UploadArchive", "codecommit:GetUploadArchiveStatus", - "codecommit:CancelUploadArchive" + "codecommit:UploadArchive" ], "Effect": "Allow", "Resource": { @@ -391,7 +391,8 @@ ":log-group:/aws/codebuild/", { "Ref": "MyBuildProject30DB9D6E" - } + }, + ":*" ] ] }, @@ -414,8 +415,7 @@ ":log-group:/aws/codebuild/", { "Ref": "MyBuildProject30DB9D6E" - }, - ":*" + } ] ] } @@ -423,8 +423,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -522,9 +522,9 @@ "Statement": [ { "Action": [ + "codebuild:RetryBuild", "codebuild:StartBuild", - "codebuild:StopBuild", - "codebuild:RetryBuild" + "codebuild:StopBuild" ], "Effect": "Allow", "Resource": { @@ -546,4 +546,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-build-multiple-inputs-outputs.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-build-multiple-inputs-outputs.expected.json index c1624ab7e2f7b..c6216fb43bc54 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-build-multiple-inputs-outputs.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-build-multiple-inputs-outputs.expected.json @@ -105,16 +105,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -152,11 +152,11 @@ }, { "Action": [ + "codecommit:CancelUploadArchive", "codecommit:GetBranch", "codecommit:GetCommit", - "codecommit:UploadArchive", "codecommit:GetUploadArchiveStatus", - "codecommit:CancelUploadArchive" + "codecommit:UploadArchive" ], "Effect": "Allow", "Resource": { @@ -168,8 +168,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -196,40 +196,6 @@ } ] }, - { - "Action": [ - "s3:DeleteObject*", - "s3:PutObject", - "s3:PutObjectLegalHold", - "s3:PutObjectRetention", - "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::GetAtt": [ - "MyBucketF68F3FF0", - "Arn" - ] - }, - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "MyBucketF68F3FF0", - "Arn" - ] - }, - "/*" - ] - ] - } - ] - }, { "Action": [ "codebuild:BatchGetBuilds", @@ -528,7 +494,8 @@ ":log-group:/aws/codebuild/", { "Ref": "MyBuildProject30DB9D6E" - } + }, + ":*" ] ] }, @@ -551,8 +518,7 @@ ":log-group:/aws/codebuild/", { "Ref": "MyBuildProject30DB9D6E" - }, - ":*" + } ] ] } @@ -560,16 +526,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -635,4 +601,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.expected.json index cb437e83eb651..b6e3478c077c7 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.expected.json @@ -55,7 +55,8 @@ ":log-group:/aws/codebuild/", { "Ref": "MyBuildProject30DB9D6E" - } + }, + ":*" ] ] }, @@ -78,8 +79,7 @@ ":log-group:/aws/codebuild/", { "Ref": "MyBuildProject30DB9D6E" - }, - ":*" + } ] ] } @@ -87,16 +87,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -127,23 +127,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineArtifactsBucketEncryptionKey01D58D69", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -176,49 +161,6 @@ ] ] } - }, - { - "Action": [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*" - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::GetAtt": [ - "PipelineArtifactsBucket22248F97", - "Arn" - ] - }, - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "PipelineArtifactsBucket22248F97", - "Arn" - ] - }, - "/*" - ] - ] - } - ] - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineArtifactsBucketEncryptionKey01D58D69", - "Arn" - ] - } } ], "Version": "2012-10-17" @@ -412,16 +354,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -452,8 +394,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -466,32 +408,26 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelinesourceCodePipelineActionRoleB7E0306A", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelinebuildCodePipelineActionRole11BCD4FF", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelinebuildtestCodePipelineActionRole467D0DFA", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "PipelinebuildCodePipelineActionRole11BCD4FF", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelinebuildtestCodePipelineActionRole467D0DFA", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelinesourceCodePipelineActionRoleB7E0306A", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -674,16 +610,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -714,8 +650,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -727,11 +663,11 @@ }, { "Action": [ + "codecommit:CancelUploadArchive", "codecommit:GetBranch", "codecommit:GetCommit", - "codecommit:UploadArchive", "codecommit:GetUploadArchiveStatus", - "codecommit:CancelUploadArchive" + "codecommit:UploadArchive" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit.expected.json index 23bdec497e551..4b563e55092f9 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit.expected.json @@ -219,16 +219,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -259,8 +259,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -273,22 +273,20 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelinesourceCodePipelineActionRoleB7E0306A", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelinebuildmanualCodePipelineActionRoleE3306AB0", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "PipelinebuildmanualCodePipelineActionRoleE3306AB0", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelinesourceCodePipelineActionRoleB7E0306A", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -429,16 +427,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -469,8 +467,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -482,11 +480,11 @@ }, { "Action": [ + "codecommit:CancelUploadArchive", "codecommit:GetBranch", "codecommit:GetCommit", - "codecommit:UploadArchive", "codecommit:GetUploadArchiveStatus", - "codecommit:CancelUploadArchive" + "codecommit:UploadArchive" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-deploy-ecs.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-deploy-ecs.expected.json index 1b20a71fd7def..3693be3cc42a8 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-deploy-ecs.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-deploy-ecs.expected.json @@ -34,16 +34,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -72,22 +72,20 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineSourceS3SourceCodePipelineActionRole8DE11A40", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineDeployCodeDeployCodePipelineActionRoleFA7F8EEF", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineDeployCodeDeployCodePipelineActionRoleFA7F8EEF", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineSourceS3SourceCodePipelineActionRole8DE11A40", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -230,8 +228,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -260,13 +258,13 @@ }, { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -438,8 +436,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -478,4 +476,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-deploy.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-deploy.expected.json index eb87655dd0e60..2908540d6e921 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-deploy.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-deploy.expected.json @@ -119,16 +119,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -157,22 +157,20 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineSourceS3SourceCodePipelineActionRole8DE11A40", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineDeployCodeDeployCodePipelineActionRoleFA7F8EEF", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineDeployCodeDeployCodePipelineActionRoleFA7F8EEF", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineSourceS3SourceCodePipelineActionRole8DE11A40", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -313,8 +311,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -343,13 +341,13 @@ }, { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -516,8 +514,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -556,4 +554,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json index 4720701233397..6436188227e18 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json @@ -29,16 +29,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -67,22 +67,20 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyPipelineSourceECRSourceCodePipelineActionRole4C6714EE", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyPipelineApproveManualApprovalCodePipelineActionRole9E338F01", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "MyPipelineApproveManualApprovalCodePipelineActionRole9E338F01", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "MyPipelineSourceECRSourceCodePipelineActionRole4C6714EE", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -219,13 +217,13 @@ }, { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -356,6 +354,11 @@ }, "MyEcrRepo767466D0": { "Type": "AWS::ECR::Repository", + "Properties": { + "ImageScanningConfiguration": { + "ScanOnPush": false + } + }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -423,4 +426,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecs-deploy.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecs-deploy.expected.json index 725008ba28aa8..067cd58ef2d4d 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecs-deploy.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecs-deploy.expected.json @@ -95,15 +95,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "Name", @@ -201,6 +201,11 @@ }, "EcrRepoBB83A592": { "Type": "AWS::ECR::Repository", + "Properties": { + "ImageScanningConfiguration": { + "ScanOnPush": false + } + }, "UpdateReplacePolicy": "Retain", "DeletionPolicy": "Retain" }, @@ -356,7 +361,8 @@ ":log-group:/aws/codebuild/", { "Ref": "EcsProject54EFDCA6" - } + }, + ":*" ] ] }, @@ -379,8 +385,7 @@ ":log-group:/aws/codebuild/", { "Ref": "EcsProject54EFDCA6" - }, - ":*" + } ] ] } @@ -389,8 +394,12 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", + "ecr:BatchGetImage", + "ecr:CompleteLayerUpload", "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:InitiateLayerUpload", + "ecr:PutImage", + "ecr:UploadLayerPart" ], "Effect": "Allow", "Resource": { @@ -407,31 +416,16 @@ }, { "Action": [ - "ecr:PutImage", - "ecr:InitiateLayerUpload", - "ecr:UploadLayerPart", - "ecr:CompleteLayerUpload" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "EcrRepoBB83A592", - "Arn" - ] - } - }, - { - "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -575,16 +569,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -613,32 +607,26 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyPipelineSourceCodePipelineActionRoleAA05D76F", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyPipelineBuildCodeBuildCodePipelineActionRoleCAE538CA", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyPipelineDeployDeployActionCodePipelineActionRole854184EF", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "MyPipelineBuildCodeBuildCodePipelineActionRoleCAE538CA", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "MyPipelineDeployDeployActionCodePipelineActionRole854184EF", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "MyPipelineSourceCodePipelineActionRoleAA05D76F", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -819,8 +807,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -849,13 +837,13 @@ }, { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -1018,8 +1006,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -1058,4 +1046,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecs-separate-source.lit.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecs-separate-source.lit.expected.json index a728e17a69655..dd96ee385872c 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecs-separate-source.lit.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecs-separate-source.lit.expected.json @@ -3,6 +3,11 @@ "Resources": { "EcsDeployRepositoryE7A569C0": { "Type": "AWS::ECR::Repository", + "Properties": { + "ImageScanningConfiguration": { + "ScanOnPush": false + } + }, "UpdateReplacePolicy": "Retain", "DeletionPolicy": "Retain" }, @@ -55,7 +60,8 @@ ":log-group:/aws/codebuild/", { "Ref": "AppCodeDockerImageBuildAndPushProject00DD6671" - } + }, + ":*" ] ] }, @@ -78,8 +84,7 @@ ":log-group:/aws/codebuild/", { "Ref": "AppCodeDockerImageBuildAndPushProject00DD6671" - }, - ":*" + } ] ] } @@ -87,11 +92,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -122,8 +127,12 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", + "ecr:BatchGetImage", + "ecr:CompleteLayerUpload", "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:InitiateLayerUpload", + "ecr:PutImage", + "ecr:UploadLayerPart" ], "Effect": "Allow", "Resource": { @@ -140,23 +149,8 @@ }, { "Action": [ - "ecr:PutImage", - "ecr:InitiateLayerUpload", - "ecr:UploadLayerPart", - "ecr:CompleteLayerUpload" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "EcsDeployRepositoryE7A569C0", - "Arn" - ] - } - }, - { - "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -326,7 +320,8 @@ ":log-group:/aws/codebuild/", { "Ref": "CdkCodeBuildProject98C8CAB8" - } + }, + ":*" ] ] }, @@ -349,8 +344,7 @@ ":log-group:/aws/codebuild/", { "Ref": "CdkCodeBuildProject98C8CAB8" - }, - ":*" + } ] ] } @@ -358,11 +352,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -392,16 +386,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -638,16 +632,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -676,52 +670,38 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "CodePipelineDeployingEcsApplicationSourceAppCodeSourceCodePipelineActionRole6D88B36F", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "CodePipelineDeployingEcsApplicationSourceCdkCodeSourceCodePipelineActionRoleA1E3A5E9", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "CodePipelineDeployingEcsApplicationBuildAppCodeDockerImageBuildAndPushCodePipelineActionRole9B025737", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "CodePipelineDeployingEcsApplicationBuildCdkCodeBuildAndSynthCodePipelineActionRole54094521", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "CodePipelineDeployingEcsApplicationDeployCFNDeployCodePipelineActionRoleC97FFCE2", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "CodePipelineDeployingEcsApplicationBuildAppCodeDockerImageBuildAndPushCodePipelineActionRole9B025737", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "CodePipelineDeployingEcsApplicationBuildCdkCodeBuildAndSynthCodePipelineActionRole54094521", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "CodePipelineDeployingEcsApplicationDeployCFNDeployCodePipelineActionRoleC97FFCE2", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "CodePipelineDeployingEcsApplicationSourceAppCodeSourceCodePipelineActionRole6D88B36F", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "CodePipelineDeployingEcsApplicationSourceCdkCodeSourceCodePipelineActionRoleA1E3A5E9", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -965,16 +945,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -1002,11 +982,11 @@ }, { "Action": [ + "codecommit:CancelUploadArchive", "codecommit:GetBranch", "codecommit:GetCommit", - "codecommit:UploadArchive", "codecommit:GetUploadArchiveStatus", - "codecommit:CancelUploadArchive" + "codecommit:UploadArchive" ], "Effect": "Allow", "Resource": { @@ -1066,16 +1046,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -1103,11 +1083,11 @@ }, { "Action": [ + "codecommit:CancelUploadArchive", "codecommit:GetBranch", "codecommit:GetCommit", - "codecommit:UploadArchive", "codecommit:GetUploadArchiveStatus", - "codecommit:CancelUploadArchive" + "codecommit:UploadArchive" ], "Effect": "Allow", "Resource": { @@ -1361,8 +1341,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -1456,8 +1436,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -1643,8 +1623,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { @@ -1762,15 +1742,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "Tags": [ { "Key": "Name", @@ -1924,4 +1904,4 @@ } } } -] +] \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json index 0a7d958491359..2463346d5f924 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json @@ -148,16 +148,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -188,8 +188,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -202,22 +202,20 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyPipelineSourceCodeCommitSourceCodePipelineActionRole0B6D0F4F", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyPipelineBuildCodeBuildActionCodePipelineActionRole3185ADC7", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "MyPipelineBuildCodeBuildActionCodePipelineActionRole3185ADC7", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "MyPipelineSourceCodeCommitSourceCodePipelineActionRole0B6D0F4F", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -373,16 +371,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -413,8 +411,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -426,11 +424,11 @@ }, { "Action": [ + "codecommit:CancelUploadArchive", "codecommit:GetBranch", "codecommit:GetCommit", - "codecommit:UploadArchive", "codecommit:GetUploadArchiveStatus", - "codecommit:CancelUploadArchive" + "codecommit:UploadArchive" ], "Effect": "Allow", "Resource": { @@ -732,7 +730,8 @@ ":log-group:/aws/codebuild/", { "Ref": "BuildProject097C5DB7" - } + }, + ":*" ] ] }, @@ -755,8 +754,7 @@ ":log-group:/aws/codebuild/", { "Ref": "BuildProject097C5DB7" - }, - ":*" + } ] ] } @@ -764,16 +762,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -804,23 +802,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyPipelineArtifactsBucketEncryptionKey8BF0A7F3", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-jenkins.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-jenkins.expected.json index eda778cf7ec55..5fc5cc38226da 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-jenkins.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-jenkins.expected.json @@ -34,16 +34,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -248,8 +248,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -278,13 +278,13 @@ }, { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -380,4 +380,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-manual-approval.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-manual-approval.expected.json index 1193cbb2f30d0..271e03333b4a4 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-manual-approval.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-manual-approval.expected.json @@ -29,16 +29,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -67,22 +67,20 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineSourceS3CodePipelineActionRole3CAFD08F", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineApproveManualApprovalCodePipelineActionRole51D669A5", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineApproveManualApprovalCodePipelineActionRole51D669A5", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineSourceS3CodePipelineActionRole3CAFD08F", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -215,8 +213,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -245,13 +243,13 @@ }, { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -357,4 +355,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-s3-deploy.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-s3-deploy.expected.json index 9cc08aec93f44..0cac0ad6b45ef 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-s3-deploy.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-s3-deploy.expected.json @@ -39,16 +39,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -77,22 +77,20 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineSourceCodePipelineActionRoleC6F9E7F5", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineDeployDeployActionCodePipelineActionRole1C288A60", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineDeployDeployActionCodePipelineActionRole1C288A60", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineSourceCodePipelineActionRoleC6F9E7F5", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -233,8 +231,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -263,13 +261,13 @@ }, { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -345,13 +343,13 @@ "Statement": [ { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -400,8 +398,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -440,4 +438,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-stepfunctions.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-stepfunctions.expected.json index d35d3f59e6bb2..2b47ced6d3afb 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-stepfunctions.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-stepfunctions.expected.json @@ -191,16 +191,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -231,8 +231,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -245,22 +245,20 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyPipelineSourceCodePipelineActionRoleAA05D76F", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyPipelineInvokeCodePipelineActionRole006B5BAD", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "MyPipelineInvokeCodePipelineActionRole006B5BAD", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "MyPipelineSourceCodePipelineActionRoleAA05D76F", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" @@ -405,8 +403,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -435,13 +433,13 @@ }, { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -469,10 +467,10 @@ }, { "Action": [ + "kms:Decrypt", "kms:Encrypt", - "kms:ReEncrypt*", "kms:GenerateDataKey*", - "kms:Decrypt" + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -532,8 +530,8 @@ "Statement": [ { "Action": [ - "states:StartExecution", - "states:DescribeStateMachine" + "states:DescribeStateMachine", + "states:StartExecution" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-codepipeline/package.json b/packages/@aws-cdk/aws-codepipeline/package.json index 29d74c51f6628..8d3f6978b445a 100644 --- a/packages/@aws-cdk/aws-codepipeline/package.json +++ b/packages/@aws-cdk/aws-codepipeline/package.json @@ -90,8 +90,8 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-codestarnotifications": "0.0.0", diff --git a/packages/@aws-cdk/aws-codestar/package.json b/packages/@aws-cdk/aws-codestar/package.json index a2ae9b1cbd339..478f09bef3b9d 100644 --- a/packages/@aws-cdk/aws-codestar/package.json +++ b/packages/@aws-cdk/aws-codestar/package.json @@ -86,7 +86,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-s3": "0.0.0", diff --git a/packages/@aws-cdk/aws-codestarconnections/package.json b/packages/@aws-cdk/aws-codestarconnections/package.json index 9d06e3ea4db51..2e8cfc5deac99 100644 --- a/packages/@aws-cdk/aws-codestarconnections/package.json +++ b/packages/@aws-cdk/aws-codestarconnections/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-codestarnotifications/package.json b/packages/@aws-cdk/aws-codestarnotifications/package.json index e6d2bf301f3b4..5e181702720cf 100644 --- a/packages/@aws-cdk/aws-codestarnotifications/package.json +++ b/packages/@aws-cdk/aws-codestarnotifications/package.json @@ -86,7 +86,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-cognito-identitypool/package.json b/packages/@aws-cdk/aws-cognito-identitypool/package.json index c4e0c079d7daa..19171391ad7be 100644 --- a/packages/@aws-cdk/aws-cognito-identitypool/package.json +++ b/packages/@aws-cdk/aws-cognito-identitypool/package.json @@ -81,8 +81,8 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-cognito": "0.0.0", diff --git a/packages/@aws-cdk/aws-cognito/README.md b/packages/@aws-cdk/aws-cognito/README.md index 96629cf13decd..c7348ad5e9b0c 100644 --- a/packages/@aws-cdk/aws-cognito/README.md +++ b/packages/@aws-cdk/aws-cognito/README.md @@ -31,7 +31,7 @@ The two main components of Amazon Cognito are [user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools.html) and [identity pools](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-identity.html). User pools are user directories that provide sign-up and sign-in options for your app users. Identity pools enable you to grant your users access to -other AWS services. Identity Pool L2 Constructs can be found [here](../aws-cognito-identitypool). +other AWS services. Identity Pool L2 Constructs can be found [here](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cognito-identitypool-alpha-readme.html). This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts index 59f3ce09f2057..a4157d629307d 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts @@ -522,6 +522,14 @@ export interface UserPoolProps { */ readonly smsRoleExternalId?: string; + /** + * The region to integrate with SNS to send SMS messages + * + * This property will do nothing if SMS configuration is not configured + * @default - The same region as the user pool, with a few exceptions - https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-sms-settings.html#user-pool-sms-settings-first-time + */ + readonly snsRegion?: string; + /** * Setting this would explicitly enable or disable SMS role creation. * When left unspecified, CDK will determine based on other properties if a role is needed or not. @@ -585,8 +593,8 @@ export interface UserPoolProps { /** * Configure the MFA types that users can use in this user pool. Ignored if `mfa` is set to `OFF`. * - * @default - { sms: true, oneTimePassword: false }, if `mfa` is set to `OPTIONAL` or `REQUIRED`. - * { sms: false, oneTimePassword: false }, otherwise + * @default - { sms: true, otp: false }, if `mfa` is set to `OPTIONAL` or `REQUIRED`. + * { sms: false, otp: false }, otherwise */ readonly mfaSecondFactor?: MfaSecondFactor; @@ -1032,6 +1040,7 @@ export class UserPool extends UserPoolBase { return { snsCallerArn: props.smsRole.roleArn, externalId: props.smsRoleExternalId, + snsRegion: props.snsRegion, }; } @@ -1072,6 +1081,7 @@ export class UserPool extends UserPoolBase { return { externalId: smsRoleExternalId, snsCallerArn: smsRole.roleArn, + snsRegion: props.snsRegion, }; } diff --git a/packages/@aws-cdk/aws-cognito/package.json b/packages/@aws-cdk/aws-cognito/package.json index e0f10c43ca32a..7f38517f6abae 100644 --- a/packages/@aws-cdk/aws-cognito/package.json +++ b/packages/@aws-cdk/aws-cognito/package.json @@ -84,9 +84,9 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "@types/punycode": "^2.1.0", - "jest": "^27.4.7" + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json index 31a16a8f26393..a5e10b6059b72 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json @@ -146,7 +146,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3BucketD609D0D9" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16" }, "S3Key": { "Fn::Join": [ @@ -159,7 +159,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -172,7 +172,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -213,17 +213,17 @@ } }, "Parameters": { - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3BucketD609D0D9": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16": { "Type": "String", - "Description": "S3 bucket for asset \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "S3 bucket for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B": { "Type": "String", - "Description": "S3 key for asset version \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "S3 key for asset version \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cArtifactHash86CFA15D": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87ArtifactHash40DDF5EE": { "Type": "String", - "Description": "Artifact hash for asset \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "Artifact hash for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json index 50da9815a769b..0811dc3173db4 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json @@ -833,6 +833,9 @@ "myuserpoolsmsRole0E16FDD9", "Arn" ] + }, + "SnsRegion": { + "Ref": "AWS::Region" } }, "SmsVerificationMessage": "verification sms message from the integ test. Code is {####}.", @@ -850,7 +853,7 @@ "myuserpoolmyuserpooldomainEE1E11AF": { "Type": "AWS::Cognito::UserPoolDomain", "Properties": { - "Domain": "myawesomeapp", + "Domain": "cdkintegrationtestuserpoolexplicitprops", "UserPoolId": { "Ref": "myuserpool01998219" } diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.ts index 1bc35003fa472..8c26481628971 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.ts @@ -69,11 +69,12 @@ const userpool = new UserPool(stack, 'myuserpool', { userMigration: dummyTrigger('userMigration'), verifyAuthChallengeResponse: dummyTrigger('verifyAuthChallengeResponse'), }, + snsRegion: Stack.of(stack).region, }); const cognitoDomain = userpool.addDomain('myuserpooldomain', { cognitoDomain: { - domainPrefix: 'myawesomeapp', + domainPrefix: 'cdkintegrationtestuserpoolexplicitprops', }, }); diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts index 1efa42aeda79b..b482d244ea6fa 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts @@ -235,6 +235,28 @@ describe('User Pool', () => { }); }); + test('snsRegion property is recognized', () => { + // GIVEN + const stack = new Stack(); + const role = Role.fromRoleArn(stack, 'smsRole', 'arn:aws:iam::664773442901:role/sms-role'); + + // WHEN + new UserPool(stack, 'Pool', { + smsRole: role, + smsRoleExternalId: 'test-external-id', + snsRegion: 'test-region-1', + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { + SmsConfiguration: { + ExternalId: 'test-external-id', + SnsCallerArn: role.roleArn, + SnsRegion: 'test-region-1', + }, + }); + }); + test('import using id', () => { // GIVEN const stack = new Stack(undefined, undefined, { diff --git a/packages/@aws-cdk/aws-config/lib/rule.ts b/packages/@aws-cdk/aws-config/lib/rule.ts index e1ac4d107ec9e..d4d176bc69c3b 100644 --- a/packages/@aws-cdk/aws-config/lib/rule.ts +++ b/packages/@aws-cdk/aws-config/lib/rule.ts @@ -1136,6 +1136,13 @@ export class ManagedRuleIdentifiers { * @see https://docs.aws.amazon.com/config/latest/developerguide/s3-account-level-public-access-blocks.html */ public static readonly S3_ACCOUNT_LEVEL_PUBLIC_ACCESS_BLOCKS = 'S3_ACCOUNT_LEVEL_PUBLIC_ACCESS_BLOCKS'; + /** + * Checks if Amazon Simple Storage Service (Amazon S3) buckets are publicly accessible. This rule is + * NON_COMPLIANT if an Amazon S3 bucket is not listed in the excludedPublicBuckets parameter and bucket level + * settings are public. + * @see https://docs.aws.amazon.com/config/latest/developerguide/s3-bucket-level-public-access-prohibited.html + */ + public static readonly S3_BUCKET_LEVEL_PUBLIC_ACCESS_PROHIBITED = 'S3_BUCKET_LEVEL_PUBLIC_ACCESS_PROHIBITED'; /** * Checks that the Amazon Simple Storage Service bucket policy does not allow * blocked bucket-level and object-level actions on resources in the bucket diff --git a/packages/@aws-cdk/aws-config/package.json b/packages/@aws-cdk/aws-config/package.json index e0cd4997a725a..8a121a8927bd4 100644 --- a/packages/@aws-cdk/aws-config/package.json +++ b/packages/@aws-cdk/aws-config/package.json @@ -85,8 +85,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", diff --git a/packages/@aws-cdk/aws-config/test/managed-rules.test.ts b/packages/@aws-cdk/aws-config/test/managed-rules.test.ts index ef7e98ff25709..b360267c97352 100644 --- a/packages/@aws-cdk/aws-config/test/managed-rules.test.ts +++ b/packages/@aws-cdk/aws-config/test/managed-rules.test.ts @@ -165,3 +165,23 @@ describe('ec2 instance', () => { }); }); }); + +describe('s3 bucket level', () => { + test('public access prohibited', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new config.ManagedRule(stack, 'S3BucketLevelPublicAccessProhibited', { + identifier: config.ManagedRuleIdentifiers.S3_BUCKET_LEVEL_PUBLIC_ACCESS_PROHIBITED, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Config::ConfigRule', { + Source: { + Owner: 'AWS', + SourceIdentifier: config.ManagedRuleIdentifiers.S3_BUCKET_LEVEL_PUBLIC_ACCESS_PROHIBITED, + }, + }); + }); +}); diff --git a/packages/@aws-cdk/aws-connect/package.json b/packages/@aws-cdk/aws-connect/package.json index 0d413aaf0db47..e9d851b1824a9 100644 --- a/packages/@aws-cdk/aws-connect/package.json +++ b/packages/@aws-cdk/aws-connect/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-cur/package.json b/packages/@aws-cdk/aws-cur/package.json index c871e8b723bc9..00adc1d4d1602 100644 --- a/packages/@aws-cdk/aws-cur/package.json +++ b/packages/@aws-cdk/aws-cur/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-customerprofiles/package.json b/packages/@aws-cdk/aws-customerprofiles/package.json index e73bd86cba198..d9a6f1632efab 100644 --- a/packages/@aws-cdk/aws-customerprofiles/package.json +++ b/packages/@aws-cdk/aws-customerprofiles/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-databrew/package.json b/packages/@aws-cdk/aws-databrew/package.json index 66e42d3cd4e94..749abf6bab9b7 100644 --- a/packages/@aws-cdk/aws-databrew/package.json +++ b/packages/@aws-cdk/aws-databrew/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-datapipeline/package.json b/packages/@aws-cdk/aws-datapipeline/package.json index 0aff6f0f1389c..24d3144f7c33d 100644 --- a/packages/@aws-cdk/aws-datapipeline/package.json +++ b/packages/@aws-cdk/aws-datapipeline/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-datasync/package.json b/packages/@aws-cdk/aws-datasync/package.json index 1dc0061ea02ec..ff9c4cdd4699b 100644 --- a/packages/@aws-cdk/aws-datasync/package.json +++ b/packages/@aws-cdk/aws-datasync/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-dax/package.json b/packages/@aws-cdk/aws-dax/package.json index c00396c2220ae..2901f449cf06e 100644 --- a/packages/@aws-cdk/aws-dax/package.json +++ b/packages/@aws-cdk/aws-dax/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-detective/package.json b/packages/@aws-cdk/aws-detective/package.json index 2522e915d02b3..cc061a9a00648 100644 --- a/packages/@aws-cdk/aws-detective/package.json +++ b/packages/@aws-cdk/aws-detective/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-devopsguru/package.json b/packages/@aws-cdk/aws-devopsguru/package.json index 2082aba14cbd3..9937e175014f4 100644 --- a/packages/@aws-cdk/aws-devopsguru/package.json +++ b/packages/@aws-cdk/aws-devopsguru/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-directoryservice/package.json b/packages/@aws-cdk/aws-directoryservice/package.json index 7e32fa22bdfc5..4d37918cd7b3a 100644 --- a/packages/@aws-cdk/aws-directoryservice/package.json +++ b/packages/@aws-cdk/aws-directoryservice/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-dlm/package.json b/packages/@aws-cdk/aws-dlm/package.json index d59d69ba32dc5..f1601bd7cc135 100644 --- a/packages/@aws-cdk/aws-dlm/package.json +++ b/packages/@aws-cdk/aws-dlm/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-dms/package.json b/packages/@aws-cdk/aws-dms/package.json index 2c7da4b13bac7..3f20999bb1e0a 100644 --- a/packages/@aws-cdk/aws-dms/package.json +++ b/packages/@aws-cdk/aws-dms/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-docdb/lib/instance.ts b/packages/@aws-cdk/aws-docdb/lib/instance.ts index 1a791b99a0bf5..9611235077389 100644 --- a/packages/@aws-cdk/aws-docdb/lib/instance.ts +++ b/packages/@aws-cdk/aws-docdb/lib/instance.ts @@ -101,7 +101,7 @@ abstract class DatabaseInstanceBase extends cdk.Resource implements IDatabaseIns */ public get instanceArn(): string { return cdk.Stack.of(this).formatArn({ - service: 'docdb', + service: 'rds', resource: 'db', arnFormat: ArnFormat.COLON_RESOURCE_NAME, resourceName: this.instanceIdentifier, diff --git a/packages/@aws-cdk/aws-docdb/package.json b/packages/@aws-cdk/aws-docdb/package.json index 4242c8e2a7622..02721228f2097 100644 --- a/packages/@aws-cdk/aws-docdb/package.json +++ b/packages/@aws-cdk/aws-docdb/package.json @@ -86,7 +86,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-docdb/test/instance.test.ts b/packages/@aws-cdk/aws-docdb/test/instance.test.ts index d7e90af3e3e90..a83525110f8f8 100644 --- a/packages/@aws-cdk/aws-docdb/test/instance.test.ts +++ b/packages/@aws-cdk/aws-docdb/test/instance.test.ts @@ -117,7 +117,7 @@ describe('DatabaseInstance', () => { [ 'arn:', { Ref: 'AWS::Partition' }, - ':docdb:us-test-1:12345:db:', + ':rds:us-test-1:12345:db:', { Ref: 'InstanceC1063A87' }, ], ], @@ -160,7 +160,7 @@ describe('DatabaseInstance', () => { [ 'arn:', { Ref: 'AWS::Partition' }, - `:docdb:us-test-1:12345:db:${instanceIdentifier}`, + `:rds:us-test-1:12345:db:${instanceIdentifier}`, ], ], }, diff --git a/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json b/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json index c800f1fbedba1..7cce62d49d375 100644 --- a/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json +++ b/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json @@ -818,7 +818,7 @@ "DatabaseRotationSingleUserSARMapping9AEB3E55": { "aws": { "applicationId": "arn:aws:serverlessrepo:us-east-1:297356227824:applications/SecretsManagerMongoDBRotationSingleUser", - "semanticVersion": "1.1.60" + "semanticVersion": "1.1.225" }, "aws-cn": { "applicationId": "arn:aws-cn:serverlessrepo:cn-north-1:193023089310:applications/SecretsManagerMongoDBRotationSingleUser", diff --git a/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json b/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json index a5d4a4668d5a2..0a5527985d286 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json +++ b/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json @@ -37,7 +37,7 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^4.3.1", "eslint-plugin-standard": "^4.1.0", - "jest": "^27.4.7", + "jest": "^27.5.1", "lambda-tester": "^3.6.0", "nock": "^13.2.4" } diff --git a/packages/@aws-cdk/aws-dynamodb-global/package.json b/packages/@aws-cdk/aws-dynamodb-global/package.json index 882e1b789e912..5618565bc6119 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/package.json +++ b/packages/@aws-cdk/aws-dynamodb-global/package.json @@ -67,8 +67,8 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "peerDependencies": { "@aws-cdk/aws-dynamodb": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.expected.json b/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.expected.json index 3aab4c4f3a64b..092eaa51cc403 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.expected.json +++ b/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.expected.json @@ -132,14 +132,14 @@ "Statement": [ { "Action": [ - "iam:CreateServiceLinkedRole", "application-autoscaling:DeleteScalingPolicy", "application-autoscaling:DeregisterScalableTarget", "dynamodb:CreateGlobalTable", - "dynamodb:DescribeLimits", "dynamodb:DeleteTable", "dynamodb:DescribeGlobalTable", - "dynamodb:UpdateGlobalTable" + "dynamodb:DescribeLimits", + "dynamodb:UpdateGlobalTable", + "iam:CreateServiceLinkedRole" ], "Effect": "Allow", "Resource": "*" diff --git a/packages/@aws-cdk/aws-dynamodb/lib/perms.ts b/packages/@aws-cdk/aws-dynamodb/lib/perms.ts index af385e57209f5..29d240d245f75 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/perms.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/perms.ts @@ -29,3 +29,5 @@ export const READ_STREAM_DATA_ACTIONS = [ 'dynamodb:GetRecords', 'dynamodb:GetShardIterator', ]; + +export const DESCRIBE_TABLE = 'dynamodb:DescribeTable'; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-dynamodb/lib/table.ts b/packages/@aws-cdk/aws-dynamodb/lib/table.ts index bc4b6ce39c9f0..00dca8dbe31e3 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/table.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/table.ts @@ -679,7 +679,7 @@ abstract class TableBase extends Resource implements ITable { /** * Permits an IAM principal all data read operations from this table: - * BatchGetItem, GetRecords, GetShardIterator, Query, GetItem, Scan. + * BatchGetItem, GetRecords, GetShardIterator, Query, GetItem, Scan, DescribeTable. * * Appropriate grants will also be added to the customer-managed KMS key * if one was configured. @@ -687,7 +687,8 @@ abstract class TableBase extends Resource implements ITable { * @param grantee The principal to grant access to */ public grantReadData(grantee: iam.IGrantable): iam.Grant { - return this.combinedGrant(grantee, { keyActions: perms.KEY_READ_ACTIONS, tableActions: perms.READ_DATA_ACTIONS }); + const tableActions = perms.READ_DATA_ACTIONS.concat(perms.DESCRIBE_TABLE); + return this.combinedGrant(grantee, { keyActions: perms.KEY_READ_ACTIONS, tableActions }); } /** @@ -724,7 +725,7 @@ abstract class TableBase extends Resource implements ITable { /** * Permits an IAM principal all data write operations to this table: - * BatchWriteItem, PutItem, UpdateItem, DeleteItem. + * BatchWriteItem, PutItem, UpdateItem, DeleteItem, DescribeTable. * * Appropriate grants will also be added to the customer-managed KMS key * if one was configured. @@ -732,13 +733,15 @@ abstract class TableBase extends Resource implements ITable { * @param grantee The principal to grant access to */ public grantWriteData(grantee: iam.IGrantable): iam.Grant { - return this.combinedGrant(grantee, { keyActions: perms.KEY_WRITE_ACTIONS, tableActions: perms.WRITE_DATA_ACTIONS }); + const tableActions = perms.WRITE_DATA_ACTIONS.concat(perms.DESCRIBE_TABLE); + const keyActions = perms.KEY_READ_ACTIONS.concat(perms.KEY_WRITE_ACTIONS); + return this.combinedGrant(grantee, { keyActions, tableActions }); } /** * Permits an IAM principal to all data read/write operations to this table. * BatchGetItem, GetRecords, GetShardIterator, Query, GetItem, Scan, - * BatchWriteItem, PutItem, UpdateItem, DeleteItem + * BatchWriteItem, PutItem, UpdateItem, DeleteItem, DescribeTable * * Appropriate grants will also be added to the customer-managed KMS key * if one was configured. @@ -746,7 +749,7 @@ abstract class TableBase extends Resource implements ITable { * @param grantee The principal to grant access to */ public grantReadWriteData(grantee: iam.IGrantable): iam.Grant { - const tableActions = perms.READ_DATA_ACTIONS.concat(perms.WRITE_DATA_ACTIONS); + const tableActions = perms.READ_DATA_ACTIONS.concat(perms.WRITE_DATA_ACTIONS).concat(perms.DESCRIBE_TABLE); const keyActions = perms.KEY_READ_ACTIONS.concat(perms.KEY_WRITE_ACTIONS); return this.combinedGrant(grantee, { keyActions, tableActions }); } diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index 7c85271772bfd..1b30eb1a07e6d 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -84,14 +84,14 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.92", - "@types/jest": "^27.4.0", + "@types/aws-lambda": "^8.10.93", + "@types/jest": "^27.4.1", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", "aws-sdk-mock": "5.6.0", - "jest": "^27.4.7", + "jest": "^27.5.1", "sinon": "^9.2.4", - "ts-jest": "^27.1.3" + "ts-jest": "^27.1.4" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts index 6ca8b3bd0cf65..d5307ef43fe61 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts @@ -1,4 +1,4 @@ -import { Match, Template } from '@aws-cdk/assertions'; +import { Annotations, Match, Template } from '@aws-cdk/assertions'; import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; import * as iam from '@aws-cdk/aws-iam'; import * as kinesis from '@aws-cdk/aws-kinesis'; @@ -643,6 +643,7 @@ testLegacyBehavior('if an encryption key is included, encrypt/decrypt permission 'dynamodb:PutItem', 'dynamodb:UpdateItem', 'dynamodb:DeleteItem', + 'dynamodb:DescribeTable', ], Effect: 'Allow', Resource: [ @@ -720,6 +721,38 @@ test('if an encryption key is included, encrypt/decrypt permissions are added to }); }); +test('if an encryption key is included, encrypt/decrypt permissions are added to the principal for grantWriteData', () => { + const stack = new Stack(); + const table = new Table(stack, 'Table A', { + tableName: TABLE_NAME, + partitionKey: TABLE_PARTITION_KEY, + encryption: TableEncryption.CUSTOMER_MANAGED, + }); + const user = new iam.User(stack, 'MyUser'); + table.grantWriteData(user); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: Match.arrayWith([{ + Action: [ + 'kms:Decrypt', + 'kms:DescribeKey', + 'kms:Encrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', + ], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'TableAKey07CC09EC', + 'Arn', + ], + }, + }]), + }, + }); +}); + test('when specifying STANDARD_INFREQUENT_ACCESS table class', () => { const stack = new Stack(); new Table(stack, CONSTRUCT_NAME, { @@ -1589,6 +1622,47 @@ test('can autoscale on a schedule', () => { }); }); +test('scheduled scaling shows warning when minute is not defined in cron', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { + readCapacity: 42, + writeCapacity: 1337, + partitionKey: { name: 'Hash', type: AttributeType.STRING }, + }); + + // WHEN + const scaling = table.autoScaleReadCapacity({ minCapacity: 1, maxCapacity: 100 }); + scaling.scaleOnSchedule('SaveMoneyByNotScalingUp', { + schedule: appscaling.Schedule.cron({}), + maxCapacity: 10, + }); + + // THEN + Annotations.fromStack(stack).hasWarning('/Default/MyTable/ReadScaling/Target', "cron: If you don't pass 'minute', by default the event runs every minute. Pass 'minute: '*'' if that's what you intend, or 'minute: 0' to run once per hour instead."); +}); + +test('scheduled scaling shows no warning when minute is * in cron', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { + readCapacity: 42, + writeCapacity: 1337, + partitionKey: { name: 'Hash', type: AttributeType.STRING }, + }); + + // WHEN + const scaling = table.autoScaleReadCapacity({ minCapacity: 1, maxCapacity: 100 }); + scaling.scaleOnSchedule('SaveMoneyByNotScalingUp', { + schedule: appscaling.Schedule.cron({ minute: '*' }), + maxCapacity: 10, + }); + + // THEN + const annotations = Annotations.fromStack(stack).findWarning('*', Match.anyValue()); + expect(annotations.length).toBe(0); +}); + describe('metrics', () => { test('Can use metricConsumedReadCapacityUnits on a Dynamodb Table', () => { // GIVEN @@ -1887,18 +1961,18 @@ describe('grants', () => { test('"grantReadData" allows the principal to read data from the table', () => { testGrant( - ['BatchGetItem', 'GetRecords', 'GetShardIterator', 'Query', 'GetItem', 'Scan', 'ConditionCheckItem'], (p, t) => t.grantReadData(p)); + ['BatchGetItem', 'GetRecords', 'GetShardIterator', 'Query', 'GetItem', 'Scan', 'ConditionCheckItem', 'DescribeTable'], (p, t) => t.grantReadData(p)); }); test('"grantWriteData" allows the principal to write data to the table', () => { testGrant( - ['BatchWriteItem', 'PutItem', 'UpdateItem', 'DeleteItem'], (p, t) => t.grantWriteData(p)); + ['BatchWriteItem', 'PutItem', 'UpdateItem', 'DeleteItem', 'DescribeTable'], (p, t) => t.grantWriteData(p)); }); test('"grantReadWriteData" allows the principal to read/write data', () => { testGrant([ 'BatchGetItem', 'GetRecords', 'GetShardIterator', 'Query', 'GetItem', 'Scan', - 'ConditionCheckItem', 'BatchWriteItem', 'PutItem', 'UpdateItem', 'DeleteItem', + 'ConditionCheckItem', 'BatchWriteItem', 'PutItem', 'UpdateItem', 'DeleteItem', 'DescribeTable', ], (p, t) => t.grantReadWriteData(p)); }); @@ -2060,6 +2134,7 @@ describe('grants', () => { 'dynamodb:GetItem', 'dynamodb:Scan', 'dynamodb:ConditionCheckItem', + 'dynamodb:DescribeTable', ], 'Effect': 'Allow', 'Resource': [ @@ -2212,6 +2287,7 @@ describe('import', () => { 'dynamodb:GetItem', 'dynamodb:Scan', 'dynamodb:ConditionCheckItem', + 'dynamodb:DescribeTable', ], 'Effect': 'Allow', 'Resource': [ @@ -2258,6 +2334,7 @@ describe('import', () => { 'dynamodb:PutItem', 'dynamodb:UpdateItem', 'dynamodb:DeleteItem', + 'dynamodb:DescribeTable', ], 'Effect': 'Allow', 'Resource': [ @@ -2400,6 +2477,7 @@ describe('import', () => { 'dynamodb:GetItem', 'dynamodb:Scan', 'dynamodb:ConditionCheckItem', + 'dynamodb:DescribeTable', ], Resource: [ { @@ -2574,6 +2652,7 @@ describe('global', () => { 'dynamodb:GetItem', 'dynamodb:Scan', 'dynamodb:ConditionCheckItem', + 'dynamodb:DescribeTable', ], Effect: 'Allow', Resource: [ @@ -2728,6 +2807,7 @@ describe('global', () => { 'dynamodb:GetItem', 'dynamodb:Scan', 'dynamodb:ConditionCheckItem', + 'dynamodb:DescribeTable', ], Effect: 'Allow', Resource: [ diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.expected.json index d20e923f3d55e..1e923947b0287 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.expected.json @@ -382,12 +382,13 @@ { "Action": [ "dynamodb:BatchGetItem", + "dynamodb:ConditionCheckItem", + "dynamodb:DescribeTable", + "dynamodb:GetItem", "dynamodb:GetRecords", "dynamodb:GetShardIterator", "dynamodb:Query", - "dynamodb:GetItem", - "dynamodb:Scan", - "dynamodb:ConditionCheckItem" + "dynamodb:Scan" ], "Effect": "Allow", "Resource": [ @@ -397,23 +398,6 @@ "Arn" ] }, - { - "Ref": "AWS::NoValue" - } - ] - }, - { - "Action": [ - "dynamodb:BatchGetItem", - "dynamodb:GetRecords", - "dynamodb:GetShardIterator", - "dynamodb:Query", - "dynamodb:GetItem", - "dynamodb:Scan", - "dynamodb:ConditionCheckItem" - ], - "Effect": "Allow", - "Resource": [ { "Fn::GetAtt": [ "TableWithGlobalAndLocalSecondaryIndexBC540710", @@ -433,6 +417,9 @@ "/index/*" ] ] + }, + { + "Ref": "AWS::NoValue" } ] } diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.expected.json index 879532d0a8879..01279e64a2b1c 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.expected.json @@ -492,12 +492,13 @@ { "Action": [ "dynamodb:BatchGetItem", + "dynamodb:ConditionCheckItem", + "dynamodb:DescribeTable", + "dynamodb:GetItem", "dynamodb:GetRecords", "dynamodb:GetShardIterator", "dynamodb:Query", - "dynamodb:GetItem", - "dynamodb:Scan", - "dynamodb:ConditionCheckItem" + "dynamodb:Scan" ], "Effect": "Allow", "Resource": [ @@ -507,36 +508,6 @@ "Arn" ] }, - { - "Ref": "AWS::NoValue" - } - ] - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "TableKey25666F95", - "Arn" - ] - } - }, - { - "Action": [ - "dynamodb:BatchGetItem", - "dynamodb:GetRecords", - "dynamodb:GetShardIterator", - "dynamodb:Query", - "dynamodb:GetItem", - "dynamodb:Scan", - "dynamodb:ConditionCheckItem" - ], - "Effect": "Allow", - "Resource": [ { "Fn::GetAtt": [ "TableWithGlobalAndLocalSecondaryIndexBC540710", @@ -556,8 +527,24 @@ "/index/*" ] ] + }, + { + "Ref": "AWS::NoValue" } ] + }, + { + "Action": [ + "kms:Decrypt", + "kms:DescribeKey" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "TableKey25666F95", + "Arn" + ] + } } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json index ce43b532ea7c6..7ac67ff4f0a2c 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json @@ -41,15 +41,6 @@ "Arn" ] }, - { - "Ref": "AWS::NoValue" - } - ] - }, - { - "Action": "dynamodb:*", - "Effect": "Allow", - "Resource": [ { "Fn::Join": [ "", @@ -58,7 +49,7 @@ { "Ref": "AWS::Partition" }, - ":dynamodb:us-east-2:", + ":dynamodb:eu-west-3:", { "Ref": "AWS::AccountId" }, @@ -77,7 +68,7 @@ { "Ref": "AWS::Partition" }, - ":dynamodb:eu-west-3:", + ":dynamodb:us-east-2:", { "Ref": "AWS::AccountId" }, @@ -87,6 +78,9 @@ } ] ] + }, + { + "Ref": "AWS::NoValue" } ] } @@ -290,7 +284,7 @@ }, "/", { - "Ref": "AssetParameters9971e87ecc84219610f1dfbd0fbdd30e29f8d1f408df3f645299eb48b1c1ed00S3BucketC986830C" + "Ref": "AssetParameters35892afbe8ff840a389ee91c3cce6d47b648fe4046b59d612100737b1486a4c1S3Bucket63728AAD" }, "/", { @@ -300,7 +294,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters9971e87ecc84219610f1dfbd0fbdd30e29f8d1f408df3f645299eb48b1c1ed00S3VersionKeyE0DA9F9E" + "Ref": "AssetParameters35892afbe8ff840a389ee91c3cce6d47b648fe4046b59d612100737b1486a4c1S3VersionKey40482FB9" } ] } @@ -313,7 +307,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters9971e87ecc84219610f1dfbd0fbdd30e29f8d1f408df3f645299eb48b1c1ed00S3VersionKeyE0DA9F9E" + "Ref": "AssetParameters35892afbe8ff840a389ee91c3cce6d47b648fe4046b59d612100737b1486a4c1S3VersionKey40482FB9" } ] } @@ -323,17 +317,17 @@ ] }, "Parameters": { - "referencetoawscdkdynamodbglobalreplicasprovisionedAssetParametersdd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776S3BucketD1258B42Ref": { - "Ref": "AssetParametersdd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776S3BucketDEBF01E6" + "referencetoawscdkdynamodbglobalreplicasprovisionedAssetParameters5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80fS3Bucket5157987FRef": { + "Ref": "AssetParameters5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80fS3Bucket1685F95F" }, - "referencetoawscdkdynamodbglobalreplicasprovisionedAssetParametersdd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776S3VersionKey0F5C355ERef": { - "Ref": "AssetParametersdd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776S3VersionKey42EBA2AE" + "referencetoawscdkdynamodbglobalreplicasprovisionedAssetParameters5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80fS3VersionKey001ABDFDRef": { + "Ref": "AssetParameters5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80fS3VersionKey11815B6C" }, - "referencetoawscdkdynamodbglobalreplicasprovisionedAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket6C51C355Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawscdkdynamodbglobalreplicasprovisionedAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket162B76E0Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawscdkdynamodbglobalreplicasprovisionedAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey84AB7371Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawscdkdynamodbglobalreplicasprovisionedAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyF86DF1C2Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -368,41 +362,41 @@ } }, "Parameters": { - "AssetParametersdd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776S3BucketDEBF01E6": { + "AssetParameters5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80fS3Bucket1685F95F": { "Type": "String", - "Description": "S3 bucket for asset \"dd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776\"" + "Description": "S3 bucket for asset \"5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80f\"" }, - "AssetParametersdd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776S3VersionKey42EBA2AE": { + "AssetParameters5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80fS3VersionKey11815B6C": { "Type": "String", - "Description": "S3 key for asset version \"dd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776\"" + "Description": "S3 key for asset version \"5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80f\"" }, - "AssetParametersdd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776ArtifactHash692B4CCE": { + "AssetParameters5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80fArtifactHash259515A1": { "Type": "String", - "Description": "Artifact hash for asset \"dd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776\"" + "Description": "Artifact hash for asset \"5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80f\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { "Type": "String", - "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { "Type": "String", - "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { "Type": "String", - "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParameters9971e87ecc84219610f1dfbd0fbdd30e29f8d1f408df3f645299eb48b1c1ed00S3BucketC986830C": { + "AssetParameters35892afbe8ff840a389ee91c3cce6d47b648fe4046b59d612100737b1486a4c1S3Bucket63728AAD": { "Type": "String", - "Description": "S3 bucket for asset \"9971e87ecc84219610f1dfbd0fbdd30e29f8d1f408df3f645299eb48b1c1ed00\"" + "Description": "S3 bucket for asset \"35892afbe8ff840a389ee91c3cce6d47b648fe4046b59d612100737b1486a4c1\"" }, - "AssetParameters9971e87ecc84219610f1dfbd0fbdd30e29f8d1f408df3f645299eb48b1c1ed00S3VersionKeyE0DA9F9E": { + "AssetParameters35892afbe8ff840a389ee91c3cce6d47b648fe4046b59d612100737b1486a4c1S3VersionKey40482FB9": { "Type": "String", - "Description": "S3 key for asset version \"9971e87ecc84219610f1dfbd0fbdd30e29f8d1f408df3f645299eb48b1c1ed00\"" + "Description": "S3 key for asset version \"35892afbe8ff840a389ee91c3cce6d47b648fe4046b59d612100737b1486a4c1\"" }, - "AssetParameters9971e87ecc84219610f1dfbd0fbdd30e29f8d1f408df3f645299eb48b1c1ed00ArtifactHash57FC5CA2": { + "AssetParameters35892afbe8ff840a389ee91c3cce6d47b648fe4046b59d612100737b1486a4c1ArtifactHash40AE3BC3": { "Type": "String", - "Description": "Artifact hash for asset \"9971e87ecc84219610f1dfbd0fbdd30e29f8d1f408df3f645299eb48b1c1ed00\"" + "Description": "Artifact hash for asset \"35892afbe8ff840a389ee91c3cce6d47b648fe4046b59d612100737b1486a4c1\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json index b1ca3b99819a0..0200e430246e0 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json @@ -56,26 +56,6 @@ "Arn" ] }, - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "TableCD117FA1", - "Arn" - ] - }, - "/index/*" - ] - ] - } - ] - }, - { - "Action": "dynamodb:*", - "Effect": "Allow", - "Resource": [ { "Fn::Join": [ "", @@ -84,7 +64,7 @@ { "Ref": "AWS::Partition" }, - ":dynamodb:eu-west-2:", + ":dynamodb:eu-central-1:", { "Ref": "AWS::AccountId" }, @@ -103,7 +83,7 @@ { "Ref": "AWS::Partition" }, - ":dynamodb:eu-central-1:", + ":dynamodb:eu-west-2:", { "Ref": "AWS::AccountId" }, @@ -113,6 +93,20 @@ } ] ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "TableCD117FA1", + "Arn" + ] + }, + "/index/*" + ] + ] } ] } @@ -253,7 +247,7 @@ }, "/", { - "Ref": "AssetParameters96d72e249e15863715342dcc64ec41ea99be4dece8798e9e96a0da55763aa4b6S3BucketB5739B2A" + "Ref": "AssetParameters380d18478d8d888ec191e1db553dc09fc6f0b9a18f335f70b5a36bc745333e9eS3Bucket30A96578" }, "/", { @@ -263,7 +257,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters96d72e249e15863715342dcc64ec41ea99be4dece8798e9e96a0da55763aa4b6S3VersionKey5404A90E" + "Ref": "AssetParameters380d18478d8d888ec191e1db553dc09fc6f0b9a18f335f70b5a36bc745333e9eS3VersionKeyD7726444" } ] } @@ -276,7 +270,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters96d72e249e15863715342dcc64ec41ea99be4dece8798e9e96a0da55763aa4b6S3VersionKey5404A90E" + "Ref": "AssetParameters380d18478d8d888ec191e1db553dc09fc6f0b9a18f335f70b5a36bc745333e9eS3VersionKeyD7726444" } ] } @@ -286,17 +280,17 @@ ] }, "Parameters": { - "referencetocdkdynamodbglobal20191121AssetParametersdd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776S3Bucket06999F76Ref": { - "Ref": "AssetParametersdd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776S3BucketDEBF01E6" + "referencetocdkdynamodbglobal20191121AssetParameters5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80fS3BucketAE26619BRef": { + "Ref": "AssetParameters5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80fS3Bucket1685F95F" }, - "referencetocdkdynamodbglobal20191121AssetParametersdd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776S3VersionKey3D988AD7Ref": { - "Ref": "AssetParametersdd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776S3VersionKey42EBA2AE" + "referencetocdkdynamodbglobal20191121AssetParameters5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80fS3VersionKey4B0E314FRef": { + "Ref": "AssetParameters5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80fS3VersionKey11815B6C" }, - "referencetocdkdynamodbglobal20191121AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketC7F3A147Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetocdkdynamodbglobal20191121AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketC23121D6Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetocdkdynamodbglobal20191121AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyB6346792Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetocdkdynamodbglobal20191121AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyDCD22417Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -305,41 +299,41 @@ } }, "Parameters": { - "AssetParametersdd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776S3BucketDEBF01E6": { + "AssetParameters5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80fS3Bucket1685F95F": { "Type": "String", - "Description": "S3 bucket for asset \"dd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776\"" + "Description": "S3 bucket for asset \"5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80f\"" }, - "AssetParametersdd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776S3VersionKey42EBA2AE": { + "AssetParameters5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80fS3VersionKey11815B6C": { "Type": "String", - "Description": "S3 key for asset version \"dd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776\"" + "Description": "S3 key for asset version \"5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80f\"" }, - "AssetParametersdd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776ArtifactHash692B4CCE": { + "AssetParameters5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80fArtifactHash259515A1": { "Type": "String", - "Description": "Artifact hash for asset \"dd0a4ac30ffa331e472caec08a7784ac440d122a6f924b1bea7d48dc85f8f776\"" + "Description": "Artifact hash for asset \"5d88959fad6bed204d22b24bf15826b8c7591c586a60a313e54f1948d9cdf80f\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { "Type": "String", - "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { "Type": "String", - "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { "Type": "String", - "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParameters96d72e249e15863715342dcc64ec41ea99be4dece8798e9e96a0da55763aa4b6S3BucketB5739B2A": { + "AssetParameters380d18478d8d888ec191e1db553dc09fc6f0b9a18f335f70b5a36bc745333e9eS3Bucket30A96578": { "Type": "String", - "Description": "S3 bucket for asset \"96d72e249e15863715342dcc64ec41ea99be4dece8798e9e96a0da55763aa4b6\"" + "Description": "S3 bucket for asset \"380d18478d8d888ec191e1db553dc09fc6f0b9a18f335f70b5a36bc745333e9e\"" }, - "AssetParameters96d72e249e15863715342dcc64ec41ea99be4dece8798e9e96a0da55763aa4b6S3VersionKey5404A90E": { + "AssetParameters380d18478d8d888ec191e1db553dc09fc6f0b9a18f335f70b5a36bc745333e9eS3VersionKeyD7726444": { "Type": "String", - "Description": "S3 key for asset version \"96d72e249e15863715342dcc64ec41ea99be4dece8798e9e96a0da55763aa4b6\"" + "Description": "S3 key for asset version \"380d18478d8d888ec191e1db553dc09fc6f0b9a18f335f70b5a36bc745333e9e\"" }, - "AssetParameters96d72e249e15863715342dcc64ec41ea99be4dece8798e9e96a0da55763aa4b6ArtifactHash539C11C9": { + "AssetParameters380d18478d8d888ec191e1db553dc09fc6f0b9a18f335f70b5a36bc745333e9eArtifactHash232CC7FB": { "Type": "String", - "Description": "Artifact hash for asset \"96d72e249e15863715342dcc64ec41ea99be4dece8798e9e96a0da55763aa4b6\"" + "Description": "Artifact hash for asset \"380d18478d8d888ec191e1db553dc09fc6f0b9a18f335f70b5a36bc745333e9e\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index fb2db769617e7..1e0f2919573db 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -199,15 +199,16 @@ MachineImage.genericLinux({ ... })` and configure the right AMI ID for the regions you want to deploy to. By default, the NAT instances will route all traffic. To control what traffic -gets routed, pass `allowAllTraffic: false` and access the -`NatInstanceProvider.connections` member after having passed it to the VPC: +gets routed, pass a custom value for `defaultAllowedTraffic` and access the +`NatInstanceProvider.connections` member after having passed the NAT provider to +the VPC: ```ts declare const instanceType: ec2.InstanceType; const provider = ec2.NatProvider.instance({ instanceType, - allowAllTraffic: false, + defaultAllowedTraffic: ec2.NatTrafficDirection.OUTBOUND_ONLY, }); new ec2.Vpc(this, 'TheVPC', { natGatewayProvider: provider, @@ -601,6 +602,73 @@ const sg = ec2.SecurityGroup.fromLookupById(this, 'SecurityGroupLookup', 'sg-123 The result of `SecurityGroup.fromLookupByName` and `SecurityGroup.fromLookupById` operations will be written to a file called `cdk.context.json`. You must commit this file to source control so that the lookup values are available in non-privileged environments such as CI build steps, and to ensure your template builds are repeatable. +### Cross Stack Connections + +If you are attempting to add a connection from a peer in one stack to a peer in a different stack, sometimes it is necessary to ensure that you are making the connection in +a specific stack in order to avoid a cyclic reference. If there are no other dependencies between stacks then it will not matter in which stack you make +the connection, but if there are existing dependencies (i.e. stack1 already depends on stack2), then it is important to make the connection in the dependent stack (i.e. stack1). + +Whenever you make a `connections` function call, the ingress and egress security group rules will be added to the stack that the calling object exists in. +So if you are doing something like `peer1.connections.allowFrom(peer2)`, then the security group rules (both ingress and egress) will be created in `peer1`'s Stack. + +As an example, if we wanted to allow a connection from a security group in one stack (egress) to a security group in a different stack (ingress), +we would make the connection like: + +**If Stack1 depends on Stack2** + +```ts fixture=with-vpc +// Stack 1 +declare const stack1: Stack; +declare const stack2: Stack; + +const sg1 = new ec2.SecurityGroup(stack1, 'SG1', { + allowAllOutbound: false, // if this is `true` then no egress rule will be created + vpc, +}); + +// Stack 2 +const sg2 = new ec2.SecurityGroup(stack2, 'SG2', { + allowAllOutbound: false, // if this is `true` then no egress rule will be created + vpc, +}); + + +// `connections.allowTo` on `sg1` since we want the +// rules to be created in Stack1 +sg1.connections.allowTo(sg2, ec2.Port.tcp(3333)); +``` + +In this case both the Ingress Rule for `sg2` and the Egress Rule for `sg1` will both be created +in `Stack 1` which avoids the cyclic reference. + + +**If Stack2 depends on Stack1** + +```ts fixture=with-vpc +// Stack 1 +declare const stack1: Stack; +declare const stack2: Stack; + +const sg1 = new ec2.SecurityGroup(stack1, 'SG1', { + allowAllOutbound: false, // if this is `true` then no egress rule will be created + vpc, +}); + +// Stack 2 +const sg2 = new ec2.SecurityGroup(stack2, 'SG2', { + allowAllOutbound: false, // if this is `true` then no egress rule will be created + vpc, +}); + + +// `connections.allowFrom` on `sg2` since we want the +// rules to be created in Stack2 +sg2.connections.allowFrom(sg1, ec2.Port.tcp(3333)); +``` + +In this case both the Ingress Rule for `sg2` and the Egress Rule for `sg1` will both be created +in `Stack 2` which avoids the cyclic reference. + ## Machine Images (AMIs) AMIs control the OS that gets launched when you start your EC2 instance. The EC2 @@ -663,7 +731,7 @@ vpc.addVpnConnection('Dynamic', { ``` By default, routes will be propagated on the route tables associated with the private subnets. If no -private subnets exists, isolated subnets are used. If no isolated subnets exists, public subnets are +private subnets exist, isolated subnets are used. If no isolated subnets exist, public subnets are used. Use the `Vpc` property `vpnRoutePropagation` to customize this behavior. VPN connections expose [metrics (cloudwatch.Metric)](https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-cloudwatch/README.md) across all tunnels in the account/region and per connection: @@ -810,7 +878,7 @@ The endpoint must use at least one [authentication method](https://docs.aws.amaz If user-based authentication is used, the [self-service portal URL](https://docs.aws.amazon.com/vpn/latest/clientvpn-user/self-service-portal.html) is made available via a CloudFormation output. -By default, a new security group is created and logging is enabled. Moreover, a rule to +By default, a new security group is created, and logging is enabled. Moreover, a rule to authorize all users to the VPC CIDR is created. To customize authorization rules, set the `authorizeAllUsersToVpcCidr` prop to `false` @@ -898,7 +966,7 @@ new ec2.Instance(this, 'Instance4', { CloudFormation Init allows you to configure your instances by writing files to them, installing software packages, starting services and running arbitrary commands. By default, if any of the instance setup -commands throw an error, the deployment will fail and roll back to the previously known good state. +commands throw an error; the deployment will fail and roll back to the previously known good state. The following documentation also applies to `AutoScalingGroup`s. For the full set of capabilities of this system, see the documentation for @@ -1201,7 +1269,7 @@ Aspects.of(this).add(aspect); VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. Flow log data can be published to Amazon CloudWatch Logs and Amazon S3. After you've created a flow log, you can retrieve and view its data in the chosen destination. (). -By default a flow log will be created with CloudWatch Logs as the destination. +By default, a flow log will be created with CloudWatch Logs as the destination. You can create a flow log like this: @@ -1235,7 +1303,7 @@ vpc.addFlowLog('FlowLogCloudWatch', { }); ``` -By default the CDK will create the necessary resources for the destination. For the CloudWatch Logs destination +By default, the CDK will create the necessary resources for the destination. For the CloudWatch Logs destination it will create a CloudWatch Logs Log Group as well as the IAM role with the necessary permissions to publish to the log group. In the case of an S3 destination, it will create the S3 bucket. @@ -1311,9 +1379,9 @@ from separate parts forming archive. The most common parts are scripts executed kinds, too. The advantage of multipart archive is in flexibility when it's needed to add additional parts or to use specialized parts to -fine tune instance startup. Some services (like AWS Batch) supports only `MultipartUserData`. +fine tune instance startup. Some services (like AWS Batch) support only `MultipartUserData`. -The parts can be executed at different moment of instance start-up and can serve a different purposes. This is controlled by `contentType` property. +The parts can be executed at different moment of instance start-up and can serve a different purpose. This is controlled by `contentType` property. For common scripts, `text/x-shellscript; charset="utf-8"` can be used as content type. In order to create archive the `MultipartUserData` has to be instantiated. Than, user can add parts to multipart archive using `addPart`. The `MultipartBody` contains methods supporting creation of body parts. @@ -1408,3 +1476,19 @@ const template = new ec2.LaunchTemplate(this, 'LaunchTemplate', { }), }); ``` + +## Detailed Monitoring + +The following demonstrates how to enable [Detailed Monitoring](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-cloudwatch-new.html) for an EC2 instance. Keep in mind that Detailed Monitoring results in [additional charges](http://aws.amazon.com/cloudwatch/pricing/). + +```ts +declare const vpc: ec2.Vpc; +declare const instanceType: ec2.InstanceType; + +new ec2.Instance(this, 'Instance1', { + vpc, + instanceType, + machineImage: new ec2.AmazonLinuxImage(), + detailedMonitoring: true, +}); +``` diff --git a/packages/@aws-cdk/aws-ec2/lib/bastion-host.ts b/packages/@aws-cdk/aws-ec2/lib/bastion-host.ts index 5f1d7d3c8709f..c956b25bdd2a6 100644 --- a/packages/@aws-cdk/aws-ec2/lib/bastion-host.ts +++ b/packages/@aws-cdk/aws-ec2/lib/bastion-host.ts @@ -97,6 +97,13 @@ export interface BastionHostLinuxProps { * @default - default options */ readonly initOptions?: ApplyCloudFormationInitOptions; + + /** + * Whether IMDSv2 should be required on this instance + * + * @default - false + */ + readonly requireImdsv2?: boolean; } /** @@ -147,14 +154,17 @@ export class BastionHostLinux extends Resource implements IInstance { * @attribute */ public readonly instancePrivateDnsName: string; + /** * @attribute */ public readonly instancePrivateIp: string; + /** * @attribute */ public readonly instancePublicDnsName: string; + /** * @attribute */ @@ -178,6 +188,7 @@ export class BastionHostLinux extends Resource implements IInstance { blockDevices: props.blockDevices ?? undefined, init: props.init, initOptions: props.initOptions, + requireImdsv2: props.requireImdsv2 ?? false, }); this.instance.addToRolePolicy(new PolicyStatement({ actions: [ diff --git a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts index cf82f9b8e40a5..4c7770d22c428 100644 --- a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts +++ b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts @@ -298,16 +298,6 @@ export enum InstanceClass { */ C5 = 'c5', - /** - * Compute optimized instances, 6th generation - */ - COMPUTE6_INTEL = 'c6i', - - /** - * Compute optimized instances, 6th generation - */ - C6I = 'c6i', - /** * Compute optimized instances with local NVME drive, 5th generation */ @@ -319,7 +309,7 @@ export enum InstanceClass { C5D = 'c5d', /** - * Compute optimized instances based on AMD EPYC, 5th generation. + * Compute optimized instances based on AMD EPYC, 5th generation */ COMPUTE5_AMD = 'c5a', @@ -329,12 +319,12 @@ export enum InstanceClass { C5A = 'c5a', /** - * Compute optimized instances with local NVME drive based on AMD EPYC, 5th generation. + * Compute optimized instances with local NVME drive based on AMD EPYC, 5th generation */ COMPUTE5_AMD_NVME_DRIVE = 'c5ad', /** - * Compute optimized instances with local NVME drive based on AMD EPYC, 5th generation. + * Compute optimized instances with local NVME drive based on AMD EPYC, 5th generation */ C5AD = 'c5ad', @@ -348,6 +338,26 @@ export enum InstanceClass { */ C5N = 'c5n', + /** + * Compute optimized instances, 6th generation + */ + COMPUTE6_INTEL = 'c6i', + + /** + * Compute optimized instances, 6th generation + */ + C6I = 'c6i', + + /** + * Compute optimized instances based on AMD EPYC (codename Milan), 6th generation + */ + COMPUTE6_AMD = 'c6a', + + /** + * Compute optimized instances based on AMD EPYC (codename Milan), 6th generation + */ + C6A = 'c6a', + /** * Compute optimized instances for high performance computing, 6th generation with Graviton2 processors */ @@ -546,6 +556,36 @@ export enum InstanceClass { */ X2GD = 'x2gd', + /** + * Memory-intensive instances with higher network bandwith, local NVME drive, and extended memory. Intel Xeon Scalable (Ice Lake) processors + */ + MEMORY_INTENSIVE_2_XT_INTEL = 'x2iedn', + + /** + * Memory-intensive instances with higher network bandwith, local NVME drive, and extended memory. Intel Xeon Scalable (Ice Lake) processors + */ + X2IEDN = 'x2iedn', + + /** + * Memory-intensive instances with higher network bandwith and local NVME drive, Intel Xeon Scalable (Ice Lake) processors + */ + MEMORY_INTENSIVE_2_INTEL = 'x2idn', + + /** + * Memory-intensive instances with higher network bandwith and local NVME drive, Intel Xeon Scalable (Ice Lake) processors + */ + X2IDN = 'x2idn', + + /** + * Memory-intensive instances with higher network bandwith and single-threaded performance, Intel Xeon Scalable (Cascade Lake) processors + */ + MEMORY_INTENSIVE_2_XTZ_INTEL = 'x2iezn', + + /** + * Memory-intensive instances with higher network bandwith and single-threaded performance, Intel Xeon Scalable (Cascade Lake) processors + */ + X2IEZN = 'x2iezn', + /** * Instances with customizable hardware acceleration, 1st generation */ diff --git a/packages/@aws-cdk/aws-ec2/lib/instance.ts b/packages/@aws-cdk/aws-ec2/lib/instance.ts index a12c3a45d6108..213b1ef0e4629 100644 --- a/packages/@aws-cdk/aws-ec2/lib/instance.ts +++ b/packages/@aws-cdk/aws-ec2/lib/instance.ts @@ -245,6 +245,15 @@ export interface InstanceProps { * @default - false */ readonly requireImdsv2?: boolean; + + /** + * Whether "Detailed Monitoring" is enabled for this instance + * Keep in mind that Detailed Monitoring results in extra charges + * + * @see http://aws.amazon.com/cloudwatch/pricing/ + * @default - false + */ + readonly detailedMonitoring?: boolean; } /** @@ -381,6 +390,7 @@ export class Instance extends Resource implements IInstance { blockDeviceMappings: props.blockDevices !== undefined ? instanceBlockDeviceMappings(this, props.blockDevices) : undefined, privateIpAddress: props.privateIpAddress, propagateTagsToVolumeOnCreation: props.propagateTagsToVolumeOnCreation, + monitoring: props.detailedMonitoring, }); this.instance.node.addDependency(this.role); diff --git a/packages/@aws-cdk/aws-ec2/lib/private/ebs-util.ts b/packages/@aws-cdk/aws-ec2/lib/private/ebs-util.ts index 52c7738afdbef..d66dc01f31398 100644 --- a/packages/@aws-cdk/aws-ec2/lib/private/ebs-util.ts +++ b/packages/@aws-cdk/aws-ec2/lib/private/ebs-util.ts @@ -31,11 +31,11 @@ function synthesizeBlockDeviceMappings(construct: Construct, blockDevic const { iops, volumeType, kmsKey, ...rest } = ebs; if (!iops) { - if (volumeType === EbsDeviceVolumeType.IO1) { - throw new Error('iops property is required with volumeType: EbsDeviceVolumeType.IO1'); + if (volumeType === EbsDeviceVolumeType.IO1 || volumeType === EbsDeviceVolumeType.IO2) { + throw new Error('iops property is required with volumeType: EbsDeviceVolumeType.IO1 and EbsDeviceVolumeType.IO2'); } - } else if (volumeType !== EbsDeviceVolumeType.IO1) { - Annotations.of(construct).addWarning('iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); + } else if (volumeType !== EbsDeviceVolumeType.IO1 && volumeType !== EbsDeviceVolumeType.IO2 && volumeType !== EbsDeviceVolumeType.GP3) { + Annotations.of(construct).addWarning('iops will be ignored without volumeType: IO1, IO2, or GP3'); } /** diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index 05914a6d35e92..741a6ceba4f07 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -969,6 +969,8 @@ export interface VpcProps { /** * The VPC name. * + * Since the VPC resource doesn't support providing a physical name, the value provided here will be recorded in the `Name` tag + * * @default this.node.path */ readonly vpcName?: string; @@ -2220,6 +2222,24 @@ const DUMMY_VPC_PROPS: cxapi.VpcContextResponse = { }, ], }, + { + name: 'Isolated', + type: cxapi.VpcSubnetGroupType.ISOLATED, + subnets: [ + { + availabilityZone: 'dummy1a', + subnetId: 'p-12345', + routeTableId: 'rtb-12345p', + cidr: '1.2.3.4/5', + }, + { + availabilityZone: 'dummy1b', + subnetId: 'p-67890', + routeTableId: 'rtb-57890p', + cidr: '1.2.3.4/5', + }, + ], + }, ], vpcId: 'vpc-12345', }; diff --git a/packages/@aws-cdk/aws-ec2/package.json b/packages/@aws-cdk/aws-ec2/package.json index 27ad97c60186d..3c523ea0fdd0a 100644 --- a/packages/@aws-cdk/aws-ec2/package.json +++ b/packages/@aws-cdk/aws-ec2/package.json @@ -86,9 +86,9 @@ "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.92", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/aws-lambda": "^8.10.93", + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-ec2/test/aspects/require-imdsv2-aspect.test.ts b/packages/@aws-cdk/aws-ec2/test/aspects/require-imdsv2-aspect.test.ts index 297de07f16005..ac705054aeb34 100644 --- a/packages/@aws-cdk/aws-ec2/test/aspects/require-imdsv2-aspect.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/aspects/require-imdsv2-aspect.test.ts @@ -1,4 +1,4 @@ -import { Template } from '@aws-cdk/assertions'; +import { Annotations, Template, Match } from '@aws-cdk/assertions'; import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; @@ -41,11 +41,7 @@ describe('RequireImdsv2Aspect', () => { // THEN expect(visitMock).toHaveBeenCalled(); - expect(construct.node.metadataEntry).not.toContainEqual({ - data: expect.stringContaining(errmsg), - type: 'aws:cdk:warning', - trace: undefined, - }); + Annotations.fromStack(stack).hasNoWarning('/Stack/Construct', errmsg); }); describe('InstanceRequireImdsv2Aspect', () => { @@ -100,11 +96,7 @@ describe('RequireImdsv2Aspect', () => { // Aspect normally creates a LaunchTemplate for the Instance to toggle IMDSv1, // so we can assert that one was not created Template.fromStack(stack).resourceCountIs('AWS::EC2::LaunchTemplate', 0); - expect(instance.node.metadataEntry).toContainEqual({ - data: expect.stringContaining('Cannot toggle IMDSv1 because this Instance is associated with an existing Launch Template.'), - type: 'aws:cdk:warning', - trace: undefined, - }); + Annotations.fromStack(stack).hasWarning('/Stack/Instance', Match.stringLikeRegexp('.*Cannot toggle IMDSv1 because this Instance is associated with an existing Launch Template.')); }); test('suppresses Launch Template warnings', () => { @@ -126,11 +118,7 @@ describe('RequireImdsv2Aspect', () => { aspect.visit(instance); // THEN - expect(instance.node.metadataEntry).not.toContainEqual({ - data: expect.stringContaining('Cannot toggle IMDSv1 because this Instance is associated with an existing Launch Template.'), - type: 'aws:cdk:warning', - trace: undefined, - }); + Annotations.fromStack(stack).hasNoWarning('/Stack/Instance', 'Cannot toggle IMDSv1 because this Instance is associated with an existing Launch Template.'); }); testFutureBehavior('launch template name is unique with feature flag', { [cxapi.EC2_UNIQUE_IMDSV2_LAUNCH_TEMPLATE_NAME]: true }, cdk.App, (app2) => { @@ -197,11 +185,7 @@ describe('RequireImdsv2Aspect', () => { aspect.visit(launchTemplate); // THEN - expect(launchTemplate.node.metadataEntry).toContainEqual({ - data: expect.stringContaining('LaunchTemplateData is a CDK token.'), - type: 'aws:cdk:warning', - trace: undefined, - }); + Annotations.fromStack(stack).hasWarning('/Stack/LaunchTemplate', Match.stringLikeRegexp('.*LaunchTemplateData is a CDK token.')); }); test('warns when MetadataOptions is a CDK token', () => { @@ -217,11 +201,7 @@ describe('RequireImdsv2Aspect', () => { aspect.visit(launchTemplate); // THEN - expect(launchTemplate.node.metadataEntry).toContainEqual({ - data: expect.stringContaining('LaunchTemplateData.MetadataOptions is a CDK token.'), - type: 'aws:cdk:warning', - trace: undefined, - }); + Annotations.fromStack(stack).hasWarning('/Stack/LaunchTemplate', Match.stringLikeRegexp('.*LaunchTemplateData.MetadataOptions is a CDK token.')); }); test('requires IMDSv2', () => { diff --git a/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts b/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts index b60248a948bad..2d21d5ac2e57a 100644 --- a/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts @@ -160,4 +160,25 @@ describe('bastion host', () => { }, }); }); + + test('imdsv2 is required', () => { + //GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + + //WHEN + new BastionHostLinux(stack, 'Bastion', { + vpc, + requireImdsv2: true, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { + LaunchTemplateData: { + MetadataOptions: { + HttpTokens: 'required', + }, + }, + }); + }); }); diff --git a/packages/@aws-cdk/aws-ec2/test/instance.test.ts b/packages/@aws-cdk/aws-ec2/test/instance.test.ts index 7f40cd8f202a0..6fd215af31bff 100644 --- a/packages/@aws-cdk/aws-ec2/test/instance.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/instance.test.ts @@ -1,13 +1,23 @@ import * as path from 'path'; -import { Match, Template } from '@aws-cdk/assertions'; +import { Annotations, Match, Template } from '@aws-cdk/assertions'; import { Key } from '@aws-cdk/aws-kms'; import { Asset } from '@aws-cdk/aws-s3-assets'; import { StringParameter } from '@aws-cdk/aws-ssm'; -import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { Stack } from '@aws-cdk/core'; import { - AmazonLinuxImage, BlockDeviceVolume, CloudFormationInit, - EbsDeviceVolumeType, InitCommand, Instance, InstanceArchitecture, InstanceClass, InstanceSize, InstanceType, LaunchTemplate, UserData, Vpc, + AmazonLinuxImage, + BlockDeviceVolume, + CloudFormationInit, + EbsDeviceVolumeType, + InitCommand, + Instance, + InstanceArchitecture, + InstanceClass, + InstanceSize, + InstanceType, + LaunchTemplate, + UserData, + Vpc, } from '../lib'; let stack: Stack; @@ -145,7 +155,7 @@ describe('instance', () => { for (const instanceClass of sampleInstanceClassKeys) { // WHEN - const key = instanceClass.key as keyof(typeof InstanceClass); + const key = instanceClass.key as keyof (typeof InstanceClass); const instanceType = InstanceClass[key]; // THEN @@ -199,6 +209,15 @@ describe('instance', () => { volumeType: EbsDeviceVolumeType.IO1, iops: 5000, }), + }, { + deviceName: 'ebs-gp3', + mappingEnabled: true, + volume: BlockDeviceVolume.ebs(15, { + deleteOnTermination: true, + encrypted: true, + volumeType: EbsDeviceVolumeType.GP3, + iops: 5000, + }), }, { deviceName: 'ebs-cmk', mappingEnabled: true, @@ -236,6 +255,16 @@ describe('instance', () => { VolumeType: 'io1', }, }, + { + DeviceName: 'ebs-gp3', + Ebs: { + DeleteOnTermination: true, + Encrypted: true, + Iops: 5000, + VolumeSize: 15, + VolumeType: 'gp3', + }, + }, { DeviceName: 'ebs-cmk', Ebs: { @@ -306,12 +335,29 @@ describe('instance', () => { }], }); }).toThrow(/ops property is required with volumeType: EbsDeviceVolumeType.IO1/); + }); - + test('throws if volumeType === IO2 without iops', () => { + // THEN + expect(() => { + new Instance(stack, 'Instance', { + vpc, + machineImage: new AmazonLinuxImage(), + instanceType: InstanceType.of(InstanceClass.T3, InstanceSize.LARGE), + blockDevices: [{ + deviceName: 'ebs', + volume: BlockDeviceVolume.ebs(15, { + deleteOnTermination: true, + encrypted: true, + volumeType: EbsDeviceVolumeType.IO2, + }), + }], + }); + }).toThrow(/ops property is required with volumeType: EbsDeviceVolumeType.IO1 and EbsDeviceVolumeType.IO2/); }); test('warning if iops without volumeType', () => { - const instance = new Instance(stack, 'Instance', { + new Instance(stack, 'Instance', { vpc, machineImage: new AmazonLinuxImage(), instanceType: InstanceType.of(InstanceClass.T3, InstanceSize.LARGE), @@ -326,14 +372,11 @@ describe('instance', () => { }); // THEN - expect(instance.node.metadataEntry[0].type).toEqual(cxschema.ArtifactMetadataEntryType.WARN); - expect(instance.node.metadataEntry[0].data).toEqual('iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); - - + Annotations.fromStack(stack).hasWarning('/Default/Instance', 'iops will be ignored without volumeType: IO1, IO2, or GP3'); }); - test('warning if iops and volumeType !== IO1', () => { - const instance = new Instance(stack, 'Instance', { + test('warning if iops and invalid volumeType', () => { + new Instance(stack, 'Instance', { vpc, machineImage: new AmazonLinuxImage(), instanceType: InstanceType.of(InstanceClass.T3, InstanceSize.LARGE), @@ -349,10 +392,7 @@ describe('instance', () => { }); // THEN - expect(instance.node.metadataEntry[0].type).toEqual(cxschema.ArtifactMetadataEntryType.WARN); - expect(instance.node.metadataEntry[0].data).toEqual('iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); - - + Annotations.fromStack(stack).hasWarning('/Default/Instance', 'iops will be ignored without volumeType: IO1, IO2, or GP3'); }); }); @@ -403,6 +443,62 @@ describe('instance', () => { }, }); }); + + describe('Detailed Monitoring', () => { + test('instance with Detailed Monitoring enabled', () => { + // WHEN + new Instance(stack, 'Instance', { + vpc, + machineImage: new AmazonLinuxImage(), + instanceType: new InstanceType('t2.micro'), + detailedMonitoring: true, + }); + + // Force stack synth so the Instance is applied + Template.fromStack(stack); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { + Monitoring: true, + }); + }); + + test('instance with Detailed Monitoring disabled', () => { + // WHEN + new Instance(stack, 'Instance', { + vpc, + machineImage: new AmazonLinuxImage(), + instanceType: new InstanceType('t2.micro'), + detailedMonitoring: false, + }); + + // Force stack synth so the Instance is applied + Template.fromStack(stack); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { + Monitoring: false, + }); + }); + + test('instance with Detailed Monitoring unset falls back to disabled', () => { + // WHEN + new Instance(stack, 'Instance', { + vpc, + machineImage: new AmazonLinuxImage(), + instanceType: new InstanceType('t2.micro'), + }); + + // Force stack synth so the Instance is applied + Template.fromStack(stack); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { + Monitoring: Match.absent(), + }); + }); + }); + }); test('add CloudFormation Init to instance', () => { @@ -490,8 +586,14 @@ test('cause replacement from s3 asset in userdata', () => { const hash = 'f88eace39faf39d7'; Template.fromStack(stack).templateMatches(Match.objectLike({ Resources: Match.objectLike({ - [`InstanceOne5B821005${hash}`]: Match.objectLike({ Type: 'AWS::EC2::Instance', Properties: Match.anyValue() }), - [`InstanceTwoDC29A7A7${hash}`]: Match.objectLike({ Type: 'AWS::EC2::Instance', Properties: Match.anyValue() }), + [`InstanceOne5B821005${hash}`]: Match.objectLike({ + Type: 'AWS::EC2::Instance', + Properties: Match.anyValue(), + }), + [`InstanceTwoDC29A7A7${hash}`]: Match.objectLike({ + Type: 'AWS::EC2::Instance', + Properties: Match.anyValue(), + }), }), })); }); diff --git a/packages/@aws-cdk/aws-ec2/test/integ.bastion-host-arm-support.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.bastion-host-arm-support.expected.json index 81f4ae3377d40..7ad67dbd9e172 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.bastion-host-arm-support.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.bastion-host-arm-support.expected.json @@ -95,15 +95,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VPCPublicSubnet2NATGateway3C070193": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "Tags": [ { "Key": "Name", @@ -289,15 +289,15 @@ "VPCPublicSubnet3NATGatewayD3048F5C": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet3EIPAD4BC883", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - }, "Tags": [ { "Key": "Name", @@ -576,9 +576,9 @@ "Statement": [ { "Action": [ - "ssmmessages:*", + "ec2messages:*", "ssm:UpdateInstanceInformation", - "ec2messages:*" + "ssmmessages:*" ], "Effect": "Allow", "Resource": "*" diff --git a/packages/@aws-cdk/aws-ec2/test/integ.bastion-host.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.bastion-host.expected.json index 4943873897e75..bbea0d3ffacd3 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.bastion-host.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.bastion-host.expected.json @@ -95,15 +95,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VPCPublicSubnet2NATGateway3C070193": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "Tags": [ { "Key": "Name", @@ -289,15 +289,15 @@ "VPCPublicSubnet3NATGatewayD3048F5C": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet3EIPAD4BC883", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - }, "Tags": [ { "Key": "Name", @@ -576,9 +576,9 @@ "Statement": [ { "Action": [ - "ssmmessages:*", + "ec2messages:*", "ssm:UpdateInstanceInformation", - "ec2messages:*" + "ssmmessages:*" ], "Effect": "Allow", "Resource": "*" diff --git a/packages/@aws-cdk/aws-ec2/test/integ.client-vpn-endpoint.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.client-vpn-endpoint.expected.json index 17e0059d601d1..75e40ab98259b 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.client-vpn-endpoint.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.client-vpn-endpoint.expected.json @@ -83,7 +83,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersbb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957S3Bucket60FDAA05" + "Ref": "AssetParametersc0eca79e4277becf35cc23c67499f47e70fd50078e025e595c51ed97b9699c5fS3Bucket42BD8ED5" }, "S3Key": { "Fn::Join": [ @@ -96,7 +96,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersbb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957S3VersionKeyF2886582" + "Ref": "AssetParametersc0eca79e4277becf35cc23c67499f47e70fd50078e025e595c51ed97b9699c5fS3VersionKeyA7C3DEE3" } ] } @@ -109,7 +109,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersbb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957S3VersionKeyF2886582" + "Ref": "AssetParametersc0eca79e4277becf35cc23c67499f47e70fd50078e025e595c51ed97b9699c5fS3VersionKeyA7C3DEE3" } ] } @@ -596,17 +596,17 @@ } }, "Parameters": { - "AssetParametersbb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957S3Bucket60FDAA05": { + "AssetParametersc0eca79e4277becf35cc23c67499f47e70fd50078e025e595c51ed97b9699c5fS3Bucket42BD8ED5": { "Type": "String", - "Description": "S3 bucket for asset \"bb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957\"" + "Description": "S3 bucket for asset \"c0eca79e4277becf35cc23c67499f47e70fd50078e025e595c51ed97b9699c5f\"" }, - "AssetParametersbb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957S3VersionKeyF2886582": { + "AssetParametersc0eca79e4277becf35cc23c67499f47e70fd50078e025e595c51ed97b9699c5fS3VersionKeyA7C3DEE3": { "Type": "String", - "Description": "S3 key for asset version \"bb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957\"" + "Description": "S3 key for asset version \"c0eca79e4277becf35cc23c67499f47e70fd50078e025e595c51ed97b9699c5f\"" }, - "AssetParametersbb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957ArtifactHashF17C10B6": { + "AssetParametersc0eca79e4277becf35cc23c67499f47e70fd50078e025e595c51ed97b9699c5fArtifactHash18BB2B9F": { "Type": "String", - "Description": "Artifact hash for asset \"bb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957\"" + "Description": "Artifact hash for asset \"c0eca79e4277becf35cc23c67499f47e70fd50078e025e595c51ed97b9699c5f\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/integ.instance-init.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.instance-init.expected.json index 2b736d3961b4c..e287246eda0a7 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.instance-init.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.instance-init.expected.json @@ -60,8 +60,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -77,7 +77,8 @@ ":s3:::", { "Ref": "AssetParametersf8a1af398dac2fad92eeea4fb7620be1c4f504e23e3bfcd859fbb5744187930bS3Bucket597083AB" - } + }, + "/*" ] ] }, @@ -92,8 +93,7 @@ ":s3:::", { "Ref": "AssetParametersf8a1af398dac2fad92eeea4fb7620be1c4f504e23e3bfcd859fbb5744187930bS3Bucket597083AB" - }, - "/*" + } ] ] } @@ -319,4 +319,4 @@ "Description": "Artifact hash for asset \"f8a1af398dac2fad92eeea4fb7620be1c4f504e23e3bfcd859fbb5744187930b\"" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/integ.instance-multipart-userdata.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.instance-multipart-userdata.expected.json index 371a30e7456f6..b2ec45e8accf3 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.instance-multipart-userdata.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.instance-multipart-userdata.expected.json @@ -95,15 +95,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VPCPublicSubnet2NATGateway3C070193": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "Tags": [ { "Key": "Name", @@ -289,15 +289,15 @@ "VPCPublicSubnet3NATGatewayD3048F5C": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet3EIPAD4BC883", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - }, "Tags": [ { "Key": "Name", @@ -585,9 +585,9 @@ "Statement": [ { "Action": [ + "ec2messages:GetMessages", "ssm:*", - "ssmmessages:*", - "ec2messages:GetMessages" + "ssmmessages:*" ], "Effect": "Allow", "Resource": "*" diff --git a/packages/@aws-cdk/aws-ec2/test/integ.instance.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.instance.expected.json index 957af9c0f453e..d30b3a47c711e 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.instance.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.instance.expected.json @@ -18,11 +18,11 @@ "VPCPublicSubnet1SubnetB4246D30": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.0.0/19", "VpcId": { "Ref": "VPCB9E5F0B4" }, "AvailabilityZone": "test-region-1a", + "CidrBlock": "10.0.0.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -95,15 +95,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "Name", @@ -115,11 +115,11 @@ "VPCPublicSubnet2Subnet74179F39": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.32.0/19", "VpcId": { "Ref": "VPCB9E5F0B4" }, "AvailabilityZone": "test-region-1b", + "CidrBlock": "10.0.32.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -192,15 +192,15 @@ "VPCPublicSubnet2NATGateway3C070193": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "Tags": [ { "Key": "Name", @@ -212,11 +212,11 @@ "VPCPublicSubnet3Subnet631C5E25": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.64.0/19", "VpcId": { "Ref": "VPCB9E5F0B4" }, "AvailabilityZone": "test-region-1c", + "CidrBlock": "10.0.64.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -289,15 +289,15 @@ "VPCPublicSubnet3NATGatewayD3048F5C": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet3EIPAD4BC883", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - }, "Tags": [ { "Key": "Name", @@ -309,11 +309,11 @@ "VPCPrivateSubnet1Subnet8BCA10E0": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.96.0/19", "VpcId": { "Ref": "VPCB9E5F0B4" }, "AvailabilityZone": "test-region-1a", + "CidrBlock": "10.0.96.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -371,11 +371,11 @@ "VPCPrivateSubnet2SubnetCFCDAA7A": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.128.0/19", "VpcId": { "Ref": "VPCB9E5F0B4" }, "AvailabilityZone": "test-region-1b", + "CidrBlock": "10.0.128.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -433,11 +433,11 @@ "VPCPrivateSubnet3Subnet3EDCD457": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.160.0/19", "VpcId": { "Ref": "VPCB9E5F0B4" }, "AvailabilityZone": "test-region-1c", + "CidrBlock": "10.0.160.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -620,6 +620,7 @@ "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" }, "InstanceType": "t3.nano", + "Monitoring": true, "SecurityGroupIds": [ { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-ec2/test/integ.instance.ts b/packages/@aws-cdk/aws-ec2/test/integ.instance.ts index bae57818521cc..1b120c511eaaa 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.instance.ts +++ b/packages/@aws-cdk/aws-ec2/test/integ.instance.ts @@ -15,6 +15,7 @@ class TestStack extends cdk.Stack { vpc, instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.NANO), machineImage: new ec2.AmazonLinuxImage({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 }), + detailedMonitoring: true, }); instance.addToRolePolicy(new PolicyStatement({ diff --git a/packages/@aws-cdk/aws-ec2/test/integ.vpc-flow-logs.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.vpc-flow-logs.expected.json index ab9eb13b2c415..24d55d814adad 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.vpc-flow-logs.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.vpc-flow-logs.expected.json @@ -95,15 +95,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VPCPublicSubnet2NATGateway3C070193": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "Tags": [ { "Key": "Name", @@ -289,15 +289,15 @@ "VPCPublicSubnet3NATGatewayD3048F5C": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet3EIPAD4BC883", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - }, "Tags": [ { "Key": "Name", @@ -606,8 +606,8 @@ { "Action": [ "logs:CreateLogStream", - "logs:PutLogEvents", - "logs:DescribeLogStreams" + "logs:DescribeLogStreams", + "logs:PutLogEvents" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-ec2/test/launch-template.test.ts b/packages/@aws-cdk/aws-ec2/test/launch-template.test.ts index 49b979ca7084d..90916eea165f5 100644 --- a/packages/@aws-cdk/aws-ec2/test/launch-template.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/launch-template.test.ts @@ -1,4 +1,4 @@ -import { Template } from '@aws-cdk/assertions'; +import { Annotations, Template, Match } from '@aws-cdk/assertions'; import { CfnInstanceProfile, Role, @@ -585,14 +585,15 @@ describe('LaunchTemplate marketOptions', () => { [7, 1], ])('for range duration errors: %p', (duration: number, expectedErrors: number) => { // WHEN - const template = new LaunchTemplate(stack, 'Template', { + new LaunchTemplate(stack, 'Template', { spotOptions: { blockDuration: Duration.hours(duration), }, }); // THEN - expect(template.node.metadataEntry).toHaveLength(expectedErrors); + const errors = Annotations.fromStack(stack).findError('/Default/Template', Match.anyValue()); + expect(errors).toHaveLength(expectedErrors); }); test('for bad duration', () => { diff --git a/packages/@aws-cdk/aws-ec2/test/userdata.test.ts b/packages/@aws-cdk/aws-ec2/test/userdata.test.ts index c385ce83a7254..fc877cbb2c7c9 100644 --- a/packages/@aws-cdk/aws-ec2/test/userdata.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/userdata.test.ts @@ -1,5 +1,5 @@ -import { Bucket } from '@aws-cdk/aws-s3'; import { Template, Match } from '@aws-cdk/assertions'; +import { Bucket } from '@aws-cdk/aws-s3'; import { Aws, Stack, CfnResource } from '@aws-cdk/core'; import * as ec2 from '../lib'; diff --git a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts index 3c9d54d25bf4f..8e383e1e630fd 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts @@ -1,4 +1,4 @@ -import { Match, Template } from '@aws-cdk/assertions'; +import { Annotations, Match, Template } from '@aws-cdk/assertions'; import { testDeprecated } from '@aws-cdk/cdk-build-tools'; import { CfnOutput, CfnResource, Fn, Lazy, Stack, Tags } from '@aws-cdk/core'; import { @@ -1557,11 +1557,7 @@ describe('vpc', () => { subnetIds: { 'Fn::Split': [',', { 'Fn::ImportValue': 'myPublicSubnetIds' }] }, }); - expect(vpc.node.metadataEntry).toContainEqual({ - data: expect.stringContaining("fromVpcAttributes: 'availabilityZones' is a list token: the imported VPC will not work with constructs that require a list of subnets at synthesis time. Use 'Vpc.fromLookup()' or 'Fn.importListValue' instead."), - type: 'aws:cdk:warning', - trace: undefined, - }); + Annotations.fromStack(stack).hasWarning('/TestStack/VPC', "fromVpcAttributes: 'availabilityZones' is a list token: the imported VPC will not work with constructs that require a list of subnets at synthesis time. Use 'Vpc.fromLookup()' or 'Fn.importListValue' instead."); }); test('fromVpcAttributes using fixed-length list tokens', () => { diff --git a/packages/@aws-cdk/aws-ecr-assets/NOTICE b/packages/@aws-cdk/aws-ecr-assets/NOTICE index b5fabb830ac84..1b7adbb891265 100644 --- a/packages/@aws-cdk/aws-ecr-assets/NOTICE +++ b/packages/@aws-cdk/aws-ecr-assets/NOTICE @@ -1,91 +1,2 @@ AWS Cloud Development Kit (AWS CDK) Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. - -------------------------------------------------------------------------------- - -The AWS CDK includes the following third-party software/licensing: - -** minimatch - https://www.npmjs.com/package/minimatch -Copyright (c) Isaac Z. Schlueter and Contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ----------------- - -** brace-expansion - https://www.npmjs.com/package/brace-expansion -Copyright (c) 2013 Julian Gruber - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ----------------- - -** balanced-match - https://www.npmjs.com/package/balanced-match -Copyright (c) 2013 Julian Gruber - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ----------------- - -** concat-map - https://www.npmjs.com/package/concat-map - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ----------------- \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecr-assets/package.json b/packages/@aws-cdk/aws-ecr-assets/package.json index 38d1459a9a713..75fb178adb95a 100644 --- a/packages/@aws-cdk/aws-ecr-assets/package.json +++ b/packages/@aws-cdk/aws-ecr-assets/package.json @@ -77,10 +77,10 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "@types/proxyquire": "^1.3.28", "aws-cdk": "0.0.0", - "jest": "^27.4.7", + "jest": "^27.5.1", "proxyquire": "^2.1.3" }, "dependencies": { @@ -90,8 +90,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.3.69", - "minimatch": "^3.0.4" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -109,9 +108,6 @@ "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "bundledDependencies": [ - "minimatch" - ], "stability": "stable", "maturity": "stable", "awscdkio": { diff --git a/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts b/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts index d931401484ba2..7640557032510 100644 --- a/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts +++ b/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts @@ -452,7 +452,7 @@ testFutureBehavior('nested assemblies share assets: default synth edition', flag // Read the asset manifests to verify the file paths for (const stageName of ['Stage1', 'Stage2']) { - const manifestArtifact = assembly.getNestedAssembly(`assembly-${stageName}`).artifacts.filter(isAssetManifestArtifact)[0]; + const manifestArtifact = assembly.getNestedAssembly(`assembly-${stageName}`).artifacts.filter(cxapi.AssetManifestArtifact.isAssetManifestArtifact)[0]; const manifest = JSON.parse(fs.readFileSync(manifestArtifact.file, { encoding: 'utf-8' })); expect(manifest.dockerImages[DEMO_IMAGE_ASSET_HASH].source).toEqual({ @@ -464,7 +464,3 @@ testFutureBehavior('nested assemblies share assets: default synth edition', flag function isStackArtifact(x: any): x is cxapi.CloudFormationStackArtifact { return x instanceof cxapi.CloudFormationStackArtifact; } - -function isAssetManifestArtifact(x: any): x is cxapi.AssetManifestArtifact { - return x instanceof cxapi.AssetManifestArtifact; -} diff --git a/packages/@aws-cdk/aws-ecr-assets/test/integ.assets-docker.expected.json b/packages/@aws-cdk/aws-ecr-assets/test/integ.assets-docker.expected.json index e2aefa9185424..3f6dd7b36d92e 100644 --- a/packages/@aws-cdk/aws-ecr-assets/test/integ.assets-docker.expected.json +++ b/packages/@aws-cdk/aws-ecr-assets/test/integ.assets-docker.expected.json @@ -11,8 +11,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { @@ -76,4 +76,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecr-assets/test/integ.nested-stacks-docker.expected.json b/packages/@aws-cdk/aws-ecr-assets/test/integ.nested-stacks-docker.expected.json index 7e23b25796d4e..8860ef52935b1 100644 --- a/packages/@aws-cdk/aws-ecr-assets/test/integ.nested-stacks-docker.expected.json +++ b/packages/@aws-cdk/aws-ecr-assets/test/integ.nested-stacks-docker.expected.json @@ -17,7 +17,7 @@ }, "/", { - "Ref": "AssetParameters08bf71a5b9aa57c58cc7510137ed079260aac01394d01f4c29a9778ac890b816S3Bucket40925BAC" + "Ref": "AssetParameters1107443cdc71fce9cccfb7fb4c7c73078878ffb8d631c739c41d45ae40616f39S3Bucket74894234" }, "/", { @@ -27,7 +27,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters08bf71a5b9aa57c58cc7510137ed079260aac01394d01f4c29a9778ac890b816S3VersionKey30F5671B" + "Ref": "AssetParameters1107443cdc71fce9cccfb7fb4c7c73078878ffb8d631c739c41d45ae40616f39S3VersionKeyD1E9C856" } ] } @@ -40,7 +40,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters08bf71a5b9aa57c58cc7510137ed079260aac01394d01f4c29a9778ac890b816S3VersionKey30F5671B" + "Ref": "AssetParameters1107443cdc71fce9cccfb7fb4c7c73078878ffb8d631c739c41d45ae40616f39S3VersionKeyD1E9C856" } ] } @@ -55,17 +55,17 @@ } }, "Parameters": { - "AssetParameters08bf71a5b9aa57c58cc7510137ed079260aac01394d01f4c29a9778ac890b816S3Bucket40925BAC": { + "AssetParameters1107443cdc71fce9cccfb7fb4c7c73078878ffb8d631c739c41d45ae40616f39S3Bucket74894234": { "Type": "String", - "Description": "S3 bucket for asset \"08bf71a5b9aa57c58cc7510137ed079260aac01394d01f4c29a9778ac890b816\"" + "Description": "S3 bucket for asset \"1107443cdc71fce9cccfb7fb4c7c73078878ffb8d631c739c41d45ae40616f39\"" }, - "AssetParameters08bf71a5b9aa57c58cc7510137ed079260aac01394d01f4c29a9778ac890b816S3VersionKey30F5671B": { + "AssetParameters1107443cdc71fce9cccfb7fb4c7c73078878ffb8d631c739c41d45ae40616f39S3VersionKeyD1E9C856": { "Type": "String", - "Description": "S3 key for asset version \"08bf71a5b9aa57c58cc7510137ed079260aac01394d01f4c29a9778ac890b816\"" + "Description": "S3 key for asset version \"1107443cdc71fce9cccfb7fb4c7c73078878ffb8d631c739c41d45ae40616f39\"" }, - "AssetParameters08bf71a5b9aa57c58cc7510137ed079260aac01394d01f4c29a9778ac890b816ArtifactHash98F3F6F7": { + "AssetParameters1107443cdc71fce9cccfb7fb4c7c73078878ffb8d631c739c41d45ae40616f39ArtifactHash4D458F5E": { "Type": "String", - "Description": "Artifact hash for asset \"08bf71a5b9aa57c58cc7510137ed079260aac01394d01f4c29a9778ac890b816\"" + "Description": "Artifact hash for asset \"1107443cdc71fce9cccfb7fb4c7c73078878ffb8d631c739c41d45ae40616f39\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecr/lib/repository.ts b/packages/@aws-cdk/aws-ecr/lib/repository.ts index 3d4e44c0776a9..f73c8990dd95f 100644 --- a/packages/@aws-cdk/aws-ecr/lib/repository.ts +++ b/packages/@aws-cdk/aws-ecr/lib/repository.ts @@ -508,9 +508,7 @@ export class Repository extends RepositoryBase { // It says "Text", but they actually mean "Object". repositoryPolicyText: Lazy.any({ produce: () => this.policyDocument }), lifecyclePolicy: Lazy.any({ produce: () => this.renderLifecyclePolicy() }), - imageScanningConfiguration: !props.imageScanOnPush ? undefined : { - scanOnPush: true, - }, + imageScanningConfiguration: props.imageScanOnPush ? { scanOnPush: true } : { scanOnPush: false }, imageTagMutability: props.imageTagMutability || undefined, encryptionConfiguration: this.parseEncryption(props), }); diff --git a/packages/@aws-cdk/aws-ecr/package.json b/packages/@aws-cdk/aws-ecr/package.json index 3141f0c8dc6d1..ae13302f8642e 100644 --- a/packages/@aws-cdk/aws-ecr/package.json +++ b/packages/@aws-cdk/aws-ecr/package.json @@ -88,7 +88,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", diff --git a/packages/@aws-cdk/aws-ecr/test/integ.basic.expected.json b/packages/@aws-cdk/aws-ecr/test/integ.basic.expected.json index 7fa399898aa8e..09075cee64a01 100644 --- a/packages/@aws-cdk/aws-ecr/test/integ.basic.expected.json +++ b/packages/@aws-cdk/aws-ecr/test/integ.basic.expected.json @@ -3,6 +3,9 @@ "Repo02AC86CF": { "Type": "AWS::ECR::Repository", "Properties": { + "ImageScanningConfiguration": { + "ScanOnPush": false + }, "LifecyclePolicy": { "LifecyclePolicyText": "{\"rules\":[{\"rulePriority\":1,\"selection\":{\"tagStatus\":\"any\",\"countType\":\"imageCountMoreThan\",\"countNumber\":5},\"action\":{\"type\":\"expire\"}}]}" } diff --git a/packages/@aws-cdk/aws-ecr/test/repository.test.ts b/packages/@aws-cdk/aws-ecr/test/repository.test.ts index 232ad400cdff6..108be6e06d065 100644 --- a/packages/@aws-cdk/aws-ecr/test/repository.test.ts +++ b/packages/@aws-cdk/aws-ecr/test/repository.test.ts @@ -20,6 +20,11 @@ describe('repository', () => { Resources: { Repo02AC86CF: { Type: 'AWS::ECR::Repository', + Properties: { + ImageScanningConfiguration: { + ScanOnPush: false, + }, + }, DeletionPolicy: 'Retain', UpdateReplacePolicy: 'Retain', }, diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts index acc2846988837..13348e103adec 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts @@ -170,6 +170,9 @@ export abstract class ScheduledTaskBase extends CoreConstruct { ruleName: props.ruleName, enabled: props.enabled, }); + + // add a warning on synth when minute is not defined in a cron schedule + props.schedule._bind(scope); } /** diff --git a/packages/@aws-cdk/aws-ecs-patterns/package.json b/packages/@aws-cdk/aws-ecs-patterns/package.json index 8bdbe1e23f377..72d98e55f86d1 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/package.json +++ b/packages/@aws-cdk/aws-ecs-patterns/package.json @@ -77,8 +77,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json index 2364b79c8b0b5..885d665752a94 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json @@ -473,8 +473,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -617,10 +617,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -655,7 +655,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -683,24 +685,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "ClusterEB0386A7", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -778,6 +762,17 @@ } } }, + "ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicFE5437FB": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Cluster/DefaultAutoScalingGroup" + } + ] + } + }, "ClusterDefaultAutoScalingGroupLifecycleHookDrainHookRole70201663": { "Type": "AWS::IAM::Role", "Properties": { @@ -824,17 +819,6 @@ ] } }, - "ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicFE5437FB": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Cluster/DefaultAutoScalingGroup" - } - ] - } - }, "ClusterDefaultAutoScalingGroupLifecycleHookDrainHook4A9A4325": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.lit.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.lit.expected.json index e96ad6a2bbad7..c068504073cba 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.lit.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.lit.expected.json @@ -293,8 +293,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -434,10 +434,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -472,7 +472,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -500,24 +502,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "EcsCluster97242B84", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -595,6 +579,17 @@ } } }, + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup" + } + ] + } + }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookRoleA38EC83B": { "Type": "AWS::IAM::Role", "Properties": { @@ -641,17 +636,6 @@ ] } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup" - } - ] - } - }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookFFA63029": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/scheduled-ecs-task.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/scheduled-ecs-task.test.ts index 71d48850d3b0d..b2321f9478045 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/scheduled-ecs-task.test.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/scheduled-ecs-task.test.ts @@ -1,4 +1,4 @@ -import { Template } from '@aws-cdk/assertions'; +import { Annotations, Match, Template } from '@aws-cdk/assertions'; import { AutoScalingGroup } from '@aws-cdk/aws-autoscaling'; import * as ec2 from '@aws-cdk/aws-ec2'; import { MachineImage } from '@aws-cdk/aws-ec2'; @@ -347,3 +347,41 @@ test('Scheduled Ec2 Task - exposes ECS Task', () => { // THEN expect(scheduledEc2Task.task).toBeDefined(); }); + +test('Scheduled Ec2 Task shows warning when minute is not defined in cron', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + new ScheduledEc2Task(stack, 'ScheduledEc2Task', { + cluster, + scheduledEc2TaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.cron({}), + }); + + // THEN + Annotations.fromStack(stack).hasWarning('/Default', "cron: If you don't pass 'minute', by default the event runs every minute. Pass 'minute: '*'' if that's what you intend, or 'minute: 0' to run once per hour instead."); +}); + +test('Scheduled Ec2 Task shows no warning when minute is * in cron', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + new ScheduledEc2Task(stack, 'ScheduledEc2Task', { + cluster, + scheduledEc2TaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.cron({ minute: '*' }), + }); + + // THEN + Annotations.fromStack(stack).hasNoWarning('/Default', Match.anyValue()); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.asset-image.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.asset-image.expected.json index 1be85fbb5e688..01c7cb601a90c 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.asset-image.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.asset-image.expected.json @@ -579,8 +579,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.circuit-breaker-queue-processing-fargate-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.circuit-breaker-queue-processing-fargate-service.expected.json index 74e53d75a507a..8e44e25a0c5ac 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.circuit-breaker-queue-processing-fargate-service.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.circuit-breaker-queue-processing-fargate-service.expected.json @@ -403,11 +403,11 @@ "Statement": [ { "Action": [ - "sqs:ReceiveMessage", "sqs:ChangeMessageVisibility", - "sqs:GetQueueUrl", "sqs:DeleteMessage", - "sqs:GetQueueAttributes" + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + "sqs:ReceiveMessage" ], "Effect": "Allow", "Resource": { @@ -530,8 +530,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.executionrole.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.executionrole.expected.json index dc83169a668a9..e05187b70855e 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.executionrole.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.executionrole.expected.json @@ -367,14 +367,10 @@ "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { - "Service": "ecs.amazonaws.com" - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "ecs-tasks.amazonaws.com" + "Service": [ + "ecs-tasks.amazonaws.com", + "ecs.amazonaws.com" + ] } } ], diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.expected.json index 2414ce426a716..07eefdc4a2629 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.expected.json @@ -712,11 +712,11 @@ "Statement": [ { "Action": [ - "sqs:ReceiveMessage", "sqs:ChangeMessageVisibility", - "sqs:GetQueueUrl", "sqs:DeleteMessage", - "sqs:GetQueueAttributes" + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + "sqs:ReceiveMessage" ], "Effect": "Allow", "Resource": { @@ -839,8 +839,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.expected.json index 8af962023d1d2..66c9a16e4a4e4 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.expected.json @@ -562,11 +562,11 @@ "Statement": [ { "Action": [ - "sqs:ReceiveMessage", "sqs:ChangeMessageVisibility", - "sqs:GetQueueUrl", "sqs:DeleteMessage", - "sqs:GetQueueAttributes" + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + "sqs:ReceiveMessage" ], "Effect": "Allow", "Resource": { @@ -606,8 +606,8 @@ "Essential": true, "HealthCheck": { "Command": [ - "CMD-SHELL", - "curl -f http://localhost/ || exit 1" + "CMD-SHELL", + "curl -f http://localhost/ || exit 1" ], "Interval": 720, "Retries": 34, @@ -698,8 +698,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json index 48bab449fe610..1eab7f10bddc6 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json @@ -403,11 +403,11 @@ "Statement": [ { "Action": [ - "sqs:ReceiveMessage", "sqs:ChangeMessageVisibility", - "sqs:GetQueueUrl", "sqs:DeleteMessage", - "sqs:GetQueueAttributes" + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + "sqs:ReceiveMessage" ], "Effect": "Allow", "Resource": { @@ -530,8 +530,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.scheduled-fargate-task.lit.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.scheduled-fargate-task.lit.expected.json index e580c83502abd..5110af7cc54eb 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.scheduled-fargate-task.lit.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.scheduled-fargate-task.lit.expected.json @@ -363,8 +363,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { @@ -459,22 +459,20 @@ { "Action": "iam:PassRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "ScheduledFargateTaskScheduledTaskDefExecutionRoleD37356D5", - "Arn" - ] - } - }, - { - "Action": "iam:PassRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "ScheduledFargateTaskScheduledTaskDefTaskRoleD0FF16AD", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "ScheduledFargateTaskScheduledTaskDefExecutionRoleD37356D5", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "ScheduledFargateTaskScheduledTaskDefTaskRoleD0FF16AD", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/scheduled-fargate-task.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/scheduled-fargate-task.test.ts index 696a413ad2def..5c84c45a68943 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/scheduled-fargate-task.test.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/scheduled-fargate-task.test.ts @@ -1,4 +1,4 @@ -import { Match, Template } from '@aws-cdk/assertions'; +import { Annotations, Match, Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import * as events from '@aws-cdk/aws-events'; @@ -410,3 +410,41 @@ test('Scheduled Fargate Task - exposes ECS Task', () => { // THEN expect(scheduledFargateTask.task).toBeDefined(); }); + +test('Scheduled Fargate Task shows warning when minute is not defined in cron', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.cron({}), + }); + + // THEN + Annotations.fromStack(stack).hasWarning('/Default', "cron: If you don't pass 'minute', by default the event runs every minute. Pass 'minute: '*'' if that's what you intend, or 'minute: 0' to run once per hour instead."); +}); + +test('Scheduled Fargate Task shows no warning when minute is * in cron', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.cron({ minute: '*' }), + }); + + // THEN + Annotations.fromStack(stack).hasNoWarning('/Default', Match.anyValue()); +}); diff --git a/packages/@aws-cdk/aws-ecs/README.md b/packages/@aws-cdk/aws-ecs/README.md index d99b830aad6dd..d0d091eda612e 100644 --- a/packages/@aws-cdk/aws-ecs/README.md +++ b/packages/@aws-cdk/aws-ecs/README.md @@ -427,6 +427,7 @@ const newContainer = taskDefinition.addContainer('container', { secrets: { // Retrieved from AWS Secrets Manager or AWS Systems Manager Parameter Store at container start-up. SECRET: ecs.Secret.fromSecretsManager(secret), DB_PASSWORD: ecs.Secret.fromSecretsManager(dbSecret, 'password'), // Reference a specific JSON field, (requires platform version 1.4.0 or later for Fargate tasks) + API_KEY: ecs.Secret.fromSecretsManagerVersion(secret, { versionId: '12345' }, 'apiKey'), // Reference a specific version of the secret by its version id or version stage (requires platform version 1.4.0 or later for Fargate tasks) PARAMETER: ecs.Secret.fromSsmParameter(parameter), }, }); diff --git a/packages/@aws-cdk/aws-ecs/lib/container-definition.ts b/packages/@aws-cdk/aws-ecs/lib/container-definition.ts index b46e66df585fa..0ee433ff951e7 100644 --- a/packages/@aws-cdk/aws-ecs/lib/container-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/container-definition.ts @@ -14,6 +14,24 @@ import { LogDriver, LogDriverConfig } from './log-drivers/log-driver'; // eslint-disable-next-line no-duplicate-imports, import/order import { Construct as CoreConstruct } from '@aws-cdk/core'; +/** + * Specify the secret's version id or version stage + */ +export interface SecretVersionInfo { + /** + * version id of the secret + * + * @default - use default version id + */ + readonly versionId?: string; + /** + * version stage of the secret + * + * @default - use default version stage + */ + readonly versionStage?: string; +} + /** * A secret environment variable. */ @@ -47,6 +65,25 @@ export abstract class Secret { }; } + /** + * Creates a environment variable value from a secret stored in AWS Secrets + * Manager. + * + * @param secret the secret stored in AWS Secrets Manager + * @param versionInfo the version information to reference the secret + * @param field the name of the field with the value that you want to set as + * the environment variable value. Only values in JSON format are supported. + * If you do not specify a JSON field, then the full content of the secret is + * used. + */ + public static fromSecretsManagerVersion(secret: secretsmanager.ISecret, versionInfo: SecretVersionInfo, field?: string): Secret { + return { + arn: `${secret.secretArn}:${field ?? ''}:${versionInfo.versionStage ?? ''}:${versionInfo.versionId ?? ''}`, + hasField: !!field, + grantRead: grantee => secret.grantRead(grantee), + }; + } + /** * The ARN of the secret */ diff --git a/packages/@aws-cdk/aws-ecs/package.json b/packages/@aws-cdk/aws-ecs/package.json index c3d3def173a2b..931a7d1b4ae1b 100644 --- a/packages/@aws-cdk/aws-ecs/package.json +++ b/packages/@aws-cdk/aws-ecs/package.json @@ -86,9 +86,9 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "@types/proxyquire": "^1.3.28", - "jest": "^27.4.7", + "jest": "^27.5.1", "proxyquire": "^2.1.3" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts index 7bee00a722c40..1aed207c1cdd5 100644 --- a/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts @@ -1261,6 +1261,8 @@ describe('container definition', () => { secrets: { SECRET: ecs.Secret.fromSecretsManager(secret), PARAMETER: ecs.Secret.fromSsmParameter(parameter), + SECRET_ID: ecs.Secret.fromSecretsManagerVersion(secret, { versionId: 'version-id' }), + SECRET_STAGE: ecs.Secret.fromSecretsManagerVersion(secret, { versionStage: 'version-stage' }), }, }); @@ -1298,6 +1300,34 @@ describe('container definition', () => { ], }, }, + { + Name: 'SECRET_ID', + ValueFrom: { + 'Fn::Join': [ + '', + [ + { + Ref: 'SecretA720EF05', + }, + ':::version-id', + ], + ], + }, + }, + { + Name: 'SECRET_STAGE', + ValueFrom: { + 'Fn::Join': [ + '', + [ + { + Ref: 'SecretA720EF05', + }, + '::version-stage:', + ], + ], + }, + }, ], }), ], @@ -1405,6 +1435,8 @@ describe('container definition', () => { memoryLimitMiB: 1024, secrets: { SECRET_KEY: ecs.Secret.fromSecretsManager(secret, 'specificKey'), + SECRET_KEY_ID: ecs.Secret.fromSecretsManagerVersion(secret, { versionId: 'version-id' }, 'specificKey'), + SECRET_KEY_STAGE: ecs.Secret.fromSecretsManagerVersion(secret, { versionStage: 'version-stage' }, 'specificKey'), }, }); @@ -1427,6 +1459,34 @@ describe('container definition', () => { ], }, }, + { + Name: 'SECRET_KEY_ID', + ValueFrom: { + 'Fn::Join': [ + '', + [ + { + Ref: 'SecretA720EF05', + }, + ':specificKey::version-id', + ], + ], + }, + }, + { + Name: 'SECRET_KEY_STAGE', + ValueFrom: { + 'Fn::Join': [ + '', + [ + { + Ref: 'SecretA720EF05', + }, + ':specificKey:version-stage:', + ], + ], + }, + }, ], }), ], diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts index 61dc1dc3c1c8a..c5171b8c94913 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts @@ -1,4 +1,4 @@ -import { Match, Template } from '@aws-cdk/assertions'; +import { Annotations, Match, Template } from '@aws-cdk/assertions'; import * as autoscaling from '@aws-cdk/aws-autoscaling'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elb from '@aws-cdk/aws-elasticloadbalancing'; @@ -1252,7 +1252,7 @@ describe('ec2 service', () => { memoryLimitMiB: 512, }); - const service = new ecs.Ec2Service(stack, 'Ec2Service', { + new ecs.Ec2Service(stack, 'Ec2Service', { cluster, taskDefinition, deploymentController: { @@ -1261,7 +1261,7 @@ describe('ec2 service', () => { }); // THEN - expect(service.node.metadataEntry[0].data).toEqual('taskDefinition and launchType are blanked out when using external deployment controller.'); + Annotations.fromStack(stack).hasWarning('/Default/Ec2Service', 'taskDefinition and launchType are blanked out when using external deployment controller.'); Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { Cluster: { Ref: 'EcsCluster97242B84', diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts index eeb20435d2cab..77b1607c13432 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { Match, Template } from '@aws-cdk/assertions'; +import { Annotations, Match, Template } from '@aws-cdk/assertions'; import { Protocol } from '@aws-cdk/aws-ec2'; import { Repository } from '@aws-cdk/aws-ecr'; import * as iam from '@aws-cdk/aws-iam'; @@ -90,8 +90,6 @@ describe('ec2 task definition', () => { }, ], }); - - }); test('correctly sets placement constraint', () => { @@ -112,8 +110,6 @@ describe('ec2 task definition', () => { ], }); - - }); test('correctly sets network mode', () => { @@ -127,8 +123,6 @@ describe('ec2 task definition', () => { Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { NetworkMode: ecs.NetworkMode.AWS_VPC, }); - - }); test('correctly sets ipc mode', () => { @@ -142,8 +136,6 @@ describe('ec2 task definition', () => { Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { IpcMode: ecs.IpcMode.TASK, }); - - }); test('correctly sets pid mode', () => { @@ -157,8 +149,6 @@ describe('ec2 task definition', () => { Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { PidMode: ecs.PidMode.HOST, }); - - }); test('correctly sets containers', () => { @@ -233,8 +223,6 @@ describe('ec2 task definition', () => { ], }, }); - - }); test('all container definition options defined', () => { @@ -439,8 +427,6 @@ describe('ec2 task definition', () => { }, ], }); - - }); test('correctly sets containers from ECR repository using all props', () => { @@ -465,6 +451,9 @@ describe('ec2 task definition', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::ECR::Repository', { + ImageScanningConfiguration: { + ScanOnPush: false, + }, LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":10,"selection":{"tagStatus":"tagged","tagPrefixList":["abc"],"countType":"imageCountMoreThan","countNumber":1},"action":{"type":"expire"}}]}', @@ -530,8 +519,6 @@ describe('ec2 task definition', () => { Name: 'web', }], }); - - }); test('correctly sets containers from ECR repository using an image tag', () => { @@ -687,9 +674,11 @@ describe('ec2 task definition', () => { }); // THEN - Template.fromStack(stack).hasResourceProperties('AWS::ECR::Repository', {}); - - + Template.fromStack(stack).hasResourceProperties('AWS::ECR::Repository', { + ImageScanningConfiguration: { + ScanOnPush: false, + }, + }); }); test('warns when setting containers from ECR repository using fromRegistry method', () => { @@ -699,14 +688,13 @@ describe('ec2 task definition', () => { const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); // WHEN - const container = taskDefinition.addContainer('web', { + taskDefinition.addContainer('web', { image: ecs.ContainerImage.fromRegistry('ACCOUNT.dkr.ecr.REGION.amazonaws.com/REPOSITORY'), memoryLimitMiB: 512, }); // THEN - expect(container.node.metadataEntry[0].data).toEqual("Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); - + Annotations.fromStack(stack).hasWarning('/Default/Ec2TaskDef/web', "Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); }); test('warns when setting containers from ECR repository by creating a RepositoryImage class', () => { @@ -718,15 +706,13 @@ describe('ec2 task definition', () => { const repo = new ecs.RepositoryImage('ACCOUNT.dkr.ecr.REGION.amazonaws.com/REPOSITORY'); // WHEN - const container = taskDefinition.addContainer('web', { + taskDefinition.addContainer('web', { image: repo, memoryLimitMiB: 512, }); // THEN - expect(container.node.metadataEntry[0].data).toEqual("Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); - - + Annotations.fromStack(stack).hasWarning('/Default/Ec2TaskDef/web', "Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); }); testFutureBehavior('correctly sets containers from asset using default props', { [cxapi.DOCKER_IGNORE_SUPPORT]: true }, cdk.App, (app) => { @@ -771,8 +757,6 @@ describe('ec2 task definition', () => { }, ], }); - - }); test('correctly sets containers from asset using all props', () => { @@ -787,8 +771,6 @@ describe('ec2 task definition', () => { }), memoryLimitMiB: 512, }); - - }); test('correctly sets scratch space', () => { @@ -879,8 +861,6 @@ describe('ec2 task definition', () => { }], })], }); - - }); test('correctly sets links', () => { const stack = new cdk.Stack(); @@ -1005,8 +985,6 @@ describe('ec2 task definition', () => { ], }, }); - - }); test('correctly sets volumes', () => { @@ -1080,8 +1058,6 @@ describe('ec2 task definition', () => { }, ], }); - - }); test('correctly sets taskRole', () => { @@ -1102,8 +1078,6 @@ describe('ec2 task definition', () => { Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { TaskRoleArn: stack.resolve(taskDefinition.taskRole.roleArn), }); - - }); test('automatically sets taskRole by default', () => { @@ -1115,8 +1089,6 @@ describe('ec2 task definition', () => { Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { TaskRoleArn: stack.resolve(taskDefinition.taskRole.roleArn), }); - - }); test('correctly sets dockerVolumeConfiguration', () => { @@ -1156,8 +1128,6 @@ describe('ec2 task definition', () => { }, }], }); - - }); test('correctly sets efsVolumeConfiguration', () => { @@ -1189,8 +1159,6 @@ describe('ec2 task definition', () => { }, }], }); - - }); }); diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json index 2e5eed7f911c6..f7b2939f2f34d 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json @@ -95,15 +95,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "Tags": [ { "Key": "Name", @@ -452,8 +452,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -596,10 +596,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -634,7 +634,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -662,24 +664,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "EcsCluster97242B84", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -757,6 +741,17 @@ } } }, + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup" + } + ] + } + }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookRoleA38EC83B": { "Type": "AWS::IAM::Role", "Properties": { @@ -803,17 +798,6 @@ ] } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup" - } - ] - } - }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookFFA63029": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json index 45ea355b976e9..5a406ea170864 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json @@ -446,8 +446,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -590,10 +590,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -628,7 +628,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -656,24 +658,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "EcsCluster97242B84", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -751,6 +735,17 @@ } } }, + "EcsClusterbottlerocketasgLifecycleHookDrainHookTopic64509A74": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg" + } + ] + } + }, "EcsClusterbottlerocketasgLifecycleHookDrainHookRoleDE4D94EB": { "Type": "AWS::IAM::Role", "Properties": { @@ -797,17 +792,6 @@ ] } }, - "EcsClusterbottlerocketasgLifecycleHookDrainHookTopic64509A74": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg" - } - ] - } - }, "EcsClusterbottlerocketasgLifecycleHookDrainHook59C31812": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.capacity-provider.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.capacity-provider.expected.json index 555d9acc46764..49a82b3c29e9d 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.capacity-provider.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.capacity-provider.expected.json @@ -95,15 +95,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "Tags": [ { "Key": "Name", @@ -509,8 +509,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -650,10 +650,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -688,7 +688,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -716,24 +718,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "EC2CPClusterD5F0FD32", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -811,6 +795,17 @@ } } }, + "ASGLifecycleHookDrainHookTopicA8AD4ACB": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "integ-ec2-capacity-provider/ASG" + } + ] + } + }, "ASGLifecycleHookDrainHookRoleD640316C": { "Type": "AWS::IAM::Role", "Properties": { @@ -857,17 +852,6 @@ ] } }, - "ASGLifecycleHookDrainHookTopicA8AD4ACB": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "integ-ec2-capacity-provider/ASG" - } - ] - } - }, "ASGLifecycleHookDrainHookFE4AFEBE": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json index 77ccc9c6c36c6..2443f10d52c04 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json @@ -95,15 +95,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "Tags": [ { "Key": "Name", @@ -473,8 +473,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -617,10 +617,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -655,7 +655,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -683,24 +685,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "EcsCluster97242B84", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -778,6 +762,17 @@ } } }, + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup" + } + ] + } + }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookRoleA38EC83B": { "Type": "AWS::IAM::Role", "Properties": { @@ -824,17 +819,6 @@ ] } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup" - } - ] - } - }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookFFA63029": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.cloudmap-container-port.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.cloudmap-container-port.expected.json index da866432d8539..6ff4de4f72d44 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.cloudmap-container-port.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.cloudmap-container-port.expected.json @@ -273,8 +273,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -418,10 +418,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -456,7 +456,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -484,24 +486,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "FargateCluster7CCD5F93", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -579,6 +563,17 @@ } } }, + "FargateClustercapacityLifecycleHookDrainHookTopic390A0E34": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/FargateCluster/capacity" + } + ] + } + }, "FargateClustercapacityLifecycleHookDrainHookRoleDD26E39B": { "Type": "AWS::IAM::Role", "Properties": { @@ -625,17 +620,6 @@ ] } }, - "FargateClustercapacityLifecycleHookDrainHookTopic390A0E34": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/FargateCluster/capacity" - } - ] - } - }, "FargateClustercapacityLifecycleHookDrainHook8AEDE53B": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json index 9219258ba7016..875db62f1a654 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json @@ -33,9 +33,9 @@ "Statement": [ { "Action": [ + "s3:DeleteObject*", "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*" + "s3:List*" ], "Effect": "Allow", "Principal": { @@ -635,8 +635,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -779,10 +779,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -817,7 +817,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -845,24 +847,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "EcsCluster97242B84", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -1174,7 +1158,7 @@ "Properties": { "Content": { "S3Bucket": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" }, "S3Key": { "Fn::Join": [ @@ -1187,7 +1171,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -1200,7 +1184,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -1308,8 +1292,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -1325,7 +1309,8 @@ ":s3:::", { "Ref": "AssetParameters972240f9dd6e036a93d5f081af9a24315b2053828ac049b3b19b2fa12d7ae64aS3Bucket1F1A8472" - } + }, + "/*" ] ] }, @@ -1340,8 +1325,7 @@ ":s3:::", { "Ref": "AssetParameters972240f9dd6e036a93d5f081af9a24315b2053828ac049b3b19b2fa12d7ae64aS3Bucket1F1A8472" - }, - "/*" + } ] ] } @@ -1349,16 +1333,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -1400,7 +1384,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameterse3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0S3BucketB3DDCC13" + "Ref": "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3BucketF23C0DE7" }, "S3Key": { "Fn::Join": [ @@ -1413,7 +1397,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterse3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0S3VersionKey3418DF70" + "Ref": "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3VersionKey5E97B17D" } ] } @@ -1426,7 +1410,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterse3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0S3VersionKey3418DF70" + "Ref": "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3VersionKey5E97B17D" } ] } @@ -1525,29 +1509,29 @@ "Type": "String", "Description": "Artifact hash for asset \"be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488": { "Type": "String", - "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 bucket for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2": { "Type": "String", - "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 key for asset version \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95ArtifactHash16B60F6C": { "Type": "String", - "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "Artifact hash for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0S3BucketB3DDCC13": { + "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3BucketF23C0DE7": { "Type": "String", - "Description": "S3 bucket for asset \"e3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0\"" + "Description": "S3 bucket for asset \"f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da\"" }, - "AssetParameterse3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0S3VersionKey3418DF70": { + "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3VersionKey5E97B17D": { "Type": "String", - "Description": "S3 key for asset version \"e3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0\"" + "Description": "S3 key for asset version \"f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da\"" }, - "AssetParameterse3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0ArtifactHash9D8F179A": { + "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daArtifactHashD85D28D8": { "Type": "String", - "Description": "Artifact hash for asset \"e3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0\"" + "Description": "Artifact hash for asset \"f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da\"" }, "AssetParameters972240f9dd6e036a93d5f081af9a24315b2053828ac049b3b19b2fa12d7ae64aS3Bucket1F1A8472": { "Type": "String", diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.exec-command.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.exec-command.expected.json index 8748132b68636..7e4e0f4fb0eb4 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.exec-command.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.exec-command.expected.json @@ -385,11 +385,11 @@ }, { "Action": [ - "kms:Encrypt*", "kms:Decrypt*", - "kms:ReEncrypt*", + "kms:Describe*", + "kms:Encrypt*", "kms:GenerateDataKey*", - "kms:Describe*" + "kms:ReEncrypt*" ], "Condition": { "ArnLike": { @@ -596,8 +596,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -740,10 +740,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -778,7 +778,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -806,24 +808,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "Ec2ClusterEE43E89D", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -1006,6 +990,8 @@ "Statement": [ { "Action": [ + "logs:DescribeLogGroups", + "s3:GetBucketLocation", "ssmmessages:CreateControlChannel", "ssmmessages:CreateDataChannel", "ssmmessages:OpenControlChannel", @@ -1027,11 +1013,6 @@ ] } }, - { - "Action": "logs:DescribeLogGroups", - "Effect": "Allow", - "Resource": "*" - }, { "Action": [ "logs:CreateLogStream", @@ -1064,11 +1045,6 @@ ] } }, - { - "Action": "s3:GetBucketLocation", - "Effect": "Allow", - "Resource": "*" - }, { "Action": "s3:PutObject", "Effect": "Allow", diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json index b082b18fd7281..aca6607f04d70 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json @@ -452,8 +452,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -596,10 +596,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -634,7 +634,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -662,24 +664,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "EcsCluster97242B84", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -757,6 +741,17 @@ } } }, + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup" + } + ] + } + }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookRoleA38EC83B": { "Type": "AWS::IAM::Role", "Properties": { @@ -803,17 +798,6 @@ ] } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup" - } - ] - } - }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookFFA63029": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { @@ -996,10 +980,10 @@ "Statement": [ { "Action": [ - "ecr:GetAuthorizationToken", "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetAuthorizationToken", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": "*" diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton-bottlerocket.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton-bottlerocket.expected.json index f2c15441bbe28..6dfbe283bb327 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton-bottlerocket.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton-bottlerocket.expected.json @@ -478,8 +478,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -622,10 +622,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -660,7 +660,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -688,24 +690,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "EcsCluster97242B84", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -783,6 +767,17 @@ } } }, + "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" + } + ] + } + }, "EcsClustergravitonclusterLifecycleHookDrainHookRoleA16C85AD": { "Type": "AWS::IAM::Role", "Properties": { @@ -829,17 +824,6 @@ ] } }, - "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" - } - ] - } - }, "EcsClustergravitonclusterLifecycleHookDrainHookA1F91B1B": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { @@ -871,4 +855,4 @@ "Default": "/aws/service/bottlerocket/aws-ecs-1/arm64/latest/image_id" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton.expected.json index c2b3eeecc8ddf..16c47fb72cba6 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton.expected.json @@ -452,8 +452,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -596,10 +596,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -634,7 +634,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -662,24 +664,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "EcsCluster97242B84", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -757,6 +741,17 @@ } } }, + "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" + } + ] + } + }, "EcsClustergravitonclusterLifecycleHookDrainHookRoleA16C85AD": { "Type": "AWS::IAM::Role", "Properties": { @@ -803,17 +798,6 @@ ] } }, - "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" - } - ] - } - }, "EcsClustergravitonclusterLifecycleHookDrainHookA1F91B1B": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json index fb1143317da2c..d46faf1396a29 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json @@ -452,8 +452,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -596,10 +596,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -634,7 +634,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -662,24 +664,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "EcsCluster97242B84", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -757,6 +741,17 @@ } } }, + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup" + } + ] + } + }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookRoleA38EC83B": { "Type": "AWS::IAM::Role", "Properties": { @@ -803,17 +798,6 @@ ] } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup" - } - ] - } - }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookFFA63029": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json index 662773111278c..d5599176ddb20 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json @@ -473,8 +473,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -617,10 +617,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -655,7 +655,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -683,24 +685,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "EcsCluster97242B84", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -778,6 +762,17 @@ } } }, + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup" + } + ] + } + }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookRoleA38EC83B": { "Type": "AWS::IAM::Role", "Properties": { @@ -824,17 +819,6 @@ ] } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup" - } - ] - } - }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookFFA63029": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json index 353debc6de544..5faebad17a091 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json @@ -95,15 +95,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "Tags": [ { "Key": "Name", @@ -452,8 +452,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -596,10 +596,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -634,7 +634,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -662,24 +664,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "EcsCluster97242B84", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -757,6 +741,17 @@ } } }, + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup" + } + ] + } + }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookRoleA38EC83B": { "Type": "AWS::IAM::Role", "Properties": { @@ -803,17 +798,6 @@ ] } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup" - } - ] - } - }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookFFA63029": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json index 4722ee003bef2..b5b5299e5dc50 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json @@ -95,15 +95,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "Tags": [ { "Key": "Name", @@ -452,8 +452,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -596,10 +596,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -634,7 +634,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -662,24 +664,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "EcsCluster97242B84", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -757,6 +741,17 @@ } } }, + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup" + } + ] + } + }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookRoleA38EC83B": { "Type": "AWS::IAM::Role", "Properties": { @@ -803,17 +798,6 @@ ] } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup" - } - ] - } - }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookFFA63029": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.secret-json-field.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.secret-json-field.expected.json index b14c1d7855e8c..e48ef0159d603 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.secret-json-field.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.secret-json-field.expected.json @@ -98,8 +98,8 @@ "Statement": [ { "Action": [ - "secretsmanager:GetSecretValue", - "secretsmanager:DescribeSecret" + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json index 20ba3cf89516e..15f4ab5f3a8fb 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json @@ -95,15 +95,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "Tags": [ { "Key": "Name", @@ -452,8 +452,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -598,10 +598,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -636,7 +636,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -664,24 +666,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "EcsCluster97242B84", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -759,6 +743,17 @@ } } }, + "EcsClusterasgSpotLifecycleHookDrainHookTopic6212EC83": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-spot/EcsCluster/asgSpot" + } + ] + } + }, "EcsClusterasgSpotLifecycleHookDrainHookRole1B427C77": { "Type": "AWS::IAM::Role", "Properties": { @@ -805,17 +800,6 @@ ] } }, - "EcsClusterasgSpotLifecycleHookDrainHookTopic6212EC83": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-spot/EcsCluster/asgSpot" - } - ] - } - }, "EcsClusterasgSpotLifecycleHookDrainHook91178D34": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { @@ -934,8 +918,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -1079,10 +1063,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -1117,7 +1101,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -1145,24 +1131,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "EcsCluster97242B84", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -1240,6 +1208,17 @@ } } }, + "EcsClusterasgOdLifecycleHookDrainHookTopic673CE202": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-spot/EcsCluster/asgOd" + } + ] + } + }, "EcsClusterasgOdLifecycleHookDrainHookRole695B2DF1": { "Type": "AWS::IAM::Role", "Properties": { @@ -1286,17 +1265,6 @@ ] } }, - "EcsClusterasgOdLifecycleHookDrainHookTopic673CE202": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-spot/EcsCluster/asgOd" - } - ] - } - }, "EcsClusterasgOdLifecycleHookDrainHook03AC5A9E": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { diff --git a/packages/@aws-cdk/aws-ecs/test/external/external-task-definition.test.ts b/packages/@aws-cdk/aws-ecs/test/external/external-task-definition.test.ts index 756569d405d6d..bcb65634c353d 100644 --- a/packages/@aws-cdk/aws-ecs/test/external/external-task-definition.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/external/external-task-definition.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { Template } from '@aws-cdk/assertions'; +import { Annotations, Template } from '@aws-cdk/assertions'; import { Protocol } from '@aws-cdk/aws-ec2'; import { Repository } from '@aws-cdk/aws-ecr'; import * as iam from '@aws-cdk/aws-iam'; @@ -60,8 +60,6 @@ describe('external task definition', () => { ], }, }); - - }); test('correctly sets containers', () => { @@ -127,8 +125,6 @@ describe('external task definition', () => { ], }, }); - - }); test('all container definition options defined', () => { @@ -330,8 +326,6 @@ describe('external task definition', () => { }, ], }); - - }); test('correctly sets containers from ECR repository using all props', () => { @@ -356,6 +350,9 @@ describe('external task definition', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::ECR::Repository', { + ImageScanningConfiguration: { + ScanOnPush: false, + }, LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":10,"selection":{"tagStatus":"tagged","tagPrefixList":["abc"],"countType":"imageCountMoreThan","countNumber":1},"action":{"type":"expire"}}]}', @@ -423,8 +420,6 @@ describe('external task definition', () => { Name: 'web', }], }); - - }); }); @@ -498,8 +493,6 @@ describe('external task definition', () => { Name: 'web', }], }); - - }); test('correctly sets containers from ECR repository using an image digest', () => { @@ -571,8 +564,6 @@ describe('external task definition', () => { Name: 'web', }], }); - - }); test('correctly sets containers from ECR repository using default props', () => { @@ -587,9 +578,11 @@ describe('external task definition', () => { }); // THEN - Template.fromStack(stack).hasResourceProperties('AWS::ECR::Repository', {}); - - + Template.fromStack(stack).hasResourceProperties('AWS::ECR::Repository', { + ImageScanningConfiguration: { + ScanOnPush: false, + }, + }); }); test('warns when setting containers from ECR repository using fromRegistry method', () => { @@ -597,16 +590,15 @@ describe('external task definition', () => { const stack = new cdk.Stack(); const taskDefinition = new ecs.ExternalTaskDefinition(stack, 'ExternalTaskDef'); + // WHEN - const container = taskDefinition.addContainer('web', { + taskDefinition.addContainer('web', { image: ecs.ContainerImage.fromRegistry('ACCOUNT.dkr.ecr.REGION.amazonaws.com/REPOSITORY'), memoryLimitMiB: 512, }); // THEN - expect(container.node.metadataEntry[0].data).toEqual("Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); - - + Annotations.fromStack(stack).hasWarning('/Default/ExternalTaskDef/web', "Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); }); test('correctly sets volumes from', () => { @@ -620,8 +612,6 @@ describe('external task definition', () => { }, name: 'scratch', })).toThrow('External task definitions doesnt support volumes' ); - - }); test('error when interferenceAccelerators set', () => { @@ -633,7 +623,5 @@ describe('external task definition', () => { deviceName: 'device1', deviceType: 'eia2.medium', })).toThrow('Cannot use inference accelerators on tasks that run on External service'); - - }); }); diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts index e28ebda720b52..b12a7e1748d52 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts @@ -1,4 +1,4 @@ -import { Match, Template } from '@aws-cdk/assertions'; +import { Annotations, Match, Template } from '@aws-cdk/assertions'; import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; @@ -84,8 +84,6 @@ describe('fargate service', () => { }); expect(service.node.defaultChild).toBeDefined(); - - }); test('can create service with default settings if VPC only has public subnets', () => { @@ -113,7 +111,6 @@ describe('fargate service', () => { }); // THEN -- did not throw - }); testDeprecated('does not set launchType when capacity provider strategies specified (deprecated)', () => { @@ -201,8 +198,6 @@ describe('fargate service', () => { }, }, }); - - }); test('does not set launchType when capacity provider strategies specified', () => { @@ -292,8 +287,6 @@ describe('fargate service', () => { }, }, }); - - }); test('with custom cloudmap namespace', () => { @@ -359,8 +352,6 @@ describe('fargate service', () => { Ref: 'MyVpcF9F0CA6F', }, }); - - }); test('with user-provided cloudmap service', () => { @@ -409,8 +400,6 @@ describe('fargate service', () => { }, ], }); - - }); test('errors when more than one service registry used', () => { @@ -454,8 +443,6 @@ describe('fargate service', () => { containerPort: 8000, }); }).toThrow(/at most one service registry/i); - - }); test('with all properties set', () => { @@ -560,8 +547,6 @@ describe('fargate service', () => { }, ], }); - - }); test('throws when task definition is not Fargate compatible', () => { @@ -608,8 +593,6 @@ describe('fargate service', () => { platformVersion: ecs.FargatePlatformVersion.VERSION1_3, }); }).toThrow(new RegExp(`uses at least one container that references a secret JSON field.+platform version ${ecs.FargatePlatformVersion.VERSION1_4} or later`)); - - }); test('ignore task definition and launch type if deployment controller is set to be EXTERNAL', () => { @@ -623,7 +606,7 @@ describe('fargate service', () => { image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), }); - const service = new ecs.FargateService(stack, 'FargateService', { + new ecs.FargateService(stack, 'FargateService', { cluster, taskDefinition, deploymentController: { @@ -632,7 +615,7 @@ describe('fargate service', () => { }); // THEN - expect(service.node.metadataEntry[0].data).toEqual('taskDefinition and launchType are blanked out when using external deployment controller.'); + Annotations.fromStack(stack).hasWarning('/Default/FargateService', 'taskDefinition and launchType are blanked out when using external deployment controller.'); Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { Cluster: { Ref: 'EcsCluster97242B84', @@ -667,8 +650,6 @@ describe('fargate service', () => { }, }, }); - - }); test('errors when no container specified on task definition', () => { @@ -688,8 +669,6 @@ describe('fargate service', () => { expect(() => { Template.fromStack(stack); }).toThrow(/one essential container/); - - }); test('allows adding the default container after creating the service', () => { @@ -744,8 +723,6 @@ describe('fargate service', () => { }, }, }); - - }); test('allows specifying 0 for minimumHealthyPercent', () => { @@ -771,8 +748,6 @@ describe('fargate service', () => { MinimumHealthyPercent: 0, }, }); - - }); testDeprecated('throws when securityGroup and securityGroups are supplied', () => { @@ -807,8 +782,6 @@ describe('fargate service', () => { securityGroups: [securityGroup2], }); }).toThrow(/Only one of SecurityGroup or SecurityGroups can be populated./); - - }); test('with multiple securty groups, it correctly updates cloudformation template', () => { @@ -914,10 +887,7 @@ describe('fargate service', () => { Ref: 'MyVpcF9F0CA6F', }, }); - - }); - }); describe('When setting up a health check', () => { @@ -942,8 +912,6 @@ describe('fargate service', () => { Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { HealthCheckGracePeriodSeconds: 10, }); - - }); }); @@ -1020,8 +988,6 @@ describe('fargate service', () => { // set, then it should default to 60 seconds. HealthCheckGracePeriodSeconds: 60, }); - - }); test('allows auto scaling by ALB with new service arn format', () => { @@ -1077,8 +1043,6 @@ describe('fargate service', () => { ], }, }); - - }); describe('allows specify any existing container name and port in a service', () => { @@ -1133,8 +1097,6 @@ describe('fargate service', () => { FromPort: 8000, ToPort: 8000, }); - - }); test('with TCP protocol', () => { @@ -1167,8 +1129,6 @@ describe('fargate service', () => { protocol: ecs.Protocol.TCP, })], }); - - }); test('with UDP protocol', () => { @@ -1201,8 +1161,6 @@ describe('fargate service', () => { protocol: ecs.Protocol.UDP, })], }); - - }); test('throws when protocol does not match', () => { @@ -1237,8 +1195,6 @@ describe('fargate service', () => { })], }); }).toThrow(/Container 'Default\/FargateTaskDef\/MainContainer' has no mapping for port 8001 and protocol tcp. Did you call "container.addPortMappings\(\)"\?/); - - }); test('throws when port does not match', () => { @@ -1272,8 +1228,6 @@ describe('fargate service', () => { })], }); }).toThrow(/Container 'Default\/FargateTaskDef\/MainContainer' has no mapping for port 8002 and protocol tcp. Did you call "container.addPortMappings\(\)"\?/); - - }); test('throws when container does not exist', () => { @@ -1307,8 +1261,6 @@ describe('fargate service', () => { })], }); }).toThrow(/No container named 'SideContainer'. Did you call "addContainer()"?/); - - }); }); @@ -1360,8 +1312,6 @@ describe('fargate service', () => { Port: 80, Protocol: 'HTTP', }); - - }); test('with default target group port and HTTP protocol', () => { @@ -1412,8 +1362,6 @@ describe('fargate service', () => { Port: 80, Protocol: 'HTTP', }); - - }); test('with default target group port and HTTPS protocol', () => { @@ -1464,8 +1412,6 @@ describe('fargate service', () => { Port: 443, Protocol: 'HTTPS', }); - - }); test('with any target group port and protocol', () => { @@ -1517,8 +1463,6 @@ describe('fargate service', () => { Port: 83, Protocol: 'HTTP', }); - - }); }); @@ -1569,8 +1513,6 @@ describe('fargate service', () => { Port: 80, Protocol: 'TCP', }); - - }); test('with any target group port', () => { @@ -1621,205 +1563,250 @@ describe('fargate service', () => { Port: 81, Protocol: 'TCP', }); - - }); }); }); }); - test('allows scaling on a specified scheduled time', () => { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'MyVpc', {}); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); - const container = taskDefinition.addContainer('MainContainer', { - image: ecs.ContainerImage.fromRegistry('hello'), - }); - container.addPortMappings({ containerPort: 8000 }); + describe('autoscaling tests', () => { + test('allows scaling on a specified scheduled time', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + const container = taskDefinition.addContainer('MainContainer', { + image: ecs.ContainerImage.fromRegistry('hello'), + }); + container.addPortMappings({ containerPort: 8000 }); - const service = new ecs.FargateService(stack, 'Service', { - cluster, - taskDefinition, - }); + const service = new ecs.FargateService(stack, 'Service', { + cluster, + taskDefinition, + }); - // WHEN - const capacity = service.autoScaleTaskCount({ maxCapacity: 10, minCapacity: 1 }); - capacity.scaleOnSchedule('ScaleOnSchedule', { - schedule: appscaling.Schedule.cron({ hour: '8', minute: '0' }), - minCapacity: 10, - }); + // WHEN + const capacity = service.autoScaleTaskCount({ maxCapacity: 10, minCapacity: 1 }); + capacity.scaleOnSchedule('ScaleOnSchedule', { + schedule: appscaling.Schedule.cron({ hour: '8', minute: '0' }), + minCapacity: 10, + }); - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalableTarget', { - ScheduledActions: [ - { - ScalableTargetAction: { - MinCapacity: 10, + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalableTarget', { + ScheduledActions: [ + { + ScalableTargetAction: { + MinCapacity: 10, + }, + Schedule: 'cron(0 8 * * ? *)', + ScheduledActionName: 'ScaleOnSchedule', }, - Schedule: 'cron(0 8 * * ? *)', - ScheduledActionName: 'ScaleOnSchedule', - }, - ], - }); - - - }); - - test('allows scaling on a specified metric value', () => { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'MyVpc', {}); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); - const container = taskDefinition.addContainer('MainContainer', { - image: ecs.ContainerImage.fromRegistry('hello'), + ], + }); }); - container.addPortMappings({ containerPort: 8000 }); - const service = new ecs.FargateService(stack, 'Service', { - cluster, - taskDefinition, - }); + test('allows scaling on a specified metric value', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + const container = taskDefinition.addContainer('MainContainer', { + image: ecs.ContainerImage.fromRegistry('hello'), + }); + container.addPortMappings({ containerPort: 8000 }); - // WHEN - const capacity = service.autoScaleTaskCount({ maxCapacity: 10, minCapacity: 1 }); - capacity.scaleOnMetric('ScaleOnMetric', { - metric: new cloudwatch.Metric({ namespace: 'Test', metricName: 'Metric' }), - scalingSteps: [ - { upper: 0, change: -1 }, - { lower: 100, change: +1 }, - { lower: 500, change: +5 }, - ], - }); + const service = new ecs.FargateService(stack, 'Service', { + cluster, + taskDefinition, + }); - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalingPolicy', { - PolicyType: 'StepScaling', - ScalingTargetId: { - Ref: 'ServiceTaskCountTarget23E25614', - }, - StepScalingPolicyConfiguration: { - AdjustmentType: 'ChangeInCapacity', - MetricAggregationType: 'Average', - StepAdjustments: [ - { - MetricIntervalUpperBound: 0, - ScalingAdjustment: -1, - }, + // WHEN + const capacity = service.autoScaleTaskCount({ maxCapacity: 10, minCapacity: 1 }); + capacity.scaleOnMetric('ScaleOnMetric', { + metric: new cloudwatch.Metric({ namespace: 'Test', metricName: 'Metric' }), + scalingSteps: [ + { upper: 0, change: -1 }, + { lower: 100, change: +1 }, + { lower: 500, change: +5 }, ], - }, - }); + }); + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalingPolicy', { + PolicyType: 'StepScaling', + ScalingTargetId: { + Ref: 'ServiceTaskCountTarget23E25614', + }, + StepScalingPolicyConfiguration: { + AdjustmentType: 'ChangeInCapacity', + MetricAggregationType: 'Average', + StepAdjustments: [ + { + MetricIntervalUpperBound: 0, + ScalingAdjustment: -1, + }, + ], + }, + }); + }); - }); + test('allows scaling on a target CPU utilization', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + const container = taskDefinition.addContainer('MainContainer', { + image: ecs.ContainerImage.fromRegistry('hello'), + }); + container.addPortMappings({ containerPort: 8000 }); - test('allows scaling on a target CPU utilization', () => { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'MyVpc', {}); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); - const container = taskDefinition.addContainer('MainContainer', { - image: ecs.ContainerImage.fromRegistry('hello'), - }); - container.addPortMappings({ containerPort: 8000 }); + const service = new ecs.FargateService(stack, 'Service', { + cluster, + taskDefinition, + }); - const service = new ecs.FargateService(stack, 'Service', { - cluster, - taskDefinition, - }); + // WHEN + const capacity = service.autoScaleTaskCount({ maxCapacity: 10, minCapacity: 1 }); + capacity.scaleOnCpuUtilization('ScaleOnCpu', { + targetUtilizationPercent: 30, + }); - // WHEN - const capacity = service.autoScaleTaskCount({ maxCapacity: 10, minCapacity: 1 }); - capacity.scaleOnCpuUtilization('ScaleOnCpu', { - targetUtilizationPercent: 30, + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalingPolicy', { + PolicyType: 'TargetTrackingScaling', + TargetTrackingScalingPolicyConfiguration: { + PredefinedMetricSpecification: { PredefinedMetricType: 'ECSServiceAverageCPUUtilization' }, + TargetValue: 30, + }, + }); }); - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalingPolicy', { - PolicyType: 'TargetTrackingScaling', - TargetTrackingScalingPolicyConfiguration: { - PredefinedMetricSpecification: { PredefinedMetricType: 'ECSServiceAverageCPUUtilization' }, - TargetValue: 30, - }, - }); + test('allows scaling on memory utilization', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + const container = taskDefinition.addContainer('MainContainer', { + image: ecs.ContainerImage.fromRegistry('hello'), + }); + container.addPortMappings({ containerPort: 8000 }); + const service = new ecs.FargateService(stack, 'Service', { + cluster, + taskDefinition, + }); - }); + // WHEN + const capacity = service.autoScaleTaskCount({ maxCapacity: 10, minCapacity: 1 }); + capacity.scaleOnMemoryUtilization('ScaleOnMemory', { + targetUtilizationPercent: 30, + }); - test('allows scaling on memory utilization', () => { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'MyVpc', {}); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); - const container = taskDefinition.addContainer('MainContainer', { - image: ecs.ContainerImage.fromRegistry('hello'), + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalingPolicy', { + PolicyType: 'TargetTrackingScaling', + TargetTrackingScalingPolicyConfiguration: { + PredefinedMetricSpecification: { PredefinedMetricType: 'ECSServiceAverageMemoryUtilization' }, + TargetValue: 30, + }, + }); }); - container.addPortMappings({ containerPort: 8000 }); - const service = new ecs.FargateService(stack, 'Service', { - cluster, - taskDefinition, - }); + test('allows scaling on custom CloudWatch metric', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + const container = taskDefinition.addContainer('MainContainer', { + image: ecs.ContainerImage.fromRegistry('hello'), + }); + container.addPortMappings({ containerPort: 8000 }); - // WHEN - const capacity = service.autoScaleTaskCount({ maxCapacity: 10, minCapacity: 1 }); - capacity.scaleOnMemoryUtilization('ScaleOnMemory', { - targetUtilizationPercent: 30, - }); + const service = new ecs.FargateService(stack, 'Service', { + cluster, + taskDefinition, + }); - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalingPolicy', { - PolicyType: 'TargetTrackingScaling', - TargetTrackingScalingPolicyConfiguration: { - PredefinedMetricSpecification: { PredefinedMetricType: 'ECSServiceAverageMemoryUtilization' }, - TargetValue: 30, - }, + // WHEN + const capacity = service.autoScaleTaskCount({ maxCapacity: 10, minCapacity: 1 }); + capacity.scaleToTrackCustomMetric('ScaleOnCustomMetric', { + metric: new cloudwatch.Metric({ namespace: 'Test', metricName: 'Metric' }), + targetValue: 5, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalingPolicy', { + PolicyType: 'TargetTrackingScaling', + TargetTrackingScalingPolicyConfiguration: { + CustomizedMetricSpecification: { + MetricName: 'Metric', + Namespace: 'Test', + Statistic: 'Average', + }, + TargetValue: 5, + }, + }); }); + test('scheduled scaling shows warning when minute is not defined in cron', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + const container = taskDefinition.addContainer('MainContainer', { + image: ecs.ContainerImage.fromRegistry('hello'), + }); + container.addPortMappings({ containerPort: 8000 }); - }); + const service = new ecs.FargateService(stack, 'Service', { + cluster, + taskDefinition, + }); - test('allows scaling on custom CloudWatch metric', () => { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'MyVpc', {}); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); - const container = taskDefinition.addContainer('MainContainer', { - image: ecs.ContainerImage.fromRegistry('hello'), - }); - container.addPortMappings({ containerPort: 8000 }); + // WHEN + const capacity = service.autoScaleTaskCount({ maxCapacity: 10, minCapacity: 1 }); + capacity.scaleOnSchedule('ScaleOnSchedule', { + schedule: appscaling.Schedule.cron({ hour: '8' }), + minCapacity: 10, + }); - const service = new ecs.FargateService(stack, 'Service', { - cluster, - taskDefinition, + // THEN + Annotations.fromStack(stack).hasWarning('/Default/Service/TaskCount/Target', "cron: If you don't pass 'minute', by default the event runs every minute. Pass 'minute: '*'' if that's what you intend, or 'minute: 0' to run once per hour instead."); }); - // WHEN - const capacity = service.autoScaleTaskCount({ maxCapacity: 10, minCapacity: 1 }); - capacity.scaleToTrackCustomMetric('ScaleOnCustomMetric', { - metric: new cloudwatch.Metric({ namespace: 'Test', metricName: 'Metric' }), - targetValue: 5, - }); + test('scheduled scaling shows no warning when minute is * in cron', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + const container = taskDefinition.addContainer('MainContainer', { + image: ecs.ContainerImage.fromRegistry('hello'), + }); + container.addPortMappings({ containerPort: 8000 }); - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalingPolicy', { - PolicyType: 'TargetTrackingScaling', - TargetTrackingScalingPolicyConfiguration: { - CustomizedMetricSpecification: { - MetricName: 'Metric', - Namespace: 'Test', - Statistic: 'Average', - }, - TargetValue: 5, - }, - }); + const service = new ecs.FargateService(stack, 'Service', { + cluster, + taskDefinition, + }); + // WHEN + const capacity = service.autoScaleTaskCount({ maxCapacity: 10, minCapacity: 1 }); + capacity.scaleOnSchedule('ScaleOnSchedule', { + schedule: appscaling.Schedule.cron({ hour: '8', minute: '*' }), + minCapacity: 10, + }); + // THEN + const annotations = Annotations.fromStack(stack).findWarning('*', Match.anyValue()); + expect(annotations.length).toBe(0); + }); }); describe('When enabling service discovery', () => { @@ -1845,8 +1832,6 @@ describe('fargate service', () => { }, }); }).toThrow(/Cannot enable service discovery if a Cloudmap Namespace has not been created in the cluster./); - - }); test('creates cloud map service for Private DNS namespace', () => { @@ -1902,8 +1887,6 @@ describe('fargate service', () => { ], }, }); - - }); test('creates AWS Cloud Map service for Private DNS namespace with SRV records with proper defaults', () => { @@ -1963,8 +1946,6 @@ describe('fargate service', () => { ], }, }); - - }); test('creates AWS Cloud Map service for Private DNS namespace with SRV records with overriden defaults', () => { @@ -2025,8 +2006,6 @@ describe('fargate service', () => { ], }, }); - - }); test('user can select any container and port', () => { @@ -2071,8 +2050,6 @@ describe('fargate service', () => { }, ], }); - - }); }); @@ -2103,8 +2080,6 @@ describe('fargate service', () => { period: cdk.Duration.minutes(5), statistic: 'Average', }); - - }); describe('When import a Fargate Service', () => { @@ -2143,8 +2118,6 @@ describe('fargate service', () => { // THEN expect(stack.resolve(service.serviceArn)).toEqual(stack.resolve(`arn:${pseudo.partition}:ecs:${pseudo.region}:${pseudo.accountId}:service/my-http-service`)); expect(service.serviceName).toEqual('my-http-service'); - - }); test('with circuit breaker', () => { @@ -2178,8 +2151,6 @@ describe('fargate service', () => { Type: ecs.DeploymentControllerType.ECS, }, }); - - }); test('throws an exception if both serviceArn and serviceName were provided for fromEc2ServiceAttributes', () => { @@ -2194,8 +2165,6 @@ describe('fargate service', () => { cluster, }); }).toThrow(/only specify either serviceArn or serviceName/); - - }); test('throws an exception if neither serviceArn nor serviceName were provided for fromEc2ServiceAttributes', () => { @@ -2208,8 +2177,6 @@ describe('fargate service', () => { cluster, }); }).toThrow(/only specify either serviceArn or serviceName/); - - }); test('allows setting enable execute command', () => { @@ -2304,8 +2271,6 @@ describe('fargate service', () => { }, ], }); - - }); test('no logging enabled when logging field is set to NONE', () => { @@ -2364,8 +2329,6 @@ describe('fargate service', () => { }, ], }); - - }); test('enables execute command logging with logging field set to OVERRIDE', () => { @@ -2489,8 +2452,6 @@ describe('fargate service', () => { }, ], }); - - }); test('enables only execute command session encryption', () => { @@ -2700,8 +2661,6 @@ describe('fargate service', () => { Version: '2012-10-17', }, }); - - }); test('enables encryption for execute command logging', () => { @@ -2986,8 +2945,6 @@ describe('fargate service', () => { Version: '2012-10-17', }, }); - - }); testDeprecated('with both propagateTags and propagateTaskTagsFrom defined', () => { @@ -3011,7 +2968,6 @@ describe('fargate service', () => { propagateTaskTagsFrom: PropagatedTagSource.SERVICE, }); }).toThrow(/You can only specify either propagateTags or propagateTaskTagsFrom. Alternatively, you can leave both blank/); - }); }); }); diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.exec-command.expected.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.exec-command.expected.json index 19e6073340ac7..c721e1a88a58f 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/integ.exec-command.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.exec-command.expected.json @@ -385,11 +385,11 @@ }, { "Action": [ - "kms:Encrypt*", "kms:Decrypt*", - "kms:ReEncrypt*", + "kms:Describe*", + "kms:Encrypt*", "kms:GenerateDataKey*", - "kms:Describe*" + "kms:ReEncrypt*" ], "Condition": { "ArnLike": { @@ -526,6 +526,8 @@ "Statement": [ { "Action": [ + "logs:DescribeLogGroups", + "s3:GetBucketLocation", "ssmmessages:CreateControlChannel", "ssmmessages:CreateDataChannel", "ssmmessages:OpenControlChannel", @@ -547,11 +549,6 @@ ] } }, - { - "Action": "logs:DescribeLogGroups", - "Effect": "Allow", - "Resource": "*" - }, { "Action": [ "logs:CreateLogStream", @@ -584,11 +581,6 @@ ] } }, - { - "Action": "s3:GetBucketLocation", - "Effect": "Allow", - "Resource": "*" - }, { "Action": "s3:PutObject", "Effect": "Allow", diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.firelens-cloudwatch.expected.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.firelens-cloudwatch.expected.json index a10c635e498d6..cb9c0a2de453d 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/integ.firelens-cloudwatch.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.firelens-cloudwatch.expected.json @@ -497,10 +497,10 @@ "Statement": [ { "Action": [ - "ecr:GetAuthorizationToken", "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetAuthorizationToken", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": "*" diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.secret.expected.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.secret.expected.json index f86ae24841bbf..b67b0d4c5df1d 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/integ.secret.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.secret.expected.json @@ -105,8 +105,8 @@ "Statement": [ { "Action": [ - "secretsmanager:GetSecretValue", - "secretsmanager:DescribeSecret" + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-efs/lib/access-point.ts b/packages/@aws-cdk/aws-efs/lib/access-point.ts index 07039df8d6a6e..055be8306e521 100644 --- a/packages/@aws-cdk/aws-efs/lib/access-point.ts +++ b/packages/@aws-cdk/aws-efs/lib/access-point.ts @@ -267,7 +267,7 @@ class ImportedAccessPoint extends AccessPointBase { public get fileSystem() { if (!this._fileSystem) { - throw new Error("fileSystem is not available when 'fromAccessPointId()' is used. Use 'fromAccessPointAttributes()' instead"); + throw new Error("fileSystem is only available if 'fromAccessPointAttributes()' is used and a fileSystem is passed in as an attribute."); } return this._fileSystem; diff --git a/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts b/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts index 9abe09c49e8a2..59344e3b81692 100644 --- a/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts +++ b/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts @@ -341,15 +341,21 @@ export class FileSystem extends FileSystemBase { const encrypted = props.encrypted ?? (FeatureFlags.of(this).isEnabled( cxapi.EFS_DEFAULT_ENCRYPTION_AT_REST) ? true : undefined); + // LifecyclePolicies is an array of lists containing a single policy + let lifecyclePolicies = []; + + if (props.lifecyclePolicy) { + lifecyclePolicies.push({ transitionToIa: props.lifecyclePolicy }); + } + + if (props.outOfInfrequentAccessPolicy) { + lifecyclePolicies.push({ transitionToPrimaryStorageClass: props.outOfInfrequentAccessPolicy }); + } + const filesystem = new CfnFileSystem(this, 'Resource', { encrypted: encrypted, kmsKeyId: props.kmsKey?.keyArn, - lifecyclePolicies: ( - (props.lifecyclePolicy || props.outOfInfrequentAccessPolicy) ? - [{ - transitionToIa: props.lifecyclePolicy, - transitionToPrimaryStorageClass: props.outOfInfrequentAccessPolicy, - }] : undefined), + lifecyclePolicies: lifecyclePolicies.length > 0 ? lifecyclePolicies : undefined, performanceMode: props.performanceMode, throughputMode: props.throughputMode, provisionedThroughputInMibps: props.provisionedThroughputPerSecond?.toMebibytes(), diff --git a/packages/@aws-cdk/aws-efs/package.json b/packages/@aws-cdk/aws-efs/package.json index 09d1c1f6f2ca6..73151d18d3aff 100644 --- a/packages/@aws-cdk/aws-efs/package.json +++ b/packages/@aws-cdk/aws-efs/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-efs/test/access-point.test.ts b/packages/@aws-cdk/aws-efs/test/access-point.test.ts index dd29d5aff5dc3..488dbb93dee4f 100644 --- a/packages/@aws-cdk/aws-efs/test/access-point.test.ts +++ b/packages/@aws-cdk/aws-efs/test/access-point.test.ts @@ -48,7 +48,7 @@ test('import an AccessPoint using fromAccessPointId throws when accessing fileSy }); const imported = AccessPoint.fromAccessPointId(stack, 'ImportedAccessPoint', ap.accessPointId); // THEN - expect(() => imported.fileSystem).toThrow(/fileSystem is not available when 'fromAccessPointId\(\)' is used. Use 'fromAccessPointAttributes\(\)' instead/); + expect(() => imported.fileSystem).toThrow(/fileSystem is only available if 'fromAccessPointAttributes\(\)' is used and a fileSystem is passed in as an attribute./); }); test('import an AccessPoint using fromAccessPointAttributes and the accessPointId', () => { diff --git a/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts b/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts index 7e22cd7602472..f6eb888575078 100644 --- a/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts +++ b/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts @@ -137,10 +137,14 @@ test('file system is created correctly with a life cycle property and out of inf }); // THEN Template.fromStack(stack).hasResourceProperties('AWS::EFS::FileSystem', { - LifecyclePolicies: [{ - TransitionToIA: 'AFTER_7_DAYS', - TransitionToPrimaryStorageClass: 'AFTER_1_ACCESS', - }], + LifecyclePolicies: [ + { + TransitionToIA: 'AFTER_7_DAYS', + }, + { + TransitionToPrimaryStorageClass: 'AFTER_1_ACCESS', + }, + ], }); }); diff --git a/packages/@aws-cdk/aws-eks-legacy/package.json b/packages/@aws-cdk/aws-eks-legacy/package.json index c05d56e6b3ddb..ede28f6869cdf 100644 --- a/packages/@aws-cdk/aws-eks-legacy/package.json +++ b/packages/@aws-cdk/aws-eks-legacy/package.json @@ -82,8 +82,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", diff --git a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.defaults.expected.json b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.defaults.expected.json index f98225e84b35e..5c74a6682063e 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.defaults.expected.json +++ b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.defaults.expected.json @@ -108,15 +108,15 @@ "ClusterDefaultVpcPublicSubnet1NATGateway6E21013E": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "ClusterDefaultVpcPublicSubnet1Subnet3BFE1BDA" + }, "AllocationId": { "Fn::GetAtt": [ "ClusterDefaultVpcPublicSubnet1EIP498E2BD2", "AllocationId" ] }, - "SubnetId": { - "Ref": "ClusterDefaultVpcPublicSubnet1Subnet3BFE1BDA" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -221,15 +221,15 @@ "ClusterDefaultVpcPublicSubnet2NATGateway4AF4B728": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "ClusterDefaultVpcPublicSubnet2SubnetC4E9A966" + }, "AllocationId": { "Fn::GetAtt": [ "ClusterDefaultVpcPublicSubnet2EIP265F4810", "AllocationId" ] }, - "SubnetId": { - "Ref": "ClusterDefaultVpcPublicSubnet2SubnetC4E9A966" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -334,15 +334,15 @@ "ClusterDefaultVpcPublicSubnet3NATGatewayEF4BA49A": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "ClusterDefaultVpcPublicSubnet3Subnet1A46184A" + }, "AllocationId": { "Fn::GetAtt": [ "ClusterDefaultVpcPublicSubnet3EIP0CBF6D05", "AllocationId" ] }, - "SubnetId": { - "Ref": "ClusterDefaultVpcPublicSubnet3Subnet1A46184A" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -706,8 +706,8 @@ { "Action": [ "eks:CreateCluster", - "eks:DescribeCluster", "eks:DeleteCluster", + "eks:DescribeCluster", "eks:UpdateClusterVersion" ], "Effect": "Allow", @@ -775,14 +775,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "ClusterResourceHandlerServiceRole7FB16465", "Arn" ] }, - "Runtime": "python3.7", + "Handler": "index.handler", "Layers": [ { "Fn::GetAtt": [ @@ -792,6 +791,7 @@ } ], "MemorySize": 512, + "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -891,14 +891,12 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "ClusterResourceHandlerServiceRole7FB16465", "Arn" ] }, - "Runtime": "python3.7", "Environment": { "Variables": { "CLUSTER_NAME": { @@ -906,6 +904,7 @@ } } }, + "Handler": "index.handler", "Layers": [ { "Fn::GetAtt": [ @@ -915,6 +914,7 @@ } ], "MemorySize": 256, + "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.lit.expected.json b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.lit.expected.json index 254e46a33dfd5..d393b5ea37f10 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.lit.expected.json +++ b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.lit.expected.json @@ -108,15 +108,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -221,15 +221,15 @@ "VPCPublicSubnet2NATGateway3C070193": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -334,15 +334,15 @@ "VPCPublicSubnet3NATGatewayD3048F5C": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet3EIPAD4BC883", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -706,8 +706,8 @@ { "Action": [ "eks:CreateCluster", - "eks:DescribeCluster", "eks:DeleteCluster", + "eks:DescribeCluster", "eks:UpdateClusterVersion" ], "Effect": "Allow", @@ -775,14 +775,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "EKSClusterResourceHandlerServiceRoleFD631254", "Arn" ] }, - "Runtime": "python3.7", + "Handler": "index.handler", "Layers": [ { "Fn::GetAtt": [ @@ -792,6 +791,7 @@ } ], "MemorySize": 512, + "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -891,14 +891,12 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "EKSClusterResourceHandlerServiceRoleFD631254", "Arn" ] }, - "Runtime": "python3.7", "Environment": { "Variables": { "CLUSTER_NAME": { @@ -906,6 +904,7 @@ } } }, + "Handler": "index.handler", "Layers": [ { "Fn::GetAtt": [ @@ -915,6 +914,7 @@ } ], "MemorySize": 256, + "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-helm.lit.expected.json b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-helm.lit.expected.json index ba37ddbe77d70..114dd6f18a77c 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-helm.lit.expected.json +++ b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-helm.lit.expected.json @@ -108,15 +108,15 @@ "vpcPublicSubnet1NATGateway9C16659E": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "vpcPublicSubnet1Subnet2E65531E" + }, "AllocationId": { "Fn::GetAtt": [ "vpcPublicSubnet1EIPDA49DCBE", "AllocationId" ] }, - "SubnetId": { - "Ref": "vpcPublicSubnet1Subnet2E65531E" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -221,15 +221,15 @@ "vpcPublicSubnet2NATGateway9B8AE11A": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "vpcPublicSubnet2Subnet009B674F" + }, "AllocationId": { "Fn::GetAtt": [ "vpcPublicSubnet2EIP9B3743B1", "AllocationId" ] }, - "SubnetId": { - "Ref": "vpcPublicSubnet2Subnet009B674F" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -570,8 +570,8 @@ { "Action": [ "eks:CreateCluster", - "eks:DescribeCluster", "eks:DeleteCluster", + "eks:DescribeCluster", "eks:UpdateClusterVersion" ], "Effect": "Allow", @@ -639,14 +639,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "cluster22ResourceHandlerServiceRoleC2E4F327", "Arn" ] }, - "Runtime": "python3.7", + "Handler": "index.handler", "Layers": [ { "Fn::GetAtt": [ @@ -656,6 +655,7 @@ } ], "MemorySize": 512, + "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -749,14 +749,12 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "cluster22ResourceHandlerServiceRoleC2E4F327", "Arn" ] }, - "Runtime": "python3.7", "Environment": { "Variables": { "CLUSTER_NAME": { @@ -764,6 +762,7 @@ } } }, + "Handler": "index.handler", "Layers": [ { "Fn::GetAtt": [ @@ -773,6 +772,7 @@ } ], "MemorySize": 256, + "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -1159,14 +1159,12 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "cluster22ResourceHandlerServiceRoleC2E4F327", "Arn" ] }, - "Runtime": "python3.7", "Environment": { "Variables": { "CLUSTER_NAME": { @@ -1174,6 +1172,7 @@ } } }, + "Handler": "index.handler", "Layers": [ { "Fn::GetAtt": [ @@ -1183,6 +1182,7 @@ } ], "MemorySize": 256, + "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-kubectl.lit.expected.json b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-kubectl.lit.expected.json index fd726b6e62f29..a940f5d6d2f91 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-kubectl.lit.expected.json +++ b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-kubectl.lit.expected.json @@ -108,15 +108,15 @@ "vpcPublicSubnet1NATGateway9C16659E": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "vpcPublicSubnet1Subnet2E65531E" + }, "AllocationId": { "Fn::GetAtt": [ "vpcPublicSubnet1EIPDA49DCBE", "AllocationId" ] }, - "SubnetId": { - "Ref": "vpcPublicSubnet1Subnet2E65531E" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -221,15 +221,15 @@ "vpcPublicSubnet2NATGateway9B8AE11A": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "vpcPublicSubnet2Subnet009B674F" + }, "AllocationId": { "Fn::GetAtt": [ "vpcPublicSubnet2EIP9B3743B1", "AllocationId" ] }, - "SubnetId": { - "Ref": "vpcPublicSubnet2Subnet009B674F" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -570,8 +570,8 @@ { "Action": [ "eks:CreateCluster", - "eks:DescribeCluster", "eks:DeleteCluster", + "eks:DescribeCluster", "eks:UpdateClusterVersion" ], "Effect": "Allow", @@ -639,14 +639,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "cluster22ResourceHandlerServiceRoleC2E4F327", "Arn" ] }, - "Runtime": "python3.7", + "Handler": "index.handler", "Layers": [ { "Fn::GetAtt": [ @@ -656,6 +655,7 @@ } ], "MemorySize": 512, + "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -749,14 +749,12 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "cluster22ResourceHandlerServiceRoleC2E4F327", "Arn" ] }, - "Runtime": "python3.7", "Environment": { "Variables": { "CLUSTER_NAME": { @@ -764,6 +762,7 @@ } } }, + "Handler": "index.handler", "Layers": [ { "Fn::GetAtt": [ @@ -773,6 +772,7 @@ } ], "MemorySize": 256, + "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-spot.expected.json b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-spot.expected.json index 56f7f71864838..86083856ff4db 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-spot.expected.json +++ b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-spot.expected.json @@ -108,15 +108,15 @@ "vpcPublicSubnet1NATGateway9C16659E": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "vpcPublicSubnet1Subnet2E65531E" + }, "AllocationId": { "Fn::GetAtt": [ "vpcPublicSubnet1EIPDA49DCBE", "AllocationId" ] }, - "SubnetId": { - "Ref": "vpcPublicSubnet1Subnet2E65531E" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -221,15 +221,15 @@ "vpcPublicSubnet2NATGateway9B8AE11A": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "vpcPublicSubnet2Subnet009B674F" + }, "AllocationId": { "Fn::GetAtt": [ "vpcPublicSubnet2EIP9B3743B1", "AllocationId" ] }, - "SubnetId": { - "Ref": "vpcPublicSubnet2Subnet009B674F" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -544,8 +544,8 @@ { "Action": [ "eks:CreateCluster", - "eks:DescribeCluster", "eks:DeleteCluster", + "eks:DescribeCluster", "eks:UpdateClusterVersion" ], "Effect": "Allow", @@ -613,14 +613,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "myClusterResourceHandlerServiceRole95F554E2", "Arn" ] }, - "Runtime": "python3.7", + "Handler": "index.handler", "Layers": [ { "Fn::GetAtt": [ @@ -630,6 +629,7 @@ } ], "MemorySize": 512, + "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -723,14 +723,12 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "myClusterResourceHandlerServiceRole95F554E2", "Arn" ] }, - "Runtime": "python3.7", "Environment": { "Variables": { "CLUSTER_NAME": { @@ -738,6 +736,7 @@ } } }, + "Handler": "index.handler", "Layers": [ { "Fn::GetAtt": [ @@ -747,6 +746,7 @@ } ], "MemorySize": 256, + "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-eks/README.md b/packages/@aws-cdk/aws-eks/README.md index 668c70fd96d98..001a2cbb3022a 100644 --- a/packages/@aws-cdk/aws-eks/README.md +++ b/packages/@aws-cdk/aws-eks/README.md @@ -1144,6 +1144,24 @@ cluster.addHelmChart('test-chart', { }); ``` +### OCI Charts + +OCI charts are also supported. +Also replace the `${VARS}` with appropriate values. + +```ts +declare const cluster: eks.Cluster; +// option 1: use a construct +new eks.HelmChart(this, 'MyOCIChart', { + cluster, + chart: 'some-chart', + repository: 'oci://${ACCOUNT_ID}.dkr.ecr.${ACCOUNT_REGION}.amazonaws.com/${REPO_NAME}', + namespace: 'oci', + version: '0.0.1' +}); + +``` + Helm charts are implemented as CloudFormation resources in CDK. This means that if the chart is deleted from your code (or the stack is deleted), the next `cdk deploy` will issue a `helm uninstall` command and the diff --git a/packages/@aws-cdk/aws-eks/lib/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster.ts index f4449ff30e9a8..66821aed579e9 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster.ts @@ -946,7 +946,7 @@ abstract class ClusterBase extends Resource implements ICluster { if (!this._spotInterruptHandler) { this._spotInterruptHandler = this.addHelmChart('spot-interrupt-handler', { chart: 'aws-node-termination-handler', - version: '0.13.2', + version: '1.14.1', repository: 'https://aws.github.io/eks-charts', namespace: 'kube-system', values: { diff --git a/packages/@aws-cdk/aws-eks/lib/kubectl-handler/helm/__init__.py b/packages/@aws-cdk/aws-eks/lib/kubectl-handler/helm/__init__.py index f83fc204b73e3..8ede6a23a07e8 100644 --- a/packages/@aws-cdk/aws-eks/lib/kubectl-handler/helm/__init__.py +++ b/packages/@aws-cdk/aws-eks/lib/kubectl-handler/helm/__init__.py @@ -1,8 +1,10 @@ import json import logging import os +import re import subprocess import shutil +import tempfile import zipfile from urllib.parse import urlparse, unquote @@ -78,6 +80,11 @@ def helm_handler(event, context): # future work: support versions from s3 assets chart = get_chart_asset_from_url(chart_asset_url) + if repository is not None and repository.startswith('oci://'): + tmpdir = tempfile.TemporaryDirectory() + chart_dir = get_chart_from_oci(tmpdir.name, release, repository, version) + chart = chart_dir + helm('upgrade', release, chart, repository, values_file, namespace, version, wait, timeout, create_namespace) elif request_type == "Delete": try: @@ -85,6 +92,58 @@ def helm_handler(event, context): except Exception as e: logger.info("delete error: %s" % e) + +def get_oci_cmd(repository, version): + + cmnd = [] + pattern = '\d+.dkr.ecr.[a-z]+-[a-z]+-\d.amazonaws.com' + + registry = repository.rsplit('/', 1)[0].replace('oci://', '') + + if re.fullmatch(pattern, registry) is not None: + region = registry.replace('.amazonaws.com', '').split('.')[-1] + cmnd = [ + f"aws ecr get-login-password --region {region} | " \ + f"helm registry login --username AWS --password-stdin {registry}; helm pull {repository} --version {version} --untar" + ] + else: + logger.info("Non AWS OCI repository found") + cmnd = ['HELM_EXPERIMENTAL_OCI=1', 'helm', 'pull', repository, '--version', version, '--untar'] + + return cmnd + + +def get_chart_from_oci(tmpdir, release, repository = None, version = None): + + cmnd = get_oci_cmd(repository, version) + + maxAttempts = 3 + retry = maxAttempts + while retry > 0: + try: + logger.info(cmnd) + env = get_env_with_oci_flag() + output = subprocess.check_output(cmnd, stderr=subprocess.STDOUT, cwd=tmpdir, env=env, shell=True) + logger.info(output) + + return os.path.join(tmpdir, release) + except subprocess.CalledProcessError as exc: + output = exc.output + if b'Broken pipe' in output: + retry = retry - 1 + logger.info("Broken pipe, retries left: %s" % retry) + else: + raise Exception(output) + raise Exception(f'Operation failed after {maxAttempts} attempts: {output}') + + +def get_env_with_oci_flag(): + env = os.environ.copy() + env['HELM_EXPERIMENTAL_OCI'] = '1' + + return env + + def helm(verb, release, chart = None, repo = None, file = None, namespace = None, version = None, wait = False, timeout = None, create_namespace = None): import subprocess @@ -113,7 +172,8 @@ def helm(verb, release, chart = None, repo = None, file = None, namespace = None retry = maxAttempts while retry > 0: try: - output = subprocess.check_output(cmnd, stderr=subprocess.STDOUT, cwd=outdir) + env = get_env_with_oci_flag() + output = subprocess.check_output(cmnd, stderr=subprocess.STDOUT, cwd=outdir, env=env) logger.info(output) return except subprocess.CalledProcessError as exc: diff --git a/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts b/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts index 161ef77cfe3f3..eef07598abf27 100644 --- a/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts +++ b/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts @@ -168,6 +168,11 @@ export class KubectlProvider extends NestedStack implements IKubectlProvider { resources: [cluster.clusterArn], })); + // For OCI helm chart authorization. + this.handlerRole.addManagedPolicy( + iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEC2ContainerRegistryReadOnly'), + ); + // allow this handler to assume the kubectl role cluster.kubectlRole.grant(this.handlerRole, 'sts:AssumeRole'); diff --git a/packages/@aws-cdk/aws-eks/lib/service-account.ts b/packages/@aws-cdk/aws-eks/lib/service-account.ts index c49e2a944a765..a330aa41e0df5 100644 --- a/packages/@aws-cdk/aws-eks/lib/service-account.ts +++ b/packages/@aws-cdk/aws-eks/lib/service-account.ts @@ -14,12 +14,18 @@ import { Construct as CoreConstruct } from '@aws-cdk/core'; export interface ServiceAccountOptions { /** * The name of the service account. + * + * The name of a ServiceAccount object must be a valid DNS subdomain name. + * https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ * @default - If no name is given, it will use the id of the resource. */ readonly name?: string; /** * The namespace of the service account. + * + * All namespace names must be valid RFC 1123 DNS labels. + * https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/#namespaces-and-dns * @default "default" */ readonly namespace?: string; @@ -65,6 +71,16 @@ export class ServiceAccount extends CoreConstruct implements IPrincipal { this.serviceAccountName = props.name ?? Names.uniqueId(this).toLowerCase(); this.serviceAccountNamespace = props.namespace ?? 'default'; + // From K8s docs: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ + if (!this.isValidDnsSubdomainName(this.serviceAccountName)) { + throw RangeError('The name of a ServiceAccount object must be a valid DNS subdomain name.'); + } + + // From K8s docs: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/#namespaces-and-dns + if (!this.isValidDnsLabelName(this.serviceAccountNamespace)) { + throw RangeError('All namespace names must be valid RFC 1123 DNS labels.'); + } + /* Add conditions to the role to improve security. This prevents other pods in the same namespace to assume the role. * See documentation: https://docs.aws.amazon.com/eks/latest/userguide/create-service-account-iam-policy-and-role.html */ @@ -117,4 +133,22 @@ export class ServiceAccount extends CoreConstruct implements IPrincipal { public addToPrincipalPolicy(statement: PolicyStatement): AddToPrincipalPolicyResult { return this.role.addToPrincipalPolicy(statement); } + + /** + * If the value is a DNS subdomain name as defined in RFC 1123, from K8s docs. + * + * https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names + */ + private isValidDnsSubdomainName(value: string): boolean { + return value.length <= 253 && /^[a-z0-9]+[a-z0-9-.]*[a-z0-9]+$/.test(value); + } + + /** + * If the value follows DNS label standard as defined in RFC 1123, from K8s docs. + * + * https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names + */ + private isValidDnsLabelName(value: string): boolean { + return value.length <= 63 && /^[a-z0-9]+[a-z0-9-]*[a-z0-9]+$/.test(value); + } } diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index bc96952be1a43..6585171d0ea0c 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -84,14 +84,14 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.92", - "@types/jest": "^27.4.0", + "@types/aws-lambda": "^8.10.93", + "@types/jest": "^27.4.1", "@types/sinon": "^9.0.11", "@types/yaml": "1.9.6", "aws-sdk": "^2.848.0", - "cdk8s": "^1.5.7", - "cdk8s-plus-21": "^1.0.0-beta.81", - "jest": "^27.4.7", + "cdk8s": "^1.5.56", + "cdk8s-plus-21": "^1.0.0-beta.124", + "jest": "^27.5.1", "sinon": "^9.2.4" }, "dependencies": { @@ -137,7 +137,8 @@ "props-no-arn-refs:@aws-cdk/aws-eks.ClusterProps.outputMastersRoleArn", "props-physical-name:@aws-cdk/aws-eks.OpenIdConnectProviderProps", "resource-attribute:@aws-cdk/aws-eks.Cluster.clusterKubernetesNetworkConfigServiceIpv6Cidr", - "resource-attribute:@aws-cdk/aws-eks.FargateCluster.clusterKubernetesNetworkConfigServiceIpv6Cidr" + "resource-attribute:@aws-cdk/aws-eks.FargateCluster.clusterKubernetesNetworkConfigServiceIpv6Cidr", + "resource-attribute:@aws-cdk/aws-eks.Nodegroup.nodegroupId" ] }, "stability": "stable", diff --git a/packages/@aws-cdk/aws-eks/test/cluster.test.ts b/packages/@aws-cdk/aws-eks/test/cluster.test.ts index 77556af1a0da4..5e579c4f2a247 100644 --- a/packages/@aws-cdk/aws-eks/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-eks/test/cluster.test.ts @@ -2107,7 +2107,41 @@ describe('cluster', () => { ], }); - + Template.fromStack(providerStack).hasResourceProperties('AWS::IAM::Role', { + 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', + ]], + }, + { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole', + ]], + }, + { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':iam::aws:policy/AmazonEC2ContainerRegistryReadOnly', + ]], + }, + ], + }); }); test('coreDnsComputeType will patch the coreDNS configuration to use a "fargate" compute type and restore to "ec2" upon removal', () => { @@ -2274,8 +2308,42 @@ describe('cluster', () => { }, }); + Template.fromStack(providerStack).hasResourceProperties('AWS::IAM::Role', { + 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', + ]], + }, + { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole', + ]], + }, + { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':iam::aws:policy/AmazonEC2ContainerRegistryReadOnly', + ]], + }, + ], + }); }); - }); test('kubectl provider passes security group to provider', () => { diff --git a/packages/@aws-cdk/aws-eks/test/integ.alb-controller.expected.json b/packages/@aws-cdk/aws-eks/test/integ.alb-controller.expected.json index 9d6734c074f69..b8bc3541bb0cd 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.alb-controller.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.alb-controller.expected.json @@ -629,54 +629,30 @@ }, { "Action": [ + "ec2:DescribeDhcpOptions", + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeRouteTables", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeVpcs", "eks:CreateCluster", + "eks:CreateFargateProfile", + "eks:DeleteCluster", + "eks:DeleteFargateProfile", "eks:DescribeCluster", + "eks:DescribeFargateProfile", "eks:DescribeUpdate", - "eks:DeleteCluster", - "eks:UpdateClusterVersion", - "eks:UpdateClusterConfig", - "eks:CreateFargateProfile", "eks:TagResource", - "eks:UntagResource" - ], - "Effect": "Allow", - "Resource": [ - "*" - ] - }, - { - "Action": [ - "eks:DescribeFargateProfile", - "eks:DeleteFargateProfile" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ + "eks:UntagResource", + "eks:UpdateClusterConfig", + "eks:UpdateClusterVersion", + "iam:CreateServiceLinkedRole", "iam:GetRole", "iam:listAttachedRolePolicies" ], "Effect": "Allow", "Resource": "*" - }, - { - "Action": "iam:CreateServiceLinkedRole", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ec2:DescribeInstances", - "ec2:DescribeNetworkInterfaces", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSubnets", - "ec2:DescribeRouteTables", - "ec2:DescribeDhcpOptions", - "ec2:DescribeVpcs" - ], - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -1124,7 +1100,7 @@ }, "/", { - "Ref": "AssetParameters37fb4b0217f335596d51df351c0bf073aeaaa768b390fe4945560700f60ecd31S3BucketBEA8E31E" + "Ref": "AssetParameters712e670f4e8905b5bf48e7a7fc59cce8d2d81e350618d910eaae52d3e93579b9S3Bucket1FB496C9" }, "/", { @@ -1134,7 +1110,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters37fb4b0217f335596d51df351c0bf073aeaaa768b390fe4945560700f60ecd31S3VersionKey86EE1B0C" + "Ref": "AssetParameters712e670f4e8905b5bf48e7a7fc59cce8d2d81e350618d910eaae52d3e93579b9S3VersionKey412AA341" } ] } @@ -1147,7 +1123,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters37fb4b0217f335596d51df351c0bf073aeaaa768b390fe4945560700f60ecd31S3VersionKey86EE1B0C" + "Ref": "AssetParameters712e670f4e8905b5bf48e7a7fc59cce8d2d81e350618d910eaae52d3e93579b9S3VersionKey412AA341" } ] } @@ -1157,11 +1133,11 @@ ] }, "Parameters": { - "referencetoawscdkeksclusteralbcontrollertestAssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket4FD6630ARef": { - "Ref": "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1B280681" + "referencetoawscdkeksclusteralbcontrollertestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket11BD506ARef": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097" }, - "referencetoawscdkeksclusteralbcontrollertestAssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKey991D5128Ref": { - "Ref": "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB1E02791" + "referencetoawscdkeksclusteralbcontrollertestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKeyCDACFD96Ref": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224" }, "referencetoawscdkeksclusteralbcontrollertestClusterCreationRoleA16C24E9Arn": { "Fn::GetAtt": [ @@ -1169,17 +1145,17 @@ "Arn" ] }, - "referencetoawscdkeksclusteralbcontrollertestAssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3BucketE25795A8Ref": { - "Ref": "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3Bucket9AE1EC0F" + "referencetoawscdkeksclusteralbcontrollertestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket09170EE6Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E" }, - "referencetoawscdkeksclusteralbcontrollertestAssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3VersionKeyE4320F93Ref": { - "Ref": "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3VersionKey451EAA56" + "referencetoawscdkeksclusteralbcontrollertestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey1E6A5085Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF" }, - "referencetoawscdkeksclusteralbcontrollertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketED32B211Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawscdkeksclusteralbcontrollertestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketC19FFBF9Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawscdkeksclusteralbcontrollertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey6FD8F5E5Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawscdkeksclusteralbcontrollertestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKey33198584Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1199,7 +1175,7 @@ }, "/", { - "Ref": "AssetParameters06035c90bda92ff37322a329e214af5f2a1e591c6920e0cea4c6816e0f38ac4bS3BucketFAB8EA28" + "Ref": "AssetParametersb02782818b74bd22aefbc8f68291d7c3c5f66f69b40cb21db82e38b460678ba2S3Bucket30803CC9" }, "/", { @@ -1209,7 +1185,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters06035c90bda92ff37322a329e214af5f2a1e591c6920e0cea4c6816e0f38ac4bS3VersionKey33497690" + "Ref": "AssetParametersb02782818b74bd22aefbc8f68291d7c3c5f66f69b40cb21db82e38b460678ba2S3VersionKeyCAAA61AB" } ] } @@ -1222,7 +1198,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters06035c90bda92ff37322a329e214af5f2a1e591c6920e0cea4c6816e0f38ac4bS3VersionKey33497690" + "Ref": "AssetParametersb02782818b74bd22aefbc8f68291d7c3c5f66f69b40cb21db82e38b460678ba2S3VersionKeyCAAA61AB" } ] } @@ -1244,11 +1220,11 @@ "Arn" ] }, - "referencetoawscdkeksclusteralbcontrollertestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3Bucket71A947E9Ref": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" + "referencetoawscdkeksclusteralbcontrollertestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3BucketA8BA1BB9Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3" }, - "referencetoawscdkeksclusteralbcontrollertestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey515289E4Ref": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" + "referencetoawscdkeksclusteralbcontrollertestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKey9A9C820BRef": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291" }, "referencetoawscdkeksclusteralbcontrollertestVpcPrivateSubnet1Subnet7C7DBEE5Ref": { "Ref": "VpcPrivateSubnet1Subnet536B997A" @@ -1265,11 +1241,11 @@ "ClusterSecurityGroupId" ] }, - "referencetoawscdkeksclusteralbcontrollertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3Bucket6CB090A8Ref": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" + "referencetoawscdkeksclusteralbcontrollertestAssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3Bucket916394C8Ref": { + "Ref": "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3Bucket940CB35D" }, - "referencetoawscdkeksclusteralbcontrollertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKey980A7F7CRef": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + "referencetoawscdkeksclusteralbcontrollertestAssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3VersionKey639D7E45Ref": { + "Ref": "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3VersionKey248C9936" }, "referencetoawscdkeksclusteralbcontrollertestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket65F5BE5ARef": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" @@ -1277,11 +1253,11 @@ "referencetoawscdkeksclusteralbcontrollertestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKey036DDFD3Ref": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, - "referencetoawscdkeksclusteralbcontrollertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketED32B211Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawscdkeksclusteralbcontrollertestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketC19FFBF9Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawscdkeksclusteralbcontrollertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey6FD8F5E5Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawscdkeksclusteralbcontrollertestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKey33198584Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1389,69 +1365,62 @@ }, { "Action": [ + "acm:DescribeCertificate", + "acm:ListCertificates", + "cognito-idp:DescribeUserPoolClient", + "ec2:AuthorizeSecurityGroupIngress", + "ec2:CreateSecurityGroup", "ec2:DescribeAccountAttributes", "ec2:DescribeAddresses", "ec2:DescribeAvailabilityZones", - "ec2:DescribeInternetGateways", - "ec2:DescribeVpcs", - "ec2:DescribeVpcPeeringConnections", - "ec2:DescribeSubnets", - "ec2:DescribeSecurityGroups", + "ec2:DescribeCoipPools", "ec2:DescribeInstances", + "ec2:DescribeInternetGateways", "ec2:DescribeNetworkInterfaces", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", "ec2:DescribeTags", + "ec2:DescribeVpcPeeringConnections", + "ec2:DescribeVpcs", "ec2:GetCoipPoolUsage", - "ec2:DescribeCoipPools", - "elasticloadbalancing:DescribeLoadBalancers", - "elasticloadbalancing:DescribeLoadBalancerAttributes", - "elasticloadbalancing:DescribeListeners", + "ec2:RevokeSecurityGroupIngress", + "elasticloadbalancing:AddListenerCertificates", + "elasticloadbalancing:CreateListener", + "elasticloadbalancing:CreateRule", + "elasticloadbalancing:DeleteListener", + "elasticloadbalancing:DeleteRule", "elasticloadbalancing:DescribeListenerCertificates", - "elasticloadbalancing:DescribeSSLPolicies", + "elasticloadbalancing:DescribeListeners", + "elasticloadbalancing:DescribeLoadBalancerAttributes", + "elasticloadbalancing:DescribeLoadBalancers", "elasticloadbalancing:DescribeRules", - "elasticloadbalancing:DescribeTargetGroups", + "elasticloadbalancing:DescribeSSLPolicies", + "elasticloadbalancing:DescribeTags", "elasticloadbalancing:DescribeTargetGroupAttributes", + "elasticloadbalancing:DescribeTargetGroups", "elasticloadbalancing:DescribeTargetHealth", - "elasticloadbalancing:DescribeTags" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "cognito-idp:DescribeUserPoolClient", - "acm:ListCertificates", - "acm:DescribeCertificate", - "iam:ListServerCertificates", + "elasticloadbalancing:ModifyListener", + "elasticloadbalancing:ModifyRule", + "elasticloadbalancing:RemoveListenerCertificates", + "elasticloadbalancing:SetWebAcl", "iam:GetServerCertificate", - "waf-regional:GetWebACL", - "waf-regional:GetWebACLForResource", + "iam:ListServerCertificates", + "shield:CreateProtection", + "shield:DeleteProtection", + "shield:DescribeProtection", + "shield:GetSubscriptionState", "waf-regional:AssociateWebACL", "waf-regional:DisassociateWebACL", - "wafv2:GetWebACL", - "wafv2:GetWebACLForResource", + "waf-regional:GetWebACL", + "waf-regional:GetWebACLForResource", "wafv2:AssociateWebACL", "wafv2:DisassociateWebACL", - "shield:GetSubscriptionState", - "shield:DescribeProtection", - "shield:CreateProtection", - "shield:DeleteProtection" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ec2:AuthorizeSecurityGroupIngress", - "ec2:RevokeSecurityGroupIngress" + "wafv2:GetWebACL", + "wafv2:GetWebACLForResource" ], "Effect": "Allow", "Resource": "*" }, - { - "Action": "ec2:CreateSecurityGroup", - "Effect": "Allow", - "Resource": "*" - }, { "Action": "ec2:CreateTags", "Condition": { @@ -1482,8 +1451,16 @@ { "Action": [ "ec2:AuthorizeSecurityGroupIngress", + "ec2:DeleteSecurityGroup", "ec2:RevokeSecurityGroupIngress", - "ec2:DeleteSecurityGroup" + "elasticloadbalancing:DeleteLoadBalancer", + "elasticloadbalancing:DeleteTargetGroup", + "elasticloadbalancing:ModifyLoadBalancerAttributes", + "elasticloadbalancing:ModifyTargetGroup", + "elasticloadbalancing:ModifyTargetGroupAttributes", + "elasticloadbalancing:SetIpAddressType", + "elasticloadbalancing:SetSecurityGroups", + "elasticloadbalancing:SetSubnets" ], "Condition": { "Null": { @@ -1506,16 +1483,6 @@ "Effect": "Allow", "Resource": "*" }, - { - "Action": [ - "elasticloadbalancing:CreateListener", - "elasticloadbalancing:DeleteListener", - "elasticloadbalancing:CreateRule", - "elasticloadbalancing:DeleteRule" - ], - "Effect": "Allow", - "Resource": "*" - }, { "Action": [ "elasticloadbalancing:AddTags", @@ -1529,9 +1496,9 @@ }, "Effect": "Allow", "Resource": [ - "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*", + "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*", "arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*", - "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*" + "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*" ] }, { @@ -1541,49 +1508,19 @@ ], "Effect": "Allow", "Resource": [ - "arn:aws:elasticloadbalancing:*:*:listener/net/*/*/*", - "arn:aws:elasticloadbalancing:*:*:listener/app/*/*/*", + "arn:aws:elasticloadbalancing:*:*:listener-rule/app/*/*/*", "arn:aws:elasticloadbalancing:*:*:listener-rule/net/*/*/*", - "arn:aws:elasticloadbalancing:*:*:listener-rule/app/*/*/*" + "arn:aws:elasticloadbalancing:*:*:listener/app/*/*/*", + "arn:aws:elasticloadbalancing:*:*:listener/net/*/*/*" ] }, { "Action": [ - "elasticloadbalancing:ModifyLoadBalancerAttributes", - "elasticloadbalancing:SetIpAddressType", - "elasticloadbalancing:SetSecurityGroups", - "elasticloadbalancing:SetSubnets", - "elasticloadbalancing:DeleteLoadBalancer", - "elasticloadbalancing:ModifyTargetGroup", - "elasticloadbalancing:ModifyTargetGroupAttributes", - "elasticloadbalancing:DeleteTargetGroup" - ], - "Condition": { - "Null": { - "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" - } - }, - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "elasticloadbalancing:RegisterTargets", - "elasticloadbalancing:DeregisterTargets" + "elasticloadbalancing:DeregisterTargets", + "elasticloadbalancing:RegisterTargets" ], "Effect": "Allow", "Resource": "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*" - }, - { - "Action": [ - "elasticloadbalancing:SetWebAcl", - "elasticloadbalancing:ModifyListener", - "elasticloadbalancing:AddListenerCertificates", - "elasticloadbalancing:RemoveListenerCertificates", - "elasticloadbalancing:ModifyRule" - ], - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -1748,7 +1685,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3BucketF7BC1777" + "Ref": "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3Bucket211A9156" }, "S3Key": { "Fn::Join": [ @@ -1761,7 +1698,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3VersionKey1C340B30" + "Ref": "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3VersionKey822D04EC" } ] } @@ -1774,7 +1711,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3VersionKey1C340B30" + "Ref": "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3VersionKey822D04EC" } ] } @@ -1826,7 +1763,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3BucketB7E1A9C0" + "Ref": "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3Bucket6F458959" }, "S3Key": { "Fn::Join": [ @@ -1839,7 +1776,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3VersionKey542FDEBD" + "Ref": "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3VersionKeyBDD0572E" } ] } @@ -1852,7 +1789,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3VersionKey542FDEBD" + "Ref": "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3VersionKeyBDD0572E" } ] } @@ -2051,12 +1988,28 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "IngressPingerFunction54746D9B", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "IngressPingerFunction54746D9B", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "IngressPingerFunction54746D9B", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -2074,7 +2027,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, "S3Key": { "Fn::Join": [ @@ -2087,7 +2040,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -2100,7 +2053,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -2215,65 +2168,65 @@ } }, "Parameters": { - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1B280681": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097": { "Type": "String", - "Description": "S3 bucket for asset \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "S3 bucket for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB1E02791": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224": { "Type": "String", - "Description": "S3 key for asset version \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "S3 key for asset version \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665ArtifactHash9EA5AC29": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeArtifactHash515E16AE": { "Type": "String", - "Description": "Artifact hash for asset \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "Artifact hash for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3Bucket9AE1EC0F": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E": { "Type": "String", - "Description": "S3 bucket for asset \"00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5af\"" + "Description": "S3 bucket for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3VersionKey451EAA56": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF": { "Type": "String", - "Description": "S3 key for asset version \"00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5af\"" + "Description": "S3 key for asset version \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afArtifactHash761F4689": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647ArtifactHashE94F67E3": { "Type": "String", - "Description": "Artifact hash for asset \"00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5af\"" + "Description": "Artifact hash for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { "Type": "String", - "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { "Type": "String", - "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { "Type": "String", - "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3": { "Type": "String", - "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 bucket for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291": { "Type": "String", - "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 key for asset version \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8ArtifactHashA4AB6609": { "Type": "String", - "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "Artifact hash for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { + "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3Bucket940CB35D": { "Type": "String", - "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 bucket for asset \"d78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { + "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3VersionKey248C9936": { "Type": "String", - "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 key for asset version \"d78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { + "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27ArtifactHash934284DB": { "Type": "String", - "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "Artifact hash for asset \"d78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27\"" }, "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", @@ -2287,29 +2240,29 @@ "Type": "String", "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3BucketF7BC1777": { + "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3Bucket211A9156": { "Type": "String", - "Description": "S3 bucket for asset \"b7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4\"" + "Description": "S3 bucket for asset \"5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2\"" }, - "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3VersionKey1C340B30": { + "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3VersionKey822D04EC": { "Type": "String", - "Description": "S3 key for asset version \"b7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4\"" + "Description": "S3 key for asset version \"5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2\"" }, - "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4ArtifactHashD6EA1BC7": { + "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2ArtifactHashCA4A1831": { "Type": "String", - "Description": "Artifact hash for asset \"b7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4\"" + "Description": "Artifact hash for asset \"5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2\"" }, - "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3BucketB7E1A9C0": { + "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3Bucket6F458959": { "Type": "String", - "Description": "S3 bucket for asset \"6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3\"" + "Description": "S3 bucket for asset \"f850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4\"" }, - "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3VersionKey542FDEBD": { + "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3VersionKeyBDD0572E": { "Type": "String", - "Description": "S3 key for asset version \"6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3\"" + "Description": "S3 key for asset version \"f850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4\"" }, - "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3ArtifactHash5E61FCA5": { + "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4ArtifactHash4D5DD9E9": { "Type": "String", - "Description": "Artifact hash for asset \"6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3\"" + "Description": "Artifact hash for asset \"f850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4\"" }, "AssetParameters5f49893093e1ad14831626016699156d48da5f0890f19eb930bc3c46cf5f636dS3BucketA6642550": { "Type": "String", @@ -2323,29 +2276,29 @@ "Type": "String", "Description": "Artifact hash for asset \"5f49893093e1ad14831626016699156d48da5f0890f19eb930bc3c46cf5f636d\"" }, - "AssetParameters37fb4b0217f335596d51df351c0bf073aeaaa768b390fe4945560700f60ecd31S3BucketBEA8E31E": { + "AssetParameters712e670f4e8905b5bf48e7a7fc59cce8d2d81e350618d910eaae52d3e93579b9S3Bucket1FB496C9": { "Type": "String", - "Description": "S3 bucket for asset \"37fb4b0217f335596d51df351c0bf073aeaaa768b390fe4945560700f60ecd31\"" + "Description": "S3 bucket for asset \"712e670f4e8905b5bf48e7a7fc59cce8d2d81e350618d910eaae52d3e93579b9\"" }, - "AssetParameters37fb4b0217f335596d51df351c0bf073aeaaa768b390fe4945560700f60ecd31S3VersionKey86EE1B0C": { + "AssetParameters712e670f4e8905b5bf48e7a7fc59cce8d2d81e350618d910eaae52d3e93579b9S3VersionKey412AA341": { "Type": "String", - "Description": "S3 key for asset version \"37fb4b0217f335596d51df351c0bf073aeaaa768b390fe4945560700f60ecd31\"" + "Description": "S3 key for asset version \"712e670f4e8905b5bf48e7a7fc59cce8d2d81e350618d910eaae52d3e93579b9\"" }, - "AssetParameters37fb4b0217f335596d51df351c0bf073aeaaa768b390fe4945560700f60ecd31ArtifactHash4201F140": { + "AssetParameters712e670f4e8905b5bf48e7a7fc59cce8d2d81e350618d910eaae52d3e93579b9ArtifactHashA7B6B572": { "Type": "String", - "Description": "Artifact hash for asset \"37fb4b0217f335596d51df351c0bf073aeaaa768b390fe4945560700f60ecd31\"" + "Description": "Artifact hash for asset \"712e670f4e8905b5bf48e7a7fc59cce8d2d81e350618d910eaae52d3e93579b9\"" }, - "AssetParameters06035c90bda92ff37322a329e214af5f2a1e591c6920e0cea4c6816e0f38ac4bS3BucketFAB8EA28": { + "AssetParametersb02782818b74bd22aefbc8f68291d7c3c5f66f69b40cb21db82e38b460678ba2S3Bucket30803CC9": { "Type": "String", - "Description": "S3 bucket for asset \"06035c90bda92ff37322a329e214af5f2a1e591c6920e0cea4c6816e0f38ac4b\"" + "Description": "S3 bucket for asset \"b02782818b74bd22aefbc8f68291d7c3c5f66f69b40cb21db82e38b460678ba2\"" }, - "AssetParameters06035c90bda92ff37322a329e214af5f2a1e591c6920e0cea4c6816e0f38ac4bS3VersionKey33497690": { + "AssetParametersb02782818b74bd22aefbc8f68291d7c3c5f66f69b40cb21db82e38b460678ba2S3VersionKeyCAAA61AB": { "Type": "String", - "Description": "S3 key for asset version \"06035c90bda92ff37322a329e214af5f2a1e591c6920e0cea4c6816e0f38ac4b\"" + "Description": "S3 key for asset version \"b02782818b74bd22aefbc8f68291d7c3c5f66f69b40cb21db82e38b460678ba2\"" }, - "AssetParameters06035c90bda92ff37322a329e214af5f2a1e591c6920e0cea4c6816e0f38ac4bArtifactHash78FCAA4C": { + "AssetParametersb02782818b74bd22aefbc8f68291d7c3c5f66f69b40cb21db82e38b460678ba2ArtifactHashDEC7863C": { "Type": "String", - "Description": "Artifact hash for asset \"06035c90bda92ff37322a329e214af5f2a1e591c6920e0cea4c6816e0f38ac4b\"" + "Description": "Artifact hash for asset \"b02782818b74bd22aefbc8f68291d7c3c5f66f69b40cb21db82e38b460678ba2\"" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-bottlerocket-ng.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-bottlerocket-ng.expected.json index 7755a615e42e5..0eee8a839c230 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-bottlerocket-ng.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-bottlerocket-ng.expected.json @@ -657,54 +657,30 @@ }, { "Action": [ + "ec2:DescribeDhcpOptions", + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeRouteTables", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeVpcs", "eks:CreateCluster", + "eks:CreateFargateProfile", + "eks:DeleteCluster", + "eks:DeleteFargateProfile", "eks:DescribeCluster", + "eks:DescribeFargateProfile", "eks:DescribeUpdate", - "eks:DeleteCluster", - "eks:UpdateClusterVersion", - "eks:UpdateClusterConfig", - "eks:CreateFargateProfile", "eks:TagResource", - "eks:UntagResource" - ], - "Effect": "Allow", - "Resource": [ - "*" - ] - }, - { - "Action": [ - "eks:DescribeFargateProfile", - "eks:DeleteFargateProfile" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ + "eks:UntagResource", + "eks:UpdateClusterConfig", + "eks:UpdateClusterVersion", + "iam:CreateServiceLinkedRole", "iam:GetRole", "iam:listAttachedRolePolicies" ], "Effect": "Allow", "Resource": "*" - }, - { - "Action": "iam:CreateServiceLinkedRole", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ec2:DescribeInstances", - "ec2:DescribeNetworkInterfaces", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSubnets", - "ec2:DescribeRouteTables", - "ec2:DescribeDhcpOptions", - "ec2:DescribeVpcs" - ], - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -1124,7 +1100,7 @@ }, "/", { - "Ref": "AssetParametersdcdc759e2644fb3c4847d9a160ce99f0f40f137c825ae9cc094323ed4839bab9S3BucketA775E312" + "Ref": "AssetParametersc24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30S3Bucket9C6DDDD3" }, "/", { @@ -1134,7 +1110,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdcdc759e2644fb3c4847d9a160ce99f0f40f137c825ae9cc094323ed4839bab9S3VersionKeyFDABEE9B" + "Ref": "AssetParametersc24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30S3VersionKey6C690A2F" } ] } @@ -1147,7 +1123,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdcdc759e2644fb3c4847d9a160ce99f0f40f137c825ae9cc094323ed4839bab9S3VersionKeyFDABEE9B" + "Ref": "AssetParametersc24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30S3VersionKey6C690A2F" } ] } @@ -1157,11 +1133,11 @@ ] }, "Parameters": { - "referencetoawscdkeksclustertestAssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1771F046Ref": { - "Ref": "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1B280681" + "referencetoawscdkeksclustertestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket1BB3BF46Ref": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097" }, - "referencetoawscdkeksclustertestAssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyDA854AFERef": { - "Ref": "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB1E02791" + "referencetoawscdkeksclustertestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKeyC416ABD8Ref": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224" }, "referencetoawscdkeksclustertestClusterCreationRole95F44854Arn": { "Fn::GetAtt": [ @@ -1169,17 +1145,17 @@ "Arn" ] }, - "referencetoawscdkeksclustertestAssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3BucketDA4E9DCDRef": { - "Ref": "AssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3Bucket3B443230" + "referencetoawscdkeksclustertestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket9814F3B6Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E" }, - "referencetoawscdkeksclustertestAssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3VersionKey6F8004B6Ref": { - "Ref": "AssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3VersionKeyAA4674FB" + "referencetoawscdkeksclustertestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey97942939Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF" }, - "referencetoawscdkeksclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket0815E7B5Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawscdkeksclustertestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket98314848Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawscdkeksclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey657736ADRef": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawscdkeksclustertestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKey4302577BRef": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1199,7 +1175,7 @@ }, "/", { - "Ref": "AssetParameters8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22S3Bucket0782C98E" + "Ref": "AssetParameters4dba0dfaed85cee1f7dccbd9e9afe4346fad85c265fe07665d0fd0a7b46318b0S3Bucket9DC31431" }, "/", { @@ -1209,7 +1185,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22S3VersionKey5E9D14CC" + "Ref": "AssetParameters4dba0dfaed85cee1f7dccbd9e9afe4346fad85c265fe07665d0fd0a7b46318b0S3VersionKey8E264DE6" } ] } @@ -1222,7 +1198,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22S3VersionKey5E9D14CC" + "Ref": "AssetParameters4dba0dfaed85cee1f7dccbd9e9afe4346fad85c265fe07665d0fd0a7b46318b0S3VersionKey8E264DE6" } ] } @@ -1244,11 +1220,11 @@ "Arn" ] }, - "referencetoawscdkeksclustertestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3Bucket3929FA93Ref": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" + "referencetoawscdkeksclustertestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket1FA24F91Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3" }, - "referencetoawscdkeksclustertestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey14530D6BRef": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" + "referencetoawscdkeksclustertestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyA4D2B6C0Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291" }, "referencetoawscdkeksclustertestVpcPrivateSubnet1Subnet32A4EC2ARef": { "Ref": "VpcPrivateSubnet1Subnet536B997A" @@ -1265,11 +1241,11 @@ "ClusterSecurityGroupId" ] }, - "referencetoawscdkeksclustertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketB4E9C142Ref": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" + "referencetoawscdkeksclustertestAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3Bucket07BA6433Ref": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" }, - "referencetoawscdkeksclustertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKey1C7C1F5FRef": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + "referencetoawscdkeksclustertestAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKeyD5B2E756Ref": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" }, "referencetoawscdkeksclustertestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket6ADB5CE5Ref": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" @@ -1277,11 +1253,11 @@ "referencetoawscdkeksclustertestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKey314C5B11Ref": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, - "referencetoawscdkeksclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket0815E7B5Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawscdkeksclustertestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket98314848Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawscdkeksclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey657736ADRef": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawscdkeksclustertestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKey4302577BRef": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1332,65 +1308,65 @@ } }, "Parameters": { - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1B280681": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097": { "Type": "String", - "Description": "S3 bucket for asset \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "S3 bucket for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB1E02791": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224": { "Type": "String", - "Description": "S3 key for asset version \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "S3 key for asset version \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665ArtifactHash9EA5AC29": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeArtifactHash515E16AE": { "Type": "String", - "Description": "Artifact hash for asset \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "Artifact hash for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3Bucket3B443230": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E": { "Type": "String", - "Description": "S3 bucket for asset \"5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720\"" + "Description": "S3 bucket for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3VersionKeyAA4674FB": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF": { "Type": "String", - "Description": "S3 key for asset version \"5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720\"" + "Description": "S3 key for asset version \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720ArtifactHash3D7A279D": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647ArtifactHashE94F67E3": { "Type": "String", - "Description": "Artifact hash for asset \"5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720\"" + "Description": "Artifact hash for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { "Type": "String", - "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { "Type": "String", - "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { "Type": "String", - "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3": { "Type": "String", - "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 bucket for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291": { "Type": "String", - "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 key for asset version \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8ArtifactHashA4AB6609": { "Type": "String", - "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "Artifact hash for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488": { "Type": "String", - "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 bucket for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2": { "Type": "String", - "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 key for asset version \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95ArtifactHash16B60F6C": { "Type": "String", - "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "Artifact hash for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", @@ -1404,29 +1380,29 @@ "Type": "String", "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParametersdcdc759e2644fb3c4847d9a160ce99f0f40f137c825ae9cc094323ed4839bab9S3BucketA775E312": { + "AssetParametersc24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30S3Bucket9C6DDDD3": { "Type": "String", - "Description": "S3 bucket for asset \"dcdc759e2644fb3c4847d9a160ce99f0f40f137c825ae9cc094323ed4839bab9\"" + "Description": "S3 bucket for asset \"c24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30\"" }, - "AssetParametersdcdc759e2644fb3c4847d9a160ce99f0f40f137c825ae9cc094323ed4839bab9S3VersionKeyFDABEE9B": { + "AssetParametersc24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30S3VersionKey6C690A2F": { "Type": "String", - "Description": "S3 key for asset version \"dcdc759e2644fb3c4847d9a160ce99f0f40f137c825ae9cc094323ed4839bab9\"" + "Description": "S3 key for asset version \"c24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30\"" }, - "AssetParametersdcdc759e2644fb3c4847d9a160ce99f0f40f137c825ae9cc094323ed4839bab9ArtifactHashBC5BD0D7": { + "AssetParametersc24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30ArtifactHash00AF8D30": { "Type": "String", - "Description": "Artifact hash for asset \"dcdc759e2644fb3c4847d9a160ce99f0f40f137c825ae9cc094323ed4839bab9\"" + "Description": "Artifact hash for asset \"c24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30\"" }, - "AssetParameters8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22S3Bucket0782C98E": { + "AssetParameters4dba0dfaed85cee1f7dccbd9e9afe4346fad85c265fe07665d0fd0a7b46318b0S3Bucket9DC31431": { "Type": "String", - "Description": "S3 bucket for asset \"8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22\"" + "Description": "S3 bucket for asset \"4dba0dfaed85cee1f7dccbd9e9afe4346fad85c265fe07665d0fd0a7b46318b0\"" }, - "AssetParameters8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22S3VersionKey5E9D14CC": { + "AssetParameters4dba0dfaed85cee1f7dccbd9e9afe4346fad85c265fe07665d0fd0a7b46318b0S3VersionKey8E264DE6": { "Type": "String", - "Description": "S3 key for asset version \"8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22\"" + "Description": "S3 key for asset version \"4dba0dfaed85cee1f7dccbd9e9afe4346fad85c265fe07665d0fd0a7b46318b0\"" }, - "AssetParameters8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22ArtifactHash75F0D468": { + "AssetParameters4dba0dfaed85cee1f7dccbd9e9afe4346fad85c265fe07665d0fd0a7b46318b0ArtifactHashF406B4ED": { "Type": "String", - "Description": "Artifact hash for asset \"8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22\"" + "Description": "Artifact hash for asset \"4dba0dfaed85cee1f7dccbd9e9afe4346fad85c265fe07665d0fd0a7b46318b0\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json index bc3c838b43ef3..f3803ec0ac8bf 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json @@ -713,54 +713,30 @@ }, { "Action": [ + "ec2:DescribeDhcpOptions", + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeRouteTables", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeVpcs", "eks:CreateCluster", + "eks:CreateFargateProfile", + "eks:DeleteCluster", + "eks:DeleteFargateProfile", "eks:DescribeCluster", + "eks:DescribeFargateProfile", "eks:DescribeUpdate", - "eks:DeleteCluster", - "eks:UpdateClusterVersion", - "eks:UpdateClusterConfig", - "eks:CreateFargateProfile", "eks:TagResource", - "eks:UntagResource" - ], - "Effect": "Allow", - "Resource": [ - "*" - ] - }, - { - "Action": [ - "eks:DescribeFargateProfile", - "eks:DeleteFargateProfile" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ + "eks:UntagResource", + "eks:UpdateClusterConfig", + "eks:UpdateClusterVersion", + "iam:CreateServiceLinkedRole", "iam:GetRole", "iam:listAttachedRolePolicies" ], "Effect": "Allow", "Resource": "*" - }, - { - "Action": "iam:CreateServiceLinkedRole", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ec2:DescribeInstances", - "ec2:DescribeNetworkInterfaces", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSubnets", - "ec2:DescribeRouteTables", - "ec2:DescribeDhcpOptions", - "ec2:DescribeVpcs" - ], - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -1115,7 +1091,7 @@ }, "/", { - "Ref": "AssetParameters30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742S3BucketA4A228F5" + "Ref": "AssetParameters33ac00c6a6001ad858775fd6a695ae1b0fd3da2b808727d9b9ec63bc0705df91S3Bucket4DF48841" }, "/", { @@ -1125,7 +1101,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742S3VersionKey6CE1DED5" + "Ref": "AssetParameters33ac00c6a6001ad858775fd6a695ae1b0fd3da2b808727d9b9ec63bc0705df91S3VersionKey6A058A19" } ] } @@ -1138,7 +1114,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742S3VersionKey6CE1DED5" + "Ref": "AssetParameters33ac00c6a6001ad858775fd6a695ae1b0fd3da2b808727d9b9ec63bc0705df91S3VersionKey6A058A19" } ] } @@ -1148,6 +1124,12 @@ ] }, "Parameters": { + "referencetoawscdkekshandlersinvpctestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket6DC627E9Ref": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097" + }, + "referencetoawscdkekshandlersinvpctestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey9AC6A4FARef": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224" + }, "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackCreationRoleADAAC7FDArn": { "Fn::GetAtt": [ "EksAllHandlersInVpcStackCreationRole0BAA4CDC", @@ -1157,11 +1139,11 @@ "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcE40EA7ACRef": { "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" }, - "referencetoawscdkekshandlersinvpctestAssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket4A93429DRef": { - "Ref": "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket5B1EB03C" + "referencetoawscdkekshandlersinvpctestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket63474479Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E" }, - "referencetoawscdkekshandlersinvpctestAssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey7F5C23CBRef": { - "Ref": "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey51E064E9" + "referencetoawscdkekshandlersinvpctestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey242EB671Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF" }, "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcPrivateSubnet1Subnet9479BAA8Ref": { "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1SubnetE2B86978" @@ -1172,17 +1154,11 @@ "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcPrivateSubnet3Subnet1B127970Ref": { "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3SubnetA75A8BA9" }, - "referencetoawscdkekshandlersinvpctestAssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3BucketE24ADE21Ref": { - "Ref": "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3Bucket40405135" - }, - "referencetoawscdkekshandlersinvpctestAssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKeyEA8B9B47Ref": { - "Ref": "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKey50B477EB" - }, - "referencetoawscdkekshandlersinvpctestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket9D7E9998Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawscdkekshandlersinvpctestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket87D96D8BRef": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawscdkekshandlersinvpctestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyE6908FD8Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawscdkekshandlersinvpctestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyEADC88E8Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1202,7 +1178,7 @@ }, "/", { - "Ref": "AssetParameters21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345S3BucketC59A67EA" + "Ref": "AssetParameters2353e7155f6271d0534137266dd20c095799e2cdb7c8fdc967b92623d409b445S3Bucket4885A6BF" }, "/", { @@ -1212,7 +1188,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345S3VersionKey10DC54D0" + "Ref": "AssetParameters2353e7155f6271d0534137266dd20c095799e2cdb7c8fdc967b92623d409b445S3VersionKey805E5D19" } ] } @@ -1225,7 +1201,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345S3VersionKey10DC54D0" + "Ref": "AssetParameters2353e7155f6271d0534137266dd20c095799e2cdb7c8fdc967b92623d409b445S3VersionKey805E5D19" } ] } @@ -1247,11 +1223,11 @@ "Arn" ] }, - "referencetoawscdkekshandlersinvpctestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3Bucket4673F14ERef": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" + "referencetoawscdkekshandlersinvpctestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket00F0F0C9Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3" }, - "referencetoawscdkekshandlersinvpctestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey61C348A6Ref": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" + "referencetoawscdkekshandlersinvpctestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyD069F335Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291" }, "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcPrivateSubnet1Subnet9479BAA8Ref": { "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1SubnetE2B86978" @@ -1268,11 +1244,11 @@ "ClusterSecurityGroupId" ] }, - "referencetoawscdkekshandlersinvpctestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3Bucket124CC58FRef": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" + "referencetoawscdkekshandlersinvpctestAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3Bucket407B19DCRef": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" }, - "referencetoawscdkekshandlersinvpctestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyF4C27F59Ref": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + "referencetoawscdkekshandlersinvpctestAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKeyE1EC5F2DRef": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" }, "referencetoawscdkekshandlersinvpctestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket95C9D5A0Ref": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" @@ -1280,11 +1256,11 @@ "referencetoawscdkekshandlersinvpctestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKey2505ECB3Ref": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, - "referencetoawscdkekshandlersinvpctestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket9D7E9998Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawscdkekshandlersinvpctestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket87D96D8BRef": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawscdkekshandlersinvpctestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyE6908FD8Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawscdkekshandlersinvpctestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyEADC88E8Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1335,65 +1311,65 @@ } }, "Parameters": { - "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket5B1EB03C": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097": { "Type": "String", - "Description": "S3 bucket for asset \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + "Description": "S3 bucket for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey51E064E9": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224": { "Type": "String", - "Description": "S3 key for asset version \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + "Description": "S3 key for asset version \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4ArtifactHash26192139": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeArtifactHash515E16AE": { "Type": "String", - "Description": "Artifact hash for asset \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + "Description": "Artifact hash for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3Bucket40405135": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E": { "Type": "String", - "Description": "S3 bucket for asset \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" + "Description": "S3 bucket for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKey50B477EB": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF": { "Type": "String", - "Description": "S3 key for asset version \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" + "Description": "S3 key for asset version \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccArtifactHashCC7E7A09": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647ArtifactHashE94F67E3": { "Type": "String", - "Description": "Artifact hash for asset \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" + "Description": "Artifact hash for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { "Type": "String", - "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { "Type": "String", - "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { "Type": "String", - "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3": { "Type": "String", - "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 bucket for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291": { "Type": "String", - "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 key for asset version \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8ArtifactHashA4AB6609": { "Type": "String", - "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "Artifact hash for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488": { "Type": "String", - "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 bucket for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2": { "Type": "String", - "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 key for asset version \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95ArtifactHash16B60F6C": { "Type": "String", - "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "Artifact hash for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", @@ -1407,29 +1383,29 @@ "Type": "String", "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameters30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742S3BucketA4A228F5": { + "AssetParameters33ac00c6a6001ad858775fd6a695ae1b0fd3da2b808727d9b9ec63bc0705df91S3Bucket4DF48841": { "Type": "String", - "Description": "S3 bucket for asset \"30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742\"" + "Description": "S3 bucket for asset \"33ac00c6a6001ad858775fd6a695ae1b0fd3da2b808727d9b9ec63bc0705df91\"" }, - "AssetParameters30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742S3VersionKey6CE1DED5": { + "AssetParameters33ac00c6a6001ad858775fd6a695ae1b0fd3da2b808727d9b9ec63bc0705df91S3VersionKey6A058A19": { "Type": "String", - "Description": "S3 key for asset version \"30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742\"" + "Description": "S3 key for asset version \"33ac00c6a6001ad858775fd6a695ae1b0fd3da2b808727d9b9ec63bc0705df91\"" }, - "AssetParameters30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742ArtifactHashBC7D3F16": { + "AssetParameters33ac00c6a6001ad858775fd6a695ae1b0fd3da2b808727d9b9ec63bc0705df91ArtifactHash5FDE9B77": { "Type": "String", - "Description": "Artifact hash for asset \"30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742\"" + "Description": "Artifact hash for asset \"33ac00c6a6001ad858775fd6a695ae1b0fd3da2b808727d9b9ec63bc0705df91\"" }, - "AssetParameters21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345S3BucketC59A67EA": { + "AssetParameters2353e7155f6271d0534137266dd20c095799e2cdb7c8fdc967b92623d409b445S3Bucket4885A6BF": { "Type": "String", - "Description": "S3 bucket for asset \"21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345\"" + "Description": "S3 bucket for asset \"2353e7155f6271d0534137266dd20c095799e2cdb7c8fdc967b92623d409b445\"" }, - "AssetParameters21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345S3VersionKey10DC54D0": { + "AssetParameters2353e7155f6271d0534137266dd20c095799e2cdb7c8fdc967b92623d409b445S3VersionKey805E5D19": { "Type": "String", - "Description": "S3 key for asset version \"21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345\"" + "Description": "S3 key for asset version \"2353e7155f6271d0534137266dd20c095799e2cdb7c8fdc967b92623d409b445\"" }, - "AssetParameters21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345ArtifactHash9BBC26F6": { + "AssetParameters2353e7155f6271d0534137266dd20c095799e2cdb7c8fdc967b92623d409b445ArtifactHashCB19B544": { "Type": "String", - "Description": "Artifact hash for asset \"21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345\"" + "Description": "Artifact hash for asset \"2353e7155f6271d0534137266dd20c095799e2cdb7c8fdc967b92623d409b445\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json index b4da9f1c8825f..c6b58c1af9936 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json @@ -657,54 +657,30 @@ }, { "Action": [ + "ec2:DescribeDhcpOptions", + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeRouteTables", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeVpcs", "eks:CreateCluster", + "eks:CreateFargateProfile", + "eks:DeleteCluster", + "eks:DeleteFargateProfile", "eks:DescribeCluster", + "eks:DescribeFargateProfile", "eks:DescribeUpdate", - "eks:DeleteCluster", - "eks:UpdateClusterVersion", - "eks:UpdateClusterConfig", - "eks:CreateFargateProfile", "eks:TagResource", - "eks:UntagResource" - ], - "Effect": "Allow", - "Resource": [ - "*" - ] - }, - { - "Action": [ - "eks:DescribeFargateProfile", - "eks:DeleteFargateProfile" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ + "eks:UntagResource", + "eks:UpdateClusterConfig", + "eks:UpdateClusterVersion", + "iam:CreateServiceLinkedRole", "iam:GetRole", "iam:listAttachedRolePolicies" ], "Effect": "Allow", "Resource": "*" - }, - { - "Action": "iam:CreateServiceLinkedRole", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ec2:DescribeInstances", - "ec2:DescribeNetworkInterfaces", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSubnets", - "ec2:DescribeRouteTables", - "ec2:DescribeDhcpOptions", - "ec2:DescribeVpcs" - ], - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -1048,7 +1024,7 @@ }, "/", { - "Ref": "AssetParametersa56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890S3Bucket02F74E4B" + "Ref": "AssetParameters56d17a0382b97cd4d8cca24e313a8f5563ea366d39ef4d533bfa30ee1fcbe2e9S3BucketC8527CC3" }, "/", { @@ -1058,7 +1034,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890S3VersionKey0582948B" + "Ref": "AssetParameters56d17a0382b97cd4d8cca24e313a8f5563ea366d39ef4d533bfa30ee1fcbe2e9S3VersionKeyCAEE29F8" } ] } @@ -1071,7 +1047,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890S3VersionKey0582948B" + "Ref": "AssetParameters56d17a0382b97cd4d8cca24e313a8f5563ea366d39ef4d533bfa30ee1fcbe2e9S3VersionKeyCAEE29F8" } ] } @@ -1081,29 +1057,29 @@ ] }, "Parameters": { + "referencetoawscdkeksclusterprivateendpointtestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket34ED2DA8Ref": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097" + }, + "referencetoawscdkeksclusterprivateendpointtestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKeyCF24561BRef": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224" + }, "referencetoawscdkeksclusterprivateendpointtestClusterCreationRole990BAAEAArn": { "Fn::GetAtt": [ "ClusterCreationRole360249B6", "Arn" ] }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3BucketE84B7538Ref": { - "Ref": "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket5B1EB03C" - }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey5FC346A2Ref": { - "Ref": "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey51E064E9" - }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3BucketF4479BE8Ref": { - "Ref": "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3Bucket40405135" + "referencetoawscdkeksclusterprivateendpointtestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3BucketD5AC0C08Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKeyBBC4B419Ref": { - "Ref": "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKey50B477EB" + "referencetoawscdkeksclusterprivateendpointtestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey2A8946AARef": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket7DDAFC04Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawscdkeksclusterprivateendpointtestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket8625E205Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey69BACD98Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawscdkeksclusterprivateendpointtestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyE4510C91Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1123,7 +1099,7 @@ }, "/", { - "Ref": "AssetParametersb9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026S3BucketAF6BC29D" + "Ref": "AssetParametersb89469e6b9fb664c97f084c6d6925bf4ab99d879a91d98d102881002781ac305S3Bucket7D147AE5" }, "/", { @@ -1133,7 +1109,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026S3VersionKey979EE7C4" + "Ref": "AssetParametersb89469e6b9fb664c97f084c6d6925bf4ab99d879a91d98d102881002781ac305S3VersionKeyFE3961AC" } ] } @@ -1146,7 +1122,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026S3VersionKey979EE7C4" + "Ref": "AssetParametersb89469e6b9fb664c97f084c6d6925bf4ab99d879a91d98d102881002781ac305S3VersionKeyFE3961AC" } ] } @@ -1168,11 +1144,11 @@ "Arn" ] }, - "referencetoawscdkeksclusterprivateendpointtestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3Bucket5F23B36DRef": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" + "referencetoawscdkeksclusterprivateendpointtestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket985EEE34Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey658F22A4Ref": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" + "referencetoawscdkeksclusterprivateendpointtestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKey705FAD72Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291" }, "referencetoawscdkeksclusterprivateendpointtestVpcPrivateSubnet1Subnet94DAD769Ref": { "Ref": "VpcPrivateSubnet1Subnet536B997A" @@ -1189,11 +1165,11 @@ "ClusterSecurityGroupId" ] }, - "referencetoawscdkeksclusterprivateendpointtestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketFD6C4D26Ref": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" + "referencetoawscdkeksclusterprivateendpointtestAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketD35D6C90Ref": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKey69E4725CRef": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + "referencetoawscdkeksclusterprivateendpointtestAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey0C9D3197Ref": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" }, "referencetoawscdkeksclusterprivateendpointtestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket99203424Ref": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" @@ -1201,11 +1177,11 @@ "referencetoawscdkeksclusterprivateendpointtestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKey74D35E51Ref": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket7DDAFC04Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawscdkeksclusterprivateendpointtestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket8625E205Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey69BACD98Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawscdkeksclusterprivateendpointtestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyE4510C91Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1256,65 +1232,65 @@ } }, "Parameters": { - "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket5B1EB03C": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097": { "Type": "String", - "Description": "S3 bucket for asset \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + "Description": "S3 bucket for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey51E064E9": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224": { "Type": "String", - "Description": "S3 key for asset version \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + "Description": "S3 key for asset version \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4ArtifactHash26192139": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeArtifactHash515E16AE": { "Type": "String", - "Description": "Artifact hash for asset \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + "Description": "Artifact hash for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3Bucket40405135": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E": { "Type": "String", - "Description": "S3 bucket for asset \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" + "Description": "S3 bucket for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKey50B477EB": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF": { "Type": "String", - "Description": "S3 key for asset version \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" + "Description": "S3 key for asset version \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccArtifactHashCC7E7A09": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647ArtifactHashE94F67E3": { "Type": "String", - "Description": "Artifact hash for asset \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" + "Description": "Artifact hash for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { "Type": "String", - "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { "Type": "String", - "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { "Type": "String", - "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3": { "Type": "String", - "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 bucket for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291": { "Type": "String", - "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 key for asset version \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8ArtifactHashA4AB6609": { "Type": "String", - "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "Artifact hash for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488": { "Type": "String", - "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 bucket for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2": { "Type": "String", - "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 key for asset version \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95ArtifactHash16B60F6C": { "Type": "String", - "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "Artifact hash for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", @@ -1328,29 +1304,29 @@ "Type": "String", "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParametersa56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890S3Bucket02F74E4B": { + "AssetParameters56d17a0382b97cd4d8cca24e313a8f5563ea366d39ef4d533bfa30ee1fcbe2e9S3BucketC8527CC3": { "Type": "String", - "Description": "S3 bucket for asset \"a56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890\"" + "Description": "S3 bucket for asset \"56d17a0382b97cd4d8cca24e313a8f5563ea366d39ef4d533bfa30ee1fcbe2e9\"" }, - "AssetParametersa56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890S3VersionKey0582948B": { + "AssetParameters56d17a0382b97cd4d8cca24e313a8f5563ea366d39ef4d533bfa30ee1fcbe2e9S3VersionKeyCAEE29F8": { "Type": "String", - "Description": "S3 key for asset version \"a56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890\"" + "Description": "S3 key for asset version \"56d17a0382b97cd4d8cca24e313a8f5563ea366d39ef4d533bfa30ee1fcbe2e9\"" }, - "AssetParametersa56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890ArtifactHash67434B72": { + "AssetParameters56d17a0382b97cd4d8cca24e313a8f5563ea366d39ef4d533bfa30ee1fcbe2e9ArtifactHash55D2045C": { "Type": "String", - "Description": "Artifact hash for asset \"a56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890\"" + "Description": "Artifact hash for asset \"56d17a0382b97cd4d8cca24e313a8f5563ea366d39ef4d533bfa30ee1fcbe2e9\"" }, - "AssetParametersb9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026S3BucketAF6BC29D": { + "AssetParametersb89469e6b9fb664c97f084c6d6925bf4ab99d879a91d98d102881002781ac305S3Bucket7D147AE5": { "Type": "String", - "Description": "S3 bucket for asset \"b9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026\"" + "Description": "S3 bucket for asset \"b89469e6b9fb664c97f084c6d6925bf4ab99d879a91d98d102881002781ac305\"" }, - "AssetParametersb9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026S3VersionKey979EE7C4": { + "AssetParametersb89469e6b9fb664c97f084c6d6925bf4ab99d879a91d98d102881002781ac305S3VersionKeyFE3961AC": { "Type": "String", - "Description": "S3 key for asset version \"b9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026\"" + "Description": "S3 key for asset version \"b89469e6b9fb664c97f084c6d6925bf4ab99d879a91d98d102881002781ac305\"" }, - "AssetParametersb9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026ArtifactHash8B6627D0": { + "AssetParametersb89469e6b9fb664c97f084c6d6925bf4ab99d879a91d98d102881002781ac305ArtifactHashFF9785DA": { "Type": "String", - "Description": "Artifact hash for asset \"b9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026\"" + "Description": "Artifact hash for asset \"b89469e6b9fb664c97f084c6d6925bf4ab99d879a91d98d102881002781ac305\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json index 1476182e23c37..02dc4f65277ba 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json @@ -763,70 +763,54 @@ { "Action": "iam:PassRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "ClusterRoleFA261979", - "Arn" - ] - } - }, - { - "Action": [ - "eks:CreateCluster", - "eks:DescribeCluster", - "eks:DescribeUpdate", - "eks:DeleteCluster", - "eks:UpdateClusterVersion", - "eks:UpdateClusterConfig", - "eks:CreateFargateProfile", - "eks:TagResource", - "eks:UntagResource" - ], - "Effect": "Allow", "Resource": [ - "*" + { + "Fn::GetAtt": [ + "ClusterRoleFA261979", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "ClusterfargateprofiledefaultPodExecutionRole09952CFF", + "Arn" + ] + } ] }, { "Action": [ - "eks:DescribeFargateProfile", - "eks:DeleteFargateProfile" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "iam:GetRole", - "iam:listAttachedRolePolicies" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "iam:CreateServiceLinkedRole", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ + "ec2:DescribeDhcpOptions", "ec2:DescribeInstances", "ec2:DescribeNetworkInterfaces", + "ec2:DescribeRouteTables", "ec2:DescribeSecurityGroups", "ec2:DescribeSubnets", - "ec2:DescribeRouteTables", - "ec2:DescribeDhcpOptions", - "ec2:DescribeVpcs" + "ec2:DescribeVpcs", + "eks:CreateCluster", + "eks:CreateFargateProfile", + "eks:DeleteCluster", + "eks:DeleteFargateProfile", + "eks:DescribeCluster", + "eks:DescribeFargateProfile", + "eks:DescribeUpdate", + "eks:TagResource", + "eks:UntagResource", + "eks:UpdateClusterConfig", + "eks:UpdateClusterVersion", + "iam:CreateServiceLinkedRole", + "iam:GetRole", + "iam:listAttachedRolePolicies" ], "Effect": "Allow", "Resource": "*" }, { "Action": [ - "kms:Encrypt", + "kms:CreateGrant", "kms:Decrypt", "kms:DescribeKey", - "kms:CreateGrant" + "kms:Encrypt" ], "Effect": "Allow", "Resource": { @@ -835,16 +819,6 @@ "Arn" ] } - }, - { - "Action": "iam:PassRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "ClusterfargateprofiledefaultPodExecutionRole09952CFF", - "Arn" - ] - } } ], "Version": "2012-10-17" @@ -957,10 +931,14 @@ }, "logging": { "clusterLogging": [ - { - "enabled": true, - "types": [ "api", "authenticator", "scheduler" ] - } + { + "enabled": true, + "types": [ + "api", + "authenticator", + "scheduler" + ] + } ] } }, @@ -2712,7 +2690,7 @@ }, "Release": "ksclustertestclusterchartspotinterrupthandlerf41ba997", "Chart": "aws-node-termination-handler", - "Version": "0.13.2", + "Version": "1.14.1", "Values": "{\"nodeSelector\":{\"lifecycle\":\"Ec2Spot\"}}", "Namespace": "kube-system", "Repository": "https://aws.github.io/eks-charts", @@ -3444,7 +3422,7 @@ }, "/", { - "Ref": "AssetParametersc3133e15f268838efdf38077f27fd489d312e90798517ec62d98dfd0712b563eS3Bucket297B6E78" + "Ref": "AssetParametersc24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30S3Bucket9C6DDDD3" }, "/", { @@ -3454,7 +3432,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersc3133e15f268838efdf38077f27fd489d312e90798517ec62d98dfd0712b563eS3VersionKey285AE936" + "Ref": "AssetParametersc24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30S3VersionKey6C690A2F" } ] } @@ -3467,7 +3445,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersc3133e15f268838efdf38077f27fd489d312e90798517ec62d98dfd0712b563eS3VersionKey285AE936" + "Ref": "AssetParametersc24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30S3VersionKey6C690A2F" } ] } @@ -3477,11 +3455,11 @@ ] }, "Parameters": { - "referencetoawscdkeksclustertestAssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1771F046Ref": { - "Ref": "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1B280681" + "referencetoawscdkeksclustertestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket1BB3BF46Ref": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097" }, - "referencetoawscdkeksclustertestAssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyDA854AFERef": { - "Ref": "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB1E02791" + "referencetoawscdkeksclustertestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKeyC416ABD8Ref": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224" }, "referencetoawscdkeksclustertestClusterCreationRole95F44854Arn": { "Fn::GetAtt": [ @@ -3489,17 +3467,17 @@ "Arn" ] }, - "referencetoawscdkeksclustertestAssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3Bucket958E1227Ref": { - "Ref": "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3Bucket9AE1EC0F" + "referencetoawscdkeksclustertestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket9814F3B6Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E" }, - "referencetoawscdkeksclustertestAssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3VersionKeyA985D634Ref": { - "Ref": "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3VersionKey451EAA56" + "referencetoawscdkeksclustertestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey97942939Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF" }, - "referencetoawscdkeksclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket0815E7B5Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawscdkeksclustertestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket98314848Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawscdkeksclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey657736ADRef": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawscdkeksclustertestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKey4302577BRef": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -3519,7 +3497,7 @@ }, "/", { - "Ref": "AssetParametersa28799ada83b92b06ae89cb67aaaba59b7c6fd3c23ad407578334ada0d245cebS3BucketCA5A17E3" + "Ref": "AssetParametersfedb0b025bbf74f4daee09934a81c34a6cf5b06a765baa86bf42234971244a09S3BucketB43B25F0" }, "/", { @@ -3529,7 +3507,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa28799ada83b92b06ae89cb67aaaba59b7c6fd3c23ad407578334ada0d245cebS3VersionKey4AD94792" + "Ref": "AssetParametersfedb0b025bbf74f4daee09934a81c34a6cf5b06a765baa86bf42234971244a09S3VersionKey4D3C22DF" } ] } @@ -3542,7 +3520,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa28799ada83b92b06ae89cb67aaaba59b7c6fd3c23ad407578334ada0d245cebS3VersionKey4AD94792" + "Ref": "AssetParametersfedb0b025bbf74f4daee09934a81c34a6cf5b06a765baa86bf42234971244a09S3VersionKey4D3C22DF" } ] } @@ -3567,11 +3545,11 @@ "referencetoawscdkeksclustertestAssetParametersd65fbdc11b108e0386ed8577c454d4544f6d4e7960f84a0d2e211478d6324dbfS3BucketE84D6FBERef": { "Ref": "AssetParametersd65fbdc11b108e0386ed8577c454d4544f6d4e7960f84a0d2e211478d6324dbfS3BucketBFD29DFB" }, - "referencetoawscdkeksclustertestAssetParameters7405215c9dec361c2c285bc67b8571f1fd93fd2e0ab73eaf1d9deefb26f45d5bS3Bucket04A6A2E9Ref": { - "Ref": "AssetParameters7405215c9dec361c2c285bc67b8571f1fd93fd2e0ab73eaf1d9deefb26f45d5bS3Bucket130CFDEE" + "referencetoawscdkeksclustertestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket1FA24F91Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3" }, - "referencetoawscdkeksclustertestAssetParameters7405215c9dec361c2c285bc67b8571f1fd93fd2e0ab73eaf1d9deefb26f45d5bS3VersionKeyD150E066Ref": { - "Ref": "AssetParameters7405215c9dec361c2c285bc67b8571f1fd93fd2e0ab73eaf1d9deefb26f45d5bS3VersionKeyB48A0274" + "referencetoawscdkeksclustertestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyA4D2B6C0Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291" }, "referencetoawscdkeksclustertestVpcPrivateSubnet1Subnet32A4EC2ARef": { "Ref": "VpcPrivateSubnet1Subnet536B997A" @@ -3588,11 +3566,11 @@ "ClusterSecurityGroupId" ] }, - "referencetoawscdkeksclustertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketB4E9C142Ref": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" + "referencetoawscdkeksclustertestAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3Bucket07BA6433Ref": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" }, - "referencetoawscdkeksclustertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKey1C7C1F5FRef": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + "referencetoawscdkeksclustertestAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKeyD5B2E756Ref": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" }, "referencetoawscdkeksclustertestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket6ADB5CE5Ref": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" @@ -3600,11 +3578,11 @@ "referencetoawscdkeksclustertestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKey314C5B11Ref": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, - "referencetoawscdkeksclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket0815E7B5Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawscdkeksclustertestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket98314848Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawscdkeksclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey657736ADRef": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawscdkeksclustertestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKey4302577BRef": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -3711,7 +3689,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3BucketF7BC1777" + "Ref": "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3Bucket211A9156" }, "S3Key": { "Fn::Join": [ @@ -3724,7 +3702,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3VersionKey1C340B30" + "Ref": "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3VersionKey822D04EC" } ] } @@ -3737,7 +3715,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3VersionKey1C340B30" + "Ref": "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3VersionKey822D04EC" } ] } @@ -3789,7 +3767,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3BucketB7E1A9C0" + "Ref": "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3Bucket6F458959" }, "S3Key": { "Fn::Join": [ @@ -3802,7 +3780,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3VersionKey542FDEBD" + "Ref": "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3VersionKeyBDD0572E" } ] } @@ -3815,7 +3793,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3VersionKey542FDEBD" + "Ref": "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3VersionKeyBDD0572E" } ] } @@ -3929,65 +3907,65 @@ } }, "Parameters": { - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1B280681": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097": { "Type": "String", - "Description": "S3 bucket for asset \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "S3 bucket for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB1E02791": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224": { "Type": "String", - "Description": "S3 key for asset version \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "S3 key for asset version \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665ArtifactHash9EA5AC29": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeArtifactHash515E16AE": { "Type": "String", - "Description": "Artifact hash for asset \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "Artifact hash for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3Bucket9AE1EC0F": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E": { "Type": "String", - "Description": "S3 bucket for asset \"00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5af\"" + "Description": "S3 bucket for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3VersionKey451EAA56": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF": { "Type": "String", - "Description": "S3 key for asset version \"00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5af\"" + "Description": "S3 key for asset version \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afArtifactHash761F4689": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647ArtifactHashE94F67E3": { "Type": "String", - "Description": "Artifact hash for asset \"00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5af\"" + "Description": "Artifact hash for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { "Type": "String", - "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { "Type": "String", - "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { "Type": "String", - "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParameters7405215c9dec361c2c285bc67b8571f1fd93fd2e0ab73eaf1d9deefb26f45d5bS3Bucket130CFDEE": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3": { "Type": "String", - "Description": "S3 bucket for asset \"7405215c9dec361c2c285bc67b8571f1fd93fd2e0ab73eaf1d9deefb26f45d5b\"" + "Description": "S3 bucket for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters7405215c9dec361c2c285bc67b8571f1fd93fd2e0ab73eaf1d9deefb26f45d5bS3VersionKeyB48A0274": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291": { "Type": "String", - "Description": "S3 key for asset version \"7405215c9dec361c2c285bc67b8571f1fd93fd2e0ab73eaf1d9deefb26f45d5b\"" + "Description": "S3 key for asset version \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters7405215c9dec361c2c285bc67b8571f1fd93fd2e0ab73eaf1d9deefb26f45d5bArtifactHash47D5DE75": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8ArtifactHashA4AB6609": { "Type": "String", - "Description": "Artifact hash for asset \"7405215c9dec361c2c285bc67b8571f1fd93fd2e0ab73eaf1d9deefb26f45d5b\"" + "Description": "Artifact hash for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488": { "Type": "String", - "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 bucket for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2": { "Type": "String", - "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 key for asset version \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95ArtifactHash16B60F6C": { "Type": "String", - "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "Artifact hash for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", @@ -4013,53 +3991,53 @@ "Type": "String", "Description": "Artifact hash for asset \"d65fbdc11b108e0386ed8577c454d4544f6d4e7960f84a0d2e211478d6324dbf\"" }, - "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3BucketF7BC1777": { + "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3Bucket211A9156": { "Type": "String", - "Description": "S3 bucket for asset \"b7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4\"" + "Description": "S3 bucket for asset \"5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2\"" }, - "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3VersionKey1C340B30": { + "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3VersionKey822D04EC": { "Type": "String", - "Description": "S3 key for asset version \"b7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4\"" + "Description": "S3 key for asset version \"5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2\"" }, - "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4ArtifactHashD6EA1BC7": { + "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2ArtifactHashCA4A1831": { "Type": "String", - "Description": "Artifact hash for asset \"b7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4\"" + "Description": "Artifact hash for asset \"5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2\"" }, - "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3BucketB7E1A9C0": { + "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3Bucket6F458959": { "Type": "String", - "Description": "S3 bucket for asset \"6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3\"" + "Description": "S3 bucket for asset \"f850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4\"" }, - "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3VersionKey542FDEBD": { + "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3VersionKeyBDD0572E": { "Type": "String", - "Description": "S3 key for asset version \"6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3\"" + "Description": "S3 key for asset version \"f850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4\"" }, - "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3ArtifactHash5E61FCA5": { + "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4ArtifactHash4D5DD9E9": { "Type": "String", - "Description": "Artifact hash for asset \"6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3\"" + "Description": "Artifact hash for asset \"f850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4\"" }, - "AssetParametersc3133e15f268838efdf38077f27fd489d312e90798517ec62d98dfd0712b563eS3Bucket297B6E78": { + "AssetParametersc24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30S3Bucket9C6DDDD3": { "Type": "String", - "Description": "S3 bucket for asset \"c3133e15f268838efdf38077f27fd489d312e90798517ec62d98dfd0712b563e\"" + "Description": "S3 bucket for asset \"c24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30\"" }, - "AssetParametersc3133e15f268838efdf38077f27fd489d312e90798517ec62d98dfd0712b563eS3VersionKey285AE936": { + "AssetParametersc24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30S3VersionKey6C690A2F": { "Type": "String", - "Description": "S3 key for asset version \"c3133e15f268838efdf38077f27fd489d312e90798517ec62d98dfd0712b563e\"" + "Description": "S3 key for asset version \"c24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30\"" }, - "AssetParametersc3133e15f268838efdf38077f27fd489d312e90798517ec62d98dfd0712b563eArtifactHash5FC88E83": { + "AssetParametersc24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30ArtifactHash00AF8D30": { "Type": "String", - "Description": "Artifact hash for asset \"c3133e15f268838efdf38077f27fd489d312e90798517ec62d98dfd0712b563e\"" + "Description": "Artifact hash for asset \"c24eb763169accd26e653fd1884c13dd7e1c54d9c85d1ce647422dc5ad80dc30\"" }, - "AssetParametersa28799ada83b92b06ae89cb67aaaba59b7c6fd3c23ad407578334ada0d245cebS3BucketCA5A17E3": { + "AssetParametersfedb0b025bbf74f4daee09934a81c34a6cf5b06a765baa86bf42234971244a09S3BucketB43B25F0": { "Type": "String", - "Description": "S3 bucket for asset \"a28799ada83b92b06ae89cb67aaaba59b7c6fd3c23ad407578334ada0d245ceb\"" + "Description": "S3 bucket for asset \"fedb0b025bbf74f4daee09934a81c34a6cf5b06a765baa86bf42234971244a09\"" }, - "AssetParametersa28799ada83b92b06ae89cb67aaaba59b7c6fd3c23ad407578334ada0d245cebS3VersionKey4AD94792": { + "AssetParametersfedb0b025bbf74f4daee09934a81c34a6cf5b06a765baa86bf42234971244a09S3VersionKey4D3C22DF": { "Type": "String", - "Description": "S3 key for asset version \"a28799ada83b92b06ae89cb67aaaba59b7c6fd3c23ad407578334ada0d245ceb\"" + "Description": "S3 key for asset version \"fedb0b025bbf74f4daee09934a81c34a6cf5b06a765baa86bf42234971244a09\"" }, - "AssetParametersa28799ada83b92b06ae89cb67aaaba59b7c6fd3c23ad407578334ada0d245cebArtifactHash4AC3D16B": { + "AssetParametersfedb0b025bbf74f4daee09934a81c34a6cf5b06a765baa86bf42234971244a09ArtifactHash841F190C": { "Type": "String", - "Description": "Artifact hash for asset \"a28799ada83b92b06ae89cb67aaaba59b7c6fd3c23ad407578334ada0d245ceb\"" + "Description": "Artifact hash for asset \"fedb0b025bbf74f4daee09934a81c34a6cf5b06a765baa86bf42234971244a09\"" }, "SsmParameterValueawsserviceeksoptimizedami121amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { "Type": "AWS::SSM::Parameter::Value", diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-helm-asset.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-helm-asset.expected.json new file mode 100644 index 0000000000000..8134188ef9da4 --- /dev/null +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-helm-asset.expected.json @@ -0,0 +1,1403 @@ +{ + "Resources": { + "AdminRole38563C57": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::12345678:root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-eks-helm-test/Vpc" + } + ] + } + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-helm-test/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-helm-test/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + } + } + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet1EIPD7E02669": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-helm-test/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1NATGateway4D7517AA": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-helm-test/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.32.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-helm-test/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-helm-test/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + } + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet3SubnetBE12F0B6": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-helm-test/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPublicSubnet3RouteTable93458DBB": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-helm-test/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPublicSubnet3RouteTableAssociation1F1EDF02": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet3RouteTable93458DBB" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet3SubnetBE12F0B6" + } + } + }, + "VpcPublicSubnet3DefaultRoute4697774F": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet3RouteTable93458DBB" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPrivateSubnet1Subnet536B997A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.96.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-helm-test/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableB2C5B500": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-helm-test/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + } + } + }, + "VpcPrivateSubnet2Subnet3788AAA1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-helm-test/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableA678073B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-helm-test/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + } + }, + "VpcPrivateSubnet2DefaultRoute060D2087": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + } + } + }, + "VpcPrivateSubnet3SubnetF258B56E": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.160.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-helm-test/Vpc/PrivateSubnet3" + } + ] + } + }, + "VpcPrivateSubnet3RouteTableD98824C7": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-helm-test/Vpc/PrivateSubnet3" + } + ] + } + }, + "VpcPrivateSubnet3RouteTableAssociation16BDDC43": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet3RouteTableD98824C7" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + } + } + }, + "VpcPrivateSubnet3DefaultRoute94B74F0D": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet3RouteTableD98824C7" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + } + } + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-eks-helm-test/Vpc" + } + ] + } + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + } + } + }, + "ClusterRoleFA261979": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "eks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEKSClusterPolicy" + ] + ] + } + ] + } + }, + "ClusterControlPlaneSecurityGroupD274242C": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "EKS Control Plane Security Group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "ClusterCreationRole360249B6": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::12345678:root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + }, + "DependsOn": [ + "VpcIGWD7BA715C", + "VpcPrivateSubnet1DefaultRouteBE02A9ED", + "VpcPrivateSubnet1RouteTableB2C5B500", + "VpcPrivateSubnet1RouteTableAssociation70C59FA6", + "VpcPrivateSubnet1Subnet536B997A", + "VpcPrivateSubnet2DefaultRoute060D2087", + "VpcPrivateSubnet2RouteTableA678073B", + "VpcPrivateSubnet2RouteTableAssociationA89CAD56", + "VpcPrivateSubnet2Subnet3788AAA1", + "VpcPrivateSubnet3DefaultRoute94B74F0D", + "VpcPrivateSubnet3RouteTableD98824C7", + "VpcPrivateSubnet3RouteTableAssociation16BDDC43", + "VpcPrivateSubnet3SubnetF258B56E", + "VpcPublicSubnet1DefaultRoute3DA9E72A", + "VpcPublicSubnet1EIPD7E02669", + "VpcPublicSubnet1NATGateway4D7517AA", + "VpcPublicSubnet1RouteTable6C95E38E", + "VpcPublicSubnet1RouteTableAssociation97140677", + "VpcPublicSubnet1Subnet5C2D37C4", + "VpcPublicSubnet2DefaultRoute97F91067", + "VpcPublicSubnet2RouteTable94F7E489", + "VpcPublicSubnet2RouteTableAssociationDD5762D8", + "VpcPublicSubnet2Subnet691E08A3", + "VpcPublicSubnet3DefaultRoute4697774F", + "VpcPublicSubnet3RouteTable93458DBB", + "VpcPublicSubnet3RouteTableAssociation1F1EDF02", + "VpcPublicSubnet3SubnetBE12F0B6", + "Vpc8378EB38", + "VpcVPCGWBF912B6E" + ] + }, + "ClusterCreationRoleDefaultPolicyE8BDFC7B": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "iam:PassRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "ClusterRoleFA261979", + "Arn" + ] + } + }, + { + "Action": [ + "ec2:DescribeDhcpOptions", + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeRouteTables", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeVpcs", + "eks:CreateCluster", + "eks:CreateFargateProfile", + "eks:DeleteCluster", + "eks:DeleteFargateProfile", + "eks:DescribeCluster", + "eks:DescribeFargateProfile", + "eks:DescribeUpdate", + "eks:TagResource", + "eks:UntagResource", + "eks:UpdateClusterConfig", + "eks:UpdateClusterVersion", + "iam:CreateServiceLinkedRole", + "iam:GetRole", + "iam:listAttachedRolePolicies" + ], + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ClusterCreationRoleDefaultPolicyE8BDFC7B", + "Roles": [ + { + "Ref": "ClusterCreationRole360249B6" + } + ] + }, + "DependsOn": [ + "VpcIGWD7BA715C", + "VpcPrivateSubnet1DefaultRouteBE02A9ED", + "VpcPrivateSubnet1RouteTableB2C5B500", + "VpcPrivateSubnet1RouteTableAssociation70C59FA6", + "VpcPrivateSubnet1Subnet536B997A", + "VpcPrivateSubnet2DefaultRoute060D2087", + "VpcPrivateSubnet2RouteTableA678073B", + "VpcPrivateSubnet2RouteTableAssociationA89CAD56", + "VpcPrivateSubnet2Subnet3788AAA1", + "VpcPrivateSubnet3DefaultRoute94B74F0D", + "VpcPrivateSubnet3RouteTableD98824C7", + "VpcPrivateSubnet3RouteTableAssociation16BDDC43", + "VpcPrivateSubnet3SubnetF258B56E", + "VpcPublicSubnet1DefaultRoute3DA9E72A", + "VpcPublicSubnet1EIPD7E02669", + "VpcPublicSubnet1NATGateway4D7517AA", + "VpcPublicSubnet1RouteTable6C95E38E", + "VpcPublicSubnet1RouteTableAssociation97140677", + "VpcPublicSubnet1Subnet5C2D37C4", + "VpcPublicSubnet2DefaultRoute97F91067", + "VpcPublicSubnet2RouteTable94F7E489", + "VpcPublicSubnet2RouteTableAssociationDD5762D8", + "VpcPublicSubnet2Subnet691E08A3", + "VpcPublicSubnet3DefaultRoute4697774F", + "VpcPublicSubnet3RouteTable93458DBB", + "VpcPublicSubnet3RouteTableAssociation1F1EDF02", + "VpcPublicSubnet3SubnetBE12F0B6", + "Vpc8378EB38", + "VpcVPCGWBF912B6E" + ] + }, + "Cluster9EE0221C": { + "Type": "Custom::AWSCDK-EKS-Cluster", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "awscdkawseksClusterResourceProviderNestedStackawscdkawseksClusterResourceProviderNestedStackResource9827C454", + "Outputs.awscdkekshelmtestawscdkawseksClusterResourceProviderframeworkonEventFCDC8710Arn" + ] + }, + "Config": { + "version": "1.21", + "roleArn": { + "Fn::GetAtt": [ + "ClusterRoleFA261979", + "Arn" + ] + }, + "resourcesVpcConfig": { + "subnetIds": [ + { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + { + "Ref": "VpcPublicSubnet3SubnetBE12F0B6" + }, + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + }, + { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + } + ], + "securityGroupIds": [ + { + "Fn::GetAtt": [ + "ClusterControlPlaneSecurityGroupD274242C", + "GroupId" + ] + } + ], + "endpointPublicAccess": true, + "endpointPrivateAccess": true + }, + "tags": { + "foo": "bar" + }, + "logging": { + "clusterLogging": [ + { + "enabled": true, + "types": [ + "api", + "authenticator", + "scheduler" + ] + } + ] + } + }, + "AssumeRoleArn": { + "Fn::GetAtt": [ + "ClusterCreationRole360249B6", + "Arn" + ] + }, + "AttributesRevision": 2 + }, + "DependsOn": [ + "ClusterCreationRoleDefaultPolicyE8BDFC7B", + "ClusterCreationRole360249B6", + "VpcIGWD7BA715C", + "VpcPrivateSubnet1DefaultRouteBE02A9ED", + "VpcPrivateSubnet1RouteTableB2C5B500", + "VpcPrivateSubnet1RouteTableAssociation70C59FA6", + "VpcPrivateSubnet1Subnet536B997A", + "VpcPrivateSubnet2DefaultRoute060D2087", + "VpcPrivateSubnet2RouteTableA678073B", + "VpcPrivateSubnet2RouteTableAssociationA89CAD56", + "VpcPrivateSubnet2Subnet3788AAA1", + "VpcPrivateSubnet3DefaultRoute94B74F0D", + "VpcPrivateSubnet3RouteTableD98824C7", + "VpcPrivateSubnet3RouteTableAssociation16BDDC43", + "VpcPrivateSubnet3SubnetF258B56E", + "VpcPublicSubnet1DefaultRoute3DA9E72A", + "VpcPublicSubnet1EIPD7E02669", + "VpcPublicSubnet1NATGateway4D7517AA", + "VpcPublicSubnet1RouteTable6C95E38E", + "VpcPublicSubnet1RouteTableAssociation97140677", + "VpcPublicSubnet1Subnet5C2D37C4", + "VpcPublicSubnet2DefaultRoute97F91067", + "VpcPublicSubnet2RouteTable94F7E489", + "VpcPublicSubnet2RouteTableAssociationDD5762D8", + "VpcPublicSubnet2Subnet691E08A3", + "VpcPublicSubnet3DefaultRoute4697774F", + "VpcPublicSubnet3RouteTable93458DBB", + "VpcPublicSubnet3RouteTableAssociation1F1EDF02", + "VpcPublicSubnet3SubnetBE12F0B6", + "Vpc8378EB38", + "VpcVPCGWBF912B6E" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterKubectlReadyBarrier200052AF": { + "Type": "AWS::SSM::Parameter", + "Properties": { + "Type": "String", + "Value": "aws:cdk:eks:kubectl-ready" + }, + "DependsOn": [ + "ClusterCreationRoleDefaultPolicyE8BDFC7B", + "ClusterCreationRole360249B6", + "Cluster9EE0221C" + ] + }, + "ClusterAwsAuthmanifestFE51F8AE": { + "Type": "Custom::AWSCDK-EKS-KubernetesResource", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B", + "Outputs.awscdkekshelmtestawscdkawseksKubectlProviderframeworkonEvent9D93C644Arn" + ] + }, + "Manifest": { + "Fn::Join": [ + "", + [ + "[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"aws-auth\",\"namespace\":\"kube-system\",\"labels\":{\"aws.cdk.eks/prune-c8d0612c947a128ccc926ff6124bd5462ab86f86d6\":\"\"}},\"data\":{\"mapRoles\":\"[{\\\"rolearn\\\":\\\"", + { + "Fn::GetAtt": [ + "AdminRole38563C57", + "Arn" + ] + }, + "\\\",\\\"username\\\":\\\"", + { + "Fn::GetAtt": [ + "AdminRole38563C57", + "Arn" + ] + }, + "\\\",\\\"groups\\\":[\\\"system:masters\\\"]},{\\\"rolearn\\\":\\\"", + { + "Fn::GetAtt": [ + "ClusterNodegroupDefaultCapacityNodeGroupRole55953B04", + "Arn" + ] + }, + "\\\",\\\"username\\\":\\\"system:node:{{EC2PrivateDNSName}}\\\",\\\"groups\\\":[\\\"system:bootstrappers\\\",\\\"system:nodes\\\"]}]\",\"mapUsers\":\"[]\",\"mapAccounts\":\"[]\"}}]" + ] + ] + }, + "ClusterName": { + "Ref": "Cluster9EE0221C" + }, + "RoleArn": { + "Fn::GetAtt": [ + "ClusterCreationRole360249B6", + "Arn" + ] + }, + "PruneLabel": "aws.cdk.eks/prune-c8d0612c947a128ccc926ff6124bd5462ab86f86d6", + "Overwrite": true + }, + "DependsOn": [ + "ClusterKubectlReadyBarrier200052AF" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterNodegroupDefaultCapacityNodeGroupRole55953B04": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEKSWorkerNodePolicy" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEKS_CNI_Policy" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" + ] + ] + } + ] + } + }, + "ClusterNodegroupDefaultCapacityDA0920A3": { + "Type": "AWS::EKS::Nodegroup", + "Properties": { + "ClusterName": { + "Ref": "Cluster9EE0221C" + }, + "NodeRole": { + "Fn::GetAtt": [ + "ClusterNodegroupDefaultCapacityNodeGroupRole55953B04", + "Arn" + ] + }, + "Subnets": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + }, + { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + } + ], + "AmiType": "AL2_x86_64", + "ForceUpdateEnabled": true, + "InstanceTypes": [ + "m5.large" + ], + "ScalingConfig": { + "DesiredSize": 2, + "MaxSize": 2, + "MinSize": 2 + } + } + }, + "Clustercharttestchart9FD698EB": { + "Type": "Custom::AWSCDK-EKS-HelmChart", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B", + "Outputs.awscdkekshelmtestawscdkawseksKubectlProviderframeworkonEvent9D93C644Arn" + ] + }, + "ClusterName": { + "Ref": "Cluster9EE0221C" + }, + "RoleArn": { + "Fn::GetAtt": [ + "ClusterCreationRole360249B6", + "Arn" + ] + }, + "Release": "awscdkekshelmtestclustercharttestchart0449715f", + "ChartAssetURL": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Ref": "AssetParametersd65fbdc11b108e0386ed8577c454d4544f6d4e7960f84a0d2e211478d6324dbfS3BucketBFD29DFB" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersd65fbdc11b108e0386ed8577c454d4544f6d4e7960f84a0d2e211478d6324dbfS3VersionKeyD1F874DF" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersd65fbdc11b108e0386ed8577c454d4544f6d4e7960f84a0d2e211478d6324dbfS3VersionKeyD1F874DF" + } + ] + } + ] + } + ] + ] + }, + "Namespace": "default", + "CreateNamespace": true + }, + "DependsOn": [ + "ClusterKubectlReadyBarrier200052AF" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "awscdkawseksClusterResourceProviderNestedStackawscdkawseksClusterResourceProviderNestedStackResource9827C454": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.test-region.", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "AssetParameters4dd1961319ef02ebb87375d051b83d8f755348021a7224d0bd940f6f310fedc0S3BucketE1B1B31D" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters4dd1961319ef02ebb87375d051b83d8f755348021a7224d0bd940f6f310fedc0S3VersionKey874F0E87" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters4dd1961319ef02ebb87375d051b83d8f755348021a7224d0bd940f6f310fedc0S3VersionKey874F0E87" + } + ] + } + ] + } + ] + ] + }, + "Parameters": { + "referencetoawscdkekshelmtestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket085ACFA1Ref": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097" + }, + "referencetoawscdkekshelmtestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey455E4CBARef": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224" + }, + "referencetoawscdkekshelmtestClusterCreationRole906A8995Arn": { + "Fn::GetAtt": [ + "ClusterCreationRole360249B6", + "Arn" + ] + }, + "referencetoawscdkekshelmtestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3BucketE22C6D82Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E" + }, + "referencetoawscdkekshelmtestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey73B77719Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF" + }, + "referencetoawscdkekshelmtestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket0A18730ERef": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" + }, + "referencetoawscdkekshelmtestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKey0E52DE29Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" + } + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.test-region.", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "AssetParametersa05e72b493adce669e87efd9e6b3d07cbfa8fc01fc9bc69e0825595d83d3eb62S3Bucket146F5F41" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersa05e72b493adce669e87efd9e6b3d07cbfa8fc01fc9bc69e0825595d83d3eb62S3VersionKeyF2F0D7BB" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersa05e72b493adce669e87efd9e6b3d07cbfa8fc01fc9bc69e0825595d83d3eb62S3VersionKeyF2F0D7BB" + } + ] + } + ] + } + ] + ] + }, + "Parameters": { + "referencetoawscdkekshelmtestCluster35BA672BArn": { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "Arn" + ] + }, + "referencetoawscdkekshelmtestClusterCreationRole906A8995Arn": { + "Fn::GetAtt": [ + "ClusterCreationRole360249B6", + "Arn" + ] + }, + "referencetoawscdkekshelmtestAssetParametersd65fbdc11b108e0386ed8577c454d4544f6d4e7960f84a0d2e211478d6324dbfS3Bucket5EAB45FARef": { + "Ref": "AssetParametersd65fbdc11b108e0386ed8577c454d4544f6d4e7960f84a0d2e211478d6324dbfS3BucketBFD29DFB" + }, + "referencetoawscdkekshelmtestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3BucketC59436A3Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3" + }, + "referencetoawscdkekshelmtestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKey5ECB4296Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291" + }, + "referencetoawscdkekshelmtestVpcPrivateSubnet1Subnet3D2B5C0BRef": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + "referencetoawscdkekshelmtestVpcPrivateSubnet2SubnetF5E4AFE9Ref": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + }, + "referencetoawscdkekshelmtestVpcPrivateSubnet3Subnet7C40A2F3Ref": { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + }, + "referencetoawscdkekshelmtestCluster35BA672BClusterSecurityGroupId": { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "ClusterSecurityGroupId" + ] + }, + "referencetoawscdkekshelmtestAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketDAA2F4FARef": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" + }, + "referencetoawscdkekshelmtestAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey9A7BBFDCRef": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" + }, + "referencetoawscdkekshelmtestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket355FB348Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" + }, + "referencetoawscdkekshelmtestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyA7F169F4Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" + }, + "referencetoawscdkekshelmtestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket0A18730ERef": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" + }, + "referencetoawscdkekshelmtestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKey0E52DE29Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" + } + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "Outputs": { + "ClusterConfigCommand43AAE40F": { + "Value": { + "Fn::Join": [ + "", + [ + "aws eks update-kubeconfig --name ", + { + "Ref": "Cluster9EE0221C" + }, + " --region test-region --role-arn ", + { + "Fn::GetAtt": [ + "AdminRole38563C57", + "Arn" + ] + } + ] + ] + } + }, + "ClusterGetTokenCommand06AE992E": { + "Value": { + "Fn::Join": [ + "", + [ + "aws eks get-token --cluster-name ", + { + "Ref": "Cluster9EE0221C" + }, + " --region test-region --role-arn ", + { + "Fn::GetAtt": [ + "AdminRole38563C57", + "Arn" + ] + } + ] + ] + } + } + }, + "Parameters": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097": { + "Type": "String", + "Description": "S3 bucket for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" + }, + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224": { + "Type": "String", + "Description": "S3 key for asset version \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" + }, + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeArtifactHash515E16AE": { + "Type": "String", + "Description": "Artifact hash for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" + }, + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E": { + "Type": "String", + "Description": "S3 bucket for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" + }, + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF": { + "Type": "String", + "Description": "S3 key for asset version \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" + }, + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647ArtifactHashE94F67E3": { + "Type": "String", + "Description": "Artifact hash for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" + }, + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { + "Type": "String", + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" + }, + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { + "Type": "String", + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" + }, + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { + "Type": "String", + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" + }, + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3": { + "Type": "String", + "Description": "S3 bucket for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" + }, + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291": { + "Type": "String", + "Description": "S3 key for asset version \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" + }, + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8ArtifactHashA4AB6609": { + "Type": "String", + "Description": "Artifact hash for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" + }, + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488": { + "Type": "String", + "Description": "S3 bucket for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" + }, + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2": { + "Type": "String", + "Description": "S3 key for asset version \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" + }, + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95ArtifactHash16B60F6C": { + "Type": "String", + "Description": "Artifact hash for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" + }, + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { + "Type": "String", + "Description": "S3 bucket for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" + }, + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565": { + "Type": "String", + "Description": "S3 key for asset version \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" + }, + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eArtifactHash4654D012": { + "Type": "String", + "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" + }, + "AssetParametersd65fbdc11b108e0386ed8577c454d4544f6d4e7960f84a0d2e211478d6324dbfS3BucketBFD29DFB": { + "Type": "String", + "Description": "S3 bucket for asset \"d65fbdc11b108e0386ed8577c454d4544f6d4e7960f84a0d2e211478d6324dbf\"" + }, + "AssetParametersd65fbdc11b108e0386ed8577c454d4544f6d4e7960f84a0d2e211478d6324dbfS3VersionKeyD1F874DF": { + "Type": "String", + "Description": "S3 key for asset version \"d65fbdc11b108e0386ed8577c454d4544f6d4e7960f84a0d2e211478d6324dbf\"" + }, + "AssetParametersd65fbdc11b108e0386ed8577c454d4544f6d4e7960f84a0d2e211478d6324dbfArtifactHash5A9B7775": { + "Type": "String", + "Description": "Artifact hash for asset \"d65fbdc11b108e0386ed8577c454d4544f6d4e7960f84a0d2e211478d6324dbf\"" + }, + "AssetParameters4dd1961319ef02ebb87375d051b83d8f755348021a7224d0bd940f6f310fedc0S3BucketE1B1B31D": { + "Type": "String", + "Description": "S3 bucket for asset \"4dd1961319ef02ebb87375d051b83d8f755348021a7224d0bd940f6f310fedc0\"" + }, + "AssetParameters4dd1961319ef02ebb87375d051b83d8f755348021a7224d0bd940f6f310fedc0S3VersionKey874F0E87": { + "Type": "String", + "Description": "S3 key for asset version \"4dd1961319ef02ebb87375d051b83d8f755348021a7224d0bd940f6f310fedc0\"" + }, + "AssetParameters4dd1961319ef02ebb87375d051b83d8f755348021a7224d0bd940f6f310fedc0ArtifactHash9ED35B8F": { + "Type": "String", + "Description": "Artifact hash for asset \"4dd1961319ef02ebb87375d051b83d8f755348021a7224d0bd940f6f310fedc0\"" + }, + "AssetParametersa05e72b493adce669e87efd9e6b3d07cbfa8fc01fc9bc69e0825595d83d3eb62S3Bucket146F5F41": { + "Type": "String", + "Description": "S3 bucket for asset \"a05e72b493adce669e87efd9e6b3d07cbfa8fc01fc9bc69e0825595d83d3eb62\"" + }, + "AssetParametersa05e72b493adce669e87efd9e6b3d07cbfa8fc01fc9bc69e0825595d83d3eb62S3VersionKeyF2F0D7BB": { + "Type": "String", + "Description": "S3 key for asset version \"a05e72b493adce669e87efd9e6b3d07cbfa8fc01fc9bc69e0825595d83d3eb62\"" + }, + "AssetParametersa05e72b493adce669e87efd9e6b3d07cbfa8fc01fc9bc69e0825595d83d3eb62ArtifactHashC2BFAFC3": { + "Type": "String", + "Description": "Artifact hash for asset \"a05e72b493adce669e87efd9e6b3d07cbfa8fc01fc9bc69e0825595d83d3eb62\"" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-helm-asset.ts b/packages/@aws-cdk/aws-eks/test/integ.eks-helm-asset.ts new file mode 100644 index 0000000000000..447ae3dac82b7 --- /dev/null +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-helm-asset.ts @@ -0,0 +1,59 @@ +import * as path from 'path'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as iam from '@aws-cdk/aws-iam'; +import { Asset } from '@aws-cdk/aws-s3-assets'; +import { App } from '@aws-cdk/core'; +import * as eks from '../lib/index'; +import { TestStack } from './util'; + +class EksClusterStack extends TestStack { + private cluster: eks.Cluster; + private vpc: ec2.IVpc; + + constructor(scope: App, id: string) { + super(scope, id); + + // allow all account users to assume this role in order to admin the cluster + const mastersRole = new iam.Role(this, 'AdminRole', { + assumedBy: new iam.AccountRootPrincipal(), + }); + + // just need one nat gateway to simplify the test + this.vpc = new ec2.Vpc(this, 'Vpc', { maxAzs: 3, natGateways: 1 }); + + // create the cluster with a default nodegroup capacity + this.cluster = new eks.Cluster(this, 'Cluster', { + vpc: this.vpc, + mastersRole, + defaultCapacity: 2, + version: eks.KubernetesVersion.V1_21, + tags: { + foo: 'bar', + }, + clusterLogging: [ + eks.ClusterLoggingTypes.API, + eks.ClusterLoggingTypes.AUTHENTICATOR, + eks.ClusterLoggingTypes.SCHEDULER, + ], + }); + + this.assertHelmChartAsset(); + } + + private assertHelmChartAsset() { + // get helm chart from Asset + const chartAsset = new Asset(this, 'ChartAsset', { + path: path.join(__dirname, 'test-chart'), + }); + this.cluster.addHelmChart('test-chart', { + chartAsset: chartAsset, + }); + } +} + +const app = new App(); + +new EksClusterStack(app, 'aws-cdk-eks-helm-test'); + +app.synth(); + diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-inference.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-inference.expected.json index 5c109d1e3db26..ea0f68dd56ea8 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-inference.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-inference.expected.json @@ -650,54 +650,30 @@ }, { "Action": [ + "ec2:DescribeDhcpOptions", + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeRouteTables", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeVpcs", "eks:CreateCluster", + "eks:CreateFargateProfile", + "eks:DeleteCluster", + "eks:DeleteFargateProfile", "eks:DescribeCluster", + "eks:DescribeFargateProfile", "eks:DescribeUpdate", - "eks:DeleteCluster", - "eks:UpdateClusterVersion", - "eks:UpdateClusterConfig", - "eks:CreateFargateProfile", "eks:TagResource", - "eks:UntagResource" - ], - "Effect": "Allow", - "Resource": [ - "*" - ] - }, - { - "Action": [ - "eks:DescribeFargateProfile", - "eks:DeleteFargateProfile" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ + "eks:UntagResource", + "eks:UpdateClusterConfig", + "eks:UpdateClusterVersion", + "iam:CreateServiceLinkedRole", "iam:GetRole", "iam:listAttachedRolePolicies" ], "Effect": "Allow", "Resource": "*" - }, - { - "Action": "iam:CreateServiceLinkedRole", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ec2:DescribeInstances", - "ec2:DescribeNetworkInterfaces", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSubnets", - "ec2:DescribeRouteTables", - "ec2:DescribeDhcpOptions", - "ec2:DescribeVpcs" - ], - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -1449,7 +1425,7 @@ }, "/", { - "Ref": "AssetParameters68b9e8362de179062ef4fa2e507bcdde8ad60822541789a054589bdfefd639c3S3BucketB433C27A" + "Ref": "AssetParametersd2c6c18da00a775fab79c667ce3e22b7bb82981bd887f3558a308b7ba4fcd1e1S3Bucket14A467A8" }, "/", { @@ -1459,7 +1435,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters68b9e8362de179062ef4fa2e507bcdde8ad60822541789a054589bdfefd639c3S3VersionKey47D97053" + "Ref": "AssetParametersd2c6c18da00a775fab79c667ce3e22b7bb82981bd887f3558a308b7ba4fcd1e1S3VersionKeyC8758BD5" } ] } @@ -1472,7 +1448,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters68b9e8362de179062ef4fa2e507bcdde8ad60822541789a054589bdfefd639c3S3VersionKey47D97053" + "Ref": "AssetParametersd2c6c18da00a775fab79c667ce3e22b7bb82981bd887f3558a308b7ba4fcd1e1S3VersionKeyC8758BD5" } ] } @@ -1482,11 +1458,11 @@ ] }, "Parameters": { - "referencetoawscdkeksclusterinferencetestAssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket61E9D480Ref": { - "Ref": "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1B280681" + "referencetoawscdkeksclusterinferencetestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket59232CCDRef": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097" }, - "referencetoawscdkeksclusterinferencetestAssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyE5228CD2Ref": { - "Ref": "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB1E02791" + "referencetoawscdkeksclusterinferencetestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey7F3246C3Ref": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224" }, "referencetoawscdkeksclusterinferencetestClusterCreationRoleE75B6E1BArn": { "Fn::GetAtt": [ @@ -1494,17 +1470,17 @@ "Arn" ] }, - "referencetoawscdkeksclusterinferencetestAssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3Bucket006FF27FRef": { - "Ref": "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3Bucket9AE1EC0F" + "referencetoawscdkeksclusterinferencetestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket3B9C0B5CRef": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E" }, - "referencetoawscdkeksclusterinferencetestAssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3VersionKey6EF1226BRef": { - "Ref": "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3VersionKey451EAA56" + "referencetoawscdkeksclusterinferencetestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKeyC02F3925Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF" }, - "referencetoawscdkeksclusterinferencetestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketE649D818Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawscdkeksclusterinferencetestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketFC7DE683Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawscdkeksclusterinferencetestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey46F53AF7Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawscdkeksclusterinferencetestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyA3D6C7B6Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1524,7 +1500,7 @@ }, "/", { - "Ref": "AssetParameters246f53c56ca8842b5b10a869d641017e2a78a7b196a5c32600abe420c4013dd8S3BucketCEB8731F" + "Ref": "AssetParameters569a574833bab6f6544cebaa31935f7371f41aa0a926797d4e65b5cbbcc13d47S3Bucket690AEFE0" }, "/", { @@ -1534,7 +1510,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters246f53c56ca8842b5b10a869d641017e2a78a7b196a5c32600abe420c4013dd8S3VersionKey31DCE19E" + "Ref": "AssetParameters569a574833bab6f6544cebaa31935f7371f41aa0a926797d4e65b5cbbcc13d47S3VersionKey2F21E0C1" } ] } @@ -1547,7 +1523,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters246f53c56ca8842b5b10a869d641017e2a78a7b196a5c32600abe420c4013dd8S3VersionKey31DCE19E" + "Ref": "AssetParameters569a574833bab6f6544cebaa31935f7371f41aa0a926797d4e65b5cbbcc13d47S3VersionKey2F21E0C1" } ] } @@ -1569,11 +1545,11 @@ "Arn" ] }, - "referencetoawscdkeksclusterinferencetestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketF92D0EC1Ref": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" + "referencetoawscdkeksclusterinferencetestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket74E76A7FRef": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3" }, - "referencetoawscdkeksclusterinferencetestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey32B182B9Ref": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" + "referencetoawscdkeksclusterinferencetestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKey690A3E90Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291" }, "referencetoawscdkeksclusterinferencetestVpcPrivateSubnet1Subnet57B9547BRef": { "Ref": "VpcPrivateSubnet1Subnet536B997A" @@ -1590,11 +1566,11 @@ "ClusterSecurityGroupId" ] }, - "referencetoawscdkeksclusterinferencetestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketA131D9DBRef": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" + "referencetoawscdkeksclusterinferencetestAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3Bucket334D9D06Ref": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" }, - "referencetoawscdkeksclusterinferencetestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKey492BD4E4Ref": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + "referencetoawscdkeksclusterinferencetestAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKeyC479FB06Ref": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" }, "referencetoawscdkeksclusterinferencetestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketB71217D7Ref": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" @@ -1602,11 +1578,11 @@ "referencetoawscdkeksclusterinferencetestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyAAC64236Ref": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, - "referencetoawscdkeksclusterinferencetestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketE649D818Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawscdkeksclusterinferencetestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketFC7DE683Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawscdkeksclusterinferencetestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey46F53AF7Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawscdkeksclusterinferencetestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyA3D6C7B6Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1734,69 +1710,62 @@ }, { "Action": [ + "acm:DescribeCertificate", + "acm:ListCertificates", + "cognito-idp:DescribeUserPoolClient", + "ec2:AuthorizeSecurityGroupIngress", + "ec2:CreateSecurityGroup", "ec2:DescribeAccountAttributes", "ec2:DescribeAddresses", "ec2:DescribeAvailabilityZones", - "ec2:DescribeInternetGateways", - "ec2:DescribeVpcs", - "ec2:DescribeVpcPeeringConnections", - "ec2:DescribeSubnets", - "ec2:DescribeSecurityGroups", + "ec2:DescribeCoipPools", "ec2:DescribeInstances", + "ec2:DescribeInternetGateways", "ec2:DescribeNetworkInterfaces", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", "ec2:DescribeTags", + "ec2:DescribeVpcPeeringConnections", + "ec2:DescribeVpcs", "ec2:GetCoipPoolUsage", - "ec2:DescribeCoipPools", - "elasticloadbalancing:DescribeLoadBalancers", - "elasticloadbalancing:DescribeLoadBalancerAttributes", - "elasticloadbalancing:DescribeListeners", + "ec2:RevokeSecurityGroupIngress", + "elasticloadbalancing:AddListenerCertificates", + "elasticloadbalancing:CreateListener", + "elasticloadbalancing:CreateRule", + "elasticloadbalancing:DeleteListener", + "elasticloadbalancing:DeleteRule", "elasticloadbalancing:DescribeListenerCertificates", - "elasticloadbalancing:DescribeSSLPolicies", + "elasticloadbalancing:DescribeListeners", + "elasticloadbalancing:DescribeLoadBalancerAttributes", + "elasticloadbalancing:DescribeLoadBalancers", "elasticloadbalancing:DescribeRules", - "elasticloadbalancing:DescribeTargetGroups", + "elasticloadbalancing:DescribeSSLPolicies", + "elasticloadbalancing:DescribeTags", "elasticloadbalancing:DescribeTargetGroupAttributes", + "elasticloadbalancing:DescribeTargetGroups", "elasticloadbalancing:DescribeTargetHealth", - "elasticloadbalancing:DescribeTags" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "cognito-idp:DescribeUserPoolClient", - "acm:ListCertificates", - "acm:DescribeCertificate", - "iam:ListServerCertificates", + "elasticloadbalancing:ModifyListener", + "elasticloadbalancing:ModifyRule", + "elasticloadbalancing:RemoveListenerCertificates", + "elasticloadbalancing:SetWebAcl", "iam:GetServerCertificate", - "waf-regional:GetWebACL", - "waf-regional:GetWebACLForResource", + "iam:ListServerCertificates", + "shield:CreateProtection", + "shield:DeleteProtection", + "shield:DescribeProtection", + "shield:GetSubscriptionState", "waf-regional:AssociateWebACL", "waf-regional:DisassociateWebACL", - "wafv2:GetWebACL", - "wafv2:GetWebACLForResource", + "waf-regional:GetWebACL", + "waf-regional:GetWebACLForResource", "wafv2:AssociateWebACL", "wafv2:DisassociateWebACL", - "shield:GetSubscriptionState", - "shield:DescribeProtection", - "shield:CreateProtection", - "shield:DeleteProtection" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ec2:AuthorizeSecurityGroupIngress", - "ec2:RevokeSecurityGroupIngress" + "wafv2:GetWebACL", + "wafv2:GetWebACLForResource" ], "Effect": "Allow", "Resource": "*" }, - { - "Action": "ec2:CreateSecurityGroup", - "Effect": "Allow", - "Resource": "*" - }, { "Action": "ec2:CreateTags", "Condition": { @@ -1827,8 +1796,16 @@ { "Action": [ "ec2:AuthorizeSecurityGroupIngress", + "ec2:DeleteSecurityGroup", "ec2:RevokeSecurityGroupIngress", - "ec2:DeleteSecurityGroup" + "elasticloadbalancing:DeleteLoadBalancer", + "elasticloadbalancing:DeleteTargetGroup", + "elasticloadbalancing:ModifyLoadBalancerAttributes", + "elasticloadbalancing:ModifyTargetGroup", + "elasticloadbalancing:ModifyTargetGroupAttributes", + "elasticloadbalancing:SetIpAddressType", + "elasticloadbalancing:SetSecurityGroups", + "elasticloadbalancing:SetSubnets" ], "Condition": { "Null": { @@ -1851,16 +1828,6 @@ "Effect": "Allow", "Resource": "*" }, - { - "Action": [ - "elasticloadbalancing:CreateListener", - "elasticloadbalancing:DeleteListener", - "elasticloadbalancing:CreateRule", - "elasticloadbalancing:DeleteRule" - ], - "Effect": "Allow", - "Resource": "*" - }, { "Action": [ "elasticloadbalancing:AddTags", @@ -1874,9 +1841,9 @@ }, "Effect": "Allow", "Resource": [ - "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*", + "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*", "arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*", - "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*" + "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*" ] }, { @@ -1886,49 +1853,19 @@ ], "Effect": "Allow", "Resource": [ - "arn:aws:elasticloadbalancing:*:*:listener/net/*/*/*", - "arn:aws:elasticloadbalancing:*:*:listener/app/*/*/*", + "arn:aws:elasticloadbalancing:*:*:listener-rule/app/*/*/*", "arn:aws:elasticloadbalancing:*:*:listener-rule/net/*/*/*", - "arn:aws:elasticloadbalancing:*:*:listener-rule/app/*/*/*" + "arn:aws:elasticloadbalancing:*:*:listener/app/*/*/*", + "arn:aws:elasticloadbalancing:*:*:listener/net/*/*/*" ] }, { "Action": [ - "elasticloadbalancing:ModifyLoadBalancerAttributes", - "elasticloadbalancing:SetIpAddressType", - "elasticloadbalancing:SetSecurityGroups", - "elasticloadbalancing:SetSubnets", - "elasticloadbalancing:DeleteLoadBalancer", - "elasticloadbalancing:ModifyTargetGroup", - "elasticloadbalancing:ModifyTargetGroupAttributes", - "elasticloadbalancing:DeleteTargetGroup" - ], - "Condition": { - "Null": { - "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" - } - }, - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "elasticloadbalancing:RegisterTargets", - "elasticloadbalancing:DeregisterTargets" + "elasticloadbalancing:DeregisterTargets", + "elasticloadbalancing:RegisterTargets" ], "Effect": "Allow", "Resource": "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*" - }, - { - "Action": [ - "elasticloadbalancing:SetWebAcl", - "elasticloadbalancing:ModifyListener", - "elasticloadbalancing:AddListenerCertificates", - "elasticloadbalancing:RemoveListenerCertificates", - "elasticloadbalancing:ModifyRule" - ], - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -2123,7 +2060,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3BucketF7BC1777" + "Ref": "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3Bucket211A9156" }, "S3Key": { "Fn::Join": [ @@ -2136,7 +2073,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3VersionKey1C340B30" + "Ref": "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3VersionKey822D04EC" } ] } @@ -2149,7 +2086,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3VersionKey1C340B30" + "Ref": "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3VersionKey822D04EC" } ] } @@ -2201,7 +2138,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3BucketB7E1A9C0" + "Ref": "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3Bucket6F458959" }, "S3Key": { "Fn::Join": [ @@ -2214,7 +2151,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3VersionKey542FDEBD" + "Ref": "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3VersionKeyBDD0572E" } ] } @@ -2227,7 +2164,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3VersionKey542FDEBD" + "Ref": "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3VersionKeyBDD0572E" } ] } @@ -2296,65 +2233,65 @@ } }, "Parameters": { - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1B280681": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097": { "Type": "String", - "Description": "S3 bucket for asset \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "S3 bucket for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB1E02791": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224": { "Type": "String", - "Description": "S3 key for asset version \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "S3 key for asset version \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665ArtifactHash9EA5AC29": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeArtifactHash515E16AE": { "Type": "String", - "Description": "Artifact hash for asset \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "Artifact hash for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3Bucket9AE1EC0F": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E": { "Type": "String", - "Description": "S3 bucket for asset \"00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5af\"" + "Description": "S3 bucket for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3VersionKey451EAA56": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF": { "Type": "String", - "Description": "S3 key for asset version \"00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5af\"" + "Description": "S3 key for asset version \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afArtifactHash761F4689": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647ArtifactHashE94F67E3": { "Type": "String", - "Description": "Artifact hash for asset \"00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5af\"" + "Description": "Artifact hash for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { "Type": "String", - "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { "Type": "String", - "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { "Type": "String", - "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3": { "Type": "String", - "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 bucket for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291": { "Type": "String", - "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 key for asset version \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8ArtifactHashA4AB6609": { "Type": "String", - "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "Artifact hash for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488": { "Type": "String", - "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 bucket for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2": { "Type": "String", - "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 key for asset version \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95ArtifactHash16B60F6C": { "Type": "String", - "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "Artifact hash for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", @@ -2368,57 +2305,57 @@ "Type": "String", "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3BucketF7BC1777": { + "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3Bucket211A9156": { "Type": "String", - "Description": "S3 bucket for asset \"b7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4\"" + "Description": "S3 bucket for asset \"5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2\"" }, - "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3VersionKey1C340B30": { + "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3VersionKey822D04EC": { "Type": "String", - "Description": "S3 key for asset version \"b7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4\"" + "Description": "S3 key for asset version \"5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2\"" }, - "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4ArtifactHashD6EA1BC7": { + "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2ArtifactHashCA4A1831": { "Type": "String", - "Description": "Artifact hash for asset \"b7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4\"" + "Description": "Artifact hash for asset \"5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2\"" }, - "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3BucketB7E1A9C0": { + "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3Bucket6F458959": { "Type": "String", - "Description": "S3 bucket for asset \"6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3\"" + "Description": "S3 bucket for asset \"f850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4\"" }, - "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3VersionKey542FDEBD": { + "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3VersionKeyBDD0572E": { "Type": "String", - "Description": "S3 key for asset version \"6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3\"" + "Description": "S3 key for asset version \"f850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4\"" }, - "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3ArtifactHash5E61FCA5": { + "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4ArtifactHash4D5DD9E9": { "Type": "String", - "Description": "Artifact hash for asset \"6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3\"" + "Description": "Artifact hash for asset \"f850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4\"" }, - "AssetParameters68b9e8362de179062ef4fa2e507bcdde8ad60822541789a054589bdfefd639c3S3BucketB433C27A": { + "AssetParametersd2c6c18da00a775fab79c667ce3e22b7bb82981bd887f3558a308b7ba4fcd1e1S3Bucket14A467A8": { "Type": "String", - "Description": "S3 bucket for asset \"68b9e8362de179062ef4fa2e507bcdde8ad60822541789a054589bdfefd639c3\"" + "Description": "S3 bucket for asset \"d2c6c18da00a775fab79c667ce3e22b7bb82981bd887f3558a308b7ba4fcd1e1\"" }, - "AssetParameters68b9e8362de179062ef4fa2e507bcdde8ad60822541789a054589bdfefd639c3S3VersionKey47D97053": { + "AssetParametersd2c6c18da00a775fab79c667ce3e22b7bb82981bd887f3558a308b7ba4fcd1e1S3VersionKeyC8758BD5": { "Type": "String", - "Description": "S3 key for asset version \"68b9e8362de179062ef4fa2e507bcdde8ad60822541789a054589bdfefd639c3\"" + "Description": "S3 key for asset version \"d2c6c18da00a775fab79c667ce3e22b7bb82981bd887f3558a308b7ba4fcd1e1\"" }, - "AssetParameters68b9e8362de179062ef4fa2e507bcdde8ad60822541789a054589bdfefd639c3ArtifactHashDE01134B": { + "AssetParametersd2c6c18da00a775fab79c667ce3e22b7bb82981bd887f3558a308b7ba4fcd1e1ArtifactHashEB557581": { "Type": "String", - "Description": "Artifact hash for asset \"68b9e8362de179062ef4fa2e507bcdde8ad60822541789a054589bdfefd639c3\"" + "Description": "Artifact hash for asset \"d2c6c18da00a775fab79c667ce3e22b7bb82981bd887f3558a308b7ba4fcd1e1\"" }, - "AssetParameters246f53c56ca8842b5b10a869d641017e2a78a7b196a5c32600abe420c4013dd8S3BucketCEB8731F": { + "AssetParameters569a574833bab6f6544cebaa31935f7371f41aa0a926797d4e65b5cbbcc13d47S3Bucket690AEFE0": { "Type": "String", - "Description": "S3 bucket for asset \"246f53c56ca8842b5b10a869d641017e2a78a7b196a5c32600abe420c4013dd8\"" + "Description": "S3 bucket for asset \"569a574833bab6f6544cebaa31935f7371f41aa0a926797d4e65b5cbbcc13d47\"" }, - "AssetParameters246f53c56ca8842b5b10a869d641017e2a78a7b196a5c32600abe420c4013dd8S3VersionKey31DCE19E": { + "AssetParameters569a574833bab6f6544cebaa31935f7371f41aa0a926797d4e65b5cbbcc13d47S3VersionKey2F21E0C1": { "Type": "String", - "Description": "S3 key for asset version \"246f53c56ca8842b5b10a869d641017e2a78a7b196a5c32600abe420c4013dd8\"" + "Description": "S3 key for asset version \"569a574833bab6f6544cebaa31935f7371f41aa0a926797d4e65b5cbbcc13d47\"" }, - "AssetParameters246f53c56ca8842b5b10a869d641017e2a78a7b196a5c32600abe420c4013dd8ArtifactHashE4FBA459": { + "AssetParameters569a574833bab6f6544cebaa31935f7371f41aa0a926797d4e65b5cbbcc13d47ArtifactHash2BCCFD09": { "Type": "String", - "Description": "Artifact hash for asset \"246f53c56ca8842b5b10a869d641017e2a78a7b196a5c32600abe420c4013dd8\"" + "Description": "Artifact hash for asset \"569a574833bab6f6544cebaa31935f7371f41aa0a926797d4e65b5cbbcc13d47\"" }, "SsmParameterValueawsserviceeksoptimizedami121amazonlinux2gpurecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { "Type": "AWS::SSM::Parameter::Value", "Default": "/aws/service/eks/optimized-ami/1.21/amazon-linux-2-gpu/recommended/image_id" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-oidc-provider.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-oidc-provider.expected.json index 0f0a5c61cdf67..8a9b6ea626e05 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-oidc-provider.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-oidc-provider.expected.json @@ -79,7 +79,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3BucketF7BC1777" + "Ref": "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3Bucket211A9156" }, "S3Key": { "Fn::Join": [ @@ -92,7 +92,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3VersionKey1C340B30" + "Ref": "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3VersionKey822D04EC" } ] } @@ -105,7 +105,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3VersionKey1C340B30" + "Ref": "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3VersionKey822D04EC" } ] } @@ -132,17 +132,17 @@ } }, "Parameters": { - "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3BucketF7BC1777": { + "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3Bucket211A9156": { "Type": "String", - "Description": "S3 bucket for asset \"b7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4\"" + "Description": "S3 bucket for asset \"5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2\"" }, - "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3VersionKey1C340B30": { + "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3VersionKey822D04EC": { "Type": "String", - "Description": "S3 key for asset version \"b7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4\"" + "Description": "S3 key for asset version \"5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2\"" }, - "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4ArtifactHashD6EA1BC7": { + "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2ArtifactHashCA4A1831": { "Type": "String", - "Description": "Artifact hash for asset \"b7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4\"" + "Description": "Artifact hash for asset \"5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json b/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json index 72efc126137d7..0460488a7875d 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json @@ -704,73 +704,47 @@ { "Action": "iam:PassRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "FargateClusterRole8E36B33A", - "Arn" - ] - } - }, - { - "Action": [ - "eks:CreateCluster", - "eks:DescribeCluster", - "eks:DescribeUpdate", - "eks:DeleteCluster", - "eks:UpdateClusterVersion", - "eks:UpdateClusterConfig", - "eks:CreateFargateProfile", - "eks:TagResource", - "eks:UntagResource" - ], - "Effect": "Allow", "Resource": [ - "*" + { + "Fn::GetAtt": [ + "FargateClusterRole8E36B33A", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "FargateClusterfargateprofiledefaultPodExecutionRole66F2610E", + "Arn" + ] + } ] }, { "Action": [ - "eks:DescribeFargateProfile", - "eks:DeleteFargateProfile" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "iam:GetRole", - "iam:listAttachedRolePolicies" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "iam:CreateServiceLinkedRole", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ + "ec2:DescribeDhcpOptions", "ec2:DescribeInstances", "ec2:DescribeNetworkInterfaces", + "ec2:DescribeRouteTables", "ec2:DescribeSecurityGroups", "ec2:DescribeSubnets", - "ec2:DescribeRouteTables", - "ec2:DescribeDhcpOptions", - "ec2:DescribeVpcs" + "ec2:DescribeVpcs", + "eks:CreateCluster", + "eks:CreateFargateProfile", + "eks:DeleteCluster", + "eks:DeleteFargateProfile", + "eks:DescribeCluster", + "eks:DescribeFargateProfile", + "eks:DescribeUpdate", + "eks:TagResource", + "eks:UntagResource", + "eks:UpdateClusterConfig", + "eks:UpdateClusterVersion", + "iam:CreateServiceLinkedRole", + "iam:GetRole", + "iam:listAttachedRolePolicies" ], "Effect": "Allow", "Resource": "*" - }, - { - "Action": "iam:PassRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "FargateClusterfargateprofiledefaultPodExecutionRole66F2610E", - "Arn" - ] - } } ], "Version": "2012-10-17" @@ -1125,7 +1099,7 @@ }, "/", { - "Ref": "AssetParameters9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566S3BucketBE3E205B" + "Ref": "AssetParameters68cf6214335c0f88299431e6c7fac4d9d46a42a5f526d6a109ebe35d48cef8f3S3Bucket4539F9A2" }, "/", { @@ -1135,7 +1109,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566S3VersionKeyAEF361AA" + "Ref": "AssetParameters68cf6214335c0f88299431e6c7fac4d9d46a42a5f526d6a109ebe35d48cef8f3S3VersionKey0A53DFAE" } ] } @@ -1148,7 +1122,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566S3VersionKeyAEF361AA" + "Ref": "AssetParameters68cf6214335c0f88299431e6c7fac4d9d46a42a5f526d6a109ebe35d48cef8f3S3VersionKey0A53DFAE" } ] } @@ -1158,29 +1132,29 @@ ] }, "Parameters": { + "referencetoawscdkeksfargateclustertestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3BucketDC76B2E5Ref": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097" + }, + "referencetoawscdkeksfargateclustertestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKeyA7127FF2Ref": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224" + }, "referencetoawscdkeksfargateclustertestFargateClusterCreationRoleFB2229CFArn": { "Fn::GetAtt": [ "FargateClusterCreationRole8C524AD8", "Arn" ] }, - "referencetoawscdkeksfargateclustertestAssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket5CC464F5Ref": { - "Ref": "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket5B1EB03C" - }, - "referencetoawscdkeksfargateclustertestAssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey610B35BCRef": { - "Ref": "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey51E064E9" - }, - "referencetoawscdkeksfargateclustertestAssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3Bucket3165858DRef": { - "Ref": "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3Bucket40405135" + "referencetoawscdkeksfargateclustertestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket33183031Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E" }, - "referencetoawscdkeksfargateclustertestAssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKey1A1207D1Ref": { - "Ref": "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKey50B477EB" + "referencetoawscdkeksfargateclustertestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKeyC9143EC9Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF" }, - "referencetoawscdkeksfargateclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket8EEF0922Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawscdkeksfargateclustertestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket3204D5E8Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawscdkeksfargateclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey47333356Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawscdkeksfargateclustertestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKey4ABEA862Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1200,7 +1174,7 @@ }, "/", { - "Ref": "AssetParameters6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802dS3Bucket92B50C24" + "Ref": "AssetParameters196dc7aaf7b92bd056c4ca55632f53bbd96a92876291800c581e6e9e95458d2fS3BucketD61A27C7" }, "/", { @@ -1210,7 +1184,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802dS3VersionKeyB7108D30" + "Ref": "AssetParameters196dc7aaf7b92bd056c4ca55632f53bbd96a92876291800c581e6e9e95458d2fS3VersionKey6F1AD5E5" } ] } @@ -1223,7 +1197,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802dS3VersionKeyB7108D30" + "Ref": "AssetParameters196dc7aaf7b92bd056c4ca55632f53bbd96a92876291800c581e6e9e95458d2fS3VersionKey6F1AD5E5" } ] } @@ -1245,11 +1219,11 @@ "Arn" ] }, - "referencetoawscdkeksfargateclustertestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC4DF4301Ref": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" + "referencetoawscdkeksfargateclustertestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3BucketC8170E38Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3" }, - "referencetoawscdkeksfargateclustertestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey013AD4DERef": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" + "referencetoawscdkeksfargateclustertestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyFC5034F5Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291" }, "referencetoawscdkeksfargateclustertestFargateClusterDefaultVpcPrivateSubnet1Subnet0278E6BCRef": { "Ref": "FargateClusterDefaultVpcPrivateSubnet1Subnet50EA43AA" @@ -1266,11 +1240,11 @@ "ClusterSecurityGroupId" ] }, - "referencetoawscdkeksfargateclustertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3Bucket4F20F642Ref": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" + "referencetoawscdkeksfargateclustertestAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketB010C1C1Ref": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" }, - "referencetoawscdkeksfargateclustertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyB82BAEF8Ref": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + "referencetoawscdkeksfargateclustertestAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey0118D441Ref": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" }, "referencetoawscdkeksfargateclustertestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket899EE5ABRef": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" @@ -1278,11 +1252,11 @@ "referencetoawscdkeksfargateclustertestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKey1296E713Ref": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, - "referencetoawscdkeksfargateclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket8EEF0922Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawscdkeksfargateclustertestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket3204D5E8Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawscdkeksfargateclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey47333356Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawscdkeksfargateclustertestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKey4ABEA862Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1333,65 +1307,65 @@ } }, "Parameters": { - "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket5B1EB03C": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097": { "Type": "String", - "Description": "S3 bucket for asset \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + "Description": "S3 bucket for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey51E064E9": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224": { "Type": "String", - "Description": "S3 key for asset version \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + "Description": "S3 key for asset version \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4ArtifactHash26192139": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeArtifactHash515E16AE": { "Type": "String", - "Description": "Artifact hash for asset \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + "Description": "Artifact hash for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3Bucket40405135": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E": { "Type": "String", - "Description": "S3 bucket for asset \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" + "Description": "S3 bucket for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKey50B477EB": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF": { "Type": "String", - "Description": "S3 key for asset version \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" + "Description": "S3 key for asset version \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccArtifactHashCC7E7A09": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647ArtifactHashE94F67E3": { "Type": "String", - "Description": "Artifact hash for asset \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" + "Description": "Artifact hash for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { "Type": "String", - "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { "Type": "String", - "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { "Type": "String", - "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3": { "Type": "String", - "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 bucket for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291": { "Type": "String", - "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 key for asset version \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8ArtifactHashA4AB6609": { "Type": "String", - "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "Artifact hash for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488": { "Type": "String", - "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 bucket for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2": { "Type": "String", - "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 key for asset version \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95ArtifactHash16B60F6C": { "Type": "String", - "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "Artifact hash for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", @@ -1405,29 +1379,29 @@ "Type": "String", "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameters9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566S3BucketBE3E205B": { + "AssetParameters68cf6214335c0f88299431e6c7fac4d9d46a42a5f526d6a109ebe35d48cef8f3S3Bucket4539F9A2": { "Type": "String", - "Description": "S3 bucket for asset \"9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566\"" + "Description": "S3 bucket for asset \"68cf6214335c0f88299431e6c7fac4d9d46a42a5f526d6a109ebe35d48cef8f3\"" }, - "AssetParameters9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566S3VersionKeyAEF361AA": { + "AssetParameters68cf6214335c0f88299431e6c7fac4d9d46a42a5f526d6a109ebe35d48cef8f3S3VersionKey0A53DFAE": { "Type": "String", - "Description": "S3 key for asset version \"9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566\"" + "Description": "S3 key for asset version \"68cf6214335c0f88299431e6c7fac4d9d46a42a5f526d6a109ebe35d48cef8f3\"" }, - "AssetParameters9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566ArtifactHashE4B867B7": { + "AssetParameters68cf6214335c0f88299431e6c7fac4d9d46a42a5f526d6a109ebe35d48cef8f3ArtifactHash391F4841": { "Type": "String", - "Description": "Artifact hash for asset \"9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566\"" + "Description": "Artifact hash for asset \"68cf6214335c0f88299431e6c7fac4d9d46a42a5f526d6a109ebe35d48cef8f3\"" }, - "AssetParameters6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802dS3Bucket92B50C24": { + "AssetParameters196dc7aaf7b92bd056c4ca55632f53bbd96a92876291800c581e6e9e95458d2fS3BucketD61A27C7": { "Type": "String", - "Description": "S3 bucket for asset \"6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802d\"" + "Description": "S3 bucket for asset \"196dc7aaf7b92bd056c4ca55632f53bbd96a92876291800c581e6e9e95458d2f\"" }, - "AssetParameters6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802dS3VersionKeyB7108D30": { + "AssetParameters196dc7aaf7b92bd056c4ca55632f53bbd96a92876291800c581e6e9e95458d2fS3VersionKey6F1AD5E5": { "Type": "String", - "Description": "S3 key for asset version \"6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802d\"" + "Description": "S3 key for asset version \"196dc7aaf7b92bd056c4ca55632f53bbd96a92876291800c581e6e9e95458d2f\"" }, - "AssetParameters6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802dArtifactHashE3B502E1": { + "AssetParameters196dc7aaf7b92bd056c4ca55632f53bbd96a92876291800c581e6e9e95458d2fArtifactHash7F76D826": { "Type": "String", - "Description": "Artifact hash for asset \"6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802d\"" + "Description": "Artifact hash for asset \"196dc7aaf7b92bd056c4ca55632f53bbd96a92876291800c581e6e9e95458d2f\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/service-account.test.ts b/packages/@aws-cdk/aws-eks/test/service-account.test.ts index e4db2f6680a97..7ece468d200d0 100644 --- a/packages/@aws-cdk/aws-eks/test/service-account.test.ts +++ b/packages/@aws-cdk/aws-eks/test/service-account.test.ts @@ -174,4 +174,101 @@ describe('service account', () => { }); }); + + describe('Service Account name must follow Kubernetes spec', () => { + test('throw error on capital letters', () => { + // GIVEN + const { cluster } = testFixtureCluster(); + + // WHEN + expect(() => cluster.addServiceAccount('InvalidServiceAccount', { + name: 'XXX', + })) + // THEN + .toThrowError(RangeError); + }); + test('throw error if ends with dot', () => { + // GIVEN + const { cluster } = testFixtureCluster(); + + // WHEN + expect(() => cluster.addServiceAccount('InvalidServiceAccount', { + name: 'test.', + })) + // THEN + .toThrowError(RangeError); + }); + test('dot in the name is allowed', () => { + // GIVEN + const { cluster } = testFixtureCluster(); + const valueWithDot = 'test.name'; + + // WHEN + const sa = cluster.addServiceAccount('InvalidServiceAccount', { + name: valueWithDot, + }); + + // THEN + expect(sa.serviceAccountName).toEqual(valueWithDot); + }); + test('throw error if name is too long', () => { + // GIVEN + const { cluster } = testFixtureCluster(); + + // WHEN + expect(() => cluster.addServiceAccount('InvalidServiceAccount', { + name: 'x'.repeat(255), + })) + // THEN + .toThrowError(RangeError); + }); + }); + + describe('Service Account namespace must follow Kubernetes spec', () => { + test('throw error on capital letters', () => { + // GIVEN + const { cluster } = testFixtureCluster(); + + // WHEN + expect(() => cluster.addServiceAccount('InvalidServiceAccount', { + namespace: 'XXX', + })) + // THEN + .toThrowError(RangeError); + }); + test('throw error if ends with dot', () => { + // GIVEN + const { cluster } = testFixtureCluster(); + + // WHEN + expect(() => cluster.addServiceAccount('InvalidServiceAccount', { + namespace: 'test.', + })) + // THEN + .toThrowError(RangeError); + }); + test('throw error if dot is in the name', () => { + // GIVEN + const { cluster } = testFixtureCluster(); + const valueWithDot = 'test.name'; + + // WHEN + expect(() => cluster.addServiceAccount('InvalidServiceAccount', { + namespace: valueWithDot, + })) + // THEN + .toThrowError(RangeError); + }); + test('throw error if name is too long', () => { + // GIVEN + const { cluster } = testFixtureCluster(); + + // WHEN + expect(() => cluster.addServiceAccount('InvalidServiceAccount', { + namespace: 'x'.repeat(65), + })) + // THEN + .toThrowError(RangeError); + }); + }); }); diff --git a/packages/@aws-cdk/aws-elasticache/package.json b/packages/@aws-cdk/aws-elasticache/package.json index 61fe8976e0ced..50e6f1e715664 100644 --- a/packages/@aws-cdk/aws-elasticache/package.json +++ b/packages/@aws-cdk/aws-elasticache/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/package.json b/packages/@aws-cdk/aws-elasticbeanstalk/package.json index 46506c219aedb..c3813016c4e6a 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/package.json +++ b/packages/@aws-cdk/aws-elasticbeanstalk/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/package.json b/packages/@aws-cdk/aws-elasticloadbalancing/package.json index c43acdd739437..be344c056d66e 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json index deaf25cd5eda8..bc600f17e2974 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json @@ -76,8 +76,8 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-cognito": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json index 76d0b7ba72ee8..b00b793851348 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json @@ -76,8 +76,8 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7", + "@types/jest": "^27.4.1", + "jest": "^27.5.1", "@aws-cdk/aws-ecs": "0.0.0", "@aws-cdk/aws-ecs-patterns": "0.0.0" }, diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts index 2994a437b3929..52bfd666a0ed4 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts @@ -83,15 +83,15 @@ export interface BaseApplicationListenerProps { readonly defaultAction?: ListenerAction; /** - * Allow anyone to connect to this listener + * Allow anyone to connect to the load balancer on the listener port * - * If this is specified, the listener will be opened up to anyone who can reach it. + * If this is specified, the load balancer will be opened up to anyone who can reach it. * For internal load balancers this is anyone in the same VPC. For public load * balancers, this is anyone on the internet. * * If you want to be more selective about who can access this load * balancer, set this to `false` and use the listener's `connections` - * object to selectively grant access to the listener. + * object to selectively grant access to the load balancer on the listener port. * * @default true */ @@ -858,7 +858,8 @@ export interface AddApplicationTargetsProps extends AddRuleProps { /** * Health check configuration * - * @default No health check + * @default - The default value for each property in this configuration varies depending on the target. + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-targetgroup.html#aws-resource-elasticloadbalancingv2-targetgroup-properties */ readonly healthCheck?: HealthCheck; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts index cf34ee5a7857e..98bfdc90796bb 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts @@ -134,6 +134,17 @@ export class ApplicationTargetGroup extends TargetGroupBase implements IApplicat this.protocol = protocol; this.port = port; + // this.targetType is lazy + this.node.addValidation({ + validate: () => { + if (this.targetType === TargetType.LAMBDA && (this.port || this.protocol)) { + return ['port/protocol should not be specified for Lambda targets']; + } else { + return []; + } + }, + }); + this.connectableMembers = []; this.listeners = []; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts index 4cfed265217f5..d48dbafc8202a 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts @@ -361,7 +361,8 @@ export interface AddNetworkTargetsProps { /** * Health check configuration * - * @default No health check + * @default - The default value for each property in this configuration varies depending on the target. + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-targetgroup.html#aws-resource-elasticloadbalancingv2-targetgroup-properties */ readonly healthCheck?: HealthCheck; } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts index 0fcb0f4916c87..b7e13aafae83d 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts @@ -300,4 +300,27 @@ export abstract class BaseLoadBalancer extends Resource { public removeAttribute(key: string) { this.setAttribute(key, undefined); } + + protected validate(): string[] { + const ret = super.validate(); + + // https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-loadbalancer.html#cfn-elasticloadbalancingv2-loadbalancer-name + const loadBalancerName = this.physicalName; + if (!Token.isUnresolved(loadBalancerName) && loadBalancerName !== undefined) { + if (loadBalancerName.length > 32) { + ret.push(`Load balancer name: "${loadBalancerName}" can have a maximum of 32 characters.`); + } + if (loadBalancerName.startsWith('internal-')) { + ret.push(`Load balancer name: "${loadBalancerName}" must not begin with "internal-".`); + } + if (loadBalancerName.startsWith('-') || loadBalancerName.endsWith('-')) { + ret.push(`Load balancer name: "${loadBalancerName}" must not begin or end with a hyphen.`); + } + if (!/^[0-9a-z-]+$/i.test(loadBalancerName)) { + ret.push(`Load balancer name: "${loadBalancerName}" must contain only alphanumeric characters or hyphens.`); + } + } + + return ret; + } } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts index e090b61ce2a2f..0fa47d8670e05 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts @@ -45,7 +45,8 @@ export interface BaseTargetGroupProps { /** * Health check configuration * - * @default - None. + * @default - The default value for each property in this configuration varies depending on the target. + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-targetgroup.html#aws-resource-elasticloadbalancingv2-targetgroup-properties */ readonly healthCheck?: HealthCheck; @@ -338,6 +339,20 @@ export abstract class TargetGroupBase extends CoreConstruct implements ITargetGr ret.push("'vpc' is required for a non-Lambda TargetGroup"); } + // https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-targetgroup.html#cfn-elasticloadbalancingv2-targetgroup-name + const targetGroupName = this.resource.name; + if (!cdk.Token.isUnresolved(targetGroupName) && targetGroupName !== undefined) { + if (targetGroupName.length > 32) { + ret.push(`Target group name: "${targetGroupName}" can have a maximum of 32 characters.`); + } + if (targetGroupName.startsWith('-') || targetGroupName.endsWith('-')) { + ret.push(`Target group name: "${targetGroupName}" must not begin or end with a hyphen.`); + } + if (!/^[0-9a-z-]+$/i.test(targetGroupName)) { + ret.push(`Target group name: "${targetGroupName}" must contain only alphanumeric characters or hyphens.`); + } + } + return ret; } } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json index 4d98964505e22..1668c5ffc511f 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts index 98c25a1e5cb70..57a3aabe6a11b 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts @@ -48,6 +48,35 @@ describe('tests', () => { expect(Object.keys(matches).length).toBe(0); }); + test('Lambda target should not have port set', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + + const tg = new elbv2.ApplicationTargetGroup(stack, 'TG2', { + protocol: elbv2.ApplicationProtocol.HTTPS, + }); + tg.addTarget({ + attachToApplicationTargetGroup(_targetGroup: elbv2.IApplicationTargetGroup): elbv2.LoadBalancerTargetProps { + return { + targetType: elbv2.TargetType.LAMBDA, + targetJson: { id: 'arn:aws:lambda:eu-west-1:123456789012:function:myFn' }, + }; + }, + }); + expect(() => app.synth()).toThrow(/port\/protocol should not be specified for Lambda targets/); + }); + + test('Lambda target should not have protocol set', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + + new elbv2.ApplicationTargetGroup(stack, 'TG', { + port: 443, + targetType: elbv2.TargetType.LAMBDA, + }); + expect(() => app.synth()).toThrow(/port\/protocol should not be specified for Lambda targets/); + }); + test('Can add self-registering target to imported TargetGroup', () => { // GIVEN const app = new cdk.App(); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts index 2454cd1ccfb01..b0509e9a4e894 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts @@ -241,6 +241,96 @@ describe('tests', () => { }); }); + test('loadBalancerName unallowed: more than 32 characters', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app); + const vpc = new ec2.Vpc(stack, 'Stack'); + + // WHEN + new elbv2.NetworkLoadBalancer(stack, 'NLB', { + loadBalancerName: 'a'.repeat(33), + vpc, + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow('Load balancer name: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" can have a maximum of 32 characters.'); + }); + + test('loadBalancerName unallowed: starts with "internal-"', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app); + const vpc = new ec2.Vpc(stack, 'Stack'); + + // WHEN + new elbv2.NetworkLoadBalancer(stack, 'NLB', { + loadBalancerName: 'internal-myLoadBalancer', + vpc, + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow('Load balancer name: "internal-myLoadBalancer" must not begin with "internal-".'); + }); + + test('loadBalancerName unallowed: starts with hyphen', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app); + const vpc = new ec2.Vpc(stack, 'Stack'); + + // WHEN + new elbv2.NetworkLoadBalancer(stack, 'NLB', { + loadBalancerName: '-myLoadBalancer', + vpc, + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow('Load balancer name: "-myLoadBalancer" must not begin or end with a hyphen.'); + }); + + test('loadBalancerName unallowed: ends with hyphen', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app); + const vpc = new ec2.Vpc(stack, 'Stack'); + + // WHEN + new elbv2.NetworkLoadBalancer(stack, 'NLB', { + loadBalancerName: 'myLoadBalancer-', + vpc, + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow('Load balancer name: "myLoadBalancer-" must not begin or end with a hyphen.'); + }); + + test('loadBalancerName unallowed: unallowed characters', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app); + const vpc = new ec2.Vpc(stack, 'Stack'); + + // WHEN + new elbv2.NetworkLoadBalancer(stack, 'NLB', { + loadBalancerName: 'my load balancer', + vpc, + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow('Load balancer name: "my load balancer" must contain only alphanumeric characters or hyphens.'); + }); + test('imported network load balancer with no vpc specified throws error when calling addTargets', () => { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts index 7caaf465b045d..d7ac75aa2f78b 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts @@ -144,6 +144,82 @@ describe('tests', () => { }).toThrow(/Health check interval '5' not supported. Must be one of the following values '10,30'./); }); + test('targetGroupName unallowed: more than 32 characters', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app); + const vpc = new ec2.Vpc(stack, 'Stack'); + + // WHEN + new elbv2.NetworkTargetGroup(stack, 'Group', { + vpc, + port: 80, + targetGroupName: 'a'.repeat(33), + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow('Target group name: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" can have a maximum of 32 characters.'); + }); + + test('targetGroupName unallowed: starts with hyphen', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app); + const vpc = new ec2.Vpc(stack, 'Stack'); + + // WHEN + new elbv2.NetworkTargetGroup(stack, 'Group', { + vpc, + port: 80, + targetGroupName: '-myTargetGroup', + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow('Target group name: "-myTargetGroup" must not begin or end with a hyphen.'); + }); + + test('targetGroupName unallowed: ends with hyphen', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app); + const vpc = new ec2.Vpc(stack, 'Stack'); + + // WHEN + new elbv2.NetworkTargetGroup(stack, 'Group', { + vpc, + port: 80, + targetGroupName: 'myTargetGroup-', + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow('Target group name: "myTargetGroup-" must not begin or end with a hyphen.'); + }); + + test('targetGroupName unallowed: unallowed characters', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app); + const vpc = new ec2.Vpc(stack, 'Stack'); + + // WHEN + new elbv2.NetworkTargetGroup(stack, 'Group', { + vpc, + port: 80, + targetGroupName: 'my target group', + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow('Target group name: "my target group" must contain only alphanumeric characters or hyphens.'); + }); + test.each([elbv2.Protocol.UDP, elbv2.Protocol.TCP_UDP, elbv2.Protocol.TLS])( 'Throws validation error, when `healthCheck` has `protocol` set to %s', (protocol) => { diff --git a/packages/@aws-cdk/aws-elasticsearch/README.md b/packages/@aws-cdk/aws-elasticsearch/README.md index 6de168cf70f7b..fab6cc2691548 100644 --- a/packages/@aws-cdk/aws-elasticsearch/README.md +++ b/packages/@aws-cdk/aws-elasticsearch/README.md @@ -3,20 +3,9 @@ --- -Features | Stability ------------------------------------|---------------------------------------------------------------- -CFN Resources | ![Stable](https://img.shields.io/badge/stable-success.svg?style=for-the-badge) -Higher level constructs for Domain | ![Stable](https://img.shields.io/badge/stable-success.svg?style=for-the-badge) +![Deprecated](https://img.shields.io/badge/deprecated-critical.svg?style=for-the-badge) -> **CFN Resources:** All classes with the `Cfn` prefix in this module ([CFN Resources]) are always -> stable and safe to use. -> -> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib - - - -> **Stable:** Higher level constructs in this module that are marked stable will not undergo any -> breaking changes. They will strictly follow the [Semantic Versioning](https://semver.org/) model. +> This API may emit warnings. Backward compatibility is not guaranteed. --- @@ -233,7 +222,62 @@ const domain = new es.Domain(this, 'Domain', { const masterUserPassword = domain.masterUserPassword; ``` +## Custom access policies + +If the domain requires custom access control it can be configured either as a +constructor property, or later by means of a helper method. +For simple permissions the `accessPolicies` constructor may be sufficient: + +```ts +const domain = new es.Domain(this, 'Domain', { + version: es.ElasticsearchVersion.V7_1, + accessPolicies: [ + new iam.PolicyStatement({ + actions: ['es:*ESHttpPost', 'es:ESHttpPut*'], + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('123456789012')], + resources: ['*'], + }), + ] +}); +``` + +For more complex use-cases, for example, to set the domain up to receive data from a +[cross-account Kinesis Firehose](https://aws.amazon.com/premiumsupport/knowledge-center/kinesis-firehose-cross-account-streaming/) the `addAccessPolicies` helper method +allows for policies that include the explicit domain ARN. + +```ts +const domain = new es.Domain(this, 'Domain', { + version: es.ElasticsearchVersion.V7_1, +}); + +domain.addAccessPolicies( + new iam.PolicyStatement({ + actions: ['es:ESHttpPost', 'es:ESHttpPut'], + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('123456789012')], + resources: [domain.domainArn, `${domain.domainArn}/*`], + }), + new iam.PolicyStatement({ + actions: ['es:ESHttpGet'], + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('123456789012')], + resources: [ + `${domain.domainArn}/_all/_settings`, + `${domain.domainArn}/_cluster/stats`, + `${domain.domainArn}/index-name*/_mapping/type-name`, + `${domain.domainArn}/roletest*/_mapping/roletest`, + `${domain.domainArn}/_nodes`, + `${domain.domainArn}/_nodes/stats`, + `${domain.domainArn}/_nodes/*/stats`, + `${domain.domainArn}/_stats`, + `${domain.domainArn}/index-name*/_stats`, + `${domain.domainArn}/roletest*/_stat`, + ], + }), +); +``` ## Audit logs @@ -400,7 +444,7 @@ Make the following modifications to your CDK application to migrate to the `@aws Follow these steps to migrate your application without data loss: - Ensure that the [removal policy](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.RemovalPolicy.html) on your domains are set to `RemovalPolicy.RETAIN`. This is the default for the domain construct, so nothing is required unless you have specifically set the removal policy to some other value. -- Remove the domain resource from your CloudFormation stacks by manually modifying the synthesized templates used to create the CloudFormation stacks. This may also involve modifying or deleting dependent resources, such as the custom resources that CDK creates to manage the domain's access policy or any other resource you have connected to the domain. You will need to search for references to each domain's logical ID to determine which other resources refer to it and replace or delete those references. Do not remove resources that are dependencies of the domain or you will have to recreate or import them before importing the domain. After modification, deploy the stacks through the AWS Management Console or using the AWS CLI. +- Remove the domain resource from your CloudFormation stacks by manually modifying the synthesized templates used to create the CloudFormation stacks. This may also involve modifying or deleting dependent resources, such as the custom resources that CDK creates to manage the domain's access policy or any other resource you have connected to the domain. You will need to search for references to each domain's logical ID to determine which other resources refer to it and replace or delete those references. Do not remove resources that are dependencies of the domain or you will have to recreate or import them before importing the domain. After modification, deploy the stacks through the AWS Management Console or using the AWS CLI. - Migrate your CDK application to use the new `@aws-cdk/aws-opensearchservice` module by applying the necessary modifications listed above. Synthesize your application and obtain the resulting stack templates. - Copy just the definition of the domain from the "migrated" templates to the corresponding "stripped" templates that you deployed above. [Import](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resource-import-existing-stack.html) the orphaned domains into your CloudFormation stacks using these templates. - Synthesize and deploy your CDK application to reconfigure/recreate the modified dependent resources. The CloudFormation stacks should now contain the same resources as existed prior to migration. diff --git a/packages/@aws-cdk/aws-elasticsearch/lib/domain.ts b/packages/@aws-cdk/aws-elasticsearch/lib/domain.ts index e8808958929fc..fbd769440fab1 100644 --- a/packages/@aws-cdk/aws-elasticsearch/lib/domain.ts +++ b/packages/@aws-cdk/aws-elasticsearch/lib/domain.ts @@ -20,61 +20,99 @@ import * as perms from './perms'; * Elasticsearch version */ export class ElasticsearchVersion { - /** AWS Elasticsearch 1.5 */ + /** + * AWS Elasticsearch 1.5 + */ public static readonly V1_5 = ElasticsearchVersion.of('1.5'); - /** AWS Elasticsearch 2.3 */ + /** + * AWS Elasticsearch 2.3 + */ public static readonly V2_3 = ElasticsearchVersion.of('2.3'); - /** AWS Elasticsearch 5.1 */ + /** + * AWS Elasticsearch 5.1 + */ public static readonly V5_1 = ElasticsearchVersion.of('5.1'); - /** AWS Elasticsearch 5.3 */ + /** + * AWS Elasticsearch 5.3 + */ public static readonly V5_3 = ElasticsearchVersion.of('5.3'); - /** AWS Elasticsearch 5.5 */ + /** + * AWS Elasticsearch 5.5 + */ public static readonly V5_5 = ElasticsearchVersion.of('5.5'); - /** AWS Elasticsearch 5.6 */ + /** + * AWS Elasticsearch 5.6 + */ public static readonly V5_6 = ElasticsearchVersion.of('5.6'); - /** AWS Elasticsearch 6.0 */ + /** + * AWS Elasticsearch 6.0 + */ public static readonly V6_0 = ElasticsearchVersion.of('6.0'); - /** AWS Elasticsearch 6.2 */ + /** + * AWS Elasticsearch 6.2 + */ public static readonly V6_2 = ElasticsearchVersion.of('6.2'); - /** AWS Elasticsearch 6.3 */ + /** + * AWS Elasticsearch 6.3 + */ public static readonly V6_3 = ElasticsearchVersion.of('6.3'); - /** AWS Elasticsearch 6.4 */ + /** + * AWS Elasticsearch 6.4 + */ public static readonly V6_4 = ElasticsearchVersion.of('6.4'); - /** AWS Elasticsearch 6.5 */ + /** + * AWS Elasticsearch 6.5 + */ public static readonly V6_5 = ElasticsearchVersion.of('6.5'); - /** AWS Elasticsearch 6.7 */ + /** + * AWS Elasticsearch 6.7 + */ public static readonly V6_7 = ElasticsearchVersion.of('6.7'); - /** AWS Elasticsearch 6.8 */ + /** + * AWS Elasticsearch 6.8 + */ public static readonly V6_8 = ElasticsearchVersion.of('6.8'); - /** AWS Elasticsearch 7.1 */ + /** + * AWS Elasticsearch 7.1 + */ public static readonly V7_1 = ElasticsearchVersion.of('7.1'); - /** AWS Elasticsearch 7.4 */ + /** + * AWS Elasticsearch 7.4 + */ public static readonly V7_4 = ElasticsearchVersion.of('7.4'); - /** AWS Elasticsearch 7.7 */ + /** + * AWS Elasticsearch 7.7 + */ public static readonly V7_7 = ElasticsearchVersion.of('7.7'); - /** AWS Elasticsearch 7.8 */ + /** + * AWS Elasticsearch 7.8 + */ public static readonly V7_8 = ElasticsearchVersion.of('7.8'); - /** AWS Elasticsearch 7.9 */ + /** + * AWS Elasticsearch 7.9 + */ public static readonly V7_9 = ElasticsearchVersion.of('7.9'); - /** AWS Elasticsearch 7.10 */ + /** + * AWS Elasticsearch 7.10 + */ public static readonly V7_10 = ElasticsearchVersion.of('7.10'); /** @@ -93,12 +131,15 @@ export class ElasticsearchVersion { /** * Configures the capacity of the cluster such as the instance type and the * number of instances. + * + * @deprecated use opensearchservice module instead */ export interface CapacityConfig { /** * The number of instances to use for the master node. * * @default - no dedicated master nodes + * @deprecated use opensearchservice module instead */ readonly masterNodes?: number; @@ -110,6 +151,7 @@ export interface CapacityConfig { * in the Amazon Elasticsearch Service Developer Guide. * * @default - r5.large.elasticsearch + * @deprecated use opensearchservice module instead */ readonly masterNodeInstanceType?: string; @@ -117,6 +159,7 @@ export interface CapacityConfig { * The number of data nodes (instances) to use in the Amazon ES domain. * * @default - 1 + * @deprecated use opensearchservice module instead */ readonly dataNodes?: number; @@ -127,6 +170,7 @@ export interface CapacityConfig { * in the Amazon Elasticsearch Service Developer Guide. * * @default - r5.large.elasticsearch + * @deprecated use opensearchservice module instead */ readonly dataNodeInstanceType?: string; @@ -134,6 +178,7 @@ export interface CapacityConfig { * The number of UltraWarm nodes (instances) to use in the Amazon ES domain. * * @default - no UltraWarm nodes + * @deprecated use opensearchservice module instead */ readonly warmNodes?: number; @@ -144,6 +189,7 @@ export interface CapacityConfig { * in the Amazon Elasticsearch Service Developer Guide. * * @default - ultrawarm1.medium.elasticsearch + * @deprecated use opensearchservice module instead */ readonly warmInstanceType?: string; @@ -151,6 +197,8 @@ export interface CapacityConfig { /** * Specifies zone awareness configuration options. + * + * @deprecated use opensearchservice module instead */ export interface ZoneAwarenessConfig { /** @@ -165,6 +213,7 @@ export interface ZoneAwarenessConfig { * in the Amazon Elasticsearch Service Developer Guide. * * @default - false + * @deprecated use opensearchservice module instead */ readonly enabled?: boolean; @@ -173,6 +222,7 @@ export interface ZoneAwarenessConfig { * want the domain to use. Valid values are 2 and 3. * * @default - 2 if zone awareness is enabled. + * @deprecated use opensearchservice module instead */ readonly availabilityZoneCount?: number; } @@ -183,6 +233,8 @@ export interface ZoneAwarenessConfig { * [Configuring EBS-based Storage] * (https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-createupdatedomains.html#es-createdomain-configure-ebs) * in the Amazon Elasticsearch Service Developer Guide. + * + * @deprecated use opensearchservice module instead */ export interface EbsOptions { /** @@ -190,6 +242,7 @@ export interface EbsOptions { * Amazon ES domain. * * @default - true + * @deprecated use opensearchservice module instead */ readonly enabled?: boolean; @@ -199,6 +252,7 @@ export interface EbsOptions { * volume type. * * @default - iops are not set. + * @deprecated use opensearchservice module instead */ readonly iops?: number; @@ -211,6 +265,7 @@ export interface EbsOptions { * in the Amazon Elasticsearch Service Developer Guide. * * @default 10 + * @deprecated use opensearchservice module instead */ readonly volumeSize?: number; @@ -221,12 +276,15 @@ export interface EbsOptions { * in the Amazon Elasticsearch Service Developer Guide. * * @default gp2 + * @deprecated use opensearchservice module instead */ readonly volumeType?: ec2.EbsDeviceVolumeType; } /** * Configures log settings for the domain. + * + * @deprecated use opensearchservice module instead */ export interface LoggingOptions { /** @@ -234,6 +292,7 @@ export interface LoggingOptions { * Requires Elasticsearch version 5.1 or later. * * @default - false + * @deprecated use opensearchservice module instead */ readonly slowSearchLogEnabled?: boolean; @@ -241,6 +300,7 @@ export interface LoggingOptions { * Log slow searches to this log group. * * @default - a new log group is created if slow search logging is enabled + * @deprecated use opensearchservice module instead */ readonly slowSearchLogGroup?: logs.ILogGroup; @@ -249,6 +309,7 @@ export interface LoggingOptions { * Requires Elasticsearch version 5.1 or later. * * @default - false + * @deprecated use opensearchservice module instead */ readonly slowIndexLogEnabled?: boolean; @@ -256,6 +317,7 @@ export interface LoggingOptions { * Log slow indices to this log group. * * @default - a new log group is created if slow index logging is enabled + * @deprecated use opensearchservice module instead */ readonly slowIndexLogGroup?: logs.ILogGroup; @@ -264,6 +326,7 @@ export interface LoggingOptions { * Requires Elasticsearch version 5.1 or later. * * @default - false + * @deprecated use opensearchservice module instead */ readonly appLogEnabled?: boolean; @@ -271,6 +334,7 @@ export interface LoggingOptions { * Log Elasticsearch application logs to this log group. * * @default - a new log group is created if app logging is enabled + * @deprecated use opensearchservice module instead */ readonly appLogGroup?: logs.ILogGroup; @@ -279,6 +343,7 @@ export interface LoggingOptions { * Requires Elasticsearch version 6.7 or later and fine grained access control to be enabled. * * @default - false + * @deprecated use opensearchservice module instead */ readonly auditLogEnabled?: boolean; @@ -286,6 +351,7 @@ export interface LoggingOptions { * Log Elasticsearch audit logs to this log group. * * @default - a new log group is created if audit logging is enabled + * @deprecated use opensearchservice module instead */ readonly auditLogGroup?: logs.ILogGroup; } @@ -294,12 +360,15 @@ export interface LoggingOptions { * Whether the domain should encrypt data at rest, and if so, the AWS Key * Management Service (KMS) key to use. Can only be used to create a new domain, * not update an existing one. Requires Elasticsearch version 5.1 or later. + * + * @deprecated use opensearchservice module instead */ export interface EncryptionAtRestOptions { /** * Specify true to enable encryption at rest. * * @default - encryption at rest is disabled. + * @deprecated use opensearchservice module instead */ readonly enabled?: boolean; @@ -307,6 +376,7 @@ export interface EncryptionAtRestOptions { * Supply if using KMS key for encryption at rest. * * @default - uses default aws/es KMS key. + * @deprecated use opensearchservice module instead */ readonly kmsKey?: kms.IKey; } @@ -314,10 +384,13 @@ export interface EncryptionAtRestOptions { /** * Configures Amazon ES to use Amazon Cognito authentication for Kibana. * @see https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-cognito-auth.html + * @deprecated use opensearchservice module instead */ export interface CognitoOptions { /** * The Amazon Cognito identity pool ID that you want Amazon ES to use for Kibana authentication. + * + * @deprecated use opensearchservice module instead */ readonly identityPoolId: string; @@ -325,17 +398,22 @@ export interface CognitoOptions { * A role that allows Amazon ES to configure your user pool and identity pool. It must have the `AmazonESCognitoAccess` policy attached to it. * * @see https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-cognito-auth.html#es-cognito-auth-prereq + * @deprecated use opensearchservice module instead */ readonly role: iam.IRole; /** * The Amazon Cognito user pool ID that you want Amazon ES to use for Kibana authentication. + * + * @deprecated use opensearchservice module instead */ readonly userPoolId: string; } /** * The minimum TLS version required for traffic to the domain. + * + * @deprecated use opensearchservice module instead */ export enum TLSSecurityPolicy { /** Cipher suite TLS 1.0 */ @@ -346,12 +424,15 @@ export enum TLSSecurityPolicy { /** * Specifies options for fine-grained access control. + * + * @deprecated use opensearchservice module instead */ export interface AdvancedSecurityOptions { /** * ARN for the master user. Only specify this or masterUserName, but not both. * * @default - fine-grained access control is disabled + * @deprecated use opensearchservice module instead */ readonly masterUserArn?: string; @@ -359,6 +440,7 @@ export interface AdvancedSecurityOptions { * Username for the master user. Only specify this or masterUserArn, but not both. * * @default - fine-grained access control is disabled + * @deprecated use opensearchservice module instead */ readonly masterUserName?: string; @@ -370,40 +452,50 @@ export interface AdvancedSecurityOptions { * Secrets Manager. * * @default - A Secrets Manager generated password + * @deprecated use opensearchservice module instead */ readonly masterUserPassword?: cdk.SecretValue; } /** * Configures a custom domain endpoint for the ES domain + * + * @deprecated use opensearchservice module instead */ export interface CustomEndpointOptions { /** * The custom domain name to assign + * + * @deprecated use opensearchservice module instead */ readonly domainName: string; /** * The certificate to use * @default - create a new one + * @deprecated use opensearchservice module instead */ readonly certificate?: acm.ICertificate; /** * The hosted zone in Route53 to create the CNAME record in * @default - do not create a CNAME + * @deprecated use opensearchservice module instead */ readonly hostedZone?: route53.IHostedZone; } /** * Properties for an AWS Elasticsearch Domain. + * + * @deprecated use opensearchservice module instead */ export interface DomainProps { /** * Domain Access policies. * * @default - No access policies. + * @deprecated use opensearchservice module instead */ readonly accessPolicies?: iam.PolicyStatement[]; @@ -412,6 +504,7 @@ export interface DomainProps { * * @see https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-createupdatedomains.html#es-createdomain-configure-advanced-options * @default - no advanced options are specified + * @deprecated use opensearchservice module instead */ readonly advancedOptions?: { [key: string]: (string) }; @@ -419,6 +512,7 @@ export interface DomainProps { * Configures Amazon ES to use Amazon Cognito authentication for Kibana. * * @default - Cognito not used for authentication to Kibana. + * @deprecated use opensearchservice module instead */ readonly cognitoKibanaAuth?: CognitoOptions; @@ -426,6 +520,7 @@ export interface DomainProps { * Enforces a particular physical domain name. * * @default - A name will be auto-generated. + * @deprecated use opensearchservice module instead */ readonly domainName?: string; @@ -437,6 +532,7 @@ export interface DomainProps { * in the Amazon Elasticsearch Service Developer Guide. * * @default - 10 GiB General Purpose (SSD) volumes per node. + * @deprecated use opensearchservice module instead */ readonly ebs?: EbsOptions; @@ -444,6 +540,7 @@ export interface DomainProps { * The cluster capacity configuration for the Amazon ES domain. * * @default - 1 r5.large.elasticsearch data node; no dedicated master nodes. + * @deprecated use opensearchservice module instead */ readonly capacity?: CapacityConfig; @@ -451,11 +548,14 @@ export interface DomainProps { * The cluster zone awareness configuration for the Amazon ES domain. * * @default - no zone awareness (1 AZ) + * @deprecated use opensearchservice module instead */ readonly zoneAwareness?: ZoneAwarenessConfig; /** * The Elasticsearch version that your domain will leverage. + * + * @deprecated use opensearchservice module instead */ readonly version: ElasticsearchVersion; @@ -463,6 +563,7 @@ export interface DomainProps { * Encryption at rest options for the cluster. * * @default - No encryption at rest + * @deprecated use opensearchservice module instead */ readonly encryptionAtRest?: EncryptionAtRestOptions; @@ -470,6 +571,7 @@ export interface DomainProps { * Configuration log publishing configuration options. * * @default - No logs are published + * @deprecated use opensearchservice module instead */ readonly logging?: LoggingOptions; @@ -478,6 +580,7 @@ export interface DomainProps { * Requires Elasticsearch version 6.0 or later. * * @default - Node to node encryption is not enabled. + * @deprecated use opensearchservice module instead */ readonly nodeToNodeEncryption?: boolean; @@ -487,6 +590,7 @@ export interface DomainProps { * versions below 5.3. * * @default - Hourly automated snapshots not used + * @deprecated use opensearchservice module instead */ readonly automatedSnapshotStartHour?: number; @@ -495,6 +599,7 @@ export interface DomainProps { * * @see https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-vpc.html * @default - Domain is not placed in a VPC. + * @deprecated use opensearchservice module instead */ readonly vpc?: ec2.IVpc; @@ -506,6 +611,7 @@ export interface DomainProps { * * @see https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html * @default - One new security group is created. + * @deprecated use opensearchservice module instead */ readonly securityGroups?: ec2.ISecurityGroup[]; @@ -518,6 +624,7 @@ export interface DomainProps { * * @see https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Subnets.html * @default - All private subnets. + * @deprecated use opensearchservice module instead */ readonly vpcSubnets?: ec2.SubnetSelection[]; @@ -525,6 +632,7 @@ export interface DomainProps { * True to require that all traffic to the domain arrive over HTTPS. * * @default - false + * @deprecated use opensearchservice module instead */ readonly enforceHttps?: boolean; @@ -532,6 +640,7 @@ export interface DomainProps { * The minimum TLS version required for traffic to the domain. * * @default - TLSSecurityPolicy.TLS_1_0 + * @deprecated use opensearchservice module instead */ readonly tlsSecurityPolicy?: TLSSecurityPolicy; @@ -542,6 +651,7 @@ export interface DomainProps { * enforced HTTPS. * * @default - fine-grained access control is disabled + * @deprecated use opensearchservice module instead */ readonly fineGrainedAccessControl?: AdvancedSecurityOptions; @@ -556,6 +666,7 @@ export interface DomainProps { * setting will cause a failure. * * @default - false + * @deprecated use opensearchservice module instead */ readonly useUnsignedBasicAuth?: boolean; @@ -565,6 +676,7 @@ export interface DomainProps { * * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-updatepolicy.html#cfn-attributes-updatepolicy-upgradeelasticsearchdomain * @default - false + * @deprecated use opensearchservice module instead */ readonly enableVersionUpgrade?: boolean; @@ -572,6 +684,7 @@ export interface DomainProps { * Policy to apply when the domain is removed from the stack * * @default RemovalPolicy.RETAIN + * @deprecated use opensearchservice module instead */ readonly removalPolicy?: cdk.RemovalPolicy; @@ -580,18 +693,22 @@ export interface DomainProps { * * If you specify a Route53 hosted zone it will create a CNAME record and use DNS validation for the certificate * @default - no custom domain endpoint will be configured + * @deprecated use opensearchservice module instead */ readonly customEndpoint?: CustomEndpointOptions; } /** * An interface that represents an Elasticsearch domain - either created with the CDK, or an existing one. + * + * @deprecated use opensearchservice module instead */ export interface IDomain extends cdk.IResource { /** * Arn of the Elasticsearch domain. * * @attribute + * @deprecated use opensearchservice module instead */ readonly domainArn: string; @@ -599,6 +716,7 @@ export interface IDomain extends cdk.IResource { * Domain name of the Elasticsearch domain. * * @attribute + * @deprecated use opensearchservice module instead */ readonly domainName: string; @@ -606,6 +724,7 @@ export interface IDomain extends cdk.IResource { * Endpoint of the Elasticsearch domain. * * @attribute + * @deprecated use opensearchservice module instead */ readonly domainEndpoint: string; @@ -614,6 +733,7 @@ export interface IDomain extends cdk.IResource { * principal (Role/Group/User). * * @param identity The principal + * @deprecated use opensearchservice module instead */ grantRead(identity: iam.IGrantable): iam.Grant; @@ -622,6 +742,7 @@ export interface IDomain extends cdk.IResource { * principal (Role/Group/User). * * @param identity The principal + * @deprecated use opensearchservice module instead */ grantWrite(identity: iam.IGrantable): iam.Grant; @@ -630,6 +751,7 @@ export interface IDomain extends cdk.IResource { * principal (Role/Group/User). * * @param identity The principal + * @deprecated use opensearchservice module instead */ grantReadWrite(identity: iam.IGrantable): iam.Grant; @@ -639,6 +761,7 @@ export interface IDomain extends cdk.IResource { * * @param index The index to grant permissions for * @param identity The principal + * @deprecated use opensearchservice module instead */ grantIndexRead(index: string, identity: iam.IGrantable): iam.Grant; @@ -648,6 +771,7 @@ export interface IDomain extends cdk.IResource { * * @param index The index to grant permissions for * @param identity The principal + * @deprecated use opensearchservice module instead */ grantIndexWrite(index: string, identity: iam.IGrantable): iam.Grant; @@ -657,6 +781,7 @@ export interface IDomain extends cdk.IResource { * * @param index The index to grant permissions for * @param identity The principal + * @deprecated use opensearchservice module instead */ grantIndexReadWrite(index: string, identity: iam.IGrantable): iam.Grant; @@ -666,6 +791,7 @@ export interface IDomain extends cdk.IResource { * * @param path The path to grant permissions for * @param identity The principal + * @deprecated use opensearchservice module instead */ grantPathRead(path: string, identity: iam.IGrantable): iam.Grant; @@ -675,6 +801,7 @@ export interface IDomain extends cdk.IResource { * * @param path The path to grant permissions for * @param identity The principal + * @deprecated use opensearchservice module instead */ grantPathWrite(path: string, identity: iam.IGrantable): iam.Grant; @@ -684,11 +811,14 @@ export interface IDomain extends cdk.IResource { * * @param path The path to grant permissions for * @param identity The principal + * @deprecated use opensearchservice module instead */ grantPathReadWrite(path: string, identity: iam.IGrantable): iam.Grant; /** * Return the given named metric for this Domain. + * + * @deprecated use opensearchservice module instead */ metric(metricName: string, props?: MetricOptions): Metric; @@ -696,6 +826,7 @@ export interface IDomain extends cdk.IResource { * Metric for the time the cluster status is red. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ metricClusterStatusRed(props?: MetricOptions): Metric; @@ -703,6 +834,7 @@ export interface IDomain extends cdk.IResource { * Metric for the time the cluster status is yellow. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ metricClusterStatusYellow(props?: MetricOptions): Metric; @@ -710,6 +842,7 @@ export interface IDomain extends cdk.IResource { * Metric for the storage space of nodes in the cluster. * * @default minimum over 5 minutes + * @deprecated use opensearchservice module instead */ metricFreeStorageSpace(props?: MetricOptions): Metric; @@ -717,6 +850,7 @@ export interface IDomain extends cdk.IResource { * Metric for the cluster blocking index writes. * * @default maximum over 1 minute + * @deprecated use opensearchservice module instead */ metricClusterIndexWritesBlocked(props?: MetricOptions): Metric; @@ -724,6 +858,7 @@ export interface IDomain extends cdk.IResource { * Metric for the number of nodes. * * @default minimum over 1 hour + * @deprecated use opensearchservice module instead */ metricNodes(props?: MetricOptions): Metric; @@ -731,6 +866,7 @@ export interface IDomain extends cdk.IResource { * Metric for automated snapshot failures. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ metricAutomatedSnapshotFailure(props?: MetricOptions): Metric; @@ -738,6 +874,7 @@ export interface IDomain extends cdk.IResource { * Metric for CPU utilization. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ metricCPUUtilization(props?: MetricOptions): Metric; @@ -745,6 +882,7 @@ export interface IDomain extends cdk.IResource { * Metric for JVM memory pressure. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ metricJVMMemoryPressure(props?: MetricOptions): Metric; @@ -752,6 +890,7 @@ export interface IDomain extends cdk.IResource { * Metric for master CPU utilization. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ metricMasterCPUUtilization(props?: MetricOptions): Metric; @@ -759,6 +898,7 @@ export interface IDomain extends cdk.IResource { * Metric for master JVM memory pressure. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ metricMasterJVMMemoryPressure(props?: MetricOptions): Metric; @@ -766,6 +906,7 @@ export interface IDomain extends cdk.IResource { * Metric for KMS key errors. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ metricKMSKeyError(props?: MetricOptions): Metric; @@ -773,6 +914,7 @@ export interface IDomain extends cdk.IResource { * Metric for KMS key being inaccessible. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ metricKMSKeyInaccessible(props?: MetricOptions): Metric; @@ -780,6 +922,7 @@ export interface IDomain extends cdk.IResource { * Metric for number of searchable documents. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ metricSearchableDocuments(props?: MetricOptions): Metric; @@ -787,6 +930,7 @@ export interface IDomain extends cdk.IResource { * Metric for search latency. * * @default p99 over 5 minutes + * @deprecated use opensearchservice module instead */ metricSearchLatency(props?: MetricOptions): Metric; @@ -794,6 +938,7 @@ export interface IDomain extends cdk.IResource { * Metric for indexing latency. * * @default p99 over 5 minutes + * @deprecated use opensearchservice module instead */ metricIndexingLatency(props?: MetricOptions): Metric; } @@ -812,6 +957,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * principal (Role/Group/User). * * @param identity The principal + * @deprecated use opensearchservice module instead */ grantRead(identity: iam.IGrantable): iam.Grant { return this.grant( @@ -827,6 +973,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * principal (Role/Group/User). * * @param identity The principal + * @deprecated use opensearchservice module instead */ grantWrite(identity: iam.IGrantable): iam.Grant { return this.grant( @@ -842,6 +989,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * principal (Role/Group/User). * * @param identity The principal + * @deprecated use opensearchservice module instead */ grantReadWrite(identity: iam.IGrantable): iam.Grant { return this.grant( @@ -858,6 +1006,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * * @param index The index to grant permissions for * @param identity The principal + * @deprecated use opensearchservice module instead */ grantIndexRead(index: string, identity: iam.IGrantable): iam.Grant { return this.grant( @@ -874,6 +1023,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * * @param index The index to grant permissions for * @param identity The principal + * @deprecated use opensearchservice module instead */ grantIndexWrite(index: string, identity: iam.IGrantable): iam.Grant { return this.grant( @@ -890,6 +1040,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * * @param index The index to grant permissions for * @param identity The principal + * @deprecated use opensearchservice module instead */ grantIndexReadWrite(index: string, identity: iam.IGrantable): iam.Grant { return this.grant( @@ -906,6 +1057,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * * @param path The path to grant permissions for * @param identity The principal + * @deprecated use opensearchservice module instead */ grantPathRead(path: string, identity: iam.IGrantable): iam.Grant { return this.grant( @@ -921,6 +1073,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * * @param path The path to grant permissions for * @param identity The principal + * @deprecated use opensearchservice module instead */ grantPathWrite(path: string, identity: iam.IGrantable): iam.Grant { return this.grant( @@ -936,6 +1089,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * * @param path The path to grant permissions for * @param identity The principal + * @deprecated use opensearchservice module instead */ grantPathReadWrite(path: string, identity: iam.IGrantable): iam.Grant { return this.grant( @@ -947,6 +1101,8 @@ abstract class DomainBase extends cdk.Resource implements IDomain { /** * Return the given named metric for this Domain. + * + * @deprecated use opensearchservice module instead */ public metric(metricName: string, props?: MetricOptions): Metric { return new Metric({ @@ -964,6 +1120,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * Metric for the time the cluster status is red. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ public metricClusterStatusRed(props?: MetricOptions): Metric { return this.metric('ClusterStatus.red', { @@ -976,6 +1133,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * Metric for the time the cluster status is yellow. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ public metricClusterStatusYellow(props?: MetricOptions): Metric { return this.metric('ClusterStatus.yellow', { @@ -988,6 +1146,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * Metric for the storage space of nodes in the cluster. * * @default minimum over 5 minutes + * @deprecated use opensearchservice module instead */ public metricFreeStorageSpace(props?: MetricOptions): Metric { return this.metric('FreeStorageSpace', { @@ -1000,6 +1159,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * Metric for the cluster blocking index writes. * * @default maximum over 1 minute + * @deprecated use opensearchservice module instead */ public metricClusterIndexWritesBlocked(props?: MetricOptions): Metric { return this.metric('ClusterIndexWritesBlocked', { @@ -1013,6 +1173,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * Metric for the number of nodes. * * @default minimum over 1 hour + * @deprecated use opensearchservice module instead */ public metricNodes(props?: MetricOptions): Metric { return this.metric('Nodes', { @@ -1026,6 +1187,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * Metric for automated snapshot failures. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ public metricAutomatedSnapshotFailure(props?: MetricOptions): Metric { return this.metric('AutomatedSnapshotFailure', { @@ -1038,6 +1200,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * Metric for CPU utilization. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ public metricCPUUtilization(props?: MetricOptions): Metric { return this.metric('CPUUtilization', { @@ -1050,6 +1213,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * Metric for JVM memory pressure. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ public metricJVMMemoryPressure(props?: MetricOptions): Metric { return this.metric('JVMMemoryPressure', { @@ -1062,6 +1226,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * Metric for master CPU utilization. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ public metricMasterCPUUtilization(props?: MetricOptions): Metric { return this.metric('MasterCPUUtilization', { @@ -1074,6 +1239,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * Metric for master JVM memory pressure. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ public metricMasterJVMMemoryPressure(props?: MetricOptions): Metric { return this.metric('MasterJVMMemoryPressure', { @@ -1086,6 +1252,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * Metric for KMS key errors. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ public metricKMSKeyError(props?: MetricOptions): Metric { return this.metric('KMSKeyError', { @@ -1098,6 +1265,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * Metric for KMS key being inaccessible. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ public metricKMSKeyInaccessible(props?: MetricOptions): Metric { return this.metric('KMSKeyInaccessible', { @@ -1110,6 +1278,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * Metric for number of searchable documents. * * @default maximum over 5 minutes + * @deprecated use opensearchservice module instead */ public metricSearchableDocuments(props?: MetricOptions): Metric { return this.metric('SearchableDocuments', { @@ -1122,6 +1291,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * Metric for search latency. * * @default p99 over 5 minutes + * @deprecated use opensearchservice module instead */ public metricSearchLatency(props?: MetricOptions): Metric { return this.metric('SearchLatency', { statistic: 'p99', ...props }); @@ -1131,6 +1301,7 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * Metric for indexing latency. * * @default p99 over 5 minutes + * @deprecated use opensearchservice module instead */ public metricIndexingLatency(props?: MetricOptions): Metric { return this.metric('IndexingLatency', { statistic: 'p99', ...props }); @@ -1159,15 +1330,21 @@ abstract class DomainBase extends cdk.Resource implements IDomain { /** * Reference to an Elasticsearch domain. + * + * @deprecated use opensearchservice module instead */ export interface DomainAttributes { /** * The ARN of the Elasticsearch domain. + * + * @deprecated use opensearchservice module instead */ readonly domainArn: string; /** * The domain endpoint of the Elasticsearch domain. + * + * @deprecated use opensearchservice module instead */ readonly domainEndpoint: string; } @@ -1175,6 +1352,8 @@ export interface DomainAttributes { /** * Provides an Elasticsearch domain. + * + * @deprecated use opensearchservice module instead */ export class Domain extends DomainBase implements IDomain, ec2.IConnectable { /** @@ -1183,6 +1362,7 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable { * @param scope The parent creating construct (usually `this`). * @param id The construct's name. * @param domainEndpoint The domain's endpoint. + * @deprecated use opensearchservice module instead */ public static fromDomainEndpoint( scope: Construct, @@ -1209,6 +1389,7 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable { * @param scope The parent creating construct (usually `this`). * @param id The construct's name. * @param attrs A `DomainAttributes` object. + * @deprecated use opensearchservice module instead */ public static fromDomainAttributes(scope: Construct, id: string, attrs: DomainAttributes): IDomain { const { domainArn, domainEndpoint } = attrs; @@ -1224,14 +1405,26 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable { }; } + /** + * @deprecated use opensearchservice module instead + */ public readonly domainArn: string; + + /** + * @deprecated use opensearchservice module instead + */ public readonly domainName: string; + + /** + * @deprecated use opensearchservice module instead + */ public readonly domainEndpoint: string; /** * Log group that slow searches are logged to. * * @attribute + * @deprecated use opensearchservice module instead */ public readonly slowSearchLogGroup?: logs.ILogGroup; @@ -1239,6 +1432,7 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable { * Log group that slow indices are logged to. * * @attribute + * @deprecated use opensearchservice module instead */ public readonly slowIndexLogGroup?: logs.ILogGroup; @@ -1246,6 +1440,7 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable { * Log group that application logs are logged to. * * @attribute + * @deprecated use opensearchservice module instead */ public readonly appLogGroup?: logs.ILogGroup; @@ -1253,17 +1448,23 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable { * Log group that audit logs are logged to. * * @attribute + * @deprecated use opensearchservice module instead */ public readonly auditLogGroup?: logs.ILogGroup; /** * Master user password if fine grained access control is configured. + * + * @deprecated use opensearchservice module instead */ public readonly masterUserPassword?: cdk.SecretValue; private readonly domain: CfnDomain; + private accessPolicy?: ElasticsearchAccessPolicy + private encryptionAtRestOptions?: EncryptionAtRestOptions + private readonly _connections: ec2.Connections | undefined; constructor(scope: Construct, id: string, props: DomainProps) { @@ -1720,39 +1921,20 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable { }); } - const accessPolicyStatements: iam.PolicyStatement[] | undefined = unsignedBasicAuthEnabled - ? (props.accessPolicies ?? []).concat(unsignedAccessPolicy) - : props.accessPolicies; - - if (accessPolicyStatements != null) { - const accessPolicy = new ElasticsearchAccessPolicy(this, 'ESAccessPolicy', { - domainName: this.domainName, - domainArn: this.domainArn, - accessPolicies: accessPolicyStatements, - }); - - if (props.encryptionAtRest?.kmsKey) { - - // https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/encryption-at-rest.html - - // these permissions are documented as required during domain creation. - // while not strictly documented for updates as well, it stands to reason that an update - // operation might require these in case the cluster uses a kms key. - // empircal evidence shows this is indeed required: https://github.com/aws/aws-cdk/issues/11412 - accessPolicy.grantPrincipal.addToPrincipalPolicy(new iam.PolicyStatement({ - actions: ['kms:List*', 'kms:Describe*', 'kms:CreateGrant'], - resources: [props.encryptionAtRest.kmsKey.keyArn], - effect: iam.Effect.ALLOW, - })); - } - - accessPolicy.node.addDependency(this.domain); + this.encryptionAtRestOptions = props.encryptionAtRest; + if (props.accessPolicies) { + this.addAccessPolicies(...props.accessPolicies); + } + if (unsignedBasicAuthEnabled) { + this.addAccessPolicies(unsignedAccessPolicy); } } /** * Manages network connections to the domain. This will throw an error in case the domain * is not placed inside a VPC. + * + * @deprecated use opensearchservice module instead */ public get connections(): ec2.Connections { if (!this._connections) { @@ -1760,6 +1942,40 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable { } return this._connections; } + + /** + * Add policy statements to the domain access policy + * + * @deprecated use opensearchservice module instead + */ + public addAccessPolicies(...accessPolicyStatements: iam.PolicyStatement[]) { + if (accessPolicyStatements.length > 0) { + if (!this.accessPolicy) { + // Only create the custom resource after there are statements to set. + this.accessPolicy = new ElasticsearchAccessPolicy(this, 'ESAccessPolicy', { + domainName: this.domainName, + domainArn: this.domainArn, + accessPolicies: accessPolicyStatements, + }); + + if (this.encryptionAtRestOptions?.kmsKey) { + // https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/encryption-at-rest.html + + // these permissions are documented as required during domain creation. + // while not strictly documented for updates as well, it stands to reason that an update + // operation might require these in case the cluster uses a kms key. + // empircal evidence shows this is indeed required: https://github.com/aws/aws-cdk/issues/11412 + this.accessPolicy.grantPrincipal.addToPrincipalPolicy(new iam.PolicyStatement({ + actions: ['kms:List*', 'kms:Describe*', 'kms:CreateGrant'], + resources: [this.encryptionAtRestOptions.kmsKey.keyArn], + effect: iam.Effect.ALLOW, + })); + } + } else { + this.accessPolicy.addAccessPolicies(...accessPolicyStatements); + } + } + } } /** diff --git a/packages/@aws-cdk/aws-elasticsearch/lib/elasticsearch-access-policy.ts b/packages/@aws-cdk/aws-elasticsearch/lib/elasticsearch-access-policy.ts index a79c716831b72..af8a4d31a77ae 100644 --- a/packages/@aws-cdk/aws-elasticsearch/lib/elasticsearch-access-policy.ts +++ b/packages/@aws-cdk/aws-elasticsearch/lib/elasticsearch-access-policy.ts @@ -1,9 +1,7 @@ import * as iam from '@aws-cdk/aws-iam'; +import * as cdk from '@aws-cdk/core'; import * as cr from '@aws-cdk/custom-resources'; - -// keep this import separate from other imports to reduce chance for merge conflicts with v2-main -// eslint-disable-next-line no-duplicate-imports, import/order -import { Construct } from '@aws-cdk/core'; +import { Construct } from 'constructs'; /** * Construction properties for ElasticsearchAccessPolicy @@ -29,11 +27,10 @@ export interface ElasticsearchAccessPolicyProps { * Creates LogGroup resource policies. */ export class ElasticsearchAccessPolicy extends cr.AwsCustomResource { - constructor(scope: Construct, id: string, props: ElasticsearchAccessPolicyProps) { - const policyDocument = new iam.PolicyDocument({ - statements: props.accessPolicies, - }); + private accessPolicyStatements: iam.PolicyStatement[] = []; + + constructor(scope: Construct, id: string, props: ElasticsearchAccessPolicyProps) { super(scope, id, { resourceType: 'Custom::ElasticsearchAccessPolicy', onUpdate: { @@ -41,7 +38,13 @@ export class ElasticsearchAccessPolicy extends cr.AwsCustomResource { service: 'ES', parameters: { DomainName: props.domainName, - AccessPolicies: JSON.stringify(policyDocument.toJSON()), + AccessPolicies: cdk.Lazy.string({ + produce: () => JSON.stringify( + new iam.PolicyDocument({ + statements: this.accessPolicyStatements, + }).toJSON(), + ), + }), }, // this is needed to limit the response body, otherwise it exceeds the CFN 4k limit outputPaths: ['DomainConfig.ElasticsearchClusterConfig.AccessPolicies'], @@ -49,5 +52,14 @@ export class ElasticsearchAccessPolicy extends cr.AwsCustomResource { }, policy: cr.AwsCustomResourcePolicy.fromSdkCalls({ resources: [props.domainArn] }), }); + + this.addAccessPolicies(...props.accessPolicies); + } + + /** + * Add policy statements to the domain access policy + */ + public addAccessPolicies(...accessPolicyStatements: iam.PolicyStatement[]) { + this.accessPolicyStatements.push(...accessPolicyStatements); } } diff --git a/packages/@aws-cdk/aws-elasticsearch/package.json b/packages/@aws-cdk/aws-elasticsearch/package.json index 0a5e8839a0843..6bc9107a0abf5 100644 --- a/packages/@aws-cdk/aws-elasticsearch/package.json +++ b/packages/@aws-cdk/aws-elasticsearch/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -118,12 +118,6 @@ }, "stability": "stable", "maturity": "stable", - "features": [ - { - "name": "Higher level constructs for Domain", - "stability": "Stable" - } - ], "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts b/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts index 3242e75d2c253..ac12536fdcd30 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts @@ -7,8 +7,10 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as logs from '@aws-cdk/aws-logs'; import * as route53 from '@aws-cdk/aws-route53'; +import { testDeprecated } from '@aws-cdk/cdk-build-tools'; import { App, Stack, Duration, SecretValue, CfnParameter, Token } from '@aws-cdk/core'; -import { Domain, ElasticsearchVersion } from '../lib'; + +import { Domain, ElasticsearchVersion } from '../lib/domain'; let app: App; let stack: Stack; @@ -29,7 +31,7 @@ const readWriteActions = [ ...writeActions, ]; -test('connections throws if domain is placed inside a vpc', () => { +testDeprecated('connections throws if domain is placed inside a vpc', () => { expect(() => { new Domain(stack, 'Domain', { @@ -38,7 +40,7 @@ test('connections throws if domain is placed inside a vpc', () => { }).toThrowError("Connections are only available on VPC enabled domains. Use the 'vpc' property to place a domain inside a VPC"); }); -test('subnets and security groups can be provided when vpc is used', () => { +testDeprecated('subnets and security groups can be provided when vpc is used', () => { const vpc = new Vpc(stack, 'Vpc'); const securityGroup = new SecurityGroup(stack, 'CustomSecurityGroup', { @@ -71,7 +73,7 @@ test('subnets and security groups can be provided when vpc is used', () => { }); }); -test('default subnets and security group when vpc is used', () => { +testDeprecated('default subnets and security group when vpc is used', () => { const vpc = new Vpc(stack, 'Vpc'); const domain = new Domain(stack, 'Domain', { @@ -105,7 +107,7 @@ test('default subnets and security group when vpc is used', () => { }); }); -test('default removalpolicy is retain', () => { +testDeprecated('default removalpolicy is retain', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_1, }); @@ -115,7 +117,7 @@ test('default removalpolicy is retain', () => { }); }); -test('grants kms permissions if needed', () => { +testDeprecated('grants kms permissions if needed', () => { const key = new kms.Key(stack, 'Key'); @@ -153,7 +155,7 @@ test('grants kms permissions if needed', () => { }); -test('minimal example renders correctly', () => { +testDeprecated('minimal example renders correctly', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_1 }); Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { @@ -187,7 +189,7 @@ test('minimal example renders correctly', () => { }); }); -test('can enable version upgrade update policy', () => { +testDeprecated('can enable version upgrade update policy', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_1, enableVersionUpgrade: true, @@ -200,9 +202,70 @@ test('can enable version upgrade update policy', () => { }); }); +testDeprecated('can set a self-referencing custom policy', () => { + const domain = new Domain(stack, 'Domain', { + version: ElasticsearchVersion.V7_1, + }); + + domain.addAccessPolicies( + new iam.PolicyStatement({ + actions: ['es:ESHttpPost', 'es:ESHttpPut'], + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('5678')], + resources: [domain.domainArn, `${domain.domainArn}/*`], + }), + ); + + const expectedPolicy = { + 'Fn::Join': [ + '', + [ + '{"action":"updateElasticsearchDomainConfig","service":"ES","parameters":{"DomainName":"', + { + Ref: 'Domain66AC69E0', + }, + '","AccessPolicies":"{\\"Statement\\":[{\\"Action\\":[\\"es:ESHttpPost\\",\\"es:ESHttpPut\\"],\\"Effect\\":\\"Allow\\",\\"Principal\\":{\\"AWS\\":\\"arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::5678:root\\"},\\"Resource\\":[\\"', + { + 'Fn::GetAtt': [ + 'Domain66AC69E0', + 'Arn', + ], + }, + '\\",\\"', + { + 'Fn::GetAtt': [ + 'Domain66AC69E0', + 'Arn', + ], + }, + '/*\\"]}],\\"Version\\":\\"2012-10-17\\"}"},"outputPaths":["DomainConfig.ElasticsearchClusterConfig.AccessPolicies"],"physicalResourceId":{"id":"', + { + Ref: 'Domain66AC69E0', + }, + 'AccessPolicy"}}', + ], + ], + }; + Template.fromStack(stack).hasResourceProperties('Custom::ElasticsearchAccessPolicy', { + ServiceToken: { + 'Fn::GetAtt': [ + 'AWS679f53fac002430cb0da5b7982bd22872D164C4C', + 'Arn', + ], + }, + Create: expectedPolicy, + Update: expectedPolicy, + }); +}); + + describe('UltraWarm instances', () => { - test('can enable UltraWarm instances', () => { + testDeprecated('can enable UltraWarm instances', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_1, capacity: { @@ -221,7 +284,7 @@ describe('UltraWarm instances', () => { }); }); - test('can enable UltraWarm instances with specific instance type', () => { + testDeprecated('can enable UltraWarm instances with specific instance type', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_1, capacity: { @@ -243,7 +306,7 @@ describe('UltraWarm instances', () => { }); -test('can use tokens in capacity configuration', () => { +testDeprecated('can use tokens in capacity configuration', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_10, capacity: { @@ -284,7 +347,7 @@ test('can use tokens in capacity configuration', () => { describe('log groups', () => { - test('slowSearchLogEnabled should create a custom log group', () => { + testDeprecated('slowSearchLogEnabled should create a custom log group', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_4, logging: { @@ -310,7 +373,7 @@ describe('log groups', () => { }); }); - test('slowIndexLogEnabled should create a custom log group', () => { + testDeprecated('slowIndexLogEnabled should create a custom log group', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_4, logging: { @@ -336,7 +399,7 @@ describe('log groups', () => { }); }); - test('appLogEnabled should create a custom log group', () => { + testDeprecated('appLogEnabled should create a custom log group', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_4, logging: { @@ -362,7 +425,7 @@ describe('log groups', () => { }); }); - test('auditLogEnabled should create a custom log group', () => { + testDeprecated('auditLogEnabled should create a custom log group', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_4, logging: { @@ -396,7 +459,7 @@ describe('log groups', () => { }); }); - test('two domains with logging enabled can be created in same stack', () => { + testDeprecated('two domains with logging enabled can be created in same stack', () => { new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V7_7, logging: { @@ -479,7 +542,7 @@ describe('log groups', () => { }); }); - test('log group policy is uniquely named for each domain', () => { + testDeprecated('log group policy is uniquely named for each domain', () => { new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V7_4, logging: { @@ -531,7 +594,7 @@ describe('log groups', () => { }); }); - test('enabling audit logs throws without fine grained access control enabled', () => { + testDeprecated('enabling audit logs throws without fine grained access control enabled', () => { expect(() => new Domain(stack, 'Domain', { version: ElasticsearchVersion.V6_7, logging: { @@ -540,7 +603,7 @@ describe('log groups', () => { })).toThrow(/Fine-grained access control is required when audit logs publishing is enabled\./); }); - test('slowSearchLogGroup should use a custom log group', () => { + testDeprecated('slowSearchLogGroup should use a custom log group', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_4, logging: { @@ -569,7 +632,7 @@ describe('log groups', () => { }); }); - test('slowIndexLogEnabled should use a custom log group', () => { + testDeprecated('slowIndexLogEnabled should use a custom log group', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_4, logging: { @@ -598,7 +661,7 @@ describe('log groups', () => { }); }); - test('appLogGroup should use a custom log group', () => { + testDeprecated('appLogGroup should use a custom log group', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_4, logging: { @@ -627,7 +690,7 @@ describe('log groups', () => { }); }); - test('auditLOgGroup should use a custom log group', () => { + testDeprecated('auditLOgGroup should use a custom log group', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_4, fineGrainedAccessControl: { @@ -668,19 +731,19 @@ describe('log groups', () => { describe('grants', () => { - test('"grantRead" allows read actions associated with this domain resource', () => { + testDeprecated('"grantRead" allows read actions associated with this domain resource', () => { testGrant(readActions, (p, d) => d.grantRead(p)); }); - test('"grantWrite" allows write actions associated with this domain resource', () => { + testDeprecated('"grantWrite" allows write actions associated with this domain resource', () => { testGrant(writeActions, (p, d) => d.grantWrite(p)); }); - test('"grantReadWrite" allows read and write actions associated with this domain resource', () => { + testDeprecated('"grantReadWrite" allows read and write actions associated with this domain resource', () => { testGrant(readWriteActions, (p, d) => d.grantReadWrite(p)); }); - test('"grantIndexRead" allows read actions associated with an index in this domain resource', () => { + testDeprecated('"grantIndexRead" allows read actions associated with an index in this domain resource', () => { testGrant( readActions, (p, d) => d.grantIndexRead('my-index', p), @@ -689,7 +752,7 @@ describe('grants', () => { ); }); - test('"grantIndexWrite" allows write actions associated with an index in this domain resource', () => { + testDeprecated('"grantIndexWrite" allows write actions associated with an index in this domain resource', () => { testGrant( writeActions, (p, d) => d.grantIndexWrite('my-index', p), @@ -698,7 +761,7 @@ describe('grants', () => { ); }); - test('"grantIndexReadWrite" allows read and write actions associated with an index in this domain resource', () => { + testDeprecated('"grantIndexReadWrite" allows read and write actions associated with an index in this domain resource', () => { testGrant( readWriteActions, (p, d) => d.grantIndexReadWrite('my-index', p), @@ -707,7 +770,7 @@ describe('grants', () => { ); }); - test('"grantPathRead" allows read actions associated with a given path in this domain resource', () => { + testDeprecated('"grantPathRead" allows read actions associated with a given path in this domain resource', () => { testGrant( readActions, (p, d) => d.grantPathRead('my-index/my-path', p), @@ -716,7 +779,7 @@ describe('grants', () => { ); }); - test('"grantPathWrite" allows write actions associated with a given path in this domain resource', () => { + testDeprecated('"grantPathWrite" allows write actions associated with a given path in this domain resource', () => { testGrant( writeActions, (p, d) => d.grantPathWrite('my-index/my-path', p), @@ -725,7 +788,7 @@ describe('grants', () => { ); }); - test('"grantPathReadWrite" allows read and write actions associated with a given path in this domain resource', () => { + testDeprecated('"grantPathReadWrite" allows read and write actions associated with a given path in this domain resource', () => { testGrant( readWriteActions, (p, d) => d.grantPathReadWrite('my-index/my-path', p), @@ -734,7 +797,7 @@ describe('grants', () => { ); }); - test('"grant" for an imported domain', () => { + testDeprecated('"grant" for an imported domain', () => { const domainEndpoint = 'https://test-domain-2w2x2u3tifly-jcjotrt6f7otem4sqcwbch3c4u.testregion.es.amazonaws.com'; const domain = Domain.fromDomainEndpoint(stack, 'Domain', domainEndpoint); const user = new iam.User(stack, 'user'); @@ -797,7 +860,7 @@ describe('grants', () => { describe('metrics', () => { - test('Can use metricClusterStatusRed on an Elasticsearch Domain', () => { + testDeprecated('Can use metricClusterStatusRed on an Elasticsearch Domain', () => { testMetric( (domain) => domain.metricClusterStatusRed(), 'ClusterStatus.red', @@ -805,7 +868,7 @@ describe('metrics', () => { ); }); - test('Can use metricClusterStatusYellow on an Elasticsearch Domain', () => { + testDeprecated('Can use metricClusterStatusYellow on an Elasticsearch Domain', () => { testMetric( (domain) => domain.metricClusterStatusYellow(), 'ClusterStatus.yellow', @@ -813,7 +876,7 @@ describe('metrics', () => { ); }); - test('Can use metricFreeStorageSpace on an Elasticsearch Domain', () => { + testDeprecated('Can use metricFreeStorageSpace on an Elasticsearch Domain', () => { testMetric( (domain) => domain.metricFreeStorageSpace(), 'FreeStorageSpace', @@ -821,7 +884,7 @@ describe('metrics', () => { ); }); - test('Can use metricClusterIndexWriteBlocked on an Elasticsearch Domain', () => { + testDeprecated('Can use metricClusterIndexWriteBlocked on an Elasticsearch Domain', () => { testMetric( (domain) => domain.metricClusterIndexWritesBlocked(), 'ClusterIndexWritesBlocked', @@ -830,7 +893,7 @@ describe('metrics', () => { ); }); - test('Can use metricNodes on an Elasticsearch Domain', () => { + testDeprecated('Can use metricNodes on an Elasticsearch Domain', () => { testMetric( (domain) => domain.metricNodes(), 'Nodes', @@ -839,7 +902,7 @@ describe('metrics', () => { ); }); - test('Can use metricAutomatedSnapshotFailure on an Elasticsearch Domain', () => { + testDeprecated('Can use metricAutomatedSnapshotFailure on an Elasticsearch Domain', () => { testMetric( (domain) => domain.metricAutomatedSnapshotFailure(), 'AutomatedSnapshotFailure', @@ -847,7 +910,7 @@ describe('metrics', () => { ); }); - test('Can use metricCPUUtilization on an Elasticsearch Domain', () => { + testDeprecated('Can use metricCPUUtilization on an Elasticsearch Domain', () => { testMetric( (domain) => domain.metricCPUUtilization(), 'CPUUtilization', @@ -855,7 +918,7 @@ describe('metrics', () => { ); }); - test('Can use metricJVMMemoryPressure on an Elasticsearch Domain', () => { + testDeprecated('Can use metricJVMMemoryPressure on an Elasticsearch Domain', () => { testMetric( (domain) => domain.metricJVMMemoryPressure(), 'JVMMemoryPressure', @@ -863,7 +926,7 @@ describe('metrics', () => { ); }); - test('Can use metricMasterCPUUtilization on an Elasticsearch Domain', () => { + testDeprecated('Can use metricMasterCPUUtilization on an Elasticsearch Domain', () => { testMetric( (domain) => domain.metricMasterCPUUtilization(), 'MasterCPUUtilization', @@ -871,7 +934,7 @@ describe('metrics', () => { ); }); - test('Can use metricMasterJVMMemoryPressure on an Elasticsearch Domain', () => { + testDeprecated('Can use metricMasterJVMMemoryPressure on an Elasticsearch Domain', () => { testMetric( (domain) => domain.metricMasterJVMMemoryPressure(), 'MasterJVMMemoryPressure', @@ -879,7 +942,7 @@ describe('metrics', () => { ); }); - test('Can use metricKMSKeyError on an Elasticsearch Domain', () => { + testDeprecated('Can use metricKMSKeyError on an Elasticsearch Domain', () => { testMetric( (domain) => domain.metricKMSKeyError(), 'KMSKeyError', @@ -887,7 +950,7 @@ describe('metrics', () => { ); }); - test('Can use metricKMSKeyInaccessible on an Elasticsearch Domain', () => { + testDeprecated('Can use metricKMSKeyInaccessible on an Elasticsearch Domain', () => { testMetric( (domain) => domain.metricKMSKeyInaccessible(), 'KMSKeyInaccessible', @@ -895,7 +958,7 @@ describe('metrics', () => { ); }); - test('Can use metricSearchableDocuments on an Elasticsearch Domain', () => { + testDeprecated('Can use metricSearchableDocuments on an Elasticsearch Domain', () => { testMetric( (domain) => domain.metricSearchableDocuments(), 'SearchableDocuments', @@ -903,7 +966,7 @@ describe('metrics', () => { ); }); - test('Can use metricSearchLatency on an Elasticsearch Domain', () => { + testDeprecated('Can use metricSearchLatency on an Elasticsearch Domain', () => { testMetric( (domain) => domain.metricSearchLatency(), 'SearchLatency', @@ -911,7 +974,7 @@ describe('metrics', () => { ); }); - test('Can use metricIndexingLatency on an Elasticsearch Domain', () => { + testDeprecated('Can use metricIndexingLatency on an Elasticsearch Domain', () => { testMetric( (domain) => domain.metricIndexingLatency(), 'IndexingLatency', @@ -923,7 +986,7 @@ describe('metrics', () => { describe('import', () => { - test('static fromDomainEndpoint(endpoint) allows importing an external/existing domain', () => { + testDeprecated('static fromDomainEndpoint(endpoint) allows importing an external/existing domain', () => { const domainName = 'test-domain-2w2x2u3tifly'; const domainEndpointWithoutHttps = `${domainName}-jcjotrt6f7otem4sqcwbch3c4u.testregion.es.amazonaws.com`; const domainEndpoint = `https://${domainEndpointWithoutHttps}`; @@ -936,7 +999,7 @@ describe('import', () => { Template.fromStack(stack).resourceCountIs('AWS::Elasticsearch::Domain', 0); }); - test('static fromDomainAttributes(attributes) allows importing an external/existing domain', () => { + testDeprecated('static fromDomainAttributes(attributes) allows importing an external/existing domain', () => { const domainName = 'test-domain-2w2x2u3tifly'; const domainArn = `arn:aws:es:testregion:1234:domain/${domainName}`; const domainEndpointWithoutHttps = `${domainName}-jcjotrt6f7otem4sqcwbch3c4u.testregion.es.amazonaws.com`; @@ -953,7 +1016,7 @@ describe('import', () => { Template.fromStack(stack).resourceCountIs('AWS::Elasticsearch::Domain', 0); }); - test('static fromDomainAttributes(attributes) allows importing with token arn and endpoint', () => { + testDeprecated('static fromDomainAttributes(attributes) allows importing with token arn and endpoint', () => { const domainArn = new CfnParameter(stack, 'domainArn', { type: 'String' }).valueAsString; const domainEndpoint = new CfnParameter(stack, 'domainEndpoint', { type: 'String' }).valueAsString; const imported = Domain.fromDomainAttributes(stack, 'Domain', { @@ -998,7 +1061,7 @@ describe('advanced security options', () => { const password = 'password'; const masterUserPassword = SecretValue.plainText(password); - test('enable fine-grained access control with a master user ARN', () => { + testDeprecated('enable fine-grained access control with a master user ARN', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_1, fineGrainedAccessControl: { @@ -1031,7 +1094,7 @@ describe('advanced security options', () => { }); }); - test('enable fine-grained access control with a master user name and password', () => { + testDeprecated('enable fine-grained access control with a master user name and password', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_1, fineGrainedAccessControl: { @@ -1066,7 +1129,7 @@ describe('advanced security options', () => { }); }); - test('enable fine-grained access control with a master user name and dynamically generated password', () => { + testDeprecated('enable fine-grained access control with a master user name and dynamically generated password', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_1, fineGrainedAccessControl: { @@ -1117,7 +1180,7 @@ describe('advanced security options', () => { }); }); - test('enabling fine-grained access control throws with Elasticsearch < 6.7', () => { + testDeprecated('enabling fine-grained access control throws with Elasticsearch < 6.7', () => { expect(() => new Domain(stack, 'Domain', { version: ElasticsearchVersion.V6_5, fineGrainedAccessControl: { @@ -1131,7 +1194,7 @@ describe('advanced security options', () => { })).toThrow(/Fine-grained access control requires Elasticsearch version 6\.7 or later/); }); - test('enabling fine-grained access control throws without node-to-node encryption enabled', () => { + testDeprecated('enabling fine-grained access control throws without node-to-node encryption enabled', () => { expect(() => new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_7, fineGrainedAccessControl: { @@ -1145,7 +1208,7 @@ describe('advanced security options', () => { })).toThrow(/Node-to-node encryption is required when fine-grained access control is enabled/); }); - test('enabling fine-grained access control throws without encryption-at-rest enabled', () => { + testDeprecated('enabling fine-grained access control throws without encryption-at-rest enabled', () => { expect(() => new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_7, fineGrainedAccessControl: { @@ -1159,7 +1222,7 @@ describe('advanced security options', () => { })).toThrow(/Encryption-at-rest is required when fine-grained access control is enabled/); }); - test('enabling fine-grained access control throws without enforceHttps enabled', () => { + testDeprecated('enabling fine-grained access control throws without enforceHttps enabled', () => { expect(() => new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_7, fineGrainedAccessControl: { @@ -1177,7 +1240,7 @@ describe('advanced security options', () => { describe('custom endpoints', () => { const customDomainName = 'search.example.com'; - test('custom domain without hosted zone and default cert', () => { + testDeprecated('custom domain without hosted zone and default cert', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_1, nodeToNodeEncryption: true, @@ -1203,7 +1266,7 @@ describe('custom endpoints', () => { }); }); - test('custom domain with hosted zone and default cert', () => { + testDeprecated('custom domain with hosted zone and default cert', () => { const zone = new route53.HostedZone(stack, 'DummyZone', { zoneName: 'example.com' }); new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_1, @@ -1254,7 +1317,7 @@ describe('custom endpoints', () => { }); }); - test('custom domain with hosted zone and given cert', () => { + testDeprecated('custom domain with hosted zone and given cert', () => { const zone = new route53.HostedZone(stack, 'DummyZone', { zoneName: 'example.com', }); @@ -1304,7 +1367,7 @@ describe('custom endpoints', () => { describe('custom error responses', () => { - test('error when availabilityZoneCount does not match vpcOptions.subnets length', () => { + testDeprecated('error when availabilityZoneCount does not match vpcOptions.subnets length', () => { const vpc = new Vpc(stack, 'Vpc', { maxAzs: 1, }); @@ -1319,7 +1382,7 @@ describe('custom error responses', () => { })).toThrow(/you need to provide a subnet for each AZ you are using/); }); - test('error when master, data or Ultra Warm instance types do not end with .elasticsearch', () => { + testDeprecated('error when master, data or Ultra Warm instance types do not end with .elasticsearch', () => { const error = /instance types must end with ".elasticsearch"/; expect(() => new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V7_4, @@ -1341,7 +1404,7 @@ describe('custom error responses', () => { })).toThrow(error); }); - test('error when Ultra Warm instance types do not start with ultrawarm', () => { + testDeprecated('error when Ultra Warm instance types do not start with ultrawarm', () => { const error = /UltraWarm node instance type must start with "ultrawarm"./; expect(() => new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V7_4, @@ -1351,13 +1414,13 @@ describe('custom error responses', () => { })).toThrow(error); }); - test('error when elasticsearchVersion is unsupported/unknown', () => { + testDeprecated('error when elasticsearchVersion is unsupported/unknown', () => { expect(() => new Domain(stack, 'Domain1', { version: ElasticsearchVersion.of('5.4'), })).toThrow(/Unknown Elasticsearch version: 5\.4/); }); - test('error when invalid domain name is given', () => { + testDeprecated('error when invalid domain name is given', () => { expect(() => new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V7_4, domainName: 'InvalidName', @@ -1372,7 +1435,7 @@ describe('custom error responses', () => { })).toThrow(/It must start with a lowercase letter/); }); - test('error when error log publishing is enabled for elasticsearch version < 5.1', () => { + testDeprecated('error when error log publishing is enabled for elasticsearch version < 5.1', () => { const error = /Error logs publishing requires Elasticsearch version 5.1 or later/; expect(() => new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V2_3, @@ -1382,7 +1445,7 @@ describe('custom error responses', () => { })).toThrow(error); }); - test('error when encryption at rest is enabled for elasticsearch version < 5.1', () => { + testDeprecated('error when encryption at rest is enabled for elasticsearch version < 5.1', () => { expect(() => new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V2_3, encryptionAtRest: { @@ -1391,7 +1454,7 @@ describe('custom error responses', () => { })).toThrow(/Encryption of data at rest requires Elasticsearch version 5.1 or later/); }); - test('error when cognito for kibana is enabled for elasticsearch version < 5.1', () => { + testDeprecated('error when cognito for kibana is enabled for elasticsearch version < 5.1', () => { const user = new iam.User(stack, 'user'); expect(() => new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V2_3, @@ -1403,7 +1466,7 @@ describe('custom error responses', () => { })).toThrow(/Cognito authentication for Kibana requires Elasticsearch version 5.1 or later/); }); - test('error when C5, I3, M5, or R5 instance types are specified for elasticsearch version < 5.1', () => { + testDeprecated('error when C5, I3, M5, or R5 instance types are specified for elasticsearch version < 5.1', () => { const error = /C5, I3, M5, and R5 instance types require Elasticsearch version 5.1 or later/; expect(() => new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V2_3, @@ -1431,14 +1494,14 @@ describe('custom error responses', () => { })).toThrow(error); }); - test('error when node to node encryption is enabled for elasticsearch version < 6.0', () => { + testDeprecated('error when node to node encryption is enabled for elasticsearch version < 6.0', () => { expect(() => new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V5_6, nodeToNodeEncryption: true, })).toThrow(/Node-to-node encryption requires Elasticsearch version 6.0 or later/); }); - test('error when i3 or r6g instance types are specified with EBS enabled', () => { + testDeprecated('error when i3 or r6g instance types are specified with EBS enabled', () => { expect(() => new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V7_4, capacity: { @@ -1461,7 +1524,7 @@ describe('custom error responses', () => { })).toThrow(/I3 and R6GD instance types do not support EBS storage volumes/); }); - test('error when m3, r3, or t2 instance types are specified with encryption at rest enabled', () => { + testDeprecated('error when m3, r3, or t2 instance types are specified with encryption at rest enabled', () => { const error = /M3, R3, and T2 instance types do not support encryption of data at rest/; expect(() => new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V7_4, @@ -1492,7 +1555,7 @@ describe('custom error responses', () => { })).toThrow(error); }); - test('error when t2.micro is specified with elasticsearch version > 2.3', () => { + testDeprecated('error when t2.micro is specified with elasticsearch version > 2.3', () => { expect(() => new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V6_7, capacity: { @@ -1501,7 +1564,7 @@ describe('custom error responses', () => { })).toThrow(/t2.micro.elasticsearch instance type supports only Elasticsearch 1.5 and 2.3/); }); - test('error when any instance type other than R3, I3 and R6GD are specified without EBS enabled', () => { + testDeprecated('error when any instance type other than R3, I3 and R6GD are specified without EBS enabled', () => { expect(() => new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V7_4, ebs: { @@ -1522,7 +1585,7 @@ describe('custom error responses', () => { })).toThrow(/EBS volumes are required when using instance types other than r3, i3 or r6gd/); }); - test('can use compatible master instance types that does not have local storage when data node type is i3 or r6gd', () => { + testDeprecated('can use compatible master instance types that does not have local storage when data node type is i3 or r6gd', () => { new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V7_4, ebs: { @@ -1548,7 +1611,7 @@ describe('custom error responses', () => { Template.fromStack(stack).resourceCountIs('AWS::Elasticsearch::Domain', 2); }); - test('error when availabilityZoneCount is not 2 or 3', () => { + testDeprecated('error when availabilityZoneCount is not 2 or 3', () => { const vpc = new Vpc(stack, 'Vpc'); expect(() => new Domain(stack, 'Domain1', { @@ -1560,7 +1623,7 @@ describe('custom error responses', () => { })).toThrow(/Invalid zone awareness configuration; availabilityZoneCount must be 2 or 3/); }); - test('error when UltraWarm instance is used and not supported by elasticsearchVersion', () => { + testDeprecated('error when UltraWarm instance is used and not supported by elasticsearchVersion', () => { expect(() => new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V6_7, capacity: { @@ -1570,7 +1633,7 @@ describe('custom error responses', () => { })).toThrow(/UltraWarm requires Elasticsearch 6\.8 or later/); }); - test('error when t2 or t3 instance types are specified with UltramWarm enabled', () => { + testDeprecated('error when t2 or t3 instance types are specified with UltramWarm enabled', () => { const error = /T2 and T3 instance types do not support UltraWarm storage/; expect(() => new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V7_4, @@ -1588,7 +1651,7 @@ describe('custom error responses', () => { })).toThrow(error); }); - test('error when UltraWarm instance is used and no dedicated master instance specified', () => { + testDeprecated('error when UltraWarm instance is used and no dedicated master instance specified', () => { expect(() => new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V7_4, capacity: { @@ -1600,7 +1663,7 @@ describe('custom error responses', () => { }); -test('can specify future version', () => { +testDeprecated('can specify future version', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.of('8.2') }); Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { @@ -1609,7 +1672,7 @@ test('can specify future version', () => { }); describe('unsigned basic auth', () => { - test('can create a domain with unsigned basic auth', () => { + testDeprecated('can create a domain with unsigned basic auth', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_7, useUnsignedBasicAuth: true, @@ -1635,7 +1698,7 @@ describe('unsigned basic auth', () => { }); }); - test('does not overwrite master user ARN configuration', () => { + testDeprecated('does not overwrite master user ARN configuration', () => { const masterUserArn = 'arn:aws:iam::123456789012:user/JohnDoe'; new Domain(stack, 'Domain', { @@ -1666,7 +1729,7 @@ describe('unsigned basic auth', () => { }); }); - test('does not overwrite master user name and password', () => { + testDeprecated('does not overwrite master user name and password', () => { const masterUserName = 'JohnDoe'; const password = 'password'; const masterUserPassword = SecretValue.plainText(password); @@ -1701,7 +1764,7 @@ describe('unsigned basic auth', () => { }); }); - test('fails to create a domain with unsigned basic auth when enforce HTTPS is disabled', () => { + testDeprecated('fails to create a domain with unsigned basic auth when enforce HTTPS is disabled', () => { expect(() => new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_7, useUnsignedBasicAuth: true, @@ -1709,7 +1772,7 @@ describe('unsigned basic auth', () => { })).toThrow(/You cannot disable HTTPS and use unsigned basic auth/); }); - test('fails to create a domain with unsigned basic auth when node to node encryption is disabled', () => { + testDeprecated('fails to create a domain with unsigned basic auth when node to node encryption is disabled', () => { expect(() => new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_7, useUnsignedBasicAuth: true, @@ -1717,7 +1780,7 @@ describe('unsigned basic auth', () => { })).toThrow(/You cannot disable node to node encryption and use unsigned basic auth/); }); - test('fails to create a domain with unsigned basic auth when encryption at rest is disabled', () => { + testDeprecated('fails to create a domain with unsigned basic auth when encryption at rest is disabled', () => { expect(() => new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_7, useUnsignedBasicAuth: true, @@ -1725,7 +1788,7 @@ describe('unsigned basic auth', () => { })).toThrow(/You cannot disable encryption at rest and use unsigned basic auth/); }); - test('using unsigned basic auth throws with Elasticsearch < 6.7', () => { + testDeprecated('using unsigned basic auth throws with Elasticsearch < 6.7', () => { expect(() => new Domain(stack, 'Domain', { version: ElasticsearchVersion.V6_5, useUnsignedBasicAuth: true, @@ -1734,7 +1797,7 @@ describe('unsigned basic auth', () => { }); describe('advanced options', () => { - test('use advanced options', () => { + testDeprecated('use advanced options', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_1, advancedOptions: { @@ -1751,7 +1814,7 @@ describe('advanced options', () => { }); }); - test('advanced options absent by default', () => { + testDeprecated('advanced options absent by default', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_1, }); diff --git a/packages/@aws-cdk/aws-elasticsearch/test/elasticsearch-access-policy.test.ts b/packages/@aws-cdk/aws-elasticsearch/test/elasticsearch-access-policy.test.ts index 38ffc94c0c05b..53086622c5231 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/elasticsearch-access-policy.test.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/elasticsearch-access-policy.test.ts @@ -55,3 +55,55 @@ test('minimal example renders correctly', () => { }), }); }); + +test('support access policy added inline and later', () => { + const elasticsearchAccessPolicy = new ElasticsearchAccessPolicy(stack, 'ElasticsearchAccessPolicy', { + domainName: 'TestDomain', + domainArn: 'test:arn', + accessPolicies: [ + new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + actions: ['es:ESHttp*'], + principals: [new iam.AnyPrincipal()], + resources: ['test:arn'], + }), + ], + }); + elasticsearchAccessPolicy.addAccessPolicies( + new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + actions: ['*'], + principals: [new iam.AnyPrincipal()], + resources: ['test:arn'], + }), + ); + + Template.fromStack(stack).hasResourceProperties('Custom::ElasticsearchAccessPolicy', { + ServiceToken: { + 'Fn::GetAtt': [ + 'AWS679f53fac002430cb0da5b7982bd22872D164C4C', + 'Arn', + ], + }, + Create: JSON.stringify({ + action: 'updateElasticsearchDomainConfig', + service: 'ES', + parameters: { + DomainName: 'TestDomain', + AccessPolicies: '{"Statement":[{"Action":"es:ESHttp*","Effect":"Allow","Principal":{"AWS":"*"},"Resource":"test:arn"},{"Action":"*","Effect":"Allow","Principal":{"AWS":"*"},"Resource":"test:arn"}],"Version":"2012-10-17"}', + }, + outputPaths: ['DomainConfig.ElasticsearchClusterConfig.AccessPolicies'], + physicalResourceId: { id: 'TestDomainAccessPolicy' }, + }), + Update: JSON.stringify({ + action: 'updateElasticsearchDomainConfig', + service: 'ES', + parameters: { + DomainName: 'TestDomain', + AccessPolicies: '{"Statement":[{"Action":"es:ESHttp*","Effect":"Allow","Principal":{"AWS":"*"},"Resource":"test:arn"},{"Action":"*","Effect":"Allow","Principal":{"AWS":"*"},"Resource":"test:arn"}],"Version":"2012-10-17"}', + }, + outputPaths: ['DomainConfig.ElasticsearchClusterConfig.AccessPolicies'], + physicalResourceId: { id: 'TestDomainAccessPolicy' }, + }), + }); +}); diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.expected.json b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.expected.json index 636acfc906b05..bad6008645b93 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.expected.json @@ -57,12 +57,10 @@ "PolicyDocument": { "Statement": [ { - "Action": "logs:PutResourcePolicy", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "logs:DeleteResourcePolicy", + "Action": [ + "logs:DeleteResourcePolicy", + "logs:PutResourcePolicy" + ], "Effect": "Allow", "Resource": "*" } @@ -222,10 +220,7 @@ "Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" } ] - }, - "DependsOn": [ - "Domain66AC69E0" - ] + } }, "DomainESAccessPolicy89986F33": { "Type": "Custom::ElasticsearchAccessPolicy", @@ -287,8 +282,7 @@ "InstallLatestAwsSdk": true }, "DependsOn": [ - "DomainESAccessPolicyCustomResourcePolicy9747FC42", - "Domain66AC69E0" + "DomainESAccessPolicyCustomResourcePolicy9747FC42" ], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" @@ -331,9 +325,9 @@ "Statement": [ { "Action": [ - "kms:List*", + "kms:CreateGrant", "kms:Describe*", - "kms:CreateGrant" + "kms:List*" ], "Effect": "Allow", "Resource": { @@ -359,7 +353,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16" }, "S3Key": { "Fn::Join": [ @@ -372,7 +366,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -385,7 +379,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -412,17 +406,17 @@ } }, "Parameters": { - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16": { "Type": "String", - "Description": "S3 bucket for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "S3 bucket for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B": { "Type": "String", - "Description": "S3 key for asset version \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "S3 key for asset version \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2ArtifactHash4BE92B79": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87ArtifactHash40DDF5EE": { "Type": "String", - "Description": "Artifact hash for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "Artifact hash for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json index 73c6624609fd4..7d14d86bb2134 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json @@ -22,12 +22,10 @@ "PolicyDocument": { "Statement": [ { - "Action": "logs:PutResourcePolicy", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "logs:DeleteResourcePolicy", + "Action": [ + "logs:DeleteResourcePolicy", + "logs:PutResourcePolicy" + ], "Effect": "Allow", "Resource": "*" } @@ -189,10 +187,7 @@ "Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" } ] - }, - "DependsOn": [ - "Domain19FCBCB91" - ] + } }, "Domain1ESAccessPolicy5D846A31": { "Type": "Custom::ElasticsearchAccessPolicy", @@ -254,8 +249,7 @@ "InstallLatestAwsSdk": true }, "DependsOn": [ - "Domain1ESAccessPolicyCustomResourcePolicyC04432B6", - "Domain19FCBCB91" + "Domain1ESAccessPolicyCustomResourcePolicyC04432B6" ], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" @@ -296,7 +290,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16" }, "S3Key": { "Fn::Join": [ @@ -309,7 +303,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -322,7 +316,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -368,12 +362,10 @@ "PolicyDocument": { "Statement": [ { - "Action": "logs:PutResourcePolicy", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "logs:DeleteResourcePolicy", + "Action": [ + "logs:DeleteResourcePolicy", + "logs:PutResourcePolicy" + ], "Effect": "Allow", "Resource": "*" } @@ -535,10 +527,7 @@ "Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" } ] - }, - "DependsOn": [ - "Domain2644FE48C" - ] + } }, "Domain2ESAccessPolicy3DF4C2BA": { "Type": "Custom::ElasticsearchAccessPolicy", @@ -600,25 +589,24 @@ "InstallLatestAwsSdk": true }, "DependsOn": [ - "Domain2ESAccessPolicyCustomResourcePolicy8EED1F24", - "Domain2644FE48C" + "Domain2ESAccessPolicyCustomResourcePolicy8EED1F24" ], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" } }, "Parameters": { - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16": { "Type": "String", - "Description": "S3 bucket for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "S3 bucket for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B": { "Type": "String", - "Description": "S3 key for asset version \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "S3 key for asset version \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2ArtifactHash4BE92B79": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87ArtifactHash40DDF5EE": { "Type": "String", - "Description": "Artifact hash for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "Artifact hash for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.expected.json b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.expected.json index 2793a8beb231f..86297ef04a7dd 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.expected.json @@ -88,10 +88,7 @@ "Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" } ] - }, - "DependsOn": [ - "Domain66AC69E0" - ] + } }, "DomainESAccessPolicy89986F33": { "Type": "Custom::ElasticsearchAccessPolicy", @@ -151,8 +148,7 @@ "InstallLatestAwsSdk": true }, "DependsOn": [ - "DomainESAccessPolicyCustomResourcePolicy9747FC42", - "Domain66AC69E0" + "DomainESAccessPolicyCustomResourcePolicy9747FC42" ], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" @@ -193,7 +189,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16" }, "S3Key": { "Fn::Join": [ @@ -206,7 +202,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -219,7 +215,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -245,17 +241,17 @@ } }, "Parameters": { - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16": { "Type": "String", - "Description": "S3 bucket for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "S3 bucket for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B": { "Type": "String", - "Description": "S3 key for asset version \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "S3 key for asset version \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2ArtifactHash4BE92B79": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87ArtifactHash40DDF5EE": { "Type": "String", - "Description": "Artifact hash for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "Artifact hash for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-emr/package.json b/packages/@aws-cdk/aws-emr/package.json index ae9f2a89744ea..d8638f3174f7a 100644 --- a/packages/@aws-cdk/aws-emr/package.json +++ b/packages/@aws-cdk/aws-emr/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-emrcontainers/package.json b/packages/@aws-cdk/aws-emrcontainers/package.json index 5762e656d6761..72b6f669f603a 100644 --- a/packages/@aws-cdk/aws-emrcontainers/package.json +++ b/packages/@aws-cdk/aws-emrcontainers/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-events-targets/README.md b/packages/@aws-cdk/aws-events-targets/README.md index 1282cee012c5e..34157fef412b5 100644 --- a/packages/@aws-cdk/aws-events-targets/README.md +++ b/packages/@aws-cdk/aws-events-targets/README.md @@ -19,7 +19,7 @@ Currently supported are: * [Start a CodePipeline pipeline](#start-a-codepipeline-pipeline) * Run an ECS task * [Invoke a Lambda function](#invoke-a-lambda-function) -* [Invoke a API Gateway REST API](#invoke-a-api-gateway-rest-api) +* [Invoke a API Gateway REST API](#invoke-an-api-gateway-rest-api) * Publish a message to an SNS topic * Send a message to an SQS queue * [Start a StepFunctions state machine](#start-a-stepfunctions-state-machine) @@ -29,6 +29,7 @@ Currently supported are: * [Log an event into a LogGroup](#log-an-event-into-a-loggroup) * Put a record to a Kinesis Data Firehose stream * [Put an event on an EventBridge bus](#put-an-event-on-an-eventbridge-bus) +* [Send an event to EventBridge API Destination](#invoke-an-api-destination) See the README of the `@aws-cdk/aws-events` library for more information on EventBridge. @@ -166,13 +167,13 @@ const role = new iam.Role(this, 'Role', { assumedBy: new iam.ServicePrincipal('events.amazonaws.com'), }); const stateMachine = new sfn.StateMachine(this, 'SM', { - definition: new sfn.Wait(this, 'Hello', { time: sfn.WaitTime.duration(cdk.Duration.seconds(10)) }), - role, + definition: new sfn.Wait(this, 'Hello', { time: sfn.WaitTime.duration(cdk.Duration.seconds(10)) }) }); rule.addTarget(new targets.SfnStateMachine(stateMachine, { input: events.RuleTargetInput.fromObject({ SomeParam: 'SomeValue' }), deadLetterQueue: dlq, + role: role })); ``` @@ -226,7 +227,7 @@ rule.addTarget(new targets.BatchJob( )); ``` -## Invoke a API Gateway REST API +## Invoke an API Gateway REST API Use the `ApiGateway` target to trigger a REST API. @@ -267,6 +268,31 @@ rule.addTarget( ) ``` +## Invoke an API Destination + +Use the `targets.ApiDestination` target to trigger an external API. You need to +create an `events.Connection` and `events.ApiDestination` as well. + +The code snippet below creates an external destination that is invoked every hour. + +```ts +const connection = new events.Connection(this, 'Connection', { + authorization: events.Authorization.apiKey('x-api-key', SecretValue.secretsManager('ApiSecretName')), + description: 'Connection with API Key x-api-key', +}); + +const destination = new events.ApiDestination(this, 'Destination', { + connection, + endpoint: 'https://example.com', + description: 'Calling example.com with API key x-api-key', +}); + +const rule = new events.Rule(this, 'Rule', { + schedule: events.Schedule.rate(cdk.Duration.minutes(1)), + targets: [new targets.ApiDestination(destination)], +}); +``` + ## Put an event on an EventBridge bus Use the `EventBus` target to route event to a different EventBus. diff --git a/packages/@aws-cdk/aws-events-targets/lib/api-destination.ts b/packages/@aws-cdk/aws-events-targets/lib/api-destination.ts new file mode 100644 index 0000000000000..8f2bc936a6d28 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/lib/api-destination.ts @@ -0,0 +1,98 @@ +import * as events from '@aws-cdk/aws-events'; +import * as iam from '@aws-cdk/aws-iam'; +import { addToDeadLetterQueueResourcePolicy, bindBaseTargetConfig, singletonEventRole, TargetBaseProps } from './util'; + +/** + * Customize the EventBridge Api Destinations Target + */ +export interface ApiDestinationProps extends TargetBaseProps { + /** + * The event to send + * + * @default - the entire EventBridge event + */ + readonly event?: events.RuleTargetInput; + + /** + * The role to assume before invoking the target + * + * @default - a new role will be created + */ + readonly eventRole?: iam.IRole; + + /** + * Additional headers sent to the API Destination + * + * These are merged with headers specified on the Connection, with + * the headers on the Connection taking precedence. + * + * You can only specify secret values on the Connection. + * + * @default - none + */ + readonly headerParameters?: Record; + + /** + * Path parameters to insert in place of path wildcards (`*`). + * + * If the API destination has a wilcard in the path, these path parts + * will be inserted in that place. + * + * @default - none + */ + readonly pathParameterValues?: string[] + + /** + * Additional query string parameters sent to the API Destination + * + * These are merged with headers specified on the Connection, with + * the headers on the Connection taking precedence. + * + * You can only specify secret values on the Connection. + * + * @default - none + */ + readonly queryStringParameters?: Record; +} + +/** + * Use an API Destination rule target. + */ +export class ApiDestination implements events.IRuleTarget { + constructor( + private readonly apiDestination: events.IApiDestination, + private readonly props: ApiDestinationProps = {}, + ) { } + + /** + * Returns a RuleTarget that can be used to trigger API destinations + * from an EventBridge event. + */ + public bind(_rule: events.IRule, _id?: string): events.RuleTargetConfig { + const httpParameters: events.CfnRule.HttpParametersProperty | undefined = + !!this.props.headerParameters ?? + !!this.props.pathParameterValues ?? + !!this.props.queryStringParameters + ? { + headerParameters: this.props.headerParameters, + pathParameterValues: this.props.pathParameterValues, + queryStringParameters: this.props.queryStringParameters, + } : undefined; + + if (this.props?.deadLetterQueue) { + addToDeadLetterQueueResourcePolicy(_rule, this.props.deadLetterQueue); + } + + return { + ...(this.props ? bindBaseTargetConfig(this.props) : {}), + arn: this.apiDestination.apiDestinationArn, + role: this.props?.eventRole ?? singletonEventRole(this.apiDestination, [new iam.PolicyStatement({ + resources: [this.apiDestination.apiDestinationArn], + actions: ['events:InvokeApiDestination'], + })]), + input: this.props.event, + targetResource: this.apiDestination, + httpParameters, + }; + } +} diff --git a/packages/@aws-cdk/aws-events-targets/lib/index.ts b/packages/@aws-cdk/aws-events-targets/lib/index.ts index bafb83751f468..6c91810ebca33 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/index.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/index.ts @@ -13,4 +13,5 @@ export * from './kinesis-stream'; export * from './log-group'; export * from './kinesis-firehose-stream'; export * from './api-gateway'; +export * from './api-destination'; export * from './util'; diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index 327f66ff9bf03..650961f9757ef 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -86,10 +86,10 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "aws-sdk": "^2.848.0", "aws-sdk-mock": "5.6.0", - "jest": "^27.4.7" + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-apigateway": "0.0.0", diff --git a/packages/@aws-cdk/aws-events-targets/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-events-targets/rosetta/default.ts-fixture index f6bf67d19e31a..0de777dbbabf0 100644 --- a/packages/@aws-cdk/aws-events-targets/rosetta/default.ts-fixture +++ b/packages/@aws-cdk/aws-events-targets/rosetta/default.ts-fixture @@ -1,5 +1,5 @@ // Fixture with packages imported, but nothing else -import { Duration, RemovalPolicy, Stack } from '@aws-cdk/core'; +import { Duration, RemovalPolicy, SecretValue, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as targets from '@aws-cdk/aws-events-targets'; diff --git a/packages/@aws-cdk/aws-events-targets/test/api-destination/api-destination.test.ts b/packages/@aws-cdk/aws-events-targets/test/api-destination/api-destination.test.ts new file mode 100644 index 0000000000000..f0f29a335fbae --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/api-destination/api-destination.test.ts @@ -0,0 +1,69 @@ +import { Template } from '@aws-cdk/assertions'; +import * as events from '@aws-cdk/aws-events'; +import * as iam from '@aws-cdk/aws-iam'; +import { Duration, SecretValue, Stack } from '@aws-cdk/core'; +import * as targets from '../../lib'; + + +describe('with basic auth connection', () => { + let stack: Stack; + let connection: events.Connection; + let destination: events.ApiDestination; + let rule: events.Rule; + + beforeEach(() => { + stack = new Stack(); + connection = new events.Connection(stack, 'Connection', { + authorization: events.Authorization.basic('username', SecretValue.plainText('password')), + description: 'ConnectionDescription', + connectionName: 'testConnection', + }); + + destination = new events.ApiDestination(stack, 'Destination', { + connection, + endpoint: 'https://endpoint.com', + }); + + rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.rate(Duration.minutes(1)), + }); + }); + + test('use api destination as an eventrule target', () => { + // WHEN + rule.addTarget(new targets.ApiDestination(destination)); + + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Events::Rule', { + ScheduleExpression: 'rate(1 minute)', + State: 'ENABLED', + Targets: [ + { + Arn: { 'Fn::GetAtt': ['DestinationApiDestinationA879FAE5', 'Arn'] }, + Id: 'Target0', + RoleArn: { 'Fn::GetAtt': ['DestinationEventsRole7DA63556', 'Arn'] }, + }, + ], + }); + }); + + test('with an explicit event role', () => { + // WHEN + const eventRole = new iam.Role(stack, 'Role', { + assumedBy: new iam.ServicePrincipal('events.amazonaws.com'), + }); + rule.addTarget(new targets.ApiDestination(destination, { eventRole })); + + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Events::Rule', { + Targets: [ + { + RoleArn: { 'Fn::GetAtt': ['Role1ABCC5F0', 'Arn'] }, + Id: 'Target0', + }, + ], + }); + }); +}); diff --git a/packages/@aws-cdk/aws-events-targets/test/aws-api/aws-api.test.ts b/packages/@aws-cdk/aws-events-targets/test/aws-api/aws-api.test.ts index cc6c58c51a43d..e8ace62395856 100644 --- a/packages/@aws-cdk/aws-events-targets/test/aws-api/aws-api.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/aws-api/aws-api.test.ts @@ -1,7 +1,7 @@ -import { Template } from '@aws-cdk/assertions'; +import { Annotations, Template } from '@aws-cdk/assertions'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; -import { App, Stack } from '@aws-cdk/core'; +import { Stack } from '@aws-cdk/core'; import * as targets from '../../lib'; test('use AwsApi as an event rule target', () => { @@ -163,9 +163,5 @@ test('with service not in AWS SDK', () => { rule.addTarget(awsApi); // THEN - const assembly = App.of(stack)!.synth().getStackArtifact(stack.stackName); - expect(assembly.messages.length).toBe(1); - const message = assembly.messages[0]; - expect(message.entry.type).toBe('aws:cdk:warning'); - expect(message.entry.data).toBe('Service no-such-service does not exist in the AWS SDK. Check the list of available services and actions from https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/index.html'); + Annotations.fromStack(stack).hasWarning('*', 'Service no-such-service does not exist in the AWS SDK. Check the list of available services and actions from https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/index.html'); }); diff --git a/packages/@aws-cdk/aws-events-targets/test/aws-api/integ.aws-api.expected.json b/packages/@aws-cdk/aws-events-targets/test/aws-api/integ.aws-api.expected.json index f5ae531bc1a27..966e633dac39f 100644 --- a/packages/@aws-cdk/aws-events-targets/test/aws-api/integ.aws-api.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/aws-api/integ.aws-api.expected.json @@ -104,17 +104,11 @@ "PolicyDocument": { "Statement": [ { - "Action": "ecs:UpdateService", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "rds:StopDBInstance", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "rds:CreateDBSnapshot", + "Action": [ + "ecs:UpdateService", + "rds:CreateDBSnapshot", + "rds:StopDBInstance" + ], "Effect": "Allow", "Resource": "*" } diff --git a/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json b/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json index e2de1fa26a6a5..e10af31aea26b 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json @@ -51,11 +51,11 @@ ] } }, + "Id": "Target0", "RetryPolicy": { "MaximumEventAgeInSeconds": 7200, "MaximumRetryAttempts": 2 }, - "Id": "Target0", "RoleArn": { "Fn::GetAtt": [ "MyProjectEventsRole5B7D93F5", @@ -138,7 +138,8 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - } + }, + ":*" ] ] }, @@ -161,8 +162,7 @@ ":log-group:/aws/codebuild/", { "Ref": "MyProject39F7B0AE" - }, - ":*" + } ] ] } @@ -170,11 +170,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -483,4 +483,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.expected.json b/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.expected.json index 912eb616ad2c8..045364b8680cb 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.expected.json @@ -154,16 +154,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -194,8 +194,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -208,22 +208,20 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "pipelinePipeline22F2A91DSourceCodeCommitCodePipelineActionRoleE54633E5", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "pipelinePipeline22F2A91DBuildHelloCodePipelineActionRoleA9729116", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "pipelinePipeline22F2A91DBuildHelloCodePipelineActionRoleA9729116", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "pipelinePipeline22F2A91DSourceCodeCommitCodePipelineActionRoleE54633E5", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-ec2-task.lit.expected.json b/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-ec2-task.lit.expected.json index a03a81e7255da..444eaab9f6152 100644 --- a/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-ec2-task.lit.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-ec2-task.lit.expected.json @@ -95,15 +95,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "Tags": [ { "Key": "Name", @@ -293,8 +293,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -434,10 +434,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -472,7 +472,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -500,24 +502,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "EcsCluster97242B84", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -595,6 +579,17 @@ } } }, + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup" + } + ] + } + }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookRoleA38EC83B": { "Type": "AWS::IAM::Role", "Properties": { @@ -641,17 +636,6 @@ ] } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup" - } - ] - } - }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookFFA63029": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { @@ -783,8 +767,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-fargate-task.expected.json b/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-fargate-task.expected.json index 40e42600e5413..9cd668c41aa03 100644 --- a/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-fargate-task.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-fargate-task.expected.json @@ -95,15 +95,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "Tags": [ { "Key": "Name", @@ -307,8 +307,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { @@ -403,22 +403,20 @@ { "Action": "iam:PassRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "TaskDefExecutionRoleB4775C97", - "Arn" - ] - } - }, - { - "Action": "iam:PassRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "TaskDefTaskRole1EDB4A67", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "TaskDefExecutionRoleB4775C97", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "TaskDefTaskRole1EDB4A67", + "Arn" + ] + } + ] } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-events-targets/test/kinesis-firehose/integ.kinesis-firehose-stream.expected.json b/packages/@aws-cdk/aws-events-targets/test/kinesis-firehose/integ.kinesis-firehose-stream.expected.json index 0c7a34c7f4bd5..2721bd7c3c250 100644 --- a/packages/@aws-cdk/aws-events-targets/test/kinesis-firehose/integ.kinesis-firehose-stream.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/kinesis-firehose/integ.kinesis-firehose-stream.expected.json @@ -29,16 +29,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -165,4 +165,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/lambda/lambda.test.ts b/packages/@aws-cdk/aws-events-targets/test/lambda/lambda.test.ts index 567f17e0a1fc9..0bdeec1a8a356 100644 --- a/packages/@aws-cdk/aws-events-targets/test/lambda/lambda.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/lambda/lambda.test.ts @@ -1,4 +1,4 @@ -import { Template } from '@aws-cdk/assertions'; +import { Annotations, Template, Match } from '@aws-cdk/assertions'; import * as events from '@aws-cdk/aws-events'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sqs from '@aws-cdk/aws-sqs'; @@ -321,8 +321,13 @@ test('must display a warning when using a Dead Letter Queue from another account Template.fromStack(stack1).resourceCountIs('AWS::SQS::QueuePolicy', 0); - let rule = stack1.node.children.find(child => child instanceof events.Rule); - expect(rule?.node.metadataEntry[0].data).toMatch(/Cannot add a resource policy to your dead letter queue associated with rule .* because the queue is in a different account\. You must add the resource policy manually to the dead letter queue in account 222222222222\./); + Annotations.fromStack(stack1).hasWarning('/Stack1/Rule', Match.objectLike({ + 'Fn::Join': Match.arrayWith([ + Match.arrayWith([ + 'Cannot add a resource policy to your dead letter queue associated with rule ', + ]), + ]), + })); }); diff --git a/packages/@aws-cdk/aws-events-targets/test/logs/integ.log-group.expected.json b/packages/@aws-cdk/aws-events-targets/test/logs/integ.log-group.expected.json index 8ef384b7f43a7..c4bb05cf2b33f 100644 --- a/packages/@aws-cdk/aws-events-targets/test/logs/integ.log-group.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/logs/integ.log-group.expected.json @@ -68,12 +68,10 @@ "PolicyDocument": { "Statement": [ { - "Action": "logs:PutResourcePolicy", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "logs:DeleteResourcePolicy", + "Action": [ + "logs:DeleteResourcePolicy", + "logs:PutResourcePolicy" + ], "Effect": "Allow", "Resource": "*" } @@ -172,7 +170,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3BucketD609D0D9" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16" }, "S3Key": { "Fn::Join": [ @@ -185,7 +183,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -198,7 +196,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -269,12 +267,10 @@ "PolicyDocument": { "Statement": [ { - "Action": "logs:PutResourcePolicy", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "logs:DeleteResourcePolicy", + "Action": [ + "logs:DeleteResourcePolicy", + "logs:PutResourcePolicy" + ], "Effect": "Allow", "Resource": "*" } @@ -392,12 +388,10 @@ "PolicyDocument": { "Statement": [ { - "Action": "logs:PutResourcePolicy", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "logs:DeleteResourcePolicy", + "Action": [ + "logs:DeleteResourcePolicy", + "logs:PutResourcePolicy" + ], "Effect": "Allow", "Resource": "*" } @@ -472,17 +466,17 @@ } }, "Parameters": { - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3BucketD609D0D9": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16": { "Type": "String", - "Description": "S3 bucket for asset \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "S3 bucket for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B": { "Type": "String", - "Description": "S3 key for asset version \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "S3 key for asset version \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cArtifactHash86CFA15D": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87ArtifactHash40DDF5EE": { "Type": "String", - "Description": "Artifact hash for asset \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "Artifact hash for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.expected.json b/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.expected.json index f35a7a93b9e42..9f300d5f03e0f 100644 --- a/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.expected.json @@ -32,8 +32,8 @@ "Action": [ "kms:Decrypt", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Principal": { @@ -94,9 +94,9 @@ "Statement": [ { "Action": [ - "sqs:SendMessage", "sqs:GetQueueAttributes", - "sqs:GetQueueUrl" + "sqs:GetQueueUrl", + "sqs:SendMessage" ], "Effect": "Allow", "Principal": { diff --git a/packages/@aws-cdk/aws-events-targets/test/stepfunctions/statemachine.test.ts b/packages/@aws-cdk/aws-events-targets/test/stepfunctions/statemachine.test.ts index 158b19f34fa0a..6327213b7a744 100644 --- a/packages/@aws-cdk/aws-events-targets/test/stepfunctions/statemachine.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/stepfunctions/statemachine.test.ts @@ -68,12 +68,12 @@ test('Existing role can be used for State machine Rule target', () => { }); const stateMachine = new sfn.StateMachine(stack, 'SM', { definition: new sfn.Wait(stack, 'Hello', { time: sfn.WaitTime.duration(cdk.Duration.seconds(10)) }), - role, }); // WHEN rule.addTarget(new targets.SfnStateMachine(stateMachine, { input: events.RuleTargetInput.fromObject({ SomeParam: 'SomeValue' }), + role: role, })); // THEN @@ -125,13 +125,13 @@ test('specifying retry policy', () => { }); const stateMachine = new sfn.StateMachine(stack, 'SM', { definition: new sfn.Wait(stack, 'Hello', { time: sfn.WaitTime.duration(cdk.Duration.seconds(10)) }), - role, }); rule.addTarget(new targets.SfnStateMachine(stateMachine, { input: events.RuleTargetInput.fromObject({ SomeParam: 'SomeValue' }), maxEventAge: cdk.Duration.hours(2), retryAttempts: 2, + role: role, })); // THEN @@ -151,7 +151,7 @@ test('specifying retry policy', () => { }, RoleArn: { 'Fn::GetAtt': [ - 'SMEventsRoleB320A902', + 'Role1ABCC5F0', 'Arn', ], }, @@ -176,13 +176,13 @@ test('use a Dead Letter Queue for the rule target', () => { }); const stateMachine = new sfn.StateMachine(stack, 'SM', { definition: new sfn.Wait(stack, 'Hello', { time: sfn.WaitTime.duration(cdk.Duration.seconds(10)) }), - role, }); // WHEN rule.addTarget(new targets.SfnStateMachine(stateMachine, { input: events.RuleTargetInput.fromObject({ SomeParam: 'SomeValue' }), deadLetterQueue: dlq, + role: role, })); // the Permission resource should be in the event stack @@ -206,7 +206,7 @@ test('use a Dead Letter Queue for the rule target', () => { Input: '{"SomeParam":"SomeValue"}', RoleArn: { 'Fn::GetAtt': [ - 'SMEventsRoleB320A902', + 'Role1ABCC5F0', 'Arn', ], }, diff --git a/packages/@aws-cdk/aws-events/README.md b/packages/@aws-cdk/aws-events/README.md index 13bd483ca54cb..edaf54e77d244 100644 --- a/packages/@aws-cdk/aws-events/README.md +++ b/packages/@aws-cdk/aws-events/README.md @@ -153,6 +153,8 @@ The following targets are supported: * `targets.SfnStateMachine`: Trigger an AWS Step Functions state machine * `targets.BatchJob`: Queue an AWS Batch Job * `targets.AwsApi`: Make an AWS API call +* `targets.ApiGateway`: Invoke an AWS API Gateway +* `targets.ApiDestination`: Make an call to an external destination ### Cross-account and cross-region targets diff --git a/packages/@aws-cdk/aws-events/lib/api-destination.ts b/packages/@aws-cdk/aws-events/lib/api-destination.ts new file mode 100644 index 0000000000000..b3def6e064287 --- /dev/null +++ b/packages/@aws-cdk/aws-events/lib/api-destination.ts @@ -0,0 +1,107 @@ +import { IResource, Resource } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { HttpMethod, IConnection } from './connection'; +import { CfnApiDestination } from './events.generated'; + +/** + * The event API Destination properties + */ +export interface ApiDestinationProps { + /** + * The name for the API destination. + * @default - A unique name will be generated + */ + readonly apiDestinationName?: string; + + /** + * A description for the API destination. + * + * @default - none + */ + readonly description?: string; + + /** + * The ARN of the connection to use for the API destination + */ + readonly connection: IConnection; + + /** + * The URL to the HTTP invocation endpoint for the API destination.. + */ + readonly endpoint: string; + + /** + * The method to use for the request to the HTTP invocation endpoint. + * + * @default HttpMethod.POST + */ + readonly httpMethod?: HttpMethod; + + /** + * The maximum number of requests per second to send to the HTTP invocation endpoint. + * + * @default - Not rate limited + */ + readonly rateLimitPerSecond?: number; +} + +/** + * Interface for API Destinations + */ +export interface IApiDestination extends IResource { + /** + * The Name of the Api Destination created. + * @attribute + */ + readonly apiDestinationName: string; + + /** + * The ARN of the Api Destination created. + * @attribute + */ + readonly apiDestinationArn: string; +} + +/** + * Define an EventBridge Api Destination + * + * @resource AWS::Events::ApiDestination + */ +export class ApiDestination extends Resource implements IApiDestination { + /** + * The Connection to associate with Api Destination + */ + public readonly connection: IConnection; + + /** + * The Name of the Api Destination created. + * @attribute + */ + public readonly apiDestinationName: string; + + /** + * The ARN of the Api Destination created. + * @attribute + */ + public readonly apiDestinationArn: string; + + constructor(scope: Construct, id: string, props: ApiDestinationProps) { + super(scope, id, { + physicalName: props.apiDestinationName, + }); + + this.connection = props.connection; + + let apiDestination = new CfnApiDestination(this, 'ApiDestination', { + connectionArn: this.connection.connectionArn, + description: props.description, + httpMethod: props.httpMethod ?? HttpMethod.POST, + invocationEndpoint: props.endpoint, + invocationRateLimitPerSecond: props.rateLimitPerSecond, + name: this.physicalName, + }); + + this.apiDestinationName = this.getResourceNameAttribute(apiDestination.ref); + this.apiDestinationArn = apiDestination.attrArn; + } +} diff --git a/packages/@aws-cdk/aws-events/lib/connection.ts b/packages/@aws-cdk/aws-events/lib/connection.ts new file mode 100644 index 0000000000000..fbedd37e8eb39 --- /dev/null +++ b/packages/@aws-cdk/aws-events/lib/connection.ts @@ -0,0 +1,422 @@ +import { IResource, Resource, Stack, SecretValue } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { CfnConnection } from './events.generated'; + +/** + * An API Destination Connection + * + * A connection defines the authorization type and credentials to use for authorization with an API destination HTTP endpoint. + */ +export interface ConnectionProps { + /** + * The name of the connection. + * + * @default - A name is automatically generated + */ + readonly connectionName?: string; + + /** + * The name of the connection. + * + * @default - none + */ + readonly description?: string; + + /** + * The authorization type for the connection. + */ + readonly authorization: Authorization; + + /** + * Additional string parameters to add to the invocation bodies + * + * @default - No additional parameters + */ + readonly bodyParameters?: Record; + + /** + * Additional string parameters to add to the invocation headers + * + * @default - No additional parameters + */ + readonly headerParameters?: Record; + + /** + * Additional string parameters to add to the invocation query strings + * + * @default - No additional parameters + */ + readonly queryStringParameters?: Record; +} + +/** + * Authorization type for an API Destination Connection + */ +export abstract class Authorization { + /** + * Use API key authorization + * + * API key authorization has two components: an API key name and an API key value. + * What these are depends on the target of your connection. + */ + public static apiKey(apiKeyName: string, apiKeyValue: SecretValue): Authorization { + return new class extends Authorization { + public _bind() { + return { + authorizationType: AuthorizationType.API_KEY, + authParameters: { + apiKeyAuthParameters: { + apiKeyName: apiKeyName, + apiKeyValue: apiKeyValue.toString(), + }, + } as CfnConnection.AuthParametersProperty, + }; + } + }(); + } + + /** + * Use username and password authorization + */ + public static basic(username: string, password: SecretValue): Authorization { + return new class extends Authorization { + public _bind() { + return { + authorizationType: AuthorizationType.BASIC, + authParameters: { + basicAuthParameters: { + username: username, + password: password.toString(), + }, + } as CfnConnection.AuthParametersProperty, + }; + } + }(); + } + + /** + * Use OAuth authorization + */ + public static oauth(props: OAuthAuthorizationProps): Authorization { + if (![HttpMethod.POST, HttpMethod.GET, HttpMethod.PUT].includes(props.httpMethod)) { + throw new Error('httpMethod must be one of GET, POST, PUT'); + } + + return new class extends Authorization { + public _bind() { + return { + authorizationType: AuthorizationType.OAUTH_CLIENT_CREDENTIALS, + authParameters: { + oAuthParameters: { + authorizationEndpoint: props.authorizationEndpoint, + clientParameters: { + clientId: props.clientId, + clientSecret: props.clientSecret.toString(), + }, + httpMethod: props.httpMethod, + oAuthHttpParameters: { + bodyParameters: renderHttpParameters(props.bodyParameters), + headerParameters: renderHttpParameters(props.headerParameters), + queryStringParameters: renderHttpParameters(props.queryStringParameters), + }, + }, + } as CfnConnection.AuthParametersProperty, + }; + } + }(); + + } + + /** + * Bind the authorization to the construct and return the authorization properties + * + * @internal + */ + public abstract _bind(): AuthorizationBindResult; +} + +/** + * Properties for `Authorization.oauth()` + */ +export interface OAuthAuthorizationProps { + + /** + * The URL to the authorization endpoint + */ + readonly authorizationEndpoint: string; + + /** + * The method to use for the authorization request. + * + * (Can only choose POST, GET or PUT). + */ + readonly httpMethod: HttpMethod; + + /** + * The client ID to use for OAuth authorization for the connection. + */ + readonly clientId: string; + + /** + * The client secret associated with the client ID to use for OAuth authorization for the connection. + */ + readonly clientSecret: SecretValue; + + /** + * Additional string parameters to add to the OAuth request body + * + * @default - No additional parameters + */ + readonly bodyParameters?: Record; + + /** + * Additional string parameters to add to the OAuth request header + * + * @default - No additional parameters + */ + readonly headerParameters?: Record; + + /** + * Additional string parameters to add to the OAuth request query string + * + * @default - No additional parameters + */ + readonly queryStringParameters?: Record; +} + +/** + * An additional HTTP parameter to send along with the OAuth request + */ +export abstract class HttpParameter { + /** + * Make an OAuthParameter from a string value + * + * The value is not treated as a secret. + */ + public static fromString(value: string): HttpParameter { + return new class extends HttpParameter { + public _render(name: string) { + return { + key: name, + value, + } as CfnConnection.ParameterProperty; + } + }(); + } + + /** + * Make an OAuthParameter from a secret + */ + public static fromSecret(value: SecretValue): HttpParameter { + return new class extends HttpParameter { + public _render(name: string) { + return { + key: name, + value: value.toString(), + isValueSecret: true, + } as CfnConnection.ParameterProperty; + } + }(); + } + + /** + * Render the paramter value + * + * @internal + */ + public abstract _render(name: string): any; +} + +/** + * Result of the 'bind' operation of the 'Authorization' class + * + * @internal + */ +export interface AuthorizationBindResult { + /** + * The authorization type + */ + readonly authorizationType: AuthorizationType; + + /** + * The authorization parameters (depends on the type) + */ + readonly authParameters: any; +} + +/** + * Interface for EventBus Connections + */ +export interface IConnection extends IResource { + /** + * The Name for the connection. + * @attribute + */ + readonly connectionName: string; + + /** + * The ARN of the connection created. + * @attribute + */ + readonly connectionArn: string; + + /** + * The ARN for the secret created for the connection. + * @attribute + */ + readonly connectionSecretArn: string; +} + +/** + * Interface with properties necessary to import a reusable Connection + */ +export interface ConnectionAttributes { + /** + * The Name for the connection. + */ + readonly connectionName: string; + + /** + * The ARN of the connection created. + */ + readonly connectionArn: string; + + /** + * The ARN for the secret created for the connection. + */ + readonly connectionSecretArn: string; +} + +/** + * Define an EventBridge Connection + * + * @resource AWS::Events::Connection + */ +export class Connection extends Resource implements IConnection { + /** + * Import an existing connection resource + * @param scope Parent construct + * @param id Construct ID + * @param connectionArn ARN of imported connection + */ + public static fromEventBusArn(scope: Construct, id: string, connectionArn: string, connectionSecretArn: string): IConnection { + const parts = Stack.of(scope).parseArn(connectionArn); + + return new ImportedConnection(scope, id, { + connectionArn: connectionArn, + connectionName: parts.resourceName || '', + connectionSecretArn: connectionSecretArn, + }); + } + + /** + * Import an existing connection resource + * @param scope Parent construct + * @param id Construct ID + * @param attrs Imported connection properties + */ + public static fromConnectionAttributes(scope: Construct, id: string, attrs: ConnectionAttributes): IConnection { + return new ImportedConnection(scope, id, attrs); + } + + /** + * The Name for the connection. + * @attribute + */ + public readonly connectionName: string; + + /** + * The ARN of the connection created. + * @attribute + */ + public readonly connectionArn: string; + + /** + * The ARN for the secret created for the connection. + * @attribute + */ + public readonly connectionSecretArn: string; + + constructor(scope: Construct, id: string, props: ConnectionProps) { + super(scope, id, { + physicalName: props.connectionName, + }); + + const authBind = props.authorization._bind(); + + const invocationHttpParameters = !!props.headerParameters || !!props.queryStringParameters || !!props.bodyParameters ? { + bodyParameters: renderHttpParameters(props.bodyParameters), + headerParameters: renderHttpParameters(props.headerParameters), + queryStringParameters: renderHttpParameters(props.queryStringParameters), + } : undefined; + + let connection = new CfnConnection(this, 'Connection', { + authorizationType: authBind.authorizationType, + authParameters: { + ...authBind.authParameters, + invocationHttpParameters: invocationHttpParameters, + }, + description: props.description, + name: this.physicalName, + }); + + this.connectionName = this.getResourceNameAttribute(connection.ref); + this.connectionArn = connection.attrArn; + this.connectionSecretArn = connection.attrSecretArn; + } +} + +class ImportedConnection extends Resource { + public readonly connectionArn: string; + public readonly connectionName: string; + public readonly connectionSecretArn: string; + constructor(scope: Construct, id: string, attrs: ConnectionAttributes) { + const arnParts = Stack.of(scope).parseArn(attrs.connectionArn); + super(scope, id, { + account: arnParts.account, + region: arnParts.region, + }); + + this.connectionArn = attrs.connectionArn; + this.connectionName = attrs.connectionName; + this.connectionSecretArn = attrs.connectionSecretArn; + } +} + +/** + * Supported HTTP operations. + */ +export enum HttpMethod { + /** POST */ + POST = 'POST', + /** GET */ + GET = 'GET', + /** HEAD */ + HEAD = 'HEAD', + /** OPTIONS */ + OPTIONS = 'OPTIONS', + /** PUT */ + PUT = 'PUT', + /** PATCH */ + PATCH = 'PATCH', + /** DELETE */ + DELETE = 'DELETE', +} + +/** + * Supported Authorization Types. + */ +enum AuthorizationType { + /** API_KEY */ + API_KEY = 'API_KEY', + /** BASIC */ + BASIC = 'BASIC', + /** OAUTH_CLIENT_CREDENTIALS */ + OAUTH_CLIENT_CREDENTIALS = 'OAUTH_CLIENT_CREDENTIALS', +} + +function renderHttpParameters(ps?: Record): CfnConnection.ParameterProperty[] | undefined { + if (!ps || Object.keys(ps).length === 0) { return undefined; } + + return Object.entries(ps).map(([name, p]) => p._render(name)); +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events/lib/index.ts b/packages/@aws-cdk/aws-events/lib/index.ts index 718b236bf6e91..34dcfcf792b9d 100644 --- a/packages/@aws-cdk/aws-events/lib/index.ts +++ b/packages/@aws-cdk/aws-events/lib/index.ts @@ -7,6 +7,8 @@ export * from './event-pattern'; export * from './schedule'; export * from './on-event-options'; export * from './archive'; +export * from './connection'; +export * from './api-destination'; // AWS::Events CloudFormation Resources: export * from './events.generated'; diff --git a/packages/@aws-cdk/aws-events/lib/input.ts b/packages/@aws-cdk/aws-events/lib/input.ts index 77798ceebd3a1..826aedaf4230a 100644 --- a/packages/@aws-cdk/aws-events/lib/input.ts +++ b/packages/@aws-cdk/aws-events/lib/input.ts @@ -11,8 +11,12 @@ export abstract class RuleTargetInput { /** * Pass text to the event target * - * May contain strings returned by EventField.from() to substitute in parts of the + * May contain strings returned by `EventField.from()` to substitute in parts of the * matched event. + * + * The Rule Target input value will be a single string: the string you pass + * here. Do not use this method to pass a complex value like a JSON object to + * a Rule Target. Use `RuleTargetInput.fromObject()` instead. */ public static fromText(text: string): RuleTargetInput { return new FieldAwareEventInput(text, InputType.Text); @@ -24,7 +28,7 @@ export abstract class RuleTargetInput { * This is only useful when passing to a target that does not * take a single argument. * - * May contain strings returned by EventField.from() to substitute in parts + * May contain strings returned by `EventField.from()` to substitute in parts * of the matched event. */ public static fromMultilineText(text: string): RuleTargetInput { @@ -34,7 +38,7 @@ export abstract class RuleTargetInput { /** * Pass a JSON object to the event target * - * May contain strings returned by EventField.from() to substitute in parts of the + * May contain strings returned by `EventField.from()` to substitute in parts of the * matched event. */ public static fromObject(obj: any): RuleTargetInput { diff --git a/packages/@aws-cdk/aws-events/lib/rule.ts b/packages/@aws-cdk/aws-events/lib/rule.ts index 19f84e8cc479c..1420a87627f8b 100644 --- a/packages/@aws-cdk/aws-events/lib/rule.ts +++ b/packages/@aws-cdk/aws-events/lib/rule.ts @@ -128,7 +128,10 @@ export class Rule extends Resource implements IRule { } this.description = props.description; - this.scheduleExpression = props.schedule && props.schedule.expressionString; + this.scheduleExpression = props.schedule?.expressionString; + + // add a warning on synth when minute is not defined in a cron schedule + props.schedule?._bind(this); const resource = new CfnRule(this, 'Resource', { name: this.physicalName, @@ -253,13 +256,13 @@ export class Rule extends Resource implements IRule { arn: targetProps.arn, roleArn, ecsParameters: targetProps.ecsParameters, + httpParameters: targetProps.httpParameters, kinesisParameters: targetProps.kinesisParameters, runCommandParameters: targetProps.runCommandParameters, batchParameters: targetProps.batchParameters, deadLetterConfig: targetProps.deadLetterConfig, retryPolicy: targetProps.retryPolicy, sqsParameters: targetProps.sqsParameters, - httpParameters: targetProps.httpParameters, input: inputProps && inputProps.input, inputPath: inputProps && inputProps.inputPath, inputTransformer: inputProps?.inputTemplate !== undefined ? { @@ -394,7 +397,7 @@ export class Rule extends Resource implements IRule { }); new CfnEventBusPolicy(eventBusPolicyStack, 'GivePermToOtherAccount', { action: 'events:PutEvents', - statementId: `Allow-account-${sourceAccount}`, + statementId: `Allow-account-${sourceAccount}-${this.node.addr}`, principal: sourceAccount, }); } diff --git a/packages/@aws-cdk/aws-events/lib/schedule.ts b/packages/@aws-cdk/aws-events/lib/schedule.ts index a3fcbaf399283..5bbf31694db5f 100644 --- a/packages/@aws-cdk/aws-events/lib/schedule.ts +++ b/packages/@aws-cdk/aws-events/lib/schedule.ts @@ -1,4 +1,8 @@ -import { Duration } from '@aws-cdk/core'; +import { Annotations, Duration } from '@aws-cdk/core'; + +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order +import { Construct } from '@aws-cdk/core'; /** * Schedule for scheduled event rules @@ -51,7 +55,15 @@ export abstract class Schedule { const day = fallback(options.day, options.weekDay !== undefined ? '?' : '*'); const weekDay = fallback(options.weekDay, '?'); - return new LiteralSchedule(`cron(${minute} ${hour} ${day} ${month} ${weekDay} ${year})`); + return new class extends Schedule { + public readonly expressionString: string = `cron(${minute} ${hour} ${day} ${month} ${weekDay} ${year})`; + public _bind(scope: Construct) { + if (!options.minute) { + Annotations.of(scope).addWarning('cron: If you don\'t pass \'minute\', by default the event runs every minute. Pass \'minute: \'*\'\' if that\'s what you intend, or \'minute: 0\' to run once per hour instead.'); + } + return new LiteralSchedule(this.expressionString); + } + }; } /** @@ -59,8 +71,13 @@ export abstract class Schedule { */ public abstract readonly expressionString: string; - protected constructor() { - } + protected constructor() {} + + /** + * + * @internal + */ + public abstract _bind(scope: Construct): void; } /** @@ -119,6 +136,8 @@ class LiteralSchedule extends Schedule { constructor(public readonly expressionString: string) { super(); } + + public _bind() {} } function fallback(x: T | undefined, def: T): T { diff --git a/packages/@aws-cdk/aws-events/lib/target.ts b/packages/@aws-cdk/aws-events/lib/target.ts index ba164f041c2a2..d90927bdaf0b0 100644 --- a/packages/@aws-cdk/aws-events/lib/target.ts +++ b/packages/@aws-cdk/aws-events/lib/target.ts @@ -66,6 +66,13 @@ export interface RuleTargetConfig { */ readonly ecsParameters?: CfnRule.EcsParametersProperty; + /** + * Contains the HTTP parameters to use when the target is a API Gateway REST endpoint + * or EventBridge API destination. + * @default - None + */ + readonly httpParameters?: CfnRule.HttpParametersProperty; + /** * Settings that control shard assignment, when the target is a Kinesis * stream. If you don't include this parameter, eventId is used as the @@ -85,11 +92,6 @@ export interface RuleTargetConfig { */ readonly sqsParameters?: CfnRule.SqsParametersProperty; - /** - * Parameters used when the rule invoke api gateway. - */ - readonly httpParameters?: CfnRule.HttpParametersProperty; - /** * What input to send to the event target * diff --git a/packages/@aws-cdk/aws-events/package.json b/packages/@aws-cdk/aws-events/package.json index 57af72c704d52..377a1c8ac9df9 100644 --- a/packages/@aws-cdk/aws-events/package.json +++ b/packages/@aws-cdk/aws-events/package.json @@ -85,8 +85,8 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -111,7 +111,8 @@ "props-default-doc:@aws-cdk/aws-events.RuleTargetConfig.role", "props-default-doc:@aws-cdk/aws-events.RuleTargetConfig.runCommandParameters", "props-default-doc:@aws-cdk/aws-events.RuleTargetConfig.sqsParameters", - "props-default-doc:@aws-cdk/aws-events.RuleTargetConfig.httpParameters" + "props-default-doc:@aws-cdk/aws-events.RuleTargetConfig.httpParameters", + "from-method:@aws-cdk/aws-events.ApiDestination" ] }, "stability": "stable", diff --git a/packages/@aws-cdk/aws-events/test/api-destination.test.ts b/packages/@aws-cdk/aws-events/test/api-destination.test.ts new file mode 100644 index 0000000000000..de0578aacf108 --- /dev/null +++ b/packages/@aws-cdk/aws-events/test/api-destination.test.ts @@ -0,0 +1,35 @@ +import { Template } from '@aws-cdk/assertions'; +import { Stack, SecretValue } from '@aws-cdk/core'; +import * as events from '../lib'; + + +test('creates an api destination for an EventBus', () => { + // GIVEN + const stack = new Stack(); + const connection = new events.Connection(stack, 'Connection', { + authorization: events.Authorization.basic('username', SecretValue.plainText('password')), + connectionName: 'testConnection', + description: 'ConnectionDescription', + }); + + // WHEN + new events.ApiDestination(stack, 'ApiDestination', { + apiDestinationName: 'ApiDestination', + connection, + description: 'ApiDestination', + httpMethod: events.HttpMethod.GET, + endpoint: 'someendpoint', + rateLimitPerSecond: 60, + }); + + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Events::ApiDestination', { + ConnectionArn: { 'Fn::GetAtt': ['Connection07624BCD', 'Arn'] }, + Description: 'ApiDestination', + HttpMethod: 'GET', + InvocationEndpoint: 'someendpoint', + InvocationRateLimitPerSecond: 60, + Name: 'ApiDestination', + }); +}); diff --git a/packages/@aws-cdk/aws-events/test/connection.test.ts b/packages/@aws-cdk/aws-events/test/connection.test.ts new file mode 100644 index 0000000000000..bb8e3073acaf9 --- /dev/null +++ b/packages/@aws-cdk/aws-events/test/connection.test.ts @@ -0,0 +1,104 @@ +import { Template } from '@aws-cdk/assertions'; +import { SecretValue, Stack } from '@aws-cdk/core'; +import * as events from '../lib'; + +test('basic connection', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new events.Connection(stack, 'Connection', { + authorization: events.Authorization.basic('username', SecretValue.plainText('password')), + connectionName: 'testConnection', + description: 'ConnectionDescription', + }); + + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Events::Connection', { + AuthorizationType: 'BASIC', + AuthParameters: { + BasicAuthParameters: { + Password: 'password', + Username: 'username', + }, + }, + Name: 'testConnection', + Description: 'ConnectionDescription', + }); +}); + +test('API key connection', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new events.Connection(stack, 'Connection', { + authorization: events.Authorization.apiKey('keyname', SecretValue.plainText('keyvalue')), + }); + + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Events::Connection', { + AuthorizationType: 'API_KEY', + AuthParameters: { + ApiKeyAuthParameters: { + ApiKeyName: 'keyname', + ApiKeyValue: 'keyvalue', + }, + }, + }); +}); + +test('oauth connection', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new events.Connection(stack, 'Connection', { + authorization: events.Authorization.oauth({ + authorizationEndpoint: 'authorizationEndpoint', + clientId: 'clientID', + clientSecret: SecretValue.plainText('clientSecret'), + httpMethod: events.HttpMethod.GET, + headerParameters: { + oAuthHeaderKey: events.HttpParameter.fromString('oAuthHeaderValue'), + }, + }), + headerParameters: { + invocationHeaderKey: events.HttpParameter.fromString('invocationHeaderValue'), + }, + connectionName: 'testConnection', + description: 'ConnectionDescription', + }); + + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Events::Connection', { + AuthorizationType: 'OAUTH_CLIENT_CREDENTIALS', + AuthParameters: { + OAuthParameters: { + AuthorizationEndpoint: 'authorizationEndpoint', + ClientParameters: { + ClientID: 'clientID', + ClientSecret: 'clientSecret', + }, + HttpMethod: 'GET', + OAuthHttpParameters: { + HeaderParameters: [{ + Key: 'oAuthHeaderKey', + Value: 'oAuthHeaderValue', + }], + }, + }, + InvocationHttpParameters: { + HeaderParameters: [{ + Key: 'invocationHeaderKey', + Value: 'invocationHeaderValue', + }], + }, + }, + Name: 'testConnection', + Description: 'ConnectionDescription', + }); +}); diff --git a/packages/@aws-cdk/aws-events/test/rule.test.ts b/packages/@aws-cdk/aws-events/test/rule.test.ts index 1cbd776441fce..b708717b7f0f3 100644 --- a/packages/@aws-cdk/aws-events/test/rule.test.ts +++ b/packages/@aws-cdk/aws-events/test/rule.test.ts @@ -1,5 +1,5 @@ /* eslint-disable object-curly-newline */ -import { Match, Template } from '@aws-cdk/assertions'; +import { Annotations, Match, Template } from '@aws-cdk/assertions'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import { EventBus, EventField, IRule, IRuleTarget, RuleTargetConfig, RuleTargetInput, Schedule } from '../lib'; @@ -28,6 +28,31 @@ describe('rule', () => { }); }); + test('rule displays warning when minutes are not included in cron', () => { + const stack = new cdk.Stack(); + new Rule(stack, 'MyRule', { + schedule: Schedule.cron({ + hour: '8', + day: '1', + }), + }); + + Annotations.fromStack(stack).hasWarning('/Default/MyRule', "cron: If you don't pass 'minute', by default the event runs every minute. Pass 'minute: '*'' if that's what you intend, or 'minute: 0' to run once per hour instead."); + }); + + test('rule does not display warning when minute is set to * in cron', () => { + const stack = new cdk.Stack(); + new Rule(stack, 'MyRule', { + schedule: Schedule.cron({ + minute: '*', + hour: '8', + day: '1', + }), + }); + + Annotations.fromStack(stack).hasNoWarning('/Default/MyRule', Match.anyValue()); + }); + test('can get rule name', () => { const stack = new cdk.Stack(); const rule = new Rule(stack, 'MyRule', { @@ -133,7 +158,7 @@ describe('rule', () => { }); }); - test('fails synthesis if neither eventPattern nor scheudleExpression are specified', () => { + test('fails synthesis if neither eventPattern nor scheduleExpression are specified', () => { const app = new cdk.App(); const stack = new cdk.Stack(app, 'MyStack'); new Rule(stack, 'Rule'); @@ -870,6 +895,7 @@ describe('rule', () => { const app = new cdk.App(); const sourceAccount = '123456789012'; + const nodeAddr = 'c810f4680339b01edf1f157c4fd07da73469742773'; const sourceStack = new cdk.Stack(app, 'SourceStack', { env: { account: sourceAccount, @@ -951,7 +977,7 @@ describe('rule', () => { const eventBusPolicyStack = app.node.findChild(`EventBusPolicy-${sourceAccount}-us-west-2-${targetAccount}`) as cdk.Stack; Template.fromStack(eventBusPolicyStack).hasResourceProperties('AWS::Events::EventBusPolicy', { 'Action': 'events:PutEvents', - 'StatementId': `Allow-account-${sourceAccount}`, + 'StatementId': `Allow-account-${sourceAccount}-${nodeAddr}`, 'Principal': sourceAccount, }); }); diff --git a/packages/@aws-cdk/aws-eventschemas/package.json b/packages/@aws-cdk/aws-eventschemas/package.json index d8d89608e6e95..42b0c59bdf000 100644 --- a/packages/@aws-cdk/aws-eventschemas/package.json +++ b/packages/@aws-cdk/aws-eventschemas/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-finspace/package.json b/packages/@aws-cdk/aws-finspace/package.json index 7c3ae60c58506..cdbf1478941c4 100644 --- a/packages/@aws-cdk/aws-finspace/package.json +++ b/packages/@aws-cdk/aws-finspace/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-fis/package.json b/packages/@aws-cdk/aws-fis/package.json index 614d64919c252..ca2716b5c2b54 100644 --- a/packages/@aws-cdk/aws-fis/package.json +++ b/packages/@aws-cdk/aws-fis/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-fms/package.json b/packages/@aws-cdk/aws-fms/package.json index 1366f66c49454..5ab1866fdca94 100644 --- a/packages/@aws-cdk/aws-fms/package.json +++ b/packages/@aws-cdk/aws-fms/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-forecast/package.json b/packages/@aws-cdk/aws-forecast/package.json index e4431039dc27c..f73f6e685b3f3 100644 --- a/packages/@aws-cdk/aws-forecast/package.json +++ b/packages/@aws-cdk/aws-forecast/package.json @@ -88,7 +88,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-frauddetector/package.json b/packages/@aws-cdk/aws-frauddetector/package.json index b30bf59153cd7..de77f2a097f9f 100644 --- a/packages/@aws-cdk/aws-frauddetector/package.json +++ b/packages/@aws-cdk/aws-frauddetector/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-fsx/package.json b/packages/@aws-cdk/aws-fsx/package.json index 0b0c1f0426004..0d1a669039c85 100644 --- a/packages/@aws-cdk/aws-fsx/package.json +++ b/packages/@aws-cdk/aws-fsx/package.json @@ -86,7 +86,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-gamelift/package.json b/packages/@aws-cdk/aws-gamelift/package.json index 8e0aa9635f092..401b1c4375cd7 100644 --- a/packages/@aws-cdk/aws-gamelift/package.json +++ b/packages/@aws-cdk/aws-gamelift/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json b/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json index 8d5cff35ebd6a..ff31bbcb08cee 100644 --- a/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json @@ -80,10 +80,10 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "aws-sdk": "^2.848.0", "aws-sdk-mock": "5.6.0", - "jest": "^27.4.7" + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/integ.globalaccelerator.expected.json b/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/integ.globalaccelerator.expected.json index 9d516680000e1..3888b9ba5d05d 100644 --- a/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/integ.globalaccelerator.expected.json +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/integ.globalaccelerator.expected.json @@ -95,15 +95,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "Name", @@ -920,7 +920,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3BucketD609D0D9" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16" }, "S3Key": { "Fn::Join": [ @@ -933,7 +933,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -946,7 +946,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -976,17 +976,17 @@ "Type": "AWS::SSM::Parameter::Value", "Default": "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2" }, - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3BucketD609D0D9": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16": { "Type": "String", - "Description": "S3 bucket for asset \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "S3 bucket for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B": { "Type": "String", - "Description": "S3 key for asset version \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "S3 key for asset version \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cArtifactHash86CFA15D": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87ArtifactHash40DDF5EE": { "Type": "String", - "Description": "Artifact hash for asset \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "Artifact hash for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-globalaccelerator/package.json b/packages/@aws-cdk/aws-globalaccelerator/package.json index 14f3c7036f24b..10223d0d40b55 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/package.json +++ b/packages/@aws-cdk/aws-globalaccelerator/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-glue/package.json b/packages/@aws-cdk/aws-glue/package.json index 7161441d63421..29c190ddeca63 100644 --- a/packages/@aws-cdk/aws-glue/package.json +++ b/packages/@aws-cdk/aws-glue/package.json @@ -85,8 +85,8 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/assets": "0.0.0", diff --git a/packages/@aws-cdk/aws-glue/test/integ.job.expected.json b/packages/@aws-cdk/aws-glue/test/integ.job.expected.json index d50a9de59a00e..435ffc2516e80 100644 --- a/packages/@aws-cdk/aws-glue/test/integ.job.expected.json +++ b/packages/@aws-cdk/aws-glue/test/integ.job.expected.json @@ -38,16 +38,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -75,8 +75,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -92,7 +92,8 @@ ":s3:::", { "Ref": "AssetParameters432033e3218068a915d2532fa9be7858a12b228a2ae6e5c10faccd9097b1e855S3Bucket4E517469" - } + }, + "/*" ] ] }, @@ -107,8 +108,7 @@ ":s3:::", { "Ref": "AssetParameters432033e3218068a915d2532fa9be7858a12b228a2ae6e5c10faccd9097b1e855S3Bucket4E517469" - }, - "/*" + } ] ] } @@ -293,8 +293,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -310,7 +310,8 @@ ":s3:::", { "Ref": "AssetParameters432033e3218068a915d2532fa9be7858a12b228a2ae6e5c10faccd9097b1e855S3Bucket4E517469" - } + }, + "/*" ] ] }, @@ -325,8 +326,7 @@ ":s3:::", { "Ref": "AssetParameters432033e3218068a915d2532fa9be7858a12b228a2ae6e5c10faccd9097b1e855S3Bucket4E517469" - }, - "/*" + } ] ] } @@ -444,8 +444,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -461,7 +461,8 @@ ":s3:::", { "Ref": "AssetParameters432033e3218068a915d2532fa9be7858a12b228a2ae6e5c10faccd9097b1e855S3Bucket4E517469" - } + }, + "/*" ] ] }, @@ -476,8 +477,7 @@ ":s3:::", { "Ref": "AssetParameters432033e3218068a915d2532fa9be7858a12b228a2ae6e5c10faccd9097b1e855S3Bucket4E517469" - }, - "/*" + } ] ] } diff --git a/packages/@aws-cdk/aws-glue/test/integ.partition-index.expected.json b/packages/@aws-cdk/aws-glue/test/integ.partition-index.expected.json index a4b3cad50cea3..6e8f232e62f03 100644 --- a/packages/@aws-cdk/aws-glue/test/integ.partition-index.expected.json +++ b/packages/@aws-cdk/aws-glue/test/integ.partition-index.expected.json @@ -235,33 +235,6 @@ "Action": "glue:UpdateTable", "Effect": "Allow", "Resource": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":glue:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":table/", - { - "Ref": "MyDatabase1E2517DB" - }, - "/", - { - "Ref": "CSVTableE499CABA" - } - ] - ] - }, { "Fn::Join": [ "", @@ -304,13 +277,7 @@ } ] ] - } - ] - }, - { - "Action": "glue:UpdateTable", - "Effect": "Allow", - "Resource": [ + }, { "Fn::Join": [ "", @@ -333,7 +300,7 @@ }, "/", { - "Ref": "JSONTable00348F1D" + "Ref": "CSVTableE499CABA" } ] ] @@ -354,29 +321,13 @@ { "Ref": "AWS::AccountId" }, - ":catalog" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":glue:", - { - "Ref": "AWS::Region" - }, - ":", + ":table/", { - "Ref": "AWS::AccountId" + "Ref": "MyDatabase1E2517DB" }, - ":database/", + "/", { - "Ref": "MyDatabase1E2517DB" + "Ref": "JSONTable00348F1D" } ] ] @@ -399,7 +350,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16" }, "S3Key": { "Fn::Join": [ @@ -412,7 +363,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -425,7 +376,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -571,17 +522,17 @@ } }, "Parameters": { - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16": { "Type": "String", - "Description": "S3 bucket for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "S3 bucket for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B": { "Type": "String", - "Description": "S3 key for asset version \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "S3 key for asset version \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2ArtifactHash4BE92B79": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87ArtifactHash40DDF5EE": { "Type": "String", - "Description": "Artifact hash for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "Artifact hash for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-glue/test/integ.table.expected.json b/packages/@aws-cdk/aws-glue/test/integ.table.expected.json index c76cbb5544660..8d4308ae40dab 100644 --- a/packages/@aws-cdk/aws-glue/test/integ.table.expected.json +++ b/packages/@aws-cdk/aws-glue/test/integ.table.expected.json @@ -433,60 +433,89 @@ "Statement": [ { "Action": [ + "glue:BatchCreatePartition", + "glue:BatchDeletePartition", "glue:BatchGetPartition", + "glue:CreatePartition", + "glue:DeletePartition", "glue:GetPartition", "glue:GetPartitions", "glue:GetTable", - "glue:GetTables", "glue:GetTableVersion", "glue:GetTableVersions", - "glue:BatchCreatePartition", - "glue:BatchDeletePartition", - "glue:CreatePartition", - "glue:DeletePartition", + "glue:GetTables", "glue:UpdatePartition" ], "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":glue:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":table/", - { - "Ref": "MyDatabase1E2517DB" - }, - "/", - { - "Ref": "CSVTableE499CABA" - } + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":glue:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":table/", + { + "Ref": "MyDatabase1E2517DB" + }, + "/", + { + "Ref": "CSVTableE499CABA" + } + ] ] - ] - } + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":glue:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":table/", + { + "Ref": "MyDatabase1E2517DB" + }, + "/", + { + "Ref": "MyEncryptedTable981A88C6" + } + ] + ] + } + ] }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -496,6 +525,12 @@ "Arn" ] }, + { + "Fn::GetAtt": [ + "MyEncryptedTableBucket7B28486D", + "Arn" + ] + }, { "Fn::Join": [ "", @@ -509,73 +544,6 @@ "/*" ] ] - } - ] - }, - { - "Action": [ - "glue:BatchGetPartition", - "glue:GetPartition", - "glue:GetPartitions", - "glue:GetTable", - "glue:GetTables", - "glue:GetTableVersion", - "glue:GetTableVersions", - "glue:BatchCreatePartition", - "glue:BatchDeletePartition", - "glue:CreatePartition", - "glue:DeletePartition", - "glue:UpdatePartition" - ], - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":glue:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":table/", - { - "Ref": "MyDatabase1E2517DB" - }, - "/", - { - "Ref": "MyEncryptedTable981A88C6" - } - ] - ] - } - }, - { - "Action": [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*", - "s3:PutObject", - "s3:PutObjectLegalHold", - "s3:PutObjectRetention", - "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::GetAtt": [ - "MyEncryptedTableBucket7B28486D", - "Arn" - ] }, { "Fn::Join": [ @@ -598,8 +566,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -630,60 +598,116 @@ "Statement": [ { "Action": [ + "glue:BatchCreatePartition", + "glue:BatchDeletePartition", "glue:BatchGetPartition", + "glue:CreatePartition", + "glue:DeletePartition", "glue:GetPartition", "glue:GetPartitions", "glue:GetTable", - "glue:GetTables", "glue:GetTableVersion", "glue:GetTableVersions", - "glue:BatchCreatePartition", - "glue:BatchDeletePartition", - "glue:CreatePartition", - "glue:DeletePartition", + "glue:GetTables", "glue:UpdatePartition" ], "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":glue:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":table/", - { - "Ref": "MyDatabase1E2517DB" - }, - "/", - { - "Ref": "AVROTable58646ABF" - } + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":glue:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":table/", + { + "Ref": "MyDatabase1E2517DB" + }, + "/", + { + "Ref": "AVROTable58646ABF" + } + ] ] - ] - } + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":glue:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":table/", + { + "Ref": "MyDatabase1E2517DB" + }, + "/", + { + "Ref": "JSONTable00348F1D" + } + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":glue:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":table/", + { + "Ref": "MyDatabase1E2517DB" + }, + "/", + { + "Ref": "ParquetTableE84E985F" + } + ] + ] + } + ] }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -708,94 +732,6 @@ ] } ] - }, - { - "Action": [ - "glue:BatchGetPartition", - "glue:GetPartition", - "glue:GetPartitions", - "glue:GetTable", - "glue:GetTables", - "glue:GetTableVersion", - "glue:GetTableVersions", - "glue:BatchCreatePartition", - "glue:BatchDeletePartition", - "glue:CreatePartition", - "glue:DeletePartition", - "glue:UpdatePartition" - ], - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":glue:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":table/", - { - "Ref": "MyDatabase1E2517DB" - }, - "/", - { - "Ref": "JSONTable00348F1D" - } - ] - ] - } - }, - { - "Action": [ - "glue:BatchGetPartition", - "glue:GetPartition", - "glue:GetPartitions", - "glue:GetTable", - "glue:GetTables", - "glue:GetTableVersion", - "glue:GetTableVersions", - "glue:BatchCreatePartition", - "glue:BatchDeletePartition", - "glue:CreatePartition", - "glue:DeletePartition", - "glue:UpdatePartition" - ], - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":glue:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":table/", - { - "Ref": "MyDatabase1E2517DB" - }, - "/", - { - "Ref": "ParquetTableE84E985F" - } - ] - ] - } } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-greengrass/package.json b/packages/@aws-cdk/aws-greengrass/package.json index d4b6a23bc436e..8677a50cafc70 100644 --- a/packages/@aws-cdk/aws-greengrass/package.json +++ b/packages/@aws-cdk/aws-greengrass/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-greengrassv2/package.json b/packages/@aws-cdk/aws-greengrassv2/package.json index af50ddd6ab9c6..4456cac21c5ff 100644 --- a/packages/@aws-cdk/aws-greengrassv2/package.json +++ b/packages/@aws-cdk/aws-greengrassv2/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-groundstation/package.json b/packages/@aws-cdk/aws-groundstation/package.json index faf4496480b5f..a6850e0bcd71a 100644 --- a/packages/@aws-cdk/aws-groundstation/package.json +++ b/packages/@aws-cdk/aws-groundstation/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-guardduty/package.json b/packages/@aws-cdk/aws-guardduty/package.json index e802c1d15247d..fd8c3f540cdd6 100644 --- a/packages/@aws-cdk/aws-guardduty/package.json +++ b/packages/@aws-cdk/aws-guardduty/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-healthlake/package.json b/packages/@aws-cdk/aws-healthlake/package.json index 20fabb1ffe47f..3c6e25ae6d523 100644 --- a/packages/@aws-cdk/aws-healthlake/package.json +++ b/packages/@aws-cdk/aws-healthlake/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iam/.npmignore b/packages/@aws-cdk/aws-iam/.npmignore index aaabf1df59065..123165033db70 100644 --- a/packages/@aws-cdk/aws-iam/.npmignore +++ b/packages/@aws-cdk/aws-iam/.npmignore @@ -21,8 +21,10 @@ tsconfig.json .eslintrc.js jest.config.js +docs/ + # exclude cdk artifacts **/cdk.out junit.xml test/ -!*.lit.ts \ No newline at end of file +!*.lit.ts diff --git a/packages/@aws-cdk/aws-iam/docs/policy-merging.als b/packages/@aws-cdk/aws-iam/docs/policy-merging.als new file mode 100644 index 0000000000000..72b4ac0aa01f5 --- /dev/null +++ b/packages/@aws-cdk/aws-iam/docs/policy-merging.als @@ -0,0 +1,201 @@ +/* +Alloy model to confirm the logic behind merging IAM Statements. + +This proves that merging two statements based on the following conditions: + +- Effects are the same +- NotAction, NotResource, NotPrincipal are the same(*) +- Of Action, Resource, Principal sets, 2 out of 3 are the same(*) + +Is sound, as the model doesn't find any examples of where the meaning +of statements is changed by merging. + +Find Alloy at https://alloytools.org/. + +(*) Some of these sets may be empty--that is fine, the logic still works out. +*/ + +//------------------------------------------------------- +// Base Statement definitions +enum Effect { Allow, Deny } +enum Resource { ResourceA, ResourceB } +enum Action { ActionA, ActionB } +enum Principal { PrincipalA, PrincipalB } + +sig Statement { + effect: Effect, + principal: set Principal, + notPrincipal: set Principal, + action: set Action, + notAction: set Action, + resource: set Resource, + notResource: set Resource, +} { + // Exactly one of Xxx and notXxx is non-empty + (some principal) iff not (some notPrincipal) + (some action) iff not (some notAction) + (some resource) iff not (some notResource) +} + +// So that we can compare Statements using =, if two Statements have +// exactly the same properties then they are the same Statement +fact { + all a, b: Statement { + ( + a.effect = b.effect and + a.principal = b.principal and + a.notPrincipal = b.notPrincipal and + a.action = b.action and + a.notAction = b.notAction and + a.resource = b.resource and + a.notResource = b.notResource) implies a = b + } +} + +//------------------------------------------------------- +// Requests and evaluations +sig Request { + principal: Principal, + action: Action, + resource: Resource, +} + +// Whether the statement applies to the given request +pred applies[s: Statement, req: Request] { + some s.principal implies req.principal in s.principal + some s.notPrincipal implies req.principal not in s.notPrincipal + some s.action implies req.action in s.action + some s.notAction implies req.action not in s.notAction + some s.resource implies req.resource in s.resource + some s.notResource implies req.resource not in s.notResource +} + +// Whether or not to allow the given request according to the given statements +// +// A request is allowed if there's at least one statement allowing it and +// no statements denying it. +pred allow[req: Request, ss: some Statement] { + some s: ss | applies[s, req] and s.effect = Allow + no s: ss | applies[s, req] and s.effect = Deny +} + +run show_some_allowed_requests { + some ss: set Statement, r: Request | allow[r, ss] and /* no useless Statements floating around */ (no s" : Statement | s" not in ss) +} for 3 but 1 Request + +//------------------------------------------------------- +// Statement merging + +// Assert that m is the merged version of a and b +// +// This encodes the important logic: the rules of merging. +pred merged[a: Statement, b: Statement, m: Statement] { + // Preconditions + a.effect = b.effect + a.notAction = b.notAction + a.notResource = b.notResource + a.notPrincipal = b.notPrincipal + + // Merging is allowed in one of 2 cases: + // - of the pairs { Resource, Action, Principal } 2 are the same (then the 3rd pair may be merged) + // - if one statement is a full subset of the other one (then it may be subsumed) [not implemented yet] + let R = a.resource = b.resource, A = a.action = b.action, P = a.principal = b.principal { + ((R and A) or (R and P) or (A and P) or + (a.resource in b.resource and a.action in b.action and a.principal in b.principal) or + (b.resource in a.resource and b.action in a.action and b.principal in a.principal)) + } + + // Result of merging + m.effect = a.effect + m.action = a.action + b.action + m.notAction = a.notAction + m.resource = a.resource + b.resource + m.notResource = a.notResource + m.principal = a.principal + b.principal + m.notPrincipal = a.notPrincipal +} + +run show_some_nontrivial_merges { + some disj s0, s1, M: Statement | merged[s0, s1, M] and s0.action != s1.action +} + +// For any pair of statements, there is only one possible merging +check merging_is_unique { + all s0, s1: Statement { + no disj m0, m1 : Statement | merged[s0, s1, m0] and merged[s0, s1, m1] + } +} for 5 + +// For all statements, the evaluation of the individual statements is the same as the evaluation +// of the merged statement. +check merging_does_not_change_evaluation { + all a: Statement, b: Statement, m: Statement, r: Request { + merged[a, b, m] implies (allow[r, a + b] iff allow[r, m]) + } +} for 3 + +// There are no 3 statements such that merged(merged(s0, s1), s2) != merged(s0, merged(s1, s2)) +check merging_is_associative { + no s0, s1, s2, h0, h1, m0, m1: Statement { + merged[s0, s1, h0] and merged[h0, s2, m0] + merged[s1, s2, h1] and merged[h1, s0, m1] + m0 != m1 + } +} for 10 + +// For all statements, merged(s0, s1) = merged(s1, s0) +check merging_is_commutative { + all s0, s1, m: Statement { + merged[s0, s1, m] implies merged[s1, s0, m] + } +} for 5 + +//------------------------------------------------------- +// Repeated application of merging + +// Whether a and b are mergeable +pred mergeable[a: Statement, b: Statement] { + some m: Statement | m != a and m != b and merged[a, b, m] +} + +// Maximally merged items in a set +pred maxMerged(input: set Statement, output: set Statement) { + no disj a, b: output | mergeable[a, b] + + input = output or { + #input > #output + some a, b: input | some m: Statement { + m != a + m != b + merged[a, b, m] + maxMerged[input - a - b + m, output] + } + } +} + +run some_interesting_maxMerged_statements { + some input, output: set Statement { + maxMerged[input, output] + #input = 3 + #output = 1 + all x: output | x not in input + } +} for 5 + +check max_merging_does_not_change_eval { + all input, output: set Statement, r: Request { + maxMerged[input, output] implies (allow[r, input] iff allow[r, output]) + } +} for 5 + +// This used to be written the opposite way. But you know: merging is NOT unique. +// Counterexample found by Alloy: +// {{ A, B, A }, {B, B, A} { A, B, B }} +// Reduces to either: +// {{ AB, B, A }, { A, B, B }} +// or {{ A, B, AB }, { B, B, A }} +run max_merging_is_not_unique { + some input, m0, m1: set Statement { + maxMerged[input, m0] and maxMerged[input, m1] and m0 != m1 + } +} for 5 diff --git a/packages/@aws-cdk/aws-iam/lib/policy-document.ts b/packages/@aws-cdk/aws-iam/lib/policy-document.ts index da43cce541158..9d73acb4693ac 100644 --- a/packages/@aws-cdk/aws-iam/lib/policy-document.ts +++ b/packages/@aws-cdk/aws-iam/lib/policy-document.ts @@ -1,5 +1,7 @@ import * as cdk from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; import { PolicyStatement } from './policy-statement'; +import { PostProcessPolicyDocument } from './private/postprocess-policy-document'; /** * Properties for a new PolicyDocument @@ -18,6 +20,24 @@ export interface PolicyDocumentProps { * @default - No statements */ readonly statements?: PolicyStatement[]; + + /** + * Try to minimize the policy by merging statements + * + * To avoid overrunning the maximum policy size, combine statements if they produce + * the same result. Merging happens according to the following rules: + * + * - The Effect of both statements is the same + * - Neither of the statements have a 'Sid' + * - Combine Principals if the rest of the statement is exactly the same. + * - Combine Resources if the rest of the statement is exactly the same. + * - Combine Actions if the rest of the statement is exactly the same. + * - We will never combine NotPrincipals, NotResources or NotActions, because doing + * so would change the meaning of the policy document. + * + * @default - false, unless the feature flag `@aws-cdk/aws-iam:minimizePolicies` is set + */ + readonly minimize?: boolean; } /** @@ -43,16 +63,21 @@ export class PolicyDocument implements cdk.IResolvable { public readonly creationStack: string[]; private readonly statements = new Array(); private readonly autoAssignSids: boolean; + private readonly minimize?: boolean; constructor(props: PolicyDocumentProps = {}) { this.creationStack = cdk.captureStackTrace(); this.autoAssignSids = !!props.assignSids; + this.minimize = props.minimize; this.addStatements(...props.statements || []); } public resolve(context: cdk.IResolveContext): any { - context.registerPostProcessor(new RemoveDuplicateStatements(this.autoAssignSids)); + context.registerPostProcessor(new PostProcessPolicyDocument( + this.autoAssignSids, + this.minimize ?? cdk.FeatureFlags.of(context.scope).isEnabled(cxapi.IAM_MINIMIZE_POLICIES) ?? false, + )); return this.render(); } @@ -153,42 +178,3 @@ export class PolicyDocument implements cdk.IResolvable { return doc; } } - -/** - * Removes duplicate statements and assign Sids if necessary - */ -class RemoveDuplicateStatements implements cdk.IPostProcessor { - constructor(private readonly autoAssignSids: boolean) { - } - - public postProcess(input: any, _context: cdk.IResolveContext): any { - if (!input || !input.Statement) { - return input; - } - - const jsonStatements = new Set(); - const uniqueStatements: any[] = []; - - for (const statement of input.Statement) { - const jsonStatement = JSON.stringify(statement); - if (!jsonStatements.has(jsonStatement)) { - uniqueStatements.push(statement); - jsonStatements.add(jsonStatement); - } - } - - // assign unique SIDs (the statement index) if `autoAssignSids` is enabled - const statements = uniqueStatements.map((s, i) => { - if (this.autoAssignSids && !s.Sid) { - s.Sid = i.toString(); - } - - return s; - }); - - return { - ...input, - Statement: statements, - }; - } -} diff --git a/packages/@aws-cdk/aws-iam/lib/policy-statement.ts b/packages/@aws-cdk/aws-iam/lib/policy-statement.ts index 08a8353e84b36..5e3b7eaabfbc7 100644 --- a/packages/@aws-cdk/aws-iam/lib/policy-statement.ts +++ b/packages/@aws-cdk/aws-iam/lib/policy-statement.ts @@ -4,6 +4,7 @@ import { AccountPrincipal, AccountRootPrincipal, AnyPrincipal, ArnPrincipal, CanonicalUserPrincipal, FederatedPrincipal, IPrincipal, PrincipalBase, PrincipalPolicyFragment, ServicePrincipal, ServicePrincipalOpts, } from './principals'; +import { normalizeStatement } from './private/postprocess-policy-document'; import { LITERAL_STRING_KEY, mergePrincipal } from './util'; const ensureArrayOrUndefined = (field: any) => { @@ -324,66 +325,17 @@ export class PolicyStatement { * Used when JSON.stringify() is called */ public toStatementJson(): any { - return noUndef({ - Action: _norm(this.action, { unique: true }), - NotAction: _norm(this.notAction, { unique: true }), - Condition: _norm(this.condition), - Effect: _norm(this.effect), - Principal: _normPrincipal(this.principal), - NotPrincipal: _normPrincipal(this.notPrincipal), - Resource: _norm(this.resource, { unique: true }), - NotResource: _norm(this.notResource, { unique: true }), - Sid: _norm(this.sid), + return normalizeStatement({ + Action: this.action, + NotAction: this.notAction, + Condition: this.condition, + Effect: this.effect, + Principal: this.principal, + NotPrincipal: this.notPrincipal, + Resource: this.resource, + NotResource: this.notResource, + Sid: this.sid, }); - - function _norm(values: any, { unique }: { unique: boolean } = { unique: false }) { - - if (typeof(values) === 'undefined') { - return undefined; - } - - if (cdk.Token.isUnresolved(values)) { - return values; - } - - if (Array.isArray(values)) { - if (!values || values.length === 0) { - return undefined; - } - - if (values.length === 1) { - return values[0]; - } - - return unique ? [...new Set(values)] : values; - } - - if (typeof(values) === 'object') { - if (Object.keys(values).length === 0) { - return undefined; - } - } - - return values; - } - - function _normPrincipal(principal: { [key: string]: any[] }) { - const keys = Object.keys(principal); - if (keys.length === 0) { return undefined; } - - if (LITERAL_STRING_KEY in principal) { - return principal[LITERAL_STRING_KEY][0]; - } - - const result: any = {}; - for (const key of keys) { - const normVal = _norm(principal[key]); - if (normVal) { - result[key] = normVal; - } - } - return result; - } } /** @@ -589,16 +541,6 @@ export interface PolicyStatementProps { readonly effect?: Effect; } -function noUndef(x: any): any { - const ret: any = {}; - for (const [key, value] of Object.entries(x)) { - if (value !== undefined) { - ret[key] = value; - } - } - return ret; -} - class JsonPrincipal extends PrincipalBase { public readonly policyFragment: PrincipalPolicyFragment; diff --git a/packages/@aws-cdk/aws-iam/lib/private/merge-statements.ts b/packages/@aws-cdk/aws-iam/lib/private/merge-statements.ts new file mode 100644 index 0000000000000..f7ef33b1ea026 --- /dev/null +++ b/packages/@aws-cdk/aws-iam/lib/private/merge-statements.ts @@ -0,0 +1,242 @@ +// IAM Statement merging +// +// See docs/policy-merging.als for a formal model of the logic +// implemented here. + + +import { LITERAL_STRING_KEY } from '../util'; +import { StatementSchema, normalizeStatement, IamValue } from './postprocess-policy-document'; + +/** + * Merge as many statements as possible to shrink the total policy doc, modifying the input array in place + * + * We compare and merge all pairs of statements (O(N^2) complexity), opportunistically + * merging them. This is not guaranteed to produce the optimal output, but it's probably + * Good Enough(tm). If it merges anything, it's at least going to produce a smaller output + * than the input. + */ +export function mergeStatements(statements: StatementSchema[]): StatementSchema[] { + const compStatements = statements.map(makeComparable); + + let i = 0; + while (i < compStatements.length) { + let didMerge = false; + + for (let j = i + 1; j < compStatements.length; j++) { + const merged = tryMerge(compStatements[i], compStatements[j]); + if (merged) { + compStatements[i] = merged; + compStatements.splice(j, 1); + didMerge = true; + break; + } + } + + if (!didMerge) { + i++; + } + } + + return compStatements.map(renderComparable); +} + +/** + * Given two statements, return their merging (if possible) + * + * We can merge two statements if: + * + * - Their effects are the same + * - They don't have Sids (not really a hard requirement, but just a simplification and an escape hatch) + * - Their Conditions are the same + * - Their NotAction, NotResource and NotPrincipal sets are the same (empty sets is fine). + * - From their Action, Resource and Principal sets, 2 are subsets of each other + * (empty sets are fine). + */ +function tryMerge(a: ComparableStatement, b: ComparableStatement): ComparableStatement | undefined { + // Effects must be the same + if (a.effect !== b.effect) { return; } + // We don't merge Sids (for now) + if (a.sid || b.sid) { return; } + + if (a.conditionString !== b.conditionString) { return; } + if (!setEqual(a.notAction, b.notAction) || !setEqual(a.notResource, b.notResource) || !setEqual(a.notPrincipal, b.notPrincipal)) { return; } + + // We can merge these statements if 2 out of the 3 sets of Action, Resource, Principal + // are the same. + const setsEqual = (setEqual(a.action, b.action) ? 1 : 0) + + (setEqual(a.resource, b.resource) ? 1 : 0) + + (setEqual(a.principal, b.principal) ? 1 : 0); + + if (setsEqual < 2 || unmergeablePrincipals(a, b)) { return; } + + return { + effect: a.effect, + conditionString: a.conditionString, + conditionValue: b.conditionValue, + notAction: a.notAction, + notPrincipal: a.notPrincipal, + notResource: a.notResource, + + action: setMerge(a.action, b.action), + resource: setMerge(a.resource, b.resource), + principal: setMerge(a.principal, b.principal), + }; +} + +/** + * Calculate and return cached string set representation of the statement elements + * + * This is to be able to do comparisons on these sets quickly. + */ +function makeComparable(s: StatementSchema): ComparableStatement { + return { + effect: s.Effect, + sid: s.Sid, + action: iamSet(s.Action), + notAction: iamSet(s.NotAction), + resource: iamSet(s.Resource), + notResource: iamSet(s.NotResource), + principal: principalIamSet(s.Principal), + notPrincipal: principalIamSet(s.NotPrincipal), + conditionString: JSON.stringify(s.Condition), + conditionValue: s.Condition, + }; + + function forceArray(x: A | Array): Array { + return Array.isArray(x) ? x : [x]; + } + + function iamSet(x: IamValue | undefined): IamValueSet { + if (x == undefined) { return {}; } + return mkdict(forceArray(x).map(e => [JSON.stringify(e), e])); + } + + function principalIamSet(x: IamValue | Record | undefined): IamValueSet { + if (x === undefined) { return {}; } + + if (Array.isArray(x) || typeof x === 'string') { + x = { [LITERAL_STRING_KEY]: x }; + } + + if (typeof x === 'object' && x !== null) { + // Turn { AWS: [a, b], Service: [c] } into [{ AWS: a }, { AWS: b }, { Service: c }] + const individualPrincipals = Object.entries(x).flatMap(([principalType, value]) => forceArray(value).map(v => ({ [principalType]: v }))); + return iamSet(individualPrincipals); + } + return {}; + } +} + +/** + * Return 'true' if the two principals are unmergeable + * + * This only happens if one of them is a literal, untyped principal (typically, + * `Principal: '*'`) and the other one is typed. + * + * `Principal: '*'` behaves subtly different than `Principal: { AWS: '*' }` and must + * therefore be preserved. + */ +function unmergeablePrincipals(a: ComparableStatement, b: ComparableStatement) { + const aHasLiteral = Object.values(a.principal).some(v => LITERAL_STRING_KEY in v); + const bHasLiteral = Object.values(b.principal).some(v => LITERAL_STRING_KEY in v); + return aHasLiteral !== bHasLiteral; +} + +/** + * Turn a ComparableStatement back into a StatementSchema + */ +function renderComparable(s: ComparableStatement): StatementSchema { + return normalizeStatement({ + Effect: s.effect, + Sid: s.sid, + Condition: s.conditionValue, + Action: renderSet(s.action), + NotAction: renderSet(s.notAction), + Resource: renderSet(s.resource), + NotResource: renderSet(s.notResource), + Principal: renderPrincipalSet(s.principal), + NotPrincipal: renderPrincipalSet(s.notPrincipal), + }); + + function renderSet(x: IamValueSet): IamValue | undefined { + // Return as sorted array so that we normalize + const keys = Object.keys(x).sort(); + return keys.length > 0 ? keys.map(key => x[key]) : undefined; + } + + function renderPrincipalSet(x: IamValueSet): Record { + const keys = Object.keys(x).sort(); + // The first level will be an object + const ret: Record = {}; + for (const key of keys) { + const principal = x[key]; + if (principal == null || typeof principal !== 'object') { + throw new Error(`Principal should be an object with a principal type, got: ${principal}`); + } + const principalKeys = Object.keys(principal); + if (principalKeys.length !== 1) { + throw new Error(`Principal should be an object with 1 key, found keys: ${principalKeys}`); + } + const pk = principalKeys[0]; + if (!ret[pk]) { + ret[pk] = []; + } + (ret[pk] as IamValue[]).push(principal[pk]); + } + return ret; + } +} + +/** + * An analyzed version of a statement that makes it easier to do comparisons and merging on + * + * We will stringify parts of the statement: comparisons are done on the strings, the original + * values are retained so we can stitch them back together into a real policy. + */ +interface ComparableStatement { + readonly effect?: string; + readonly sid?: string; + + readonly principal: IamValueSet; + readonly notPrincipal: IamValueSet; + readonly action: IamValueSet; + readonly notAction: IamValueSet; + readonly resource: IamValueSet; + readonly notResource: IamValueSet; + + readonly conditionString: string; + readonly conditionValue: any; +} + +/** + * A collection of comparable IAM values + * + * Each value is indexed by its stringified value, mapping to its original value. + * This allows us to compare values quickly and easily (even if they are complex), + * while also being able to deduplicate the originals. + */ +type IamValueSet = Record; + +/** + * Whether the given sets are equal + */ +function setEqual(a: IamValueSet, b: IamValueSet) { + const keysA = Object.keys(a); + const keysB = Object.keys(b); + return keysA.length === keysB.length && keysA.every(k => k in b); +} + +/** + * Merge two IAM value sets + */ +function setMerge(x: IamValueSet, y: IamValueSet): IamValueSet { + return { ...x, ...y }; +} + +function mkdict(xs: Array<[string, A]>): Record { + const ret: Record = {}; + for (const x of xs) { + ret[x[0]] = x[1]; + } + return ret; +} diff --git a/packages/@aws-cdk/aws-iam/lib/private/postprocess-policy-document.ts b/packages/@aws-cdk/aws-iam/lib/private/postprocess-policy-document.ts new file mode 100644 index 0000000000000..f54873aa7340c --- /dev/null +++ b/packages/@aws-cdk/aws-iam/lib/private/postprocess-policy-document.ts @@ -0,0 +1,149 @@ +import * as cdk from '@aws-cdk/core'; +import { LITERAL_STRING_KEY } from '../util'; +import { mergeStatements } from './merge-statements'; + +/** + * A Token postprocesser for policy documents + * + * Removes duplicate statements, merges statements, and assign Sids if necessary + * + * Because policy documents can contain all kinds of crazy things, + * we do all the necessary work here after the document has been mostly resolved + * into a predictable CloudFormation form. + */ +export class PostProcessPolicyDocument implements cdk.IPostProcessor { + constructor(private readonly autoAssignSids: boolean, private readonly minimize: boolean) { + } + + public postProcess(input: any, _context: cdk.IResolveContext): any { + if (!input || !input.Statement) { + return input; + } + + if (this.minimize) { + input.Statement = mergeStatements(input.Statement); + } + + // Also remove full-on duplicates (this will not be necessary if + // we minimized, but it might still dedupe statements we didn't + // minimize like 'Deny' statements, and definitely is still necessary + // if we didn't minimize) + const jsonStatements = new Set(); + const uniqueStatements: any[] = []; + + for (const statement of input.Statement) { + const jsonStatement = JSON.stringify(statement); + if (!jsonStatements.has(jsonStatement)) { + uniqueStatements.push(statement); + jsonStatements.add(jsonStatement); + } + } + + // assign unique SIDs (the statement index) if `autoAssignSids` is enabled + const statements = uniqueStatements.map((s, i) => { + if (this.autoAssignSids && !s.Sid) { + s.Sid = i.toString(); + } + + return s; + }); + + return { + ...input, + Statement: statements, + }; + } +} + +// An IAM value is a string or a CloudFormation intrinsic +export type IamValue = string | Record | Array>; + +export interface StatementSchema { + readonly Sid?: string; + readonly Effect?: string; + readonly Principal?: Record; + readonly NotPrincipal?: Record; + readonly Resource?: IamValue; + readonly NotResource?: IamValue; + readonly Action?: IamValue; + readonly NotAction?: IamValue; + readonly Condition?: unknown; +} + + +export function normalizeStatement(s: StatementSchema) { + return noUndef({ + Action: _norm(s.Action, { unique: true }), + NotAction: _norm(s.NotAction, { unique: true }), + Condition: _norm(s.Condition), + Effect: _norm(s.Effect), + Principal: _normPrincipal(s.Principal), + NotPrincipal: _normPrincipal(s.NotPrincipal), + Resource: _norm(s.Resource, { unique: true }), + NotResource: _norm(s.NotResource, { unique: true }), + Sid: _norm(s.Sid), + }); + + function _norm(values: any, { unique = false }: { unique: boolean } = { unique: false }) { + + if (values == null) { + return undefined; + } + + if (cdk.Token.isUnresolved(values)) { + return values; + } + + if (Array.isArray(values)) { + if (!values || values.length === 0) { + return undefined; + } + + if (values.length === 1) { + return values[0]; + } + + return unique ? Array.from(new Set(values)) : values; + } + + if (values && typeof(values) === 'object') { + if (Object.keys(values).length === 0) { + return undefined; + } + } + + return values; + } + + function _normPrincipal(principal?: { [key: string]: any }) { + if (!principal) { return undefined; } + + const keys = Object.keys(principal); + if (keys.length === 0) { return undefined; } + + // This is handling a special case for round-tripping a literal + // string principal loaded from JSON. + if (LITERAL_STRING_KEY in principal) { + return principal[LITERAL_STRING_KEY][0]; + } + + const result: any = {}; + for (const key of keys) { + const normVal = _norm(principal[key]); + if (normVal) { + result[key] = normVal; + } + } + return result; + } +} + +function noUndef(x: any): any { + const ret: any = {}; + for (const [key, value] of Object.entries(x)) { + if (value !== undefined) { + ret[key] = value; + } + } + return ret; +} diff --git a/packages/@aws-cdk/aws-iam/lib/role.ts b/packages/@aws-cdk/aws-iam/lib/role.ts index ac48fdd3d7710..73ba42c051800 100644 --- a/packages/@aws-cdk/aws-iam/lib/role.ts +++ b/packages/@aws-cdk/aws-iam/lib/role.ts @@ -274,6 +274,21 @@ export class Role extends Resource implements IRole { : new ImmutableRole(scope, `ImmutableRole${id}`, importedRole, options.addGrantsToResources ?? false); } + /** + * Import an external role by name. + * + * The imported role is assumed to exist in the same account as the account + * the scope's containing Stack is being deployed to. + */ + public static fromRoleName(scope: Construct, id: string, roleName: string) { + return Role.fromRoleArn(scope, id, Stack.of(scope).formatArn({ + region: '', + service: 'iam', + resource: 'role', + resourceName: roleName, + })); + } + public readonly grantPrincipal: IPrincipal = this; public readonly principalAccount: string | undefined = this.env.account; diff --git a/packages/@aws-cdk/aws-iam/package.json b/packages/@aws-cdk/aws-iam/package.json index 9fcef6fa79537..93d43238f4624 100644 --- a/packages/@aws-cdk/aws-iam/package.json +++ b/packages/@aws-cdk/aws-iam/package.json @@ -84,14 +84,15 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.92", - "@types/jest": "^27.4.0", + "@types/aws-lambda": "^8.10.93", + "@types/jest": "^27.4.1", "@types/sinon": "^9.0.11", - "jest": "^27.4.7", + "jest": "^27.5.1", "sinon": "^9.2.4" }, "dependencies": { "@aws-cdk/core": "0.0.0", + "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", "constructs": "^3.3.69" }, diff --git a/packages/@aws-cdk/aws-iam/test/integ.composite-principal.expected.json b/packages/@aws-cdk/aws-iam/test/integ.composite-principal.expected.json index 4090b7be4e15e..a715e411d83ae 100644 --- a/packages/@aws-cdk/aws-iam/test/integ.composite-principal.expected.json +++ b/packages/@aws-cdk/aws-iam/test/integ.composite-principal.expected.json @@ -19,13 +19,7 @@ } ] ] - } - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { + }, "AWS": "*" } } diff --git a/packages/@aws-cdk/aws-iam/test/integ.condition-with-ref.expected.json b/packages/@aws-cdk/aws-iam/test/integ.condition-with-ref.expected.json index 66957c3979200..f1f877242877c 100644 --- a/packages/@aws-cdk/aws-iam/test/integ.condition-with-ref.expected.json +++ b/packages/@aws-cdk/aws-iam/test/integ.condition-with-ref.expected.json @@ -4,17 +4,17 @@ "Type": "String", "Default": "developer" }, - "AssetParameters3b28f4ee261986c158a160900e3042a61238f644fe502199d60bcea592128086S3Bucket57C0655B": { + "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3Bucket6F458959": { "Type": "String", - "Description": "S3 bucket for asset \"3b28f4ee261986c158a160900e3042a61238f644fe502199d60bcea592128086\"" + "Description": "S3 bucket for asset \"f850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4\"" }, - "AssetParameters3b28f4ee261986c158a160900e3042a61238f644fe502199d60bcea592128086S3VersionKey4BC65AD6": { + "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3VersionKeyBDD0572E": { "Type": "String", - "Description": "S3 key for asset version \"3b28f4ee261986c158a160900e3042a61238f644fe502199d60bcea592128086\"" + "Description": "S3 key for asset version \"f850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4\"" }, - "AssetParameters3b28f4ee261986c158a160900e3042a61238f644fe502199d60bcea592128086ArtifactHashD8D99435": { + "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4ArtifactHash4D5DD9E9": { "Type": "String", - "Description": "Artifact hash for asset \"3b28f4ee261986c158a160900e3042a61238f644fe502199d60bcea592128086\"" + "Description": "Artifact hash for asset \"f850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4\"" } }, "Resources": { @@ -70,7 +70,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters3b28f4ee261986c158a160900e3042a61238f644fe502199d60bcea592128086S3Bucket57C0655B" + "Ref": "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3Bucket6F458959" }, "S3Key": { "Fn::Join": [ @@ -83,7 +83,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters3b28f4ee261986c158a160900e3042a61238f644fe502199d60bcea592128086S3VersionKey4BC65AD6" + "Ref": "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3VersionKeyBDD0572E" } ] } @@ -96,7 +96,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters3b28f4ee261986c158a160900e3042a61238f644fe502199d60bcea592128086S3VersionKey4BC65AD6" + "Ref": "AssetParametersf850d967c52a5f64e6436dc84abdde4d86197f2a0871f5ab27c79647a91d0bf4S3VersionKeyBDD0572E" } ] } @@ -162,4 +162,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iam/test/integ.oidc-provider.expected.json b/packages/@aws-cdk/aws-iam/test/integ.oidc-provider.expected.json index 4b04dd157155e..923dd4187af0f 100644 --- a/packages/@aws-cdk/aws-iam/test/integ.oidc-provider.expected.json +++ b/packages/@aws-cdk/aws-iam/test/integ.oidc-provider.expected.json @@ -62,7 +62,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersea46702e1c05b2735e48e826d630f7bf6acdf7e55d6fa8d9fa8df858d5542161S3Bucket0C424907" + "Ref": "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3Bucket211A9156" }, "S3Key": { "Fn::Join": [ @@ -75,7 +75,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersea46702e1c05b2735e48e826d630f7bf6acdf7e55d6fa8d9fa8df858d5542161S3VersionKey6841F1F8" + "Ref": "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3VersionKey822D04EC" } ] } @@ -88,7 +88,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersea46702e1c05b2735e48e826d630f7bf6acdf7e55d6fa8d9fa8df858d5542161S3VersionKey6841F1F8" + "Ref": "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3VersionKey822D04EC" } ] } @@ -151,17 +151,17 @@ } }, "Parameters": { - "AssetParametersea46702e1c05b2735e48e826d630f7bf6acdf7e55d6fa8d9fa8df858d5542161S3Bucket0C424907": { + "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3Bucket211A9156": { "Type": "String", - "Description": "S3 bucket for asset \"ea46702e1c05b2735e48e826d630f7bf6acdf7e55d6fa8d9fa8df858d5542161\"" + "Description": "S3 bucket for asset \"5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2\"" }, - "AssetParametersea46702e1c05b2735e48e826d630f7bf6acdf7e55d6fa8d9fa8df858d5542161S3VersionKey6841F1F8": { + "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2S3VersionKey822D04EC": { "Type": "String", - "Description": "S3 key for asset version \"ea46702e1c05b2735e48e826d630f7bf6acdf7e55d6fa8d9fa8df858d5542161\"" + "Description": "S3 key for asset version \"5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2\"" }, - "AssetParametersea46702e1c05b2735e48e826d630f7bf6acdf7e55d6fa8d9fa8df858d5542161ArtifactHash67B22EF2": { + "AssetParameters5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2ArtifactHashCA4A1831": { "Type": "String", - "Description": "Artifact hash for asset \"ea46702e1c05b2735e48e826d630f7bf6acdf7e55d6fa8d9fa8df858d5542161\"" + "Description": "Artifact hash for asset \"5507835727e005832a615aef2a6b437860f432c6cd052d07c0244464aedbe2b2\"" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iam/test/merge-statements.test.ts b/packages/@aws-cdk/aws-iam/test/merge-statements.test.ts new file mode 100644 index 0000000000000..f3114955ecd61 --- /dev/null +++ b/packages/@aws-cdk/aws-iam/test/merge-statements.test.ts @@ -0,0 +1,471 @@ +import { App, Stack } from '@aws-cdk/core'; +import * as iam from '../lib'; +import { PolicyStatement } from '../lib'; + +const PRINCIPAL_ARN1 = 'arn:aws:iam::111111111:user/user-name'; +const principal1 = new iam.ArnPrincipal(PRINCIPAL_ARN1); + +const PRINCIPAL_ARN2 = 'arn:aws:iam::111111111:role/role-name'; +const principal2 = new iam.ArnPrincipal(PRINCIPAL_ARN2); + +// Check that 'resource' statements are merged, and that 'notResource' statements are not, +// if the statements are otherwise the same. +test.each([ + ['resources', true], + ['notResources', false], +] as Array<['resources' | 'notResources', boolean]>) +('merge %p statements: %p', (key, doMerge) => { + assertMergedC(doMerge, [ + new iam.PolicyStatement({ + [key]: ['a'], + actions: ['service:Action'], + principals: [principal1], + }), + new iam.PolicyStatement({ + [key]: ['b'], + actions: ['service:Action'], + principals: [principal1], + }), + ], [ + { + Effect: 'Allow', + Resource: ['a', 'b'], + Action: 'service:Action', + Principal: { AWS: PRINCIPAL_ARN1 }, + }, + ]); +}); + +// Check that 'action' statements are merged, and that 'notAction' statements are not, +// if the statements are otherwise the same. +test.each([ + ['actions', true], + ['notActions', false], +] as Array<['actions' | 'notActions', boolean]>) +('merge %p statements: %p', (key, doMerge) => { + assertMergedC(doMerge, [ + new iam.PolicyStatement({ + resources: ['a'], + [key]: ['service:Action1'], + principals: [principal1], + }), + new iam.PolicyStatement({ + resources: ['a'], + [key]: ['service:Action2'], + principals: [principal1], + }), + ], [ + { + Effect: 'Allow', + Resource: 'a', + Action: ['service:Action1', 'service:Action2'], + Principal: { AWS: PRINCIPAL_ARN1 }, + }, + ]); +}); + +// Check that 'principal' statements are merged, and that 'notPrincipal' statements are not, +// if the statements are otherwise the same. +test.each([ + ['principals', true], + ['notPrincipals', false], +] as Array<['principals' | 'notPrincipals', boolean]>) +('merge %p statements: %p', (key, doMerge) => { + assertMergedC(doMerge, [ + new iam.PolicyStatement({ + resources: ['a'], + actions: ['service:Action'], + [key]: [principal1], + }), + new iam.PolicyStatement({ + resources: ['a'], + actions: ['service:Action'], + [key]: [principal2], + }), + ], [ + { + Effect: 'Allow', + Resource: 'a', + Action: 'service:Action', + Principal: { AWS: [PRINCIPAL_ARN1, PRINCIPAL_ARN2].sort() }, + }, + ]); +}); + +test('merge multiple types of principals', () => { + assertMerged([ + new iam.PolicyStatement({ + resources: ['a'], + actions: ['service:Action'], + principals: [principal1], + }), + new iam.PolicyStatement({ + resources: ['a'], + actions: ['service:Action'], + principals: [new iam.ServicePrincipal('service.amazonaws.com')], + }), + ], [ + { + Effect: 'Allow', + Resource: 'a', + Action: 'service:Action', + Principal: { + AWS: PRINCIPAL_ARN1, + Service: 'service.amazonaws.com', + }, + }, + ]); +}); + +test('multiple mergeable keys are not merged', () => { + assertNoMerge([ + new iam.PolicyStatement({ + resources: ['a'], + actions: ['service:Action1'], + principals: [principal1], + }), + new iam.PolicyStatement({ + resources: ['b'], + actions: ['service:Action2'], + principals: [principal1], + }), + ]); +}); + +test('can merge statements without principals', () => { + assertMerged([ + new iam.PolicyStatement({ + resources: ['a'], + actions: ['service:Action'], + }), + new iam.PolicyStatement({ + resources: ['b'], + actions: ['service:Action'], + }), + ], [ + { + Effect: 'Allow', + Resource: ['a', 'b'], + Action: 'service:Action', + }, + ]); +}); + +test('if conditions are different, statements are not merged', () => { + assertNoMerge([ + new iam.PolicyStatement({ + resources: ['a'], + actions: ['service:Action'], + principals: [principal1], + conditions: { + StringLike: { + something: 'value', + }, + }, + }), + new iam.PolicyStatement({ + resources: ['b'], + actions: ['service:Action'], + principals: [principal1], + }), + ]); +}); + +test('if conditions are the same, statements are merged', () => { + assertMerged([ + new iam.PolicyStatement({ + resources: ['a'], + actions: ['service:Action'], + principals: [principal1], + conditions: { + StringLike: { + something: 'value', + }, + }, + }), + new iam.PolicyStatement({ + resources: ['b'], + actions: ['service:Action'], + principals: [principal1], + conditions: { + StringLike: { + something: 'value', + }, + }, + }), + ], [ + { + Effect: 'Allow', + Resource: ['a', 'b'], + Action: 'service:Action', + Principal: { AWS: PRINCIPAL_ARN1 }, + Condition: { + StringLike: { + something: 'value', + }, + }, + }, + ]); +}); + +test('also merge Deny statements', () => { + assertMerged([ + new iam.PolicyStatement({ + effect: iam.Effect.DENY, + resources: ['a'], + actions: ['service:Action'], + principals: [principal1], + }), + new iam.PolicyStatement({ + effect: iam.Effect.DENY, + resources: ['b'], + actions: ['service:Action'], + principals: [principal1], + }), + ], [ + { + Effect: 'Deny', + Resource: ['a', 'b'], + Action: 'service:Action', + Principal: { AWS: PRINCIPAL_ARN1 }, + }, + ]); +}); + +test('merges 3 statements in multiple steps', () => { + assertMerged([ + new iam.PolicyStatement({ + resources: ['a'], + actions: ['service:Action'], + principals: [principal1], + }), + new iam.PolicyStatement({ + resources: ['b'], + actions: ['service:Action'], + principals: [principal1], + }), + // This can combine with the previous two once they have been merged + new iam.PolicyStatement({ + resources: ['a', 'b'], + actions: ['service:Action2'], + principals: [principal1], + }), + ], [ + { + Effect: 'Allow', + Resource: ['a', 'b'], + Action: ['service:Action', 'service:Action2'], + Principal: { AWS: PRINCIPAL_ARN1 }, + }, + ]); +}); + +test('winnow down literal duplicates', () => { + assertMerged([ + new iam.PolicyStatement({ + resources: ['a'], + actions: ['service:Action'], + principals: [principal1], + }), + new iam.PolicyStatement({ + resources: ['a', 'b'], + actions: ['service:Action'], + principals: [principal1], + }), + ], [ + { + Effect: 'Allow', + Resource: ['a', 'b'], + Action: 'service:Action', + Principal: { AWS: PRINCIPAL_ARN1 }, + }, + ]); +}); + +test('winnow down literal duplicates if they are Refs', () => { + const stack = new Stack(); + const user1 = new iam.User(stack, 'User1'); + const user2 = new iam.User(stack, 'User2'); + + assertMerged([ + new iam.PolicyStatement({ + resources: ['a'], + actions: ['service:Action'], + principals: [user1], + }), + new iam.PolicyStatement({ + resources: ['a'], + actions: ['service:Action'], + principals: [user1, user2], + }), + ], [ + { + Effect: 'Allow', + Resource: 'a', + Action: 'service:Action', + Principal: { + AWS: [ + { 'Fn::GetAtt': ['User1E278A736', 'Arn'] }, + { 'Fn::GetAtt': ['User21F1486D1', 'Arn'] }, + ], + }, + }, + ]); +}); + +test('merges 2 pairs separately', () => { + // Merges pairs (0,2) and (1,3) + assertMerged([ + new iam.PolicyStatement({ + resources: ['a'], + actions: ['service:Action'], + principals: [principal1], + }), + new iam.PolicyStatement({ + resources: ['c'], + actions: ['service:Action1'], + principals: [principal1], + }), + new iam.PolicyStatement({ + resources: ['b'], + actions: ['service:Action'], + principals: [principal1], + }), + new iam.PolicyStatement({ + resources: ['c'], + actions: ['service:Action2'], + principals: [principal1], + }), + ], [ + { + Effect: 'Allow', + Resource: ['a', 'b'], + Action: 'service:Action', + Principal: { AWS: PRINCIPAL_ARN1 }, + }, + { + Effect: 'Allow', + Resource: 'c', + Action: ['service:Action1', 'service:Action2'], + Principal: { AWS: PRINCIPAL_ARN1 }, + }, + ]); +}); + +test('do not deep-merge info Refs and GetAtts', () => { + const stack = new Stack(); + const user1 = new iam.User(stack, 'User1'); + const user2 = new iam.User(stack, 'User2'); + + assertMerged([ + new iam.PolicyStatement({ + resources: ['a'], + actions: ['service:Action'], + principals: [user1], + }), + new iam.PolicyStatement({ + resources: ['a'], + actions: ['service:Action'], + principals: [user2], + }), + ], [ + { + Effect: 'Allow', + Resource: 'a', + Action: 'service:Action', + Principal: { + AWS: [ + { 'Fn::GetAtt': ['User1E278A736', 'Arn'] }, + { 'Fn::GetAtt': ['User21F1486D1', 'Arn'] }, + ], + }, + }, + ]); +}); + +test('properly merge untyped principals (star)', () => { + const statements = [ + PolicyStatement.fromJson({ + Action: ['service:Action1'], + Effect: 'Allow', + Resource: ['Resource'], + Principal: '*', + }), + PolicyStatement.fromJson({ + Action: ['service:Action2'], + Effect: 'Allow', + Resource: ['Resource'], + Principal: '*', + }), + ]; + + assertMerged(statements, [ + { + Action: ['service:Action1', 'service:Action2'], + Effect: 'Allow', + Resource: 'Resource', + Principal: '*', + }, + ]); +}); + +test('fail merging typed and untyped principals', () => { + const statements = [ + PolicyStatement.fromJson({ + Action: ['service:Action'], + Effect: 'Allow', + Resource: ['Resource'], + Principal: '*', + }), + PolicyStatement.fromJson({ + Action: ['service:Action'], + Effect: 'Allow', + Resource: ['Resource'], + Principal: { AWS: PRINCIPAL_ARN1 }, + }), + ]; + + assertMerged(statements, [ + { + Action: 'service:Action', + Effect: 'Allow', + Resource: 'Resource', + Principal: '*', + }, + { + Action: 'service:Action', + Effect: 'Allow', + Resource: 'Resource', + Principal: { AWS: PRINCIPAL_ARN1 }, + }, + ]); +}); + +function assertNoMerge(statements: iam.PolicyStatement[]) { + const app = new App(); + const stack = new Stack(app, 'Stack'); + + const regularResult = stack.resolve(new iam.PolicyDocument({ minimize: false, statements })); + const minResult = stack.resolve(new iam.PolicyDocument({ minimize: true, statements })); + + expect(minResult).toEqual(regularResult); +} + +function assertMerged(statements: iam.PolicyStatement[], expected: any[]) { + const app = new App(); + const stack = new Stack(app, 'Stack'); + + const minResult = stack.resolve(new iam.PolicyDocument({ minimize: true, statements })); + + expect(minResult.Statement).toEqual(expected); +} + +/** + * Assert Merged Conditional + * + * Based on a boolean, either call assertMerged or assertNoMerge. The 'expected' + * argument only applies in the case where `doMerge` is true. + */ +function assertMergedC(doMerge: boolean, statements: iam.PolicyStatement[], expected: any[]) { + return doMerge ? assertMerged(statements, expected) : assertNoMerge(statements); +} diff --git a/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts b/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts index d03dd908370da..05a0fdaac4d58 100644 --- a/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts +++ b/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts @@ -560,6 +560,14 @@ describe('IAM Role.fromRoleArn', () => { }); }); +test('Role.fromRoleName', () => { + const app = new App(); + const stack = new Stack(app, 'Stack', { env: { region: 'asdf', account: '1234' } }); + const role = Role.fromRoleName(stack, 'MyRole', 'MyRole'); + + expect(stack.resolve(role.roleArn)).toEqual({ 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::1234:role/MyRole']] }); +}); + function somePolicyStatement() { return new PolicyStatement({ actions: ['s3:*'], diff --git a/packages/@aws-cdk/aws-imagebuilder/package.json b/packages/@aws-cdk/aws-imagebuilder/package.json index bacd907148a73..6d7581afc8a3f 100644 --- a/packages/@aws-cdk/aws-imagebuilder/package.json +++ b/packages/@aws-cdk/aws-imagebuilder/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-inspector/package.json b/packages/@aws-cdk/aws-inspector/package.json index 5bdb7a30c188c..446b49eec052b 100644 --- a/packages/@aws-cdk/aws-inspector/package.json +++ b/packages/@aws-cdk/aws-inspector/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-inspectorv2/package.json b/packages/@aws-cdk/aws-inspectorv2/package.json index 58bc8bd45bf6b..6d3ec7b525446 100644 --- a/packages/@aws-cdk/aws-inspectorv2/package.json +++ b/packages/@aws-cdk/aws-inspectorv2/package.json @@ -88,7 +88,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iot-actions/README.md b/packages/@aws-cdk/aws-iot-actions/README.md index 860643683efd1..088fda5f3e5b8 100644 --- a/packages/@aws-cdk/aws-iot-actions/README.md +++ b/packages/@aws-cdk/aws-iot-actions/README.md @@ -30,6 +30,7 @@ Currently supported are: - Put records to Kinesis Data stream - Put records to Kinesis Data Firehose stream - Send messages to SQS queues +- Publish messages on SNS topics ## Republish a message to another MQTT topic @@ -256,3 +257,24 @@ const topicRule = new iot.TopicRule(this, 'TopicRule', { ], }); ``` + +## Publish messages on an SNS topic + +The code snippet below creates and AWS IoT Rule that publishes messages to an SNS topic when it is triggered: + +```ts +import * as sns from '@aws-cdk/aws-sns'; + +const topic = new sns.Topic(this, 'MyTopic'); + +const topicRule = new iot.TopicRule(this, 'TopicRule', { + sql: iot.IotSql.fromStringAsVer20160323( + "SELECT topic(2) as device_id, year, month, day FROM 'device/+/data'", + ), + actions: [ + new actions.SnsTopicAction(topic, { + messageFormat: actions.SnsActionMessageFormat.JSON, // optional property, default is SnsActionMessageFormat.RAW + }), + ], +}); +``` diff --git a/packages/@aws-cdk/aws-iot-actions/lib/index.ts b/packages/@aws-cdk/aws-iot-actions/lib/index.ts index c3a7bb547b1c8..5c214f4143309 100644 --- a/packages/@aws-cdk/aws-iot-actions/lib/index.ts +++ b/packages/@aws-cdk/aws-iot-actions/lib/index.ts @@ -8,3 +8,4 @@ export * from './kinesis-put-record-action'; export * from './lambda-function-action'; export * from './s3-put-object-action'; export * from './sqs-queue-action'; +export * from './sns-topic-action'; diff --git a/packages/@aws-cdk/aws-iot-actions/lib/sns-topic-action.ts b/packages/@aws-cdk/aws-iot-actions/lib/sns-topic-action.ts new file mode 100644 index 0000000000000..701eeb0d8b39e --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/lib/sns-topic-action.ts @@ -0,0 +1,75 @@ +import * as iam from '@aws-cdk/aws-iam'; +import * as iot from '@aws-cdk/aws-iot'; +import * as sns from '@aws-cdk/aws-sns'; +import { CommonActionProps } from '.'; +import { singletonActionRole } from './private/role'; + +/** + * SNS topic action message format options. + */ +export enum SnsActionMessageFormat { + /** + * RAW message format. + */ + RAW = 'RAW', + + /** + * JSON message format. + */ + JSON = 'JSON' +} + +/** + * Configuration options for the SNS topic action. + */ +export interface SnsTopicActionProps extends CommonActionProps { + /** + * The message format of the message to publish. + * + * SNS uses this setting to determine if the payload should be parsed and relevant platform-specific bits of the payload should be extracted. + * @see https://docs.aws.amazon.com/sns/latest/dg/sns-message-and-json-formats.html + * + * @default SnsActionMessageFormat.RAW + */ + readonly messageFormat?: SnsActionMessageFormat; +} + +/** + * The action to write the data from an MQTT message to an Amazon SNS topic. + * + * @see https://docs.aws.amazon.com/iot/latest/developerguide/sns-rule-action.html + */ +export class SnsTopicAction implements iot.IAction { + private readonly role?: iam.IRole; + private readonly topic: sns.ITopic; + private readonly messageFormat?: SnsActionMessageFormat; + + /** + * @param topic The Amazon SNS topic to publish data on. Must not be a FIFO topic. + * @param props Properties to configure the action. + */ + constructor(topic: sns.ITopic, props: SnsTopicActionProps = {}) { + if (topic.fifo) { + throw Error('IoT Rule actions cannot be used with FIFO SNS Topics, please pass a non-FIFO Topic instead'); + } + + this.topic = topic; + this.role = props.role; + this.messageFormat = props.messageFormat; + } + + bind(rule: iot.ITopicRule): iot.ActionConfig { + const role = this.role ?? singletonActionRole(rule); + this.topic.grantPublish(role); + + return { + configuration: { + sns: { + targetArn: this.topic.topicArn, + roleArn: role.roleArn, + messageFormat: this.messageFormat, + }, + }, + }; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iot-actions/package.json b/packages/@aws-cdk/aws-iot-actions/package.json index f03c1b14f1bb2..a2db6d0529f63 100644 --- a/packages/@aws-cdk/aws-iot-actions/package.json +++ b/packages/@aws-cdk/aws-iot-actions/package.json @@ -82,9 +82,9 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "constructs": "^3.3.69", - "jest": "^27.4.7" + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -95,6 +95,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", "case": "1.6.3", @@ -110,6 +111,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" diff --git a/packages/@aws-cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-logs-action.expected.json b/packages/@aws-cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-logs-action.expected.json index 7d1748a084c77..de237bc1ae22f 100644 --- a/packages/@aws-cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-logs-action.expected.json +++ b/packages/@aws-cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-logs-action.expected.json @@ -49,6 +49,7 @@ { "Action": [ "logs:CreateLogStream", + "logs:DescribeLogStreams", "logs:PutLogEvents" ], "Effect": "Allow", @@ -58,16 +59,6 @@ "Arn" ] } - }, - { - "Action": "logs:DescribeLogStreams", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyLogGroup5C0DAD85", - "Arn" - ] - } } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-iot-actions/test/kinesis-firehose/integ.firehose-put-record-action.expected.json b/packages/@aws-cdk/aws-iot-actions/test/kinesis-firehose/integ.firehose-put-record-action.expected.json index 5c484ba7f5049..8de54892ebabd 100644 --- a/packages/@aws-cdk/aws-iot-actions/test/kinesis-firehose/integ.firehose-put-record-action.expected.json +++ b/packages/@aws-cdk/aws-iot-actions/test/kinesis-firehose/integ.firehose-put-record-action.expected.json @@ -118,16 +118,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ diff --git a/packages/@aws-cdk/aws-iot-actions/test/sns/integ.sns-topic-action.expected.json b/packages/@aws-cdk/aws-iot-actions/test/sns/integ.sns-topic-action.expected.json new file mode 100644 index 0000000000000..0bf9706012c93 --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/sns/integ.sns-topic-action.expected.json @@ -0,0 +1,71 @@ +{ + "Resources": { + "TopicRule40A4EA44": { + "Type": "AWS::IoT::TopicRule", + "Properties": { + "TopicRulePayload": { + "Actions": [ + { + "Sns": { + "RoleArn": { + "Fn::GetAtt": [ + "TopicRuleTopicRuleActionRole246C4F77", + "Arn" + ] + }, + "TargetArn": { + "Ref": "MyTopic86869434" + } + } + } + ], + "AwsIotSqlVersion": "2016-03-23", + "Sql": "SELECT topic(2) as device_id, year, month, day FROM 'device/+/data'" + } + } + }, + "TopicRuleTopicRuleActionRole246C4F77": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "iot.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "TopicRuleTopicRuleActionRoleDefaultPolicy99ADD687": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": { + "Ref": "MyTopic86869434" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "TopicRuleTopicRuleActionRoleDefaultPolicy99ADD687", + "Roles": [ + { + "Ref": "TopicRuleTopicRuleActionRole246C4F77" + } + ] + } + }, + "MyTopic86869434": { + "Type": "AWS::SNS::Topic" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iot-actions/test/sns/integ.sns-topic-action.ts b/packages/@aws-cdk/aws-iot-actions/test/sns/integ.sns-topic-action.ts new file mode 100644 index 0000000000000..5243ab2effab4 --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/sns/integ.sns-topic-action.ts @@ -0,0 +1,33 @@ +/** + * Stack verification steps: + * * aws sns subscribe --topic-arn "arn:aws:sns:::test-stack-MyTopic86869434-10F6E3DMK3E5P" --protocol email --notification-endpoint + * * confirm subscription from email + * * echo '{"message": "hello world"}' > testfile.txt + * * aws iot-data publish --topic device/mydevice/data --qos 1 --payload fileb://testfile.txt + * * verify that an email was sent from the SNS + * * rm testfile.txt + */ +/// !cdk-integ pragma:ignore-assets +import * as iot from '@aws-cdk/aws-iot'; +import * as sns from '@aws-cdk/aws-sns'; +import * as cdk from '@aws-cdk/core'; +import * as actions from '../../lib'; + +class TestStack extends cdk.Stack { + constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + const topicRule = new iot.TopicRule(this, 'TopicRule', { + sql: iot.IotSql.fromStringAsVer20160323( + "SELECT topic(2) as device_id, year, month, day FROM 'device/+/data'", + ), + }); + + const snsTopic = new sns.Topic(this, 'MyTopic'); + topicRule.addAction(new actions.SnsTopicAction(snsTopic)); + } +} + +const app = new cdk.App(); +new TestStack(app, 'sns-topic-action-test-stack'); +app.synth(); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iot-actions/test/sns/sns-topic-action.test.ts b/packages/@aws-cdk/aws-iot-actions/test/sns/sns-topic-action.test.ts new file mode 100644 index 0000000000000..c949b5202c72c --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/sns/sns-topic-action.test.ts @@ -0,0 +1,103 @@ +import { Match, Template } from '@aws-cdk/assertions'; +import * as iam from '@aws-cdk/aws-iam'; +import * as iot from '@aws-cdk/aws-iot'; +import * as sns from '@aws-cdk/aws-sns'; +import * as cdk from '@aws-cdk/core'; +import * as actions from '../../lib'; + +const SNS_TOPIC_ARN = 'arn:aws:sns::123456789012:test-topic'; + +let stack: cdk.Stack; +let topicRule: iot.TopicRule; +let snsTopic: sns.ITopic; + +beforeEach(() => { + stack = new cdk.Stack(); + topicRule = new iot.TopicRule(stack, 'MyTopicRule', { + sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id FROM 'device/+/data'"), + }); + snsTopic = sns.Topic.fromTopicArn(stack, 'MySnsTopic', SNS_TOPIC_ARN); +}); + +test('Default SNS topic action', () => { + // WHEN + topicRule.addAction(new actions.SnsTopicAction(snsTopic)); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { + TopicRulePayload: { + Actions: [{ + Sns: { + RoleArn: { 'Fn::GetAtt': ['MyTopicRuleTopicRuleActionRoleCE2D05DA', 'Arn'] }, + TargetArn: SNS_TOPIC_ARN, + }, + }], + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [{ + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { Service: 'iot.amazonaws.com' }, + }], + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [{ + Action: 'sns:Publish', + Effect: 'Allow', + Resource: SNS_TOPIC_ARN, + }], + }, + Roles: [{ Ref: 'MyTopicRuleTopicRuleActionRoleCE2D05DA' }], + }); +}); + +test('Can set messageFormat', () => { + // WHEN + topicRule.addAction(new actions.SnsTopicAction(snsTopic, { + messageFormat: actions.SnsActionMessageFormat.JSON, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { + TopicRulePayload: { + Actions: [ + Match.objectLike({ Sns: { MessageFormat: 'JSON' } }), + ], + }, + }); +}); + +test('Can set role', () => { + // GIVEN + const roleArn = 'arn:aws:iam::123456789012:role/testrole'; + const role = iam.Role.fromRoleArn(stack, 'MyRole', roleArn); + + // WHEN + topicRule.addAction(new actions.SnsTopicAction(snsTopic, { + role, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { + TopicRulePayload: { + Actions: [ + Match.objectLike({ Sns: { RoleArn: roleArn } }), + ], + }, + }); +}); + +test('Action with FIFO topic throws error', () => { + // GIVEN + const snsFifoTopic = sns.Topic.fromTopicArn(stack, 'MyFifoTopic', `${SNS_TOPIC_ARN}.fifo`); + + expect(() => { + topicRule.addAction(new actions.SnsTopicAction(snsFifoTopic)); + }).toThrowError('IoT Rule actions cannot be used with FIFO SNS Topics, please pass a non-FIFO Topic instead'); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iot/README.md b/packages/@aws-cdk/aws-iot/README.md index 410657b9ad71d..c331527606f2c 100644 --- a/packages/@aws-cdk/aws-iot/README.md +++ b/packages/@aws-cdk/aws-iot/README.md @@ -36,6 +36,7 @@ Import it into your code: ```ts nofixture import * as iot from '@aws-cdk/aws-iot'; +import * as actions from '@aws-cdk/aws-iot-actions'; ``` ## `TopicRule` diff --git a/packages/@aws-cdk/aws-iot/package.json b/packages/@aws-cdk/aws-iot/package.json index 11342e7489db3..e83a310c74109 100644 --- a/packages/@aws-cdk/aws-iot/package.json +++ b/packages/@aws-cdk/aws-iot/package.json @@ -84,8 +84,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iot1click/package.json b/packages/@aws-cdk/aws-iot1click/package.json index 656dee749a698..d0550686c0a7f 100644 --- a/packages/@aws-cdk/aws-iot1click/package.json +++ b/packages/@aws-cdk/aws-iot1click/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotanalytics/package.json b/packages/@aws-cdk/aws-iotanalytics/package.json index 534ffed3675a9..081930aad26ad 100644 --- a/packages/@aws-cdk/aws-iotanalytics/package.json +++ b/packages/@aws-cdk/aws-iotanalytics/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotcoredeviceadvisor/package.json b/packages/@aws-cdk/aws-iotcoredeviceadvisor/package.json index ecb59fded3ba8..15acc04b2e0f6 100644 --- a/packages/@aws-cdk/aws-iotcoredeviceadvisor/package.json +++ b/packages/@aws-cdk/aws-iotcoredeviceadvisor/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iotevents-actions/.eslintrc.js b/packages/@aws-cdk/aws-iotevents-actions/.eslintrc.js new file mode 100644 index 0000000000000..2658ee8727166 --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents-actions/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotevents-actions/.gitignore b/packages/@aws-cdk/aws-iotevents-actions/.gitignore new file mode 100644 index 0000000000000..266c0684c6844 --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents-actions/.gitignore @@ -0,0 +1,19 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +nyc.config.js +.LAST_PACKAGE +*.snk +!.eslintrc.js +!jest.config.js + +junit.xml diff --git a/packages/@aws-cdk/aws-iotevents-actions/.npmignore b/packages/@aws-cdk/aws-iotevents-actions/.npmignore new file mode 100644 index 0000000000000..9e51b66a1dba9 --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents-actions/.npmignore @@ -0,0 +1,28 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml +test/ +!*.lit.ts diff --git a/packages/@aws-cdk/aws-iotevents-actions/LICENSE b/packages/@aws-cdk/aws-iotevents-actions/LICENSE new file mode 100644 index 0000000000000..82ad00bb02d0b --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents-actions/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/aws-iotevents-actions/NOTICE b/packages/@aws-cdk/aws-iotevents-actions/NOTICE new file mode 100644 index 0000000000000..1b7adbb891265 --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents-actions/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-iotevents-actions/README.md b/packages/@aws-cdk/aws-iotevents-actions/README.md new file mode 100644 index 0000000000000..486ddd8124c34 --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents-actions/README.md @@ -0,0 +1,79 @@ +# Actions for AWS::IoTEvents Detector Model + + +--- + +![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) + +> The APIs of higher level constructs in this module are experimental and under active development. +> They are subject to non-backward compatible changes or removal in any future version. These are +> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be +> announced in the release notes. This means that while you may use them, you may need to update +> your source code when upgrading to a newer version of this package. + +--- + + + +This library contains integration classes to specify actions of state events of Detector Model in `@aws-cdk/aws-iotevents`. +Instances of these classes should be passed to `State` defined in `@aws-cdk/aws-iotevents` +You can define built-in actions to use a timer or set a variable, or send data to other AWS resources. + +This library contains integration classes to use a timer or set a variable, or send data to other AWS resources. +AWS IoT Events can trigger actions when it detects a specified event or transition event. + +Currently supported are: + +- Set variable to detector instanse +- Invoke a Lambda function + +## Set variable to detector instanse + +The code snippet below creates an Action that set variable to detector instanse +when it is triggered. + +```ts +import * as iotevents from '@aws-cdk/aws-iotevents'; +import * as actions from '@aws-cdk/aws-iotevents-actions'; + +declare const input: iotevents.IInput; + +const state = new iotevents.State({ + stateName: 'MyState', + onEnter: [{ + eventName: 'test-event', + condition: iotevents.Expression.currentInput(input), + actions: [ + actions: [ + new actions.SetVariableAction( + 'MyVariable', + iotevents.Expression.inputAttribute(input, 'payload.temperature'), + ), + ], + ], + }], +}); +``` + +## Invoke a Lambda function + +The code snippet below creates an Action that invoke a Lambda function +when it is triggered. + +```ts +import * as iotevents from '@aws-cdk/aws-iotevents'; +import * as actions from '@aws-cdk/aws-iotevents-actions'; +import * as lambda from '@aws-cdk/aws-lambda'; + +declare const input: iotevents.IInput; +declare const func: lambda.IFunction; + +const state = new iotevents.State({ + stateName: 'MyState', + onEnter: [{ + eventName: 'test-event', + condition: iotevents.Expression.currentInput(input), + actions: [new actions.LambdaInvokeAction(func)], + }], +}); +``` diff --git a/packages/@aws-cdk/aws-iotevents-actions/jest.config.js b/packages/@aws-cdk/aws-iotevents-actions/jest.config.js new file mode 100644 index 0000000000000..3a2fd93a1228a --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents-actions/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotevents-actions/lib/index.ts b/packages/@aws-cdk/aws-iotevents-actions/lib/index.ts new file mode 100644 index 0000000000000..e51394d301376 --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents-actions/lib/index.ts @@ -0,0 +1,2 @@ +export * from './set-variable-action'; +export * from './lambda-invoke-action'; diff --git a/packages/@aws-cdk/aws-iotevents-actions/lib/lambda-invoke-action.ts b/packages/@aws-cdk/aws-iotevents-actions/lib/lambda-invoke-action.ts new file mode 100644 index 0000000000000..af9dec5d32472 --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents-actions/lib/lambda-invoke-action.ts @@ -0,0 +1,25 @@ +import * as iotevents from '@aws-cdk/aws-iotevents'; +import * as lambda from '@aws-cdk/aws-lambda'; +import { Construct } from 'constructs'; + +/** + * The action to write the data to an AWS Lambda function. + */ +export class LambdaInvokeAction implements iotevents.IAction { + /** + * @param func the AWS Lambda function to be invoked by this action + */ + constructor(private readonly func: lambda.IFunction) { + } + + bind(_scope: Construct, options: iotevents.ActionBindOptions): iotevents.ActionConfig { + this.func.grantInvoke(options.role); + return { + configuration: { + lambda: { + functionArn: this.func.functionArn, + }, + }, + }; + } +} diff --git a/packages/@aws-cdk/aws-iotevents-actions/lib/set-variable-action.ts b/packages/@aws-cdk/aws-iotevents-actions/lib/set-variable-action.ts new file mode 100644 index 0000000000000..1d2596ddb866b --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents-actions/lib/set-variable-action.ts @@ -0,0 +1,25 @@ +import * as iotevents from '@aws-cdk/aws-iotevents'; +import { Construct } from 'constructs'; + +/** + * The action to create a variable with a specified value. + */ +export class SetVariableAction implements iotevents.IAction { + /** + * @param variableName the name of the variable + * @param value the new value of the variable + */ + constructor(private readonly variableName: string, private readonly value: iotevents.Expression) { + } + + bind(_scope: Construct, _options: iotevents.ActionBindOptions): iotevents.ActionConfig { + return { + configuration: { + setVariable: { + variableName: this.variableName, + value: this.value.evaluate(), + }, + }, + }; + } +} diff --git a/packages/@aws-cdk/aws-iotevents-actions/package.json b/packages/@aws-cdk/aws-iotevents-actions/package.json new file mode 100644 index 0000000000000..90a925459abc9 --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents-actions/package.json @@ -0,0 +1,106 @@ +{ + "name": "@aws-cdk/aws-iotevents-actions", + "version": "0.0.0", + "description": "Receipt Detector Model actions for AWS IoT Events", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "targets": { + "java": { + "package": "software.amazon.awscdk.services.iotevents.actions", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "iotevents-actions" + } + }, + "dotnet": { + "namespace": "Amazon.CDK.AWS.IoTEvents.Actions", + "packageId": "Amazon.CDK.AWS.IoTEvents.Actions", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "python": { + "distName": "aws-cdk.aws-iotevents-actions", + "module": "aws_cdk.aws_iotevents_actions", + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ] + } + }, + "projectReferences": true + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-iotevents-actions" + }, + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "build+test+package": "yarn build+test && yarn package", + "build+test": "yarn build && yarn test", + "compat": "cdk-compat", + "rosetta:extract": "yarn --silent jsii-rosetta extract", + "build+extract": "yarn build && yarn rosetta:extract", + "build+test+extract": "yarn build+test && yarn rosetta:extract" + }, + "cdk-build": { + "env": { + "AWSLINT_BASE_CONSTRUCT": true + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::IoTEvents", + "aws-iotevents-actions" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^27.4.1", + "jest": "^27.5.1" + }, + "dependencies": { + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-iotevents": "0.0.0", + "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "homepage": "https://github.com/aws/aws-cdk", + "peerDependencies": { + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-iotevents": "0.0.0", + "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "experimental", + "maturity": "experimental", + "awscdkio": { + "announce": false + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-iotevents-actions/test/iot/integ.set-variable-action.expected.json b/packages/@aws-cdk/aws-iotevents-actions/test/iot/integ.set-variable-action.expected.json new file mode 100644 index 0000000000000..0119afc958c1f --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents-actions/test/iot/integ.set-variable-action.expected.json @@ -0,0 +1,95 @@ +{ + "Resources": { + "MyInput08947B23": { + "Type": "AWS::IoTEvents::Input", + "Properties": { + "InputDefinition": { + "Attributes": [ + { + "JsonPath": "payload.deviceId" + }, + { + "JsonPath": "payload.temperature" + } + ] + }, + "InputName": "test_input" + } + }, + "MyDetectorModelDetectorModelRoleF2FB4D88": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "iotevents.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "MyDetectorModel559C0B0E": { + "Type": "AWS::IoTEvents::DetectorModel", + "Properties": { + "DetectorModelDefinition": { + "InitialStateName": "MyState", + "States": [ + { + "OnEnter": { + "Events": [ + { + "Actions": [ + { + "SetVariable": { + "Value": { + "Fn::Join": [ + "", + [ + "$input.", + { + "Ref": "MyInput08947B23" + }, + ".payload.temperature" + ] + ] + }, + "VariableName": "MyVariable" + } + } + ], + "Condition": { + "Fn::Join": [ + "", + [ + "currentInput(\"", + { + "Ref": "MyInput08947B23" + }, + "\")" + ] + ] + }, + "EventName": "enter-event" + } + ] + }, + "StateName": "MyState" + } + ] + }, + "RoleArn": { + "Fn::GetAtt": [ + "MyDetectorModelDetectorModelRoleF2FB4D88", + "Arn" + ] + }, + "Key": "payload.deviceId" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iotevents-actions/test/iot/integ.set-variable-action.ts b/packages/@aws-cdk/aws-iotevents-actions/test/iot/integ.set-variable-action.ts new file mode 100644 index 0000000000000..e6256e14710b2 --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents-actions/test/iot/integ.set-variable-action.ts @@ -0,0 +1,42 @@ +/** + * Stack verification steps: + * * put a message + * * aws iotevents-data batch-put-message --messages=messageId=(date | md5),inputName=test_input,payload=(echo '{"payload":{"temperature":31.9,"deviceId":"000"}}' | base64) + */ +import * as iotevents from '@aws-cdk/aws-iotevents'; +import * as cdk from '@aws-cdk/core'; +import * as actions from '../../lib'; + +class TestStack extends cdk.Stack { + constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + const input = new iotevents.Input(this, 'MyInput', { + inputName: 'test_input', + attributeJsonPaths: ['payload.deviceId', 'payload.temperature'], + }); + + const state = new iotevents.State({ + stateName: 'MyState', + onEnter: [{ + eventName: 'enter-event', + condition: iotevents.Expression.currentInput(input), + actions: [ + new actions.SetVariableAction( + 'MyVariable', + iotevents.Expression.inputAttribute(input, 'payload.temperature'), + ), + ], + }], + }); + + new iotevents.DetectorModel(this, 'MyDetectorModel', { + detectorKey: 'payload.deviceId', + initialState: state, + }); + } +} + +const app = new cdk.App(); +new TestStack(app, 'iotevents-set-variable-action-test-stack'); +app.synth(); diff --git a/packages/@aws-cdk/aws-iotevents-actions/test/iot/set-variable-action.test.ts b/packages/@aws-cdk/aws-iotevents-actions/test/iot/set-variable-action.test.ts new file mode 100644 index 0000000000000..1f779644b1a94 --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents-actions/test/iot/set-variable-action.test.ts @@ -0,0 +1,43 @@ +import { Template } from '@aws-cdk/assertions'; +import * as iotevents from '@aws-cdk/aws-iotevents'; +import * as cdk from '@aws-cdk/core'; +import * as actions from '../../lib'; + +let stack: cdk.Stack; +let input: iotevents.IInput; +beforeEach(() => { + stack = new cdk.Stack(); + input = iotevents.Input.fromInputName(stack, 'MyInput', 'test-input'); +}); + +test('Default property', () => { + // WHEN + new iotevents.DetectorModel(stack, 'MyDetectorModel', { + initialState: new iotevents.State({ + stateName: 'test-state', + onEnter: [{ + eventName: 'test-eventName', + condition: iotevents.Expression.currentInput(input), + actions: [new actions.SetVariableAction('MyVariable', iotevents.Expression.fromString('foo'))], + }], + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { + DetectorModelDefinition: { + States: [{ + OnEnter: { + Events: [{ + Actions: [{ + SetVariable: { + VariableName: 'MyVariable', + Value: 'foo', + }, + }], + }], + }, + }], + }, + }); +}); diff --git a/packages/@aws-cdk/aws-iotevents-actions/test/lambda/integ.lambda-invoke-action.expected.json b/packages/@aws-cdk/aws-iotevents-actions/test/lambda/integ.lambda-invoke-action.expected.json new file mode 100644 index 0000000000000..ab203f3fae7ca --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents-actions/test/lambda/integ.lambda-invoke-action.expected.json @@ -0,0 +1,177 @@ +{ + "Resources": { + "MyInput08947B23": { + "Type": "AWS::IoTEvents::Input", + "Properties": { + "InputDefinition": { + "Attributes": [ + { + "JsonPath": "payload.deviceId" + } + ] + }, + "InputName": "test_input" + } + }, + "MyFunctionServiceRole3C357FF2": { + "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" + ] + ] + } + ] + } + }, + "MyFunction3BAA72D1": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "\n exports.handler = (event) => {\n console.log(\"It is test for lambda action of AWS IoT Rule.\", event);\n };" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionServiceRole3C357FF2", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunctionServiceRole3C357FF2" + ] + }, + "MyDetectorModelDetectorModelRoleF2FB4D88": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "iotevents.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "MyDetectorModelDetectorModelRoleDefaultPolicy82887422": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "MyFunction3BAA72D1", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "MyFunction3BAA72D1", + "Arn" + ] + }, + ":*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyDetectorModelDetectorModelRoleDefaultPolicy82887422", + "Roles": [ + { + "Ref": "MyDetectorModelDetectorModelRoleF2FB4D88" + } + ] + } + }, + "MyDetectorModel559C0B0E": { + "Type": "AWS::IoTEvents::DetectorModel", + "Properties": { + "DetectorModelDefinition": { + "InitialStateName": "MyState", + "States": [ + { + "OnEnter": { + "Events": [ + { + "Actions": [ + { + "Lambda": { + "FunctionArn": { + "Fn::GetAtt": [ + "MyFunction3BAA72D1", + "Arn" + ] + } + } + } + ], + "Condition": { + "Fn::Join": [ + "", + [ + "currentInput(\"", + { + "Ref": "MyInput08947B23" + }, + "\")" + ] + ] + }, + "EventName": "test-event" + } + ] + }, + "StateName": "MyState" + } + ] + }, + "RoleArn": { + "Fn::GetAtt": [ + "MyDetectorModelDetectorModelRoleF2FB4D88", + "Arn" + ] + }, + "Key": "payload.deviceId" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iotevents-actions/test/lambda/integ.lambda-invoke-action.ts b/packages/@aws-cdk/aws-iotevents-actions/test/lambda/integ.lambda-invoke-action.ts new file mode 100644 index 0000000000000..2084f2cb7bd9c --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents-actions/test/lambda/integ.lambda-invoke-action.ts @@ -0,0 +1,48 @@ +/** + * Stack verification steps: + * * put a message + * * aws iotevents-data batch-put-message --messages=messageId=(date | md5),inputName=test_input,payload=(echo '{"payload":{"temperature":31.9,"deviceId":"000"}}' | base64) + * * verify that the lambda logs be put + */ +import * as iotevents from '@aws-cdk/aws-iotevents'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as cdk from '@aws-cdk/core'; +import * as actions from '../../lib'; + +class TestStack extends cdk.Stack { + constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + const input = new iotevents.Input(this, 'MyInput', { + inputName: 'test_input', + attributeJsonPaths: ['payload.deviceId'], + }); + const func = new lambda.Function(this, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_14_X, + handler: 'index.handler', + code: lambda.Code.fromInline(` + exports.handler = (event) => { + console.log("It is test for lambda action of AWS IoT Rule.", event); + };`, + ), + }); + + const state = new iotevents.State({ + stateName: 'MyState', + onEnter: [{ + eventName: 'test-event', + condition: iotevents.Expression.currentInput(input), + actions: [new actions.LambdaInvokeAction(func)], + }], + }); + + new iotevents.DetectorModel(this, 'MyDetectorModel', { + detectorKey: 'payload.deviceId', + initialState: state, + }); + } +} + +const app = new cdk.App(); +new TestStack(app, 'lambda-invoke-action-test-stack'); +app.synth(); diff --git a/packages/@aws-cdk/aws-iotevents-actions/test/lambda/lambda-invoke-action.test.ts b/packages/@aws-cdk/aws-iotevents-actions/test/lambda/lambda-invoke-action.test.ts new file mode 100644 index 0000000000000..f5ca749e3bc5b --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents-actions/test/lambda/lambda-invoke-action.test.ts @@ -0,0 +1,64 @@ +import { Template } from '@aws-cdk/assertions'; +import * as iotevents from '@aws-cdk/aws-iotevents'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as cdk from '@aws-cdk/core'; +import * as actions from '../../lib'; + +let stack: cdk.Stack; +let input: iotevents.IInput; +let func: lambda.IFunction; +beforeEach(() => { + stack = new cdk.Stack(); + input = iotevents.Input.fromInputName(stack, 'MyInput', 'test-input'); + func = lambda.Function.fromFunctionAttributes(stack, 'MyFunction', { + functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', + sameEnvironment: true, + }); +}); + +test('Default property', () => { + // WHEN + new iotevents.DetectorModel(stack, 'MyDetectorModel', { + initialState: new iotevents.State({ + stateName: 'test-state', + onEnter: [{ + eventName: 'test-eventName', + condition: iotevents.Expression.currentInput(input), + actions: [new actions.LambdaInvokeAction(func)], + }], + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { + DetectorModelDefinition: { + States: [{ + OnEnter: { + Events: [{ + Actions: [{ + Lambda: { + FunctionArn: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', + }, + }], + }], + }, + }], + }, + RoleArn: { + 'Fn::GetAtt': ['MyDetectorModelDetectorModelRoleF2FB4D88', 'Arn'], + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [{ + Action: 'lambda:InvokeFunction', + Effect: 'Allow', + Resource: ['arn:aws:lambda:us-east-1:123456789012:function:MyFn', 'arn:aws:lambda:us-east-1:123456789012:function:MyFn:*'], + }], + }, + Roles: [{ + Ref: 'MyDetectorModelDetectorModelRoleF2FB4D88', + }], + }); +}); diff --git a/packages/@aws-cdk/aws-iotevents/README.md b/packages/@aws-cdk/aws-iotevents/README.md index 809bac071ef7d..9089fdec07cbd 100644 --- a/packages/@aws-cdk/aws-iotevents/README.md +++ b/packages/@aws-cdk/aws-iotevents/README.md @@ -46,8 +46,15 @@ The following example creates an AWS IoT Events detector model to your stack. The detector model need a reference to at least one AWS IoT Events input. AWS IoT Events inputs enable the detector to get MQTT payload values from IoT Core rules. +You can define built-in actions to use a timer or set a variable, or send data to other AWS resources. +See also [@aws-cdk/aws-iotevents-actions](https://docs.aws.amazon.com/cdk/api/v1/docs/aws-iotevents-actions-readme.html) for other actions. + ```ts import * as iotevents from '@aws-cdk/aws-iotevents'; +import * as actions from '@aws-cdk/aws-iotevents-actions'; +import * as lambda from '@aws-cdk/aws-lambda'; + +declare const func: lambda.IFunction; const input = new iotevents.Input(this, 'MyInput', { inputName: 'my_input', // optional @@ -57,8 +64,17 @@ const input = new iotevents.Input(this, 'MyInput', { const warmState = new iotevents.State({ stateName: 'warm', onEnter: [{ - eventName: 'test-event', + eventName: 'test-enter-event', condition: iotevents.Expression.currentInput(input), + actions: [new actions.LambdaInvokeAction(func)], // optional + }], + onInput: [{ // optional + eventName: 'test-input-event', + actions: [new actions.LambdaInvokeAction(func)], + }], + onExit: [{ // optional + eventName: 'test-exit-event', + actions: [new actions.LambdaInvokeAction(func)], }], }); const coldState = new iotevents.State({ @@ -72,6 +88,7 @@ warmState.transitionTo(coldState, { iotevents.Expression.inputAttribute(input, 'payload.temperature'), iotevents.Expression.fromString('10'), ), + executing: [new actions.LambdaInvokeAction(func)], // optional }); // transit to warmState when temperature is 20 coldState.transitionTo(warmState, { diff --git a/packages/@aws-cdk/aws-iotevents/lib/action.ts b/packages/@aws-cdk/aws-iotevents/lib/action.ts new file mode 100644 index 0000000000000..f43c6b6c91626 --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents/lib/action.ts @@ -0,0 +1,33 @@ +import * as iam from '@aws-cdk/aws-iam'; +import { Construct } from 'constructs'; +import { CfnDetectorModel } from './iotevents.generated'; + +/** + * Options when binding a Action to a detector model. + */ +export interface ActionBindOptions { + /** + * The IAM role assumed by IoT Events to perform the action. + */ + readonly role: iam.IRole; +} + +/** + * An abstract action for DetectorModel. + */ +export interface IAction { + /** + * Returns the AWS IoT Events action specification. + */ + bind(scope: Construct, options: ActionBindOptions): ActionConfig; +} + +/** + * Properties for a AWS IoT Events action + */ +export interface ActionConfig { + /** + * The configuration for this action. + */ + readonly configuration: CfnDetectorModel.ActionProperty; +} diff --git a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts index 35128bc4531e6..1545e8ec69446 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts @@ -124,7 +124,7 @@ export class DetectorModel extends Resource implements IDetectorModel { key: props.detectorKey, detectorModelDefinition: { initialStateName: props.initialState.stateName, - states: props.initialState._collectStateJsons(new Set()), + states: props.initialState._collectStateJsons(this, { role }, new Set()), }, roleArn: role.roleArn, }); diff --git a/packages/@aws-cdk/aws-iotevents/lib/event.ts b/packages/@aws-cdk/aws-iotevents/lib/event.ts index 610469db9c32c..fd452686e054e 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/event.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/event.ts @@ -1,7 +1,8 @@ +import { IAction } from './action'; import { Expression } from './expression'; /** - * Specifies the actions to be performed when the condition evaluates to TRUE. + * Specifies the actions to be performed when the condition evaluates to `true`. */ export interface Event { /** @@ -10,9 +11,16 @@ export interface Event { readonly eventName: string; /** - * The Boolean expression that, when TRUE, causes the actions to be performed. + * The Boolean expression that, when `true`, causes the actions to be performed. * * @default - none (the actions are always executed) */ readonly condition?: Expression; + + /** + * The actions to be performed. + * + * @default - no actions will be performed + */ + readonly actions?: IAction[]; } diff --git a/packages/@aws-cdk/aws-iotevents/lib/index.ts b/packages/@aws-cdk/aws-iotevents/lib/index.ts index 24913635ebe50..b949a47454c3a 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/index.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/index.ts @@ -1,3 +1,4 @@ +export * from './action'; export * from './detector-model'; export * from './event'; export * from './expression'; diff --git a/packages/@aws-cdk/aws-iotevents/lib/state.ts b/packages/@aws-cdk/aws-iotevents/lib/state.ts index 67ee6a32802ec..ef8ce689fec47 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/state.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/state.ts @@ -1,3 +1,5 @@ +import { Construct } from 'constructs'; +import { IAction, ActionBindOptions } from './action'; import { Event } from './event'; import { Expression } from './expression'; import { CfnDetectorModel } from './iotevents.generated'; @@ -15,13 +17,20 @@ export interface TransitionOptions { /** * The condition that is used to determine to cause the state transition and the actions. - * When this was evaluated to TRUE, the state transition and the actions are triggered. + * When this was evaluated to `true`, the state transition and the actions are triggered. */ readonly when: Expression; + + /** + * The actions to be performed with the transition. + * + * @default - no actions will be performed + */ + readonly executing?: IAction[]; } /** - * Specifies the state transition and the actions to be performed when the condition evaluates to TRUE. + * Specifies the state transition and the actions to be performed when the condition evaluates to `true`. */ interface TransitionEvent { /** @@ -30,12 +39,19 @@ interface TransitionEvent { readonly eventName: string; /** - * The Boolean expression that, when TRUE, causes the state transition and the actions to be performed. + * The Boolean expression that, when `true`, causes the state transition and the actions to be performed. */ readonly condition: Expression; /** - * The next state to transit to. When the resuld of condition expression is TRUE, the state is transited. + * The actions to be performed. + * + * @default - no actions will be performed + */ + readonly actions?: IAction[]; + + /** + * The next state to transit to. When the resuld of condition expression is `true`, the state is transited. */ readonly nextState: State; } @@ -50,12 +66,28 @@ export interface StateProps { readonly stateName: string; /** - * Specifies the events on enter. the conditions of the events are evaluated when the state is entered. - * If the condition is `TRUE`, the actions of the event are performed. + * Specifies the events on enter. The conditions of the events will be evaluated when entering this state. + * If the condition of the event evaluates to `true`, the actions of the event will be executed. * - * @default - events on enter will not be set + * @default - no events will trigger on entering this state */ readonly onEnter?: Event[]; + + /** + * Specifies the events on input. The conditions of the events will be evaluated when any input is received. + * If the condition of the event evaluates to `true`, the actions of the event will be executed. + * + * @default - no events will trigger on input in this state + */ + readonly onInput?: Event[]; + + /** + * Specifies the events on exit. The conditions of the events are evaluated when an exiting this state. + * If the condition evaluates to `true`, the actions of the event will be executed. + * + * @default - no events will trigger on exiting this state + */ + readonly onExit?: Event[]; } /** @@ -75,7 +107,7 @@ export class State { /** * Add a transition event to the state. - * The transition event will be triggered if condition is evaluated to TRUE. + * The transition event will be triggered if condition is evaluated to `true`. * * @param targetState the state that will be transit to when the event triggered * @param options transition options including the condition that causes the state transition @@ -90,6 +122,7 @@ export class State { eventName: options.eventName ?? `${this.stateName}_to_${targetState.stateName}`, nextState: targetState, condition: options.when, + actions: options.executing, }); } @@ -100,16 +133,16 @@ export class State { * * @internal */ - public _collectStateJsons(collectedStates: Set): CfnDetectorModel.StateProperty[] { + public _collectStateJsons(scope: Construct, actionBindOptions: ActionBindOptions, collectedStates: Set): CfnDetectorModel.StateProperty[] { if (collectedStates.has(this)) { return []; } collectedStates.add(this); return [ - this.toStateJson(), + this.toStateJson(scope, actionBindOptions), ...this.transitionEvents.flatMap(transitionEvent => { - return transitionEvent.nextState._collectStateJsons(collectedStates); + return transitionEvent.nextState._collectStateJsons(scope, actionBindOptions, collectedStates); }), ]; } @@ -123,26 +156,41 @@ export class State { return this.props.onEnter?.some(event => event.condition) ?? false; } - private toStateJson(): CfnDetectorModel.StateProperty { - const { onEnter } = this.props; + private toStateJson(scope: Construct, actionBindOptions: ActionBindOptions): CfnDetectorModel.StateProperty { + const { onEnter, onInput, onExit } = this.props; return { stateName: this.stateName, - onEnter: onEnter && { events: toEventsJson(onEnter) }, - onInput: { - transitionEvents: toTransitionEventsJson(this.transitionEvents), + onEnter: onEnter && { + events: toEventsJson(scope, actionBindOptions, onEnter), + }, + onInput: (onInput || this.transitionEvents.length !== 0) ? { + events: toEventsJson(scope, actionBindOptions, onInput), + transitionEvents: toTransitionEventsJson(scope, actionBindOptions, this.transitionEvents), + } : undefined, + onExit: onExit && { + events: toEventsJson(scope, actionBindOptions, onExit), }, }; } } -function toEventsJson(events: Event[]): CfnDetectorModel.EventProperty[] { - return events.map(event => ({ +function toEventsJson( + scope: Construct, + actionBindOptions: ActionBindOptions, + events?: Event[], +): CfnDetectorModel.EventProperty[] | undefined { + return events?.map(event => ({ eventName: event.eventName, condition: event.condition?.evaluate(), + actions: event.actions?.map(action => action.bind(scope, actionBindOptions).configuration), })); } -function toTransitionEventsJson(transitionEvents: TransitionEvent[]): CfnDetectorModel.TransitionEventProperty[] | undefined { +function toTransitionEventsJson( + scope: Construct, + actionBindOptions: ActionBindOptions, + transitionEvents: TransitionEvent[], +): CfnDetectorModel.TransitionEventProperty[] | undefined { if (transitionEvents.length === 0) { return undefined; } @@ -150,6 +198,7 @@ function toTransitionEventsJson(transitionEvents: TransitionEvent[]): CfnDetecto return transitionEvents.map(transitionEvent => ({ eventName: transitionEvent.eventName, condition: transitionEvent.condition.evaluate(), + actions: transitionEvent.actions?.map(action => action.bind(scope, actionBindOptions).configuration), nextState: transitionEvent.nextState.stateName, })); } diff --git a/packages/@aws-cdk/aws-iotevents/package.json b/packages/@aws-cdk/aws-iotevents/package.json index 37c2035b4378f..3b3b352afe429 100644 --- a/packages/@aws-cdk/aws-iotevents/package.json +++ b/packages/@aws-cdk/aws-iotevents/package.json @@ -86,8 +86,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts index c90a10cf34374..e3844ce7915ba 100644 --- a/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts +++ b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts @@ -139,6 +139,158 @@ test('can set multiple events to State', () => { }); }); +test('can set actions to events', () => { + // WHEN + new iotevents.DetectorModel(stack, 'MyDetectorModel', { + initialState: new iotevents.State({ + stateName: 'test-state', + onEnter: [{ + eventName: 'test-eventName1', + condition: iotevents.Expression.currentInput(input), + actions: [{ + bind: () => ({ + configuration: { + lambda: { + functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', + }, + }, + }), + }], + }], + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { + DetectorModelDefinition: { + States: [ + Match.objectLike({ + OnEnter: { + Events: [{ + Actions: [{ Lambda: { FunctionArn: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn' } }], + }], + }, + }), + ], + }, + }); +}); + +test.each([ + ['onInput', { onInput: [{ eventName: 'test-eventName1' }] }, { OnInput: { Events: [{ EventName: 'test-eventName1' }] } }], + ['onExit', { onExit: [{ eventName: 'test-eventName1' }] }, { OnExit: { Events: [{ EventName: 'test-eventName1' }] } }], +])('can set %s to State', (_, events, expected) => { + // WHEN + new iotevents.DetectorModel(stack, 'MyDetectorModel', { + initialState: new iotevents.State({ + stateName: 'test-state', + onEnter: [{ eventName: 'test-eventName1', condition: iotevents.Expression.currentInput(input) }], + ...events, + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { + DetectorModelDefinition: { + States: [Match.objectLike(expected)], + }, + }); +}); + +test('can set an action to multiple detector models', () => { + // GIVEN an action + const action: iotevents.IAction = { + bind: (_, { role }) => { + role.addToPrincipalPolicy(new iam.PolicyStatement({ + actions: ['lambda:InvokeFunction'], + resources: ['arn:aws:lambda:us-east-1:123456789012:function:MyFn'], + })); + return { + configuration: { + lambda: { functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn' }, + }, + }; + }, + }; + + // WHEN the action is set to two detector models + new iotevents.DetectorModel(stack, 'MyDetectorModel1', { + detectorModelName: 'MyDetectorModel1', + initialState: new iotevents.State({ + stateName: 'test-state', + onEnter: [{ + eventName: 'test-eventName1', + condition: iotevents.Expression.currentInput(input), + actions: [action], + }], + }), + }); + new iotevents.DetectorModel(stack, 'MyDetectorModel2', { + detectorModelName: 'MyDetectorModel2', + initialState: new iotevents.State({ + stateName: 'test-state', + onEnter: [{ + eventName: 'test-eventName1', + condition: iotevents.Expression.currentInput(input), + actions: [action], + }], + }), + }); + + // THEN creates two detector model resouces and two iam policy resources + Template.fromStack(stack).resourceCountIs('AWS::IoTEvents::DetectorModel', 2); + Template.fromStack(stack).resourceCountIs('AWS::IAM::Policy', 2); + + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { + DetectorModelName: 'MyDetectorModel1', + DetectorModelDefinition: { + States: [ + Match.objectLike({ + OnEnter: { + Events: [{ + Actions: [{ Lambda: { FunctionArn: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn' } }], + }], + }, + }), + ], + }, + }); + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { + DetectorModelName: 'MyDetectorModel2', + DetectorModelDefinition: { + States: [ + Match.objectLike({ + OnEnter: { + Events: [{ + Actions: [{ Lambda: { FunctionArn: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn' } }], + }], + }, + }), + ], + }, + }); + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + Roles: [{ Ref: 'MyDetectorModel1DetectorModelRoleB36845CD' }], + PolicyDocument: { + Statement: [{ + Action: 'lambda:InvokeFunction', + Effect: 'Allow', + Resource: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', + }], + }, + }); + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + Roles: [{ Ref: 'MyDetectorModel2DetectorModelRole3C437E90' }], + PolicyDocument: { + Statement: [{ + Action: 'lambda:InvokeFunction', + Effect: 'Allow', + Resource: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', + }], + }, + }); +}); + test('can set states with transitions', () => { // GIVEN const firstState = new iotevents.State({ @@ -222,6 +374,47 @@ test('can set states with transitions', () => { }); }); +test('can set actions to transitions', () => { + // GIVEN + const firstState = new iotevents.State({ + stateName: 'firstState', + onEnter: [{ + eventName: 'test-eventName', + condition: iotevents.Expression.currentInput(input), + }], + }); + const secondState = new iotevents.State({ + stateName: 'secondState', + }); + + // WHEN + firstState.transitionTo(secondState, { + when: iotevents.Expression.eq( + iotevents.Expression.inputAttribute(input, 'payload.temperature'), + iotevents.Expression.fromString('12'), + ), + executing: [{ bind: () => ({ configuration: { setTimer: { timerName: 'test-timer' } } }) }], + }); + + new iotevents.DetectorModel(stack, 'MyDetectorModel', { + initialState: firstState, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { + DetectorModelDefinition: { + States: Match.arrayWith([Match.objectLike({ + StateName: 'firstState', + OnInput: { + TransitionEvents: [{ + Actions: [{ SetTimer: { TimerName: 'test-timer' } }], + }], + }, + })]), + }, + }); +}); + test('can set role', () => { // WHEN const role = iam.Role.fromRoleArn(stack, 'test-role', 'arn:aws:iam::123456789012:role/ForTest'); diff --git a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json index 888869a41e68e..3b24a7f7776d8 100644 --- a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json +++ b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json @@ -63,7 +63,43 @@ } ] }, + "OnExit": { + "Events": [ + { + "Condition": { + "Fn::Join": [ + "", + [ + "$input.", + { + "Ref": "MyInput08947B23" + }, + ".payload.temperature == 31.7" + ] + ] + }, + "EventName": "test-exit-event" + } + ] + }, "OnInput": { + "Events": [ + { + "Condition": { + "Fn::Join": [ + "", + [ + "$input.", + { + "Ref": "MyInput08947B23" + }, + ".payload.temperature == 31.6" + ] + ] + }, + "EventName": "test-input-event" + } + ], "TransitionEvents": [ { "Condition": { diff --git a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts index 5f6d2839f3a93..1c3996b226623 100644 --- a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts @@ -23,6 +23,20 @@ class TestStack extends cdk.Stack { ), ), }], + onInput: [{ + eventName: 'test-input-event', + condition: iotevents.Expression.eq( + iotevents.Expression.inputAttribute(input, 'payload.temperature'), + iotevents.Expression.fromString('31.6'), + ), + }], + onExit: [{ + eventName: 'test-exit-event', + condition: iotevents.Expression.eq( + iotevents.Expression.inputAttribute(input, 'payload.temperature'), + iotevents.Expression.fromString('31.7'), + ), + }], }); const offlineState = new iotevents.State({ stateName: 'offline', diff --git a/packages/@aws-cdk/aws-iotfleethub/package.json b/packages/@aws-cdk/aws-iotfleethub/package.json index dde15541e17b5..1908aae1aa512 100644 --- a/packages/@aws-cdk/aws-iotfleethub/package.json +++ b/packages/@aws-cdk/aws-iotfleethub/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iotsitewise/package.json b/packages/@aws-cdk/aws-iotsitewise/package.json index d84b4f75d06dc..fabfefa58f1e9 100644 --- a/packages/@aws-cdk/aws-iotsitewise/package.json +++ b/packages/@aws-cdk/aws-iotsitewise/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iotthingsgraph/package.json b/packages/@aws-cdk/aws-iotthingsgraph/package.json index fd5ffd5531c81..62af6298210fa 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/package.json +++ b/packages/@aws-cdk/aws-iotthingsgraph/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotwireless/package.json b/packages/@aws-cdk/aws-iotwireless/package.json index b5a5f1aee6dc7..684d07c5bd136 100644 --- a/packages/@aws-cdk/aws-iotwireless/package.json +++ b/packages/@aws-cdk/aws-iotwireless/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-ivs/package.json b/packages/@aws-cdk/aws-ivs/package.json index d078cf3eceeaa..4f8235a849a03 100644 --- a/packages/@aws-cdk/aws-ivs/package.json +++ b/packages/@aws-cdk/aws-ivs/package.json @@ -96,7 +96,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-kafkaconnect/package.json b/packages/@aws-cdk/aws-kafkaconnect/package.json index 76f3beafd989e..ec3eb36faaa42 100644 --- a/packages/@aws-cdk/aws-kafkaconnect/package.json +++ b/packages/@aws-cdk/aws-kafkaconnect/package.json @@ -88,7 +88,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-kendra/package.json b/packages/@aws-cdk/aws-kendra/package.json index 2da553adf56a5..805b53e719899 100644 --- a/packages/@aws-cdk/aws-kendra/package.json +++ b/packages/@aws-cdk/aws-kendra/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-kinesis/package.json b/packages/@aws-cdk/aws-kinesis/package.json index 0b1aea08d72df..6cc0092590712 100644 --- a/packages/@aws-cdk/aws-kinesis/package.json +++ b/packages/@aws-cdk/aws-kinesis/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-kinesis/test/integ.stream.expected.json b/packages/@aws-cdk/aws-kinesis/test/integ.stream.expected.json index e4e0a7b73bd68..3b1f6afca1bc6 100644 --- a/packages/@aws-cdk/aws-kinesis/test/integ.stream.expected.json +++ b/packages/@aws-cdk/aws-kinesis/test/integ.stream.expected.json @@ -39,15 +39,15 @@ "Statement": [ { "Action": [ + "kinesis:DescribeStream", "kinesis:DescribeStreamSummary", "kinesis:GetRecords", "kinesis:GetShardIterator", "kinesis:ListShards", - "kinesis:SubscribeToShard", - "kinesis:DescribeStream", "kinesis:ListStreams", "kinesis:PutRecord", - "kinesis:PutRecords" + "kinesis:PutRecords", + "kinesis:SubscribeToShard" ], "Effect": "Allow", "Resource": { @@ -71,11 +71,8 @@ "myStream547FAD7F": { "Type": "AWS::Kinesis::Stream", "Properties": { - "ShardCount": 1, - "StreamModeDetails": { - "StreamMode": "PROVISIONED" - }, "RetentionPeriodHours": 24, + "ShardCount": 1, "StreamEncryption": { "Fn::If": [ "AwsCdkKinesisEncryptedStreamsUnsupportedRegions", @@ -87,6 +84,9 @@ "KeyId": "alias/aws/kinesis" } ] + }, + "StreamModeDetails": { + "StreamMode": "PROVISIONED" } } } @@ -113,4 +113,4 @@ ] } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json b/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json index ebd3032722ce4..fb639112e35c2 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json @@ -77,8 +77,8 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/assets": "0.0.0", diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/test/integ.application-code-from-bucket.lit.expected.json b/packages/@aws-cdk/aws-kinesisanalytics-flink/test/integ.application-code-from-bucket.lit.expected.json index 6ab6a5f40bcab..47c34a07a09bd 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/test/integ.application-code-from-bucket.lit.expected.json +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/test/integ.application-code-from-bucket.lit.expected.json @@ -43,8 +43,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -60,7 +60,8 @@ ":s3:::", { "Ref": "AssetParameters8be9e0b5f53d41e9a3b1d51c9572c65f24f8170a7188d0ed57fb7d571de4d577S3BucketEBA17A67" - } + }, + "/*" ] ] }, @@ -75,8 +76,7 @@ ":s3:::", { "Ref": "AssetParameters8be9e0b5f53d41e9a3b1d51c9572c65f24f8170a7188d0ed57fb7d571de4d577S3BucketEBA17A67" - }, - "/*" + } ] ] } diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/test/integ.application.lit.expected.json b/packages/@aws-cdk/aws-kinesisanalytics-flink/test/integ.application.lit.expected.json index 3b4f7ecf64f7e..5ab3c94353f04 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/test/integ.application.lit.expected.json +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/test/integ.application.lit.expected.json @@ -29,8 +29,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -46,7 +46,8 @@ ":s3:::", { "Ref": "AssetParameters8be9e0b5f53d41e9a3b1d51c9572c65f24f8170a7188d0ed57fb7d571de4d577S3BucketEBA17A67" - } + }, + "/*" ] ] }, @@ -61,8 +62,7 @@ ":s3:::", { "Ref": "AssetParameters8be9e0b5f53d41e9a3b1d51c9572c65f24f8170a7188d0ed57fb7d571de4d577S3BucketEBA17A67" - }, - "/*" + } ] ] } diff --git a/packages/@aws-cdk/aws-kinesisanalytics/package.json b/packages/@aws-cdk/aws-kinesisanalytics/package.json index 637452746b169..bbdb446edb571 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/package.json +++ b/packages/@aws-cdk/aws-kinesisanalytics/package.json @@ -86,7 +86,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-kinesisanalyticsv2/package.json b/packages/@aws-cdk/aws-kinesisanalyticsv2/package.json index 6efbd4c780c43..5e618783474d5 100644 --- a/packages/@aws-cdk/aws-kinesisanalyticsv2/package.json +++ b/packages/@aws-cdk/aws-kinesisanalyticsv2/package.json @@ -88,7 +88,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json b/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json index 243fbffa41b9b..ad74666cd287a 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json +++ b/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json @@ -78,8 +78,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/integ.s3-bucket.lit.expected.json b/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/integ.s3-bucket.lit.expected.json index 913dba1638ec3..27e27e08d68d7 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/integ.s3-bucket.lit.expected.json +++ b/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/integ.s3-bucket.lit.expected.json @@ -23,9 +23,9 @@ "Statement": [ { "Action": [ + "s3:DeleteObject*", "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*" + "s3:List*" ], "Effect": "Allow", "Principal": { @@ -110,7 +110,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3Bucket4673BB1A" + "Ref": "AssetParametersbe270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824S3Bucket09A62232" }, "S3Key": { "Fn::Join": [ @@ -123,7 +123,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3VersionKey46E40510" + "Ref": "AssetParametersbe270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824S3VersionKeyA28118BE" } ] } @@ -136,7 +136,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3VersionKey46E40510" + "Ref": "AssetParametersbe270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824S3VersionKeyA28118BE" } ] } @@ -196,9 +196,9 @@ "Statement": [ { "Action": [ + "s3:DeleteObject*", "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*" + "s3:List*" ], "Effect": "Allow", "Principal": { @@ -310,7 +310,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters5ee078f2a1957fe672d6cfd84faf49e07b8460758b5cd2669b3df1212a14cd19S3BucketFEDDFB43" + "Ref": "AssetParameters9d04b6e97fcffe55f90ce717ab61c19d06df5a0c5c364c765216bf31a9c98d7dS3BucketA7AEF7D7" }, "S3Key": { "Fn::Join": [ @@ -323,7 +323,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5ee078f2a1957fe672d6cfd84faf49e07b8460758b5cd2669b3df1212a14cd19S3VersionKey244C2747" + "Ref": "AssetParameters9d04b6e97fcffe55f90ce717ab61c19d06df5a0c5c364c765216bf31a9c98d7dS3VersionKeyA7FD6E61" } ] } @@ -336,7 +336,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5ee078f2a1957fe672d6cfd84faf49e07b8460758b5cd2669b3df1212a14cd19S3VersionKey244C2747" + "Ref": "AssetParameters9d04b6e97fcffe55f90ce717ab61c19d06df5a0c5c364c765216bf31a9c98d7dS3VersionKeyA7FD6E61" } ] } @@ -476,25 +476,45 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ + { + "Fn::GetAtt": [ + "BackupBucket26B8E51C", + "Arn" + ] + }, { "Fn::GetAtt": [ "Bucket83908E77", "Arn" ] }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "BackupBucket26B8E51C", + "Arn" + ] + }, + "/*" + ] + ] + }, { "Fn::Join": [ "", @@ -517,31 +537,51 @@ "logs:PutLogEvents" ], "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "LogGroupF5B46931", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "DeliveryStreamLogGroup9D8FA3BB", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "LogGroupF5B46931", + "Arn" + ] + } + ] }, { "Action": [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*", - "s3:PutObject", - "s3:PutObjectLegalHold", - "s3:PutObjectRetention", - "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "kms:Decrypt", + "kms:Encrypt", + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": [ { "Fn::GetAtt": [ - "BackupBucket26B8E51C", + "BackupKey60B97760", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "Key961B73FD", + "Arn" + ] + } + ] + }, + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "DataProcessorFunctionAD472B9A", "Arn" ] }, @@ -551,68 +591,15 @@ [ { "Fn::GetAtt": [ - "BackupBucket26B8E51C", + "DataProcessorFunctionAD472B9A", "Arn" ] }, - "/*" + ":*" ] ] } ] - }, - { - "Action": [ - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "DeliveryStreamLogGroup9D8FA3BB", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "BackupKey60B97760", - "Arn" - ] - } - }, - { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "DataProcessorFunctionAD472B9A", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "Key961B73FD", - "Arn" - ] - } } ], "Version": "2012-10-17" @@ -775,29 +762,29 @@ } }, "Parameters": { - "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3Bucket4673BB1A": { + "AssetParametersbe270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824S3Bucket09A62232": { "Type": "String", - "Description": "S3 bucket for asset \"3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9\"" + "Description": "S3 bucket for asset \"be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824\"" }, - "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3VersionKey46E40510": { + "AssetParametersbe270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824S3VersionKeyA28118BE": { "Type": "String", - "Description": "S3 key for asset version \"3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9\"" + "Description": "S3 key for asset version \"be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824\"" }, - "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9ArtifactHashBD621721": { + "AssetParametersbe270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824ArtifactHash76F8FCF2": { "Type": "String", - "Description": "Artifact hash for asset \"3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9\"" + "Description": "Artifact hash for asset \"be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824\"" }, - "AssetParameters5ee078f2a1957fe672d6cfd84faf49e07b8460758b5cd2669b3df1212a14cd19S3BucketFEDDFB43": { + "AssetParameters9d04b6e97fcffe55f90ce717ab61c19d06df5a0c5c364c765216bf31a9c98d7dS3BucketA7AEF7D7": { "Type": "String", - "Description": "S3 bucket for asset \"5ee078f2a1957fe672d6cfd84faf49e07b8460758b5cd2669b3df1212a14cd19\"" + "Description": "S3 bucket for asset \"9d04b6e97fcffe55f90ce717ab61c19d06df5a0c5c364c765216bf31a9c98d7d\"" }, - "AssetParameters5ee078f2a1957fe672d6cfd84faf49e07b8460758b5cd2669b3df1212a14cd19S3VersionKey244C2747": { + "AssetParameters9d04b6e97fcffe55f90ce717ab61c19d06df5a0c5c364c765216bf31a9c98d7dS3VersionKeyA7FD6E61": { "Type": "String", - "Description": "S3 key for asset version \"5ee078f2a1957fe672d6cfd84faf49e07b8460758b5cd2669b3df1212a14cd19\"" + "Description": "S3 key for asset version \"9d04b6e97fcffe55f90ce717ab61c19d06df5a0c5c364c765216bf31a9c98d7d\"" }, - "AssetParameters5ee078f2a1957fe672d6cfd84faf49e07b8460758b5cd2669b3df1212a14cd19ArtifactHashC1C6FCBC": { + "AssetParameters9d04b6e97fcffe55f90ce717ab61c19d06df5a0c5c364c765216bf31a9c98d7dArtifactHashE49F8A6B": { "Type": "String", - "Description": "Artifact hash for asset \"5ee078f2a1957fe672d6cfd84faf49e07b8460758b5cd2669b3df1212a14cd19\"" + "Description": "Artifact hash for asset \"9d04b6e97fcffe55f90ce717ab61c19d06df5a0c5c364c765216bf31a9c98d7d\"" } }, "Mappings": { diff --git a/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/s3-bucket.test.ts b/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/s3-bucket.test.ts index 74d37d180f954..e4543a4215d3c 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/s3-bucket.test.ts +++ b/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/s3-bucket.test.ts @@ -333,7 +333,10 @@ describe('S3 destination', () => { { Action: 'lambda:InvokeFunction', Effect: 'Allow', - Resource: stack.resolve(lambdaFunction.functionArn), + Resource: [ + stack.resolve(lambdaFunction.functionArn), + { 'Fn::Join': ['', [stack.resolve(lambdaFunction.functionArn), ':*']] }, + ], }, ]), }, diff --git a/packages/@aws-cdk/aws-kinesisfirehose/package.json b/packages/@aws-cdk/aws-kinesisfirehose/package.json index 798a95fb5926e..066bfe78a218c 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/package.json +++ b/packages/@aws-cdk/aws-kinesisfirehose/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-kinesisfirehose/test/integ.delivery-stream.expected.json b/packages/@aws-cdk/aws-kinesisfirehose/test/integ.delivery-stream.expected.json index 65ac018add362..f82e1664494f4 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/test/integ.delivery-stream.expected.json +++ b/packages/@aws-cdk/aws-kinesisfirehose/test/integ.delivery-stream.expected.json @@ -29,16 +29,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -136,8 +136,8 @@ "Action": [ "kms:Decrypt", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-kinesisfirehose/test/integ.delivery-stream.source-stream.expected.json b/packages/@aws-cdk/aws-kinesisfirehose/test/integ.delivery-stream.source-stream.expected.json index ccbca77c32829..815c96c36137d 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/test/integ.delivery-stream.source-stream.expected.json +++ b/packages/@aws-cdk/aws-kinesisfirehose/test/integ.delivery-stream.source-stream.expected.json @@ -29,16 +29,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -121,13 +121,13 @@ "Statement": [ { "Action": [ + "kinesis:DescribeStream", "kinesis:DescribeStreamSummary", "kinesis:GetRecords", "kinesis:GetShardIterator", "kinesis:ListShards", - "kinesis:SubscribeToShard", - "kinesis:DescribeStream", - "kinesis:ListStreams" + "kinesis:ListStreams", + "kinesis:SubscribeToShard" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-kinesisvideo/package.json b/packages/@aws-cdk/aws-kinesisvideo/package.json index 6cf6f391297a3..40faddbc9de2f 100644 --- a/packages/@aws-cdk/aws-kinesisvideo/package.json +++ b/packages/@aws-cdk/aws-kinesisvideo/package.json @@ -88,7 +88,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-kms/package.json b/packages/@aws-cdk/aws-kms/package.json index 9b0c7831162cb..333bedc7b8a93 100644 --- a/packages/@aws-cdk/aws-kms/package.json +++ b/packages/@aws-cdk/aws-kms/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-lakeformation/package.json b/packages/@aws-cdk/aws-lakeformation/package.json index 2c37cb38a608f..c7ceef39cb56d 100644 --- a/packages/@aws-cdk/aws-lakeformation/package.json +++ b/packages/@aws-cdk/aws-lakeformation/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda-destinations/package.json b/packages/@aws-cdk/aws-lambda-destinations/package.json index 7f945078ba7e1..8feb76b2523f3 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/package.json +++ b/packages/@aws-cdk/aws-lambda-destinations/package.json @@ -76,8 +76,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda-destinations/test/destinations.test.ts b/packages/@aws-cdk/aws-lambda-destinations/test/destinations.test.ts index d30d292c7e510..5a94887c5673b 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/test/destinations.test.ts +++ b/packages/@aws-cdk/aws-lambda-destinations/test/destinations.test.ts @@ -90,12 +90,10 @@ test('lambda as destination', () => { { Action: 'lambda:InvokeFunction', Effect: 'Allow', - Resource: { - 'Fn::GetAtt': [ - 'SuccessFunction93C61D39', - 'Arn', - ], - }, + Resource: [ + { 'Fn::GetAtt': ['SuccessFunction93C61D39', 'Arn'] }, + { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['SuccessFunction93C61D39', 'Arn'] }, ':*']] }, + ], }, ], Version: '2012-10-17', diff --git a/packages/@aws-cdk/aws-lambda-destinations/test/integ.destinations.expected.json b/packages/@aws-cdk/aws-lambda-destinations/test/integ.destinations.expected.json index 009327c46da7e..16ab72abe7bb8 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/test/integ.destinations.expected.json +++ b/packages/@aws-cdk/aws-lambda-destinations/test/integ.destinations.expected.json @@ -53,9 +53,9 @@ }, { "Action": [ - "sqs:SendMessage", "sqs:GetQueueAttributes", - "sqs:GetQueueUrl" + "sqs:GetQueueUrl", + "sqs:SendMessage" ], "Effect": "Allow", "Resource": { @@ -243,12 +243,28 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "OnSucces8F9C946B", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "OnSucces8F9C946B", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "OnSucces8F9C946B", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-lambda-event-sources/lib/dynamodb.ts b/packages/@aws-cdk/aws-lambda-event-sources/lib/dynamodb.ts index 3d0fd78c915fc..80082453b5d84 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/lib/dynamodb.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/lib/dynamodb.ts @@ -17,8 +17,8 @@ export class DynamoEventSource extends StreamEventSource { if (this.props.batchSize !== undefined && !Token.isUnresolved(this.props.batchSize) - && (this.props.batchSize < 1 || this.props.batchSize > 1000)) { - throw new Error(`Maximum batch size must be between 1 and 1000 inclusive (given ${this.props.batchSize})`); + && (this.props.batchSize < 1 || this.props.batchSize > 10000)) { + throw new Error(`Maximum batch size must be between 1 and 10000 inclusive (given ${this.props.batchSize})`); } } diff --git a/packages/@aws-cdk/aws-lambda-event-sources/package.json b/packages/@aws-cdk/aws-lambda-event-sources/package.json index acb315b577807..c7253423991e4 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/package.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/package.json @@ -75,8 +75,8 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-apigateway": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/dynamo.test.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/dynamo.test.ts index 97bd42c07145f..a4b210156aae6 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/dynamo.test.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/dynamo.test.ts @@ -116,7 +116,7 @@ describe('DynamoEventSource', () => { // WHEN fn.addEventSource(new sources.DynamoEventSource(table, { - batchSize: 50, + batchSize: 5000, startingPosition: lambda.StartingPosition.LATEST, })); @@ -131,7 +131,7 @@ describe('DynamoEventSource', () => { 'FunctionName': { 'Ref': 'Fn9270CBC0', }, - 'BatchSize': 50, + 'BatchSize': 5000, 'StartingPosition': 'LATEST', }); @@ -153,7 +153,7 @@ describe('DynamoEventSource', () => { type: 'Number', default: 100, minValue: 1, - maxValue: 1000, + maxValue: 10000, }); // WHEN fn.addEventSource(new sources.DynamoEventSource(table, { @@ -217,12 +217,12 @@ describe('DynamoEventSource', () => { expect(() => fn.addEventSource(new sources.DynamoEventSource(table, { batchSize: 0, startingPosition: lambda.StartingPosition.LATEST, - }))).toThrow(/Maximum batch size must be between 1 and 1000 inclusive \(given 0\)/); + }))).toThrow(/Maximum batch size must be between 1 and 10000 inclusive \(given 0\)/); }); - test('fails if batch size > 1000', () => { + test('fails if batch size > 10000', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -236,9 +236,9 @@ describe('DynamoEventSource', () => { // WHEN expect(() => fn.addEventSource(new sources.DynamoEventSource(table, { - batchSize: 1001, + batchSize: 10001, startingPosition: lambda.StartingPosition.LATEST, - }))).toThrow(/Maximum batch size must be between 1 and 1000 inclusive \(given 1001\)/); + }))).toThrow(/Maximum batch size must be between 1 and 10000 inclusive \(given 10001\)/); }); diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesis.expected.json b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesis.expected.json index d14d727e34999..5f104978fe1a5 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesis.expected.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesis.expected.json @@ -38,13 +38,13 @@ "Statement": [ { "Action": [ + "kinesis:DescribeStream", "kinesis:DescribeStreamSummary", "kinesis:GetRecords", "kinesis:GetShardIterator", "kinesis:ListShards", - "kinesis:SubscribeToShard", - "kinesis:DescribeStream", - "kinesis:ListStreams" + "kinesis:ListStreams", + "kinesis:SubscribeToShard" ], "Effect": "Allow", "Resource": { @@ -53,16 +53,6 @@ "Arn" ] } - }, - { - "Action": "kinesis:DescribeStream", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "Q63C6E3AB", - "Arn" - ] - } } ], "Version": "2012-10-17" @@ -108,18 +98,15 @@ "Arn" ] }, - "TumblingWindowInSeconds": 60, - "StartingPosition": "TRIM_HORIZON" + "StartingPosition": "TRIM_HORIZON", + "TumblingWindowInSeconds": 60 } }, "Q63C6E3AB": { "Type": "AWS::Kinesis::Stream", "Properties": { - "ShardCount": 1, - "StreamModeDetails": { - "StreamMode": "PROVISIONED" - }, "RetentionPeriodHours": 24, + "ShardCount": 1, "StreamEncryption": { "Fn::If": [ "AwsCdkKinesisEncryptedStreamsUnsupportedRegions", @@ -131,6 +118,9 @@ "KeyId": "alias/aws/kinesis" } ] + }, + "StreamModeDetails": { + "StreamMode": "PROVISIONED" } } } @@ -157,4 +147,4 @@ ] } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesiswithdlq.expected.json b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesiswithdlq.expected.json index a16660f565e76..88559f3ad9675 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesiswithdlq.expected.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesiswithdlq.expected.json @@ -38,9 +38,9 @@ "Statement": [ { "Action": [ - "sqs:SendMessage", "sqs:GetQueueAttributes", - "sqs:GetQueueUrl" + "sqs:GetQueueUrl", + "sqs:SendMessage" ], "Effect": "Allow", "Resource": { @@ -52,13 +52,13 @@ }, { "Action": [ + "kinesis:DescribeStream", "kinesis:DescribeStreamSummary", "kinesis:GetRecords", "kinesis:GetShardIterator", "kinesis:ListShards", - "kinesis:SubscribeToShard", - "kinesis:DescribeStream", - "kinesis:ListStreams" + "kinesis:ListStreams", + "kinesis:SubscribeToShard" ], "Effect": "Allow", "Resource": { @@ -67,16 +67,6 @@ "Arn" ] } - }, - { - "Action": "kinesis:DescribeStream", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "S509448A1", - "Arn" - ] - } } ], "Version": "2012-10-17" @@ -139,11 +129,8 @@ "S509448A1": { "Type": "AWS::Kinesis::Stream", "Properties": { - "ShardCount": 1, - "StreamModeDetails": { - "StreamMode": "PROVISIONED" - }, "RetentionPeriodHours": 24, + "ShardCount": 1, "StreamEncryption": { "Fn::If": [ "AwsCdkKinesisEncryptedStreamsUnsupportedRegions", @@ -155,6 +142,9 @@ "KeyId": "alias/aws/kinesis" } ] + }, + "StreamModeDetails": { + "StreamMode": "PROVISIONED" } } }, @@ -206,4 +196,4 @@ ] } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.sqs.expected.json b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.sqs.expected.json index 9f5565aff21d6..7ae40ae9f962c 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.sqs.expected.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.sqs.expected.json @@ -38,11 +38,11 @@ "Statement": [ { "Action": [ - "sqs:ReceiveMessage", "sqs:ChangeMessageVisibility", - "sqs:GetQueueUrl", "sqs:DeleteMessage", - "sqs:GetQueueAttributes" + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + "sqs:ReceiveMessage" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-lambda-go/package.json b/packages/@aws-cdk/aws-lambda-go/package.json index de8eb177e133d..0383c7c0bbdd2 100644 --- a/packages/@aws-cdk/aws-lambda-go/package.json +++ b/packages/@aws-cdk/aws-lambda-go/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda-nodejs/README.md b/packages/@aws-cdk/aws-lambda-nodejs/README.md index 95d7559cf25f3..a21e5c9a6001d 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/README.md +++ b/packages/@aws-cdk/aws-lambda-nodejs/README.md @@ -170,7 +170,7 @@ Docker container even if `esbuild` is available in your environment. This can be ## Configuring `esbuild` -The `NodejsFunction` construct exposes some [esbuild options](https://esbuild.github.io/api/#build-api) +The `NodejsFunction` construct exposes [esbuild options](https://esbuild.github.io/api/#build-api) via properties under `bundling`: ```ts @@ -198,6 +198,11 @@ new lambda.NodejsFunction(this, 'my-handler', { charset: lambda.Charset.UTF8, // do not escape non-ASCII characters, defaults to Charset.ASCII format: lambda.OutputFormat.ESM, // ECMAScript module output format, defaults to OutputFormat.CJS (OutputFormat.ESM requires Node.js 14.x) mainFields: ['module', 'main'], // prefer ECMAScript versions of dependencies + inject: ['./my-shim.js', './other-shim.js'], // allows to automatically replace a global variable with an import from another file + esbuildArgs: { // Pass additional arguments to esbuild + "--log-limit": "0", + "--splitting": true, + }, }, }); ``` diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts index 8a251bf8dda24..15a9e4a4219ec 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts @@ -86,10 +86,10 @@ export class Bundling implements cdk.BundlingOptions { private readonly packageManager: PackageManager; constructor(private readonly props: BundlingProps) { - this.packageManager = PackageManager.fromLockFile(props.depsLockFilePath); + this.packageManager = PackageManager.fromLockFile(props.depsLockFilePath, props.logLevel); Bundling.esbuildInstallation = Bundling.esbuildInstallation ?? PackageInstallation.detect('esbuild'); - Bundling.tscInstallation = Bundling.tscInstallation ?? PackageInstallation.detect('tsc'); + Bundling.tscInstallation = Bundling.tscInstallation ?? PackageInstallation.detect('typescript'); this.projectRoot = props.projectRoot; this.relativeEntryPath = path.relative(this.projectRoot, path.resolve(props.entry)); @@ -198,6 +198,8 @@ export class Bundling implements cdk.BundlingOptions { ...this.props.footer ? [`--footer:js=${JSON.stringify(this.props.footer)}`] : [], ...this.props.charset ? [`--charset=${this.props.charset}`] : [], ...this.props.mainFields ? [`--main-fields=${this.props.mainFields.join(',')}`] : [], + ...this.props.inject ? this.props.inject.map(i => `--inject:${i}`) : [], + ...this.props.esbuildArgs ? [toCliArgs(this.props.esbuildArgs)] : [], ]; let depsCommand = ''; @@ -351,3 +353,17 @@ function toTarget(runtime: Runtime): string { return `node${match[1]}`; } + +function toCliArgs(esbuildArgs: { [key: string]: string | boolean }): string { + const args = []; + + for (const [key, value] of Object.entries(esbuildArgs)) { + if (value === true || value === '') { + args.push(key); + } else if (value) { + args.push(`${key}="${value}"`); + } + } + + return args.join(' '); +} diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts index 83f135a12a97b..0e17a749c2332 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts @@ -3,7 +3,7 @@ import * as path from 'path'; import * as lambda from '@aws-cdk/aws-lambda'; import { Architecture } from '@aws-cdk/aws-lambda'; import { Bundling } from './bundling'; -import { PackageManager } from './package-manager'; +import { LockFile } from './package-manager'; import { BundlingOptions } from './types'; import { callsites, findUpMultiple } from './util'; @@ -138,9 +138,9 @@ function findLockFile(depsLockFilePath?: string): string { } const lockFiles = findUpMultiple([ - PackageManager.PNPM.lockFile, - PackageManager.YARN.lockFile, - PackageManager.NPM.lockFile, + LockFile.PNPM, + LockFile.YARN, + LockFile.NPM, ]); if (lockFiles.length === 0) { diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/package-manager.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/package-manager.ts index f0206bbd19a99..05ef109993460 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/package-manager.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/package-manager.ts @@ -1,48 +1,54 @@ import * as os from 'os'; import * as path from 'path'; +import { LogLevel } from './types'; interface PackageManagerProps { readonly lockFile: string; readonly installCommand: string[]; readonly runCommand: string[]; - readonly argsSeparator?: string + readonly argsSeparator?: string; +} + +export enum LockFile { + NPM = 'package-lock.json', + YARN = 'yarn.lock', + PNPM = 'pnpm-lock.yaml', } /** * A node package manager */ export class PackageManager { - public static NPM = new PackageManager({ - lockFile: 'package-lock.json', - installCommand: ['npm', 'ci'], - runCommand: ['npx', '--no-install'], - }); - - public static YARN = new PackageManager({ - lockFile: 'yarn.lock', - installCommand: ['yarn', 'install', '--no-immutable'], - runCommand: ['yarn', 'run'], - }); - - public static PNPM = new PackageManager({ - lockFile: 'pnpm-lock.yaml', - installCommand: ['pnpm', 'install'], - runCommand: ['pnpm', 'exec'], - argsSeparator: '--', - }); - - public static fromLockFile(lockFilePath: string): PackageManager { + /** + * Use a lock file path to determine the package manager to use. Optionally, specify a log level to + * control its verbosity. + * @param lockFilePath Path of the lock file + * @param logLevel optional log level @default LogLevel.INFO + * @returns the right PackageManager for that lock file + */ + public static fromLockFile(lockFilePath: string, logLevel?: LogLevel): PackageManager { const lockFile = path.basename(lockFilePath); switch (lockFile) { - case PackageManager.NPM.lockFile: - return PackageManager.NPM; - case PackageManager.YARN.lockFile: - return PackageManager.YARN; - case PackageManager.PNPM.lockFile: - return PackageManager.PNPM; + case LockFile.YARN: + return new PackageManager({ + lockFile: LockFile.YARN, + installCommand: logLevel && logLevel !== LogLevel.INFO ? ['yarn', 'install', '--no-immutable', '--silent'] : ['yarn', 'install', '--no-immutable'], + runCommand: ['yarn', 'run'], + }); + case LockFile.PNPM: + return new PackageManager({ + lockFile: LockFile.PNPM, + installCommand: logLevel && logLevel !== LogLevel.INFO ? ['pnpm', 'install', '--reporter', 'silent'] : ['pnpm', 'install'], + runCommand: ['pnpm', 'exec'], + argsSeparator: '--', + }); default: - return PackageManager.NPM; + return new PackageManager({ + lockFile: LockFile.NPM, + installCommand: logLevel ? ['npm', 'ci', '--loglevel', logLevel] : ['npm', 'ci'], + runCommand: ['npx', '--no-install'], + }); } } diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts index e43dc6d41be1e..c9bc8f1151035 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts @@ -59,7 +59,8 @@ export interface BundlingOptions { readonly loader?: { [ext: string]: string }; /** - * Log level for esbuild + * Log level for esbuild. This is also propagated to the package manager and + * applies to its specific install command. * * @default LogLevel.WARNING */ @@ -202,12 +203,32 @@ export interface BundlingOptions { */ readonly esbuildVersion?: string; + /** + * Build arguments to pass into esbuild. + * + * For example, to add the [--log-limit](https://esbuild.github.io/api/#log-limit) flag: + * + * ```text + * new NodejsFunction(scope, id, { + * ... + * bundling: { + * esbuildArgs: { + * "--log-limit": "0", + * } + * } + * }); + * ``` + * + * @default - no additional esbuild arguments are passed + */ + readonly esbuildArgs?: { [key: string]: string | boolean }; + /** * Build arguments to pass when building the bundling image. * * @default - no build arguments are passed */ - readonly buildArgs?: { [key:string] : string }; + readonly buildArgs?: { [key: string]: string }; /** * Force bundling in a Docker container even if local bundling is @@ -278,6 +299,15 @@ export interface BundlingOptions { * @default ['main', 'module'] */ readonly mainFields?: string[]; + + /** + * This option allows you to automatically replace a global variable with an + * import from another file. + * + * @see https://esbuild.github.io/api/#inject + * @default - no code is injected + */ + readonly inject?: string[] } /** @@ -340,7 +370,7 @@ export interface ICommandHooks { } /** - * Log level for esbuild + * Log levels for esbuild and package managers' install commands. */ export enum LogLevel { /** Show everything */ diff --git a/packages/@aws-cdk/aws-lambda-nodejs/package.json b/packages/@aws-cdk/aws-lambda-nodejs/package.json index c11d91b27710b..f838c991dbcea 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/package.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/package.json @@ -76,9 +76,9 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "delay": "5.0.0", - "esbuild": "^0.14.18" + "esbuild": "^0.14.29" }, "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts index 3224d1afbd014..739c401bd3d91 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts @@ -16,6 +16,7 @@ beforeEach(() => { jest.resetAllMocks(); jest.restoreAllMocks(); Bundling.clearEsbuildInstallationCache(); + Bundling.clearTscInstallationCache(); jest.spyOn(Code, 'fromAsset'); @@ -208,6 +209,13 @@ test('esbuild bundling with esbuild options', () => { 'process.env.STRING': JSON.stringify('this is a "test"'), }, format: OutputFormat.ESM, + inject: ['./my-shim.js'], + esbuildArgs: { + '--log-limit': '0', + '--resolve-extensions': '.ts,.js', + '--splitting': true, + '--keep-names': '', + }, }); // Correctly bundles with esbuild @@ -216,7 +224,8 @@ test('esbuild bundling with esbuild options', () => { assetHashType: AssetHashType.OUTPUT, bundling: expect.objectContaining({ command: [ - 'bash', '-c', + 'bash', + '-c', [ 'esbuild --bundle "/asset-input/lib/handler.ts"', '--target=es2020 --platform=node --format=esm --outfile="/asset-output/index.mjs"', @@ -224,7 +233,8 @@ test('esbuild bundling with esbuild options', () => { defineInstructions, '--log-level=silent --keep-names --tsconfig=/asset-input/lib/custom-tsconfig.ts', '--metafile=/asset-output/index.meta.json --banner:js="/* comments */" --footer:js="/* comments */"', - '--charset=utf8 --main-fields=module,main', + '--charset=utf8 --main-fields=module,main --inject:./my-shim.js', + '--log-limit="0" --resolve-extensions=".ts,.js" --splitting --keep-names', ].join(' '), ], }), @@ -422,6 +432,7 @@ test('Local bundling', () => { environment: { KEY: 'value', }, + logLevel: LogLevel.ERROR, }); expect(bundler.local).toBeDefined(); @@ -600,6 +611,8 @@ test('esbuild bundling with pre compilations', () => { ], }), }); + + expect(detectPackageInstallationMock).toHaveBeenCalledWith('typescript'); }); test('throws with pre compilation and not found tsconfig', () => { diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies.expected.json b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies.expected.json index 1800768023419..825ac665c7141 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies.expected.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746S3Bucket01854DA0" + "Ref": "AssetParameters4c9f09adeee5f7ebc38c74c200b962852bca53042fb5e9b818e4433ccc31e663S3BucketB985628A" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746S3VersionKey1CC8C283" + "Ref": "AssetParameters4c9f09adeee5f7ebc38c74c200b962852bca53042fb5e9b818e4433ccc31e663S3VersionKeyBF22F5BF" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746S3VersionKey1CC8C283" + "Ref": "AssetParameters4c9f09adeee5f7ebc38c74c200b962852bca53042fb5e9b818e4433ccc31e663S3VersionKeyBF22F5BF" } ] } @@ -92,17 +92,17 @@ } }, "Parameters": { - "AssetParameters5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746S3Bucket01854DA0": { + "AssetParameters4c9f09adeee5f7ebc38c74c200b962852bca53042fb5e9b818e4433ccc31e663S3BucketB985628A": { "Type": "String", - "Description": "S3 bucket for asset \"5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746\"" + "Description": "S3 bucket for asset \"4c9f09adeee5f7ebc38c74c200b962852bca53042fb5e9b818e4433ccc31e663\"" }, - "AssetParameters5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746S3VersionKey1CC8C283": { + "AssetParameters4c9f09adeee5f7ebc38c74c200b962852bca53042fb5e9b818e4433ccc31e663S3VersionKeyBF22F5BF": { "Type": "String", - "Description": "S3 key for asset version \"5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746\"" + "Description": "S3 key for asset version \"4c9f09adeee5f7ebc38c74c200b962852bca53042fb5e9b818e4433ccc31e663\"" }, - "AssetParameters5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746ArtifactHashAA3B8064": { + "AssetParameters4c9f09adeee5f7ebc38c74c200b962852bca53042fb5e9b818e4433ccc31e663ArtifactHashCE7178E5": { "Type": "String", - "Description": "Artifact hash for asset \"5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746\"" + "Description": "Artifact hash for asset \"4c9f09adeee5f7ebc38c74c200b962852bca53042fb5e9b818e4433ccc31e663\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.esm.expected.json b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.esm.expected.json index 8e6b8cabf01c6..3451647e0e977 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.esm.expected.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.esm.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersa111e7aee76f0a755b83f3d35098efc1659ba3915bd52dc401cb3a972573d616S3BucketD8FC0ACA" + "Ref": "AssetParameterse1af356d995917f14ba5cf5e65cb7c4e969e2c28567bea560a8912fbbfa3fa4eS3Bucket72D078A9" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa111e7aee76f0a755b83f3d35098efc1659ba3915bd52dc401cb3a972573d616S3VersionKeyF7C65CF0" + "Ref": "AssetParameterse1af356d995917f14ba5cf5e65cb7c4e969e2c28567bea560a8912fbbfa3fa4eS3VersionKey93EC2390" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa111e7aee76f0a755b83f3d35098efc1659ba3915bd52dc401cb3a972573d616S3VersionKeyF7C65CF0" + "Ref": "AssetParameterse1af356d995917f14ba5cf5e65cb7c4e969e2c28567bea560a8912fbbfa3fa4eS3VersionKey93EC2390" } ] } @@ -92,17 +92,17 @@ } }, "Parameters": { - "AssetParametersa111e7aee76f0a755b83f3d35098efc1659ba3915bd52dc401cb3a972573d616S3BucketD8FC0ACA": { + "AssetParameterse1af356d995917f14ba5cf5e65cb7c4e969e2c28567bea560a8912fbbfa3fa4eS3Bucket72D078A9": { "Type": "String", - "Description": "S3 bucket for asset \"a111e7aee76f0a755b83f3d35098efc1659ba3915bd52dc401cb3a972573d616\"" + "Description": "S3 bucket for asset \"e1af356d995917f14ba5cf5e65cb7c4e969e2c28567bea560a8912fbbfa3fa4e\"" }, - "AssetParametersa111e7aee76f0a755b83f3d35098efc1659ba3915bd52dc401cb3a972573d616S3VersionKeyF7C65CF0": { + "AssetParameterse1af356d995917f14ba5cf5e65cb7c4e969e2c28567bea560a8912fbbfa3fa4eS3VersionKey93EC2390": { "Type": "String", - "Description": "S3 key for asset version \"a111e7aee76f0a755b83f3d35098efc1659ba3915bd52dc401cb3a972573d616\"" + "Description": "S3 key for asset version \"e1af356d995917f14ba5cf5e65cb7c4e969e2c28567bea560a8912fbbfa3fa4e\"" }, - "AssetParametersa111e7aee76f0a755b83f3d35098efc1659ba3915bd52dc401cb3a972573d616ArtifactHashDDFE4A88": { + "AssetParameterse1af356d995917f14ba5cf5e65cb7c4e969e2c28567bea560a8912fbbfa3fa4eArtifactHashB5F6BEF5": { "Type": "String", - "Description": "Artifact hash for asset \"a111e7aee76f0a755b83f3d35098efc1659ba3915bd52dc401cb3a972573d616\"" + "Description": "Artifact hash for asset \"e1af356d995917f14ba5cf5e65cb7c4e969e2c28567bea560a8912fbbfa3fa4e\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.function.expected.json b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.function.expected.json index f976b83648db4..5236e0df61376 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.function.expected.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.function.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1S3Bucket1B1D9794" + "Ref": "AssetParameters2117ac17e1ec7017f8ab1b047bddad03a85ea5d448404a33a7fcee4fb5a3d666S3Bucket9DF03081" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1S3VersionKey720EECDB" + "Ref": "AssetParameters2117ac17e1ec7017f8ab1b047bddad03a85ea5d448404a33a7fcee4fb5a3d666S3VersionKeyD292AB11" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1S3VersionKey720EECDB" + "Ref": "AssetParameters2117ac17e1ec7017f8ab1b047bddad03a85ea5d448404a33a7fcee4fb5a3d666S3VersionKeyD292AB11" } ] } @@ -126,7 +126,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6S3Bucket95EC2A4C" + "Ref": "AssetParametersdc17834bed7e16ae407d0a77361d92c9a7609557332dafffb47df61ec1b48b3eS3BucketCEC78A8C" }, "S3Key": { "Fn::Join": [ @@ -139,7 +139,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6S3VersionKey0EEB0B14" + "Ref": "AssetParametersdc17834bed7e16ae407d0a77361d92c9a7609557332dafffb47df61ec1b48b3eS3VersionKey73F73F44" } ] } @@ -152,7 +152,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6S3VersionKey0EEB0B14" + "Ref": "AssetParametersdc17834bed7e16ae407d0a77361d92c9a7609557332dafffb47df61ec1b48b3eS3VersionKey73F73F44" } ] } @@ -275,15 +275,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "Tags": [ { "Key": "Name", @@ -372,15 +372,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "Tags": [ { "Key": "Name", @@ -469,15 +469,15 @@ "VpcPublicSubnet3NATGateway7640CD1D": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet3SubnetBE12F0B6" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet3EIP3A666A23", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet3SubnetBE12F0B6" - }, "Tags": [ { "Key": "Name", @@ -758,7 +758,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfeS3Bucket6796DF76" + "Ref": "AssetParameters050b3629caed17ac6299cf2228bc7a46c2b039b1386eabf3e5935cffca2a96ddS3Bucket6289DEB0" }, "S3Key": { "Fn::Join": [ @@ -771,7 +771,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfeS3VersionKeyE83502D3" + "Ref": "AssetParameters050b3629caed17ac6299cf2228bc7a46c2b039b1386eabf3e5935cffca2a96ddS3VersionKey0271AF4F" } ] } @@ -784,7 +784,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfeS3VersionKeyE83502D3" + "Ref": "AssetParameters050b3629caed17ac6299cf2228bc7a46c2b039b1386eabf3e5935cffca2a96ddS3VersionKey0271AF4F" } ] } @@ -835,41 +835,41 @@ } }, "Parameters": { - "AssetParameters790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1S3Bucket1B1D9794": { + "AssetParameters2117ac17e1ec7017f8ab1b047bddad03a85ea5d448404a33a7fcee4fb5a3d666S3Bucket9DF03081": { "Type": "String", - "Description": "S3 bucket for asset \"790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1\"" + "Description": "S3 bucket for asset \"2117ac17e1ec7017f8ab1b047bddad03a85ea5d448404a33a7fcee4fb5a3d666\"" }, - "AssetParameters790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1S3VersionKey720EECDB": { + "AssetParameters2117ac17e1ec7017f8ab1b047bddad03a85ea5d448404a33a7fcee4fb5a3d666S3VersionKeyD292AB11": { "Type": "String", - "Description": "S3 key for asset version \"790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1\"" + "Description": "S3 key for asset version \"2117ac17e1ec7017f8ab1b047bddad03a85ea5d448404a33a7fcee4fb5a3d666\"" }, - "AssetParameters790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1ArtifactHashA9293830": { + "AssetParameters2117ac17e1ec7017f8ab1b047bddad03a85ea5d448404a33a7fcee4fb5a3d666ArtifactHashD513F670": { "Type": "String", - "Description": "Artifact hash for asset \"790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1\"" + "Description": "Artifact hash for asset \"2117ac17e1ec7017f8ab1b047bddad03a85ea5d448404a33a7fcee4fb5a3d666\"" }, - "AssetParameters55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6S3Bucket95EC2A4C": { + "AssetParametersdc17834bed7e16ae407d0a77361d92c9a7609557332dafffb47df61ec1b48b3eS3BucketCEC78A8C": { "Type": "String", - "Description": "S3 bucket for asset \"55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6\"" + "Description": "S3 bucket for asset \"dc17834bed7e16ae407d0a77361d92c9a7609557332dafffb47df61ec1b48b3e\"" }, - "AssetParameters55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6S3VersionKey0EEB0B14": { + "AssetParametersdc17834bed7e16ae407d0a77361d92c9a7609557332dafffb47df61ec1b48b3eS3VersionKey73F73F44": { "Type": "String", - "Description": "S3 key for asset version \"55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6\"" + "Description": "S3 key for asset version \"dc17834bed7e16ae407d0a77361d92c9a7609557332dafffb47df61ec1b48b3e\"" }, - "AssetParameters55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6ArtifactHashE6098BA4": { + "AssetParametersdc17834bed7e16ae407d0a77361d92c9a7609557332dafffb47df61ec1b48b3eArtifactHash7BBA4237": { "Type": "String", - "Description": "Artifact hash for asset \"55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6\"" + "Description": "Artifact hash for asset \"dc17834bed7e16ae407d0a77361d92c9a7609557332dafffb47df61ec1b48b3e\"" }, - "AssetParameters39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfeS3Bucket6796DF76": { + "AssetParameters050b3629caed17ac6299cf2228bc7a46c2b039b1386eabf3e5935cffca2a96ddS3Bucket6289DEB0": { "Type": "String", - "Description": "S3 bucket for asset \"39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfe\"" + "Description": "S3 bucket for asset \"050b3629caed17ac6299cf2228bc7a46c2b039b1386eabf3e5935cffca2a96dd\"" }, - "AssetParameters39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfeS3VersionKeyE83502D3": { + "AssetParameters050b3629caed17ac6299cf2228bc7a46c2b039b1386eabf3e5935cffca2a96ddS3VersionKey0271AF4F": { "Type": "String", - "Description": "S3 key for asset version \"39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfe\"" + "Description": "S3 key for asset version \"050b3629caed17ac6299cf2228bc7a46c2b039b1386eabf3e5935cffca2a96dd\"" }, - "AssetParameters39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfeArtifactHashB3080084": { + "AssetParameters050b3629caed17ac6299cf2228bc7a46c2b039b1386eabf3e5935cffca2a96ddArtifactHashEC0A46C5": { "Type": "String", - "Description": "Artifact hash for asset \"39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfe\"" + "Description": "Artifact hash for asset \"050b3629caed17ac6299cf2228bc7a46c2b039b1386eabf3e5935cffca2a96dd\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/package-manager.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/package-manager.test.ts index 19369bdd07d9a..8bb0682c0d568 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/package-manager.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/package-manager.test.ts @@ -1,36 +1,62 @@ import * as os from 'os'; -import { PackageManager } from '../lib/package-manager'; +import { LogLevel } from '../lib'; +import { LockFile, PackageManager } from '../lib/package-manager'; test('from a package-lock.json', () => { const packageManager = PackageManager.fromLockFile('/path/to/package-lock.json'); - expect(packageManager).toEqual(PackageManager.NPM); + expect(packageManager.lockFile).toEqual(LockFile.NPM); + expect(packageManager.argsSeparator).toBeUndefined(); + expect(packageManager.installCommand).toEqual(['npm', 'ci']); + expect(packageManager.runCommand).toEqual(['npx', '--no-install']); expect(packageManager.runBinCommand('my-bin')).toBe('npx --no-install my-bin'); }); +test('from a package-lock.json with LogLevel.ERROR', () => { + const logLevel = LogLevel.ERROR; + const packageManager = PackageManager.fromLockFile('/path/to/package-lock.json', logLevel); + expect(packageManager.installCommand).toEqual(['npm', 'ci', '--loglevel', logLevel]); +}); + test('from a yarn.lock', () => { const packageManager = PackageManager.fromLockFile('/path/to/yarn.lock'); - expect(packageManager).toEqual(PackageManager.YARN); + expect(packageManager.lockFile).toEqual(LockFile.YARN); + expect(packageManager.argsSeparator).toBeUndefined(); + expect(packageManager.installCommand).toEqual(['yarn', 'install', '--no-immutable']); + expect(packageManager.runCommand).toEqual(['yarn', 'run']); expect(packageManager.runBinCommand('my-bin')).toBe('yarn run my-bin'); }); +test('from a yarn.lock with LogLevel.ERROR', () => { + const packageManager = PackageManager.fromLockFile('/path/to/yarn.lock', LogLevel.ERROR); + expect(packageManager.installCommand).toEqual(['yarn', 'install', '--no-immutable', '--silent']); +}); + test('from a pnpm-lock.yaml', () => { const packageManager = PackageManager.fromLockFile('/path/to/pnpm-lock.yaml'); - expect(packageManager).toEqual(PackageManager.PNPM); + expect(packageManager.lockFile).toEqual(LockFile.PNPM); + expect(packageManager.argsSeparator).toEqual('--'); + expect(packageManager.installCommand).toEqual(['pnpm', 'install']); + expect(packageManager.runCommand).toEqual(['pnpm', 'exec']); expect(packageManager.runBinCommand('my-bin')).toBe('pnpm exec -- my-bin'); }); +test('from a pnpm-lock.yaml with LogLevel.ERROR', () => { + const packageManager = PackageManager.fromLockFile('/path/to/pnpm-lock.yaml', LogLevel.ERROR); + expect(packageManager.installCommand).toEqual(['pnpm', 'install', '--reporter', 'silent']); +}); + test('defaults to NPM', () => { const packageManager = PackageManager.fromLockFile('/path/to/other.lock'); - expect(packageManager).toEqual(PackageManager.NPM); + expect(packageManager.lockFile).toEqual(LockFile.NPM); }); test('Windows', () => { const osPlatformMock = jest.spyOn(os, 'platform').mockReturnValue('win32'); - const packageManager = PackageManager.NPM; + const packageManager = PackageManager.fromLockFile('/path/to/whatever'); expect(packageManager.runBinCommand('my-bin')).toEqual('npx.cmd --no-install my-bin'); osPlatformMock.mockRestore(); diff --git a/packages/@aws-cdk/aws-lambda-python/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-python/lib/bundling.ts index bd2020a5a228b..27c8d24f83558 100644 --- a/packages/@aws-cdk/aws-lambda-python/lib/bundling.ts +++ b/packages/@aws-cdk/aws-lambda-python/lib/bundling.ts @@ -34,6 +34,13 @@ export interface BundlingProps extends BundlingOptions { * @default Architecture.X86_64 */ readonly architecture?: Architecture; + + /** + * Whether or not the bundling process should be skipped + * + * @default - Does not skip bundling + */ + readonly skip?: boolean; } /** @@ -45,7 +52,7 @@ export class Bundling implements CdkBundlingOptions { assetHash: options.assetHash, assetHashType: options.assetHashType, exclude: DEPENDENCY_EXCLUDES, - bundling: new Bundling(options), + bundling: options.skip ? undefined : new Bundling(options), }); } @@ -62,7 +69,7 @@ export class Bundling implements CdkBundlingOptions { image, } = props; - const outputPath = path.join(AssetStaging.BUNDLING_OUTPUT_DIR, outputPathSuffix); + const outputPath = path.posix.join(AssetStaging.BUNDLING_OUTPUT_DIR, outputPathSuffix); const bundlingCommands = this.createBundlingCommand({ entry, @@ -70,14 +77,13 @@ export class Bundling implements CdkBundlingOptions { outputDir: outputPath, }); - const defaultImage = DockerImage.fromBuild(path.join(__dirname, '../lib'), { + this.image = image ?? DockerImage.fromBuild(path.join(__dirname, '../lib'), { buildArgs: { - ...props.buildArgs ?? {}, + ...props.buildArgs, IMAGE: runtime.bundlingImage.image, }, platform: architecture.dockerPlatform, }); - this.image = image ?? defaultImage; this.command = ['bash', '-c', chain(bundlingCommands)]; this.environment = props.environment; } diff --git a/packages/@aws-cdk/aws-lambda-python/lib/function.ts b/packages/@aws-cdk/aws-lambda-python/lib/function.ts index 7938c20219f73..15013622d2cbc 100644 --- a/packages/@aws-cdk/aws-lambda-python/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda-python/lib/function.ts @@ -1,6 +1,7 @@ import * as fs from 'fs'; import * as path from 'path'; import { Function, FunctionOptions, Runtime, RuntimeFamily } from '@aws-cdk/aws-lambda'; +import { Stack } from '@aws-cdk/core'; import { Bundling } from './bundling'; import { BundlingOptions } from './types'; @@ -79,6 +80,7 @@ export class PythonFunction extends Function { code: Bundling.bundle({ entry, runtime, + skip: !Stack.of(scope).bundlingRequired, ...props.bundling, }), handler: resolvedHandler, diff --git a/packages/@aws-cdk/aws-lambda-python/lib/layer.ts b/packages/@aws-cdk/aws-lambda-python/lib/layer.ts index d0b9bc6d0f529..516a221b588d8 100644 --- a/packages/@aws-cdk/aws-lambda-python/lib/layer.ts +++ b/packages/@aws-cdk/aws-lambda-python/lib/layer.ts @@ -1,5 +1,6 @@ import * as path from 'path'; import * as lambda from '@aws-cdk/aws-lambda'; +import { Stack } from '@aws-cdk/core'; import { Bundling } from './bundling'; import { BundlingOptions } from './types'; @@ -67,6 +68,7 @@ export class PythonLayerVersion extends lambda.LayerVersion { runtime, architecture, outputPathSuffix: 'python', + skip: !Stack.of(scope).bundlingRequired, ...props.bundling, }), }); diff --git a/packages/@aws-cdk/aws-lambda-python/package.json b/packages/@aws-cdk/aws-lambda-python/package.json index 1d4764316f4c9..74a9d8a8ffc0c 100644 --- a/packages/@aws-cdk/aws-lambda-python/package.json +++ b/packages/@aws-cdk/aws-lambda-python/package.json @@ -75,7 +75,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda-python/test/bundling.test.ts b/packages/@aws-cdk/aws-lambda-python/test/bundling.test.ts index a75ecc8625960..ca2142cce0667 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/bundling.test.ts +++ b/packages/@aws-cdk/aws-lambda-python/test/bundling.test.ts @@ -211,6 +211,7 @@ test('Bundling a function with custom bundling image', () => { }), })); + expect(DockerImage.fromBuild).toHaveBeenCalledTimes(1); expect(DockerImage.fromBuild).toHaveBeenCalledWith(expect.stringMatching(entry)); }); @@ -248,3 +249,25 @@ test('Bundling with custom environment vars`', () => { }), })); }); + +test('Do not build docker image when skipping bundling', () => { + const entry = path.join(__dirname, 'lambda-handler'); + Bundling.bundle({ + entry: entry, + runtime: Runtime.PYTHON_3_7, + skip: true, + }); + + expect(DockerImage.fromBuild).not.toHaveBeenCalled(); +}); + +test('Build docker image when bundling is not skipped', () => { + const entry = path.join(__dirname, 'lambda-handler'); + Bundling.bundle({ + entry: entry, + runtime: Runtime.PYTHON_3_7, + skip: false, + }); + + expect(DockerImage.fromBuild).toHaveBeenCalled(); +}); diff --git a/packages/@aws-cdk/aws-lambda-python/test/function.test.ts b/packages/@aws-cdk/aws-lambda-python/test/function.test.ts index 7eac6ad3df9ec..6fd12540b78c3 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/function.test.ts +++ b/packages/@aws-cdk/aws-lambda-python/test/function.test.ts @@ -167,3 +167,35 @@ test('Allows use of custom bundling image', () => { image, })); }); + +test('Skip bundling when stack does not require it', () => { + const spy = jest.spyOn(stack, 'bundlingRequired', 'get').mockReturnValue(false); + const entry = path.join(__dirname, 'lambda-handler'); + + new PythonFunction(stack, 'function', { + entry, + runtime: Runtime.PYTHON_3_8, + }); + + expect(Bundling.bundle).toHaveBeenCalledWith(expect.objectContaining({ + skip: true, + })); + + spy.mockRestore(); +}); + +test('Do not skip bundling when stack requires it', () => { + const spy = jest.spyOn(stack, 'bundlingRequired', 'get').mockReturnValue(true); + const entry = path.join(__dirname, 'lambda-handler'); + + new PythonFunction(stack, 'function', { + entry, + runtime: Runtime.PYTHON_3_8, + }); + + expect(Bundling.bundle).toHaveBeenCalledWith(expect.objectContaining({ + skip: false, + })); + + spy.mockRestore(); +}); diff --git a/packages/@aws-cdk/aws-lambda-python/test/integ.function.custom-build.expected.json b/packages/@aws-cdk/aws-lambda-python/test/integ.function.custom-build.expected.json index dd78e2d129e14..003dd758e7c8f 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/integ.function.custom-build.expected.json +++ b/packages/@aws-cdk/aws-lambda-python/test/integ.function.custom-build.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters623127c548bfba764c605bdc57770784dee3a4e8255ae2ad2590a2f5d42e7abfS3BucketE101E6F9" + "Ref": "AssetParameters89ca5c5b2234f7dbbadd142cad0414d3cdf1293dc1edfa1618f4eac392958c82S3BucketC9B359BB" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters623127c548bfba764c605bdc57770784dee3a4e8255ae2ad2590a2f5d42e7abfS3VersionKey08D4E5C6" + "Ref": "AssetParameters89ca5c5b2234f7dbbadd142cad0414d3cdf1293dc1edfa1618f4eac392958c82S3VersionKeyBF16F8DD" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters623127c548bfba764c605bdc57770784dee3a4e8255ae2ad2590a2f5d42e7abfS3VersionKey08D4E5C6" + "Ref": "AssetParameters89ca5c5b2234f7dbbadd142cad0414d3cdf1293dc1edfa1618f4eac392958c82S3VersionKeyBF16F8DD" } ] } @@ -87,17 +87,17 @@ } }, "Parameters": { - "AssetParameters623127c548bfba764c605bdc57770784dee3a4e8255ae2ad2590a2f5d42e7abfS3BucketE101E6F9": { + "AssetParameters89ca5c5b2234f7dbbadd142cad0414d3cdf1293dc1edfa1618f4eac392958c82S3BucketC9B359BB": { "Type": "String", - "Description": "S3 bucket for asset \"623127c548bfba764c605bdc57770784dee3a4e8255ae2ad2590a2f5d42e7abf\"" + "Description": "S3 bucket for asset \"89ca5c5b2234f7dbbadd142cad0414d3cdf1293dc1edfa1618f4eac392958c82\"" }, - "AssetParameters623127c548bfba764c605bdc57770784dee3a4e8255ae2ad2590a2f5d42e7abfS3VersionKey08D4E5C6": { + "AssetParameters89ca5c5b2234f7dbbadd142cad0414d3cdf1293dc1edfa1618f4eac392958c82S3VersionKeyBF16F8DD": { "Type": "String", - "Description": "S3 key for asset version \"623127c548bfba764c605bdc57770784dee3a4e8255ae2ad2590a2f5d42e7abf\"" + "Description": "S3 key for asset version \"89ca5c5b2234f7dbbadd142cad0414d3cdf1293dc1edfa1618f4eac392958c82\"" }, - "AssetParameters623127c548bfba764c605bdc57770784dee3a4e8255ae2ad2590a2f5d42e7abfArtifactHash2D0E1467": { + "AssetParameters89ca5c5b2234f7dbbadd142cad0414d3cdf1293dc1edfa1618f4eac392958c82ArtifactHashFF99ACF4": { "Type": "String", - "Description": "Artifact hash for asset \"623127c548bfba764c605bdc57770784dee3a4e8255ae2ad2590a2f5d42e7abf\"" + "Description": "Artifact hash for asset \"89ca5c5b2234f7dbbadd142cad0414d3cdf1293dc1edfa1618f4eac392958c82\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-python/test/integ.function.expected.json b/packages/@aws-cdk/aws-lambda-python/test/integ.function.expected.json index bf6248e87c68e..7f671e018e9ed 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/integ.function.expected.json +++ b/packages/@aws-cdk/aws-lambda-python/test/integ.function.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters13be70bc2398416ddd6c8e123f99becf43b8b1c3d00cad2447f9f75cea39d055S3Bucket4083148B" + "Ref": "AssetParameters94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573S3Bucket5DFF2A17" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters13be70bc2398416ddd6c8e123f99becf43b8b1c3d00cad2447f9f75cea39d055S3VersionKey32133DD4" + "Ref": "AssetParameters94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573S3VersionKey4E2330F4" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters13be70bc2398416ddd6c8e123f99becf43b8b1c3d00cad2447f9f75cea39d055S3VersionKey32133DD4" + "Ref": "AssetParameters94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573S3VersionKey4E2330F4" } ] } @@ -87,17 +87,17 @@ } }, "Parameters": { - "AssetParameters13be70bc2398416ddd6c8e123f99becf43b8b1c3d00cad2447f9f75cea39d055S3Bucket4083148B": { + "AssetParameters94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573S3Bucket5DFF2A17": { "Type": "String", - "Description": "S3 bucket for asset \"13be70bc2398416ddd6c8e123f99becf43b8b1c3d00cad2447f9f75cea39d055\"" + "Description": "S3 bucket for asset \"94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573\"" }, - "AssetParameters13be70bc2398416ddd6c8e123f99becf43b8b1c3d00cad2447f9f75cea39d055S3VersionKey32133DD4": { + "AssetParameters94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573S3VersionKey4E2330F4": { "Type": "String", - "Description": "S3 key for asset version \"13be70bc2398416ddd6c8e123f99becf43b8b1c3d00cad2447f9f75cea39d055\"" + "Description": "S3 key for asset version \"94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573\"" }, - "AssetParameters13be70bc2398416ddd6c8e123f99becf43b8b1c3d00cad2447f9f75cea39d055ArtifactHash83828A10": { + "AssetParameters94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573ArtifactHashA5E62729": { "Type": "String", - "Description": "Artifact hash for asset \"13be70bc2398416ddd6c8e123f99becf43b8b1c3d00cad2447f9f75cea39d055\"" + "Description": "Artifact hash for asset \"94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-python/test/integ.function.nodeps.expected.json b/packages/@aws-cdk/aws-lambda-python/test/integ.function.nodeps.expected.json index a12a5675b097f..6fc079bb0cadb 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/integ.function.nodeps.expected.json +++ b/packages/@aws-cdk/aws-lambda-python/test/integ.function.nodeps.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersadeacc0a6e55ff50a5243310913e886cc41725125e145a916ff3ec01369b2201S3BucketE6A02FFC" + "Ref": "AssetParameters3b772c6d8ae6957e4b380de3d18b02203a1d3eda5f37cb706ebb17cbcceb431aS3BucketAF45FF62" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersadeacc0a6e55ff50a5243310913e886cc41725125e145a916ff3ec01369b2201S3VersionKey78F64422" + "Ref": "AssetParameters3b772c6d8ae6957e4b380de3d18b02203a1d3eda5f37cb706ebb17cbcceb431aS3VersionKey4F7CFB4F" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersadeacc0a6e55ff50a5243310913e886cc41725125e145a916ff3ec01369b2201S3VersionKey78F64422" + "Ref": "AssetParameters3b772c6d8ae6957e4b380de3d18b02203a1d3eda5f37cb706ebb17cbcceb431aS3VersionKey4F7CFB4F" } ] } @@ -87,17 +87,17 @@ } }, "Parameters": { - "AssetParametersadeacc0a6e55ff50a5243310913e886cc41725125e145a916ff3ec01369b2201S3BucketE6A02FFC": { + "AssetParameters3b772c6d8ae6957e4b380de3d18b02203a1d3eda5f37cb706ebb17cbcceb431aS3BucketAF45FF62": { "Type": "String", - "Description": "S3 bucket for asset \"adeacc0a6e55ff50a5243310913e886cc41725125e145a916ff3ec01369b2201\"" + "Description": "S3 bucket for asset \"3b772c6d8ae6957e4b380de3d18b02203a1d3eda5f37cb706ebb17cbcceb431a\"" }, - "AssetParametersadeacc0a6e55ff50a5243310913e886cc41725125e145a916ff3ec01369b2201S3VersionKey78F64422": { + "AssetParameters3b772c6d8ae6957e4b380de3d18b02203a1d3eda5f37cb706ebb17cbcceb431aS3VersionKey4F7CFB4F": { "Type": "String", - "Description": "S3 key for asset version \"adeacc0a6e55ff50a5243310913e886cc41725125e145a916ff3ec01369b2201\"" + "Description": "S3 key for asset version \"3b772c6d8ae6957e4b380de3d18b02203a1d3eda5f37cb706ebb17cbcceb431a\"" }, - "AssetParametersadeacc0a6e55ff50a5243310913e886cc41725125e145a916ff3ec01369b2201ArtifactHash5EE39E2F": { + "AssetParameters3b772c6d8ae6957e4b380de3d18b02203a1d3eda5f37cb706ebb17cbcceb431aArtifactHash904EF538": { "Type": "String", - "Description": "Artifact hash for asset \"adeacc0a6e55ff50a5243310913e886cc41725125e145a916ff3ec01369b2201\"" + "Description": "Artifact hash for asset \"3b772c6d8ae6957e4b380de3d18b02203a1d3eda5f37cb706ebb17cbcceb431a\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-python/test/integ.function.pipenv.expected.json b/packages/@aws-cdk/aws-lambda-python/test/integ.function.pipenv.expected.json index 80d1579481795..3565c8f0d26c2 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/integ.function.pipenv.expected.json +++ b/packages/@aws-cdk/aws-lambda-python/test/integ.function.pipenv.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersc850e159fa69da9edb39ca17a495c47ca137fb5ea2119efb9b01468b0a4934a2S3BucketC982114B" + "Ref": "AssetParameters684a2f752f67fdc04a3b76308d5a71acb60a190f24b6dc1e5899167f6f32ce9fS3Bucket53FFD3D0" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersc850e159fa69da9edb39ca17a495c47ca137fb5ea2119efb9b01468b0a4934a2S3VersionKey6D9FF4C1" + "Ref": "AssetParameters684a2f752f67fdc04a3b76308d5a71acb60a190f24b6dc1e5899167f6f32ce9fS3VersionKey7A7468A3" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersc850e159fa69da9edb39ca17a495c47ca137fb5ea2119efb9b01468b0a4934a2S3VersionKey6D9FF4C1" + "Ref": "AssetParameters684a2f752f67fdc04a3b76308d5a71acb60a190f24b6dc1e5899167f6f32ce9fS3VersionKey7A7468A3" } ] } @@ -121,7 +121,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersebc380ae5f94c7b58c30d780f064bc980ad95d026b4e753349d00efc56f40427S3Bucket42FB475E" + "Ref": "AssetParameters069324dd6f747a462fc08bc2701fa4e72d5776318b3bf4f27bcdb08b937e77f0S3Bucket714A0D7D" }, "S3Key": { "Fn::Join": [ @@ -134,7 +134,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersebc380ae5f94c7b58c30d780f064bc980ad95d026b4e753349d00efc56f40427S3VersionKeyFFD26447" + "Ref": "AssetParameters069324dd6f747a462fc08bc2701fa4e72d5776318b3bf4f27bcdb08b937e77f0S3VersionKey53ECA362" } ] } @@ -147,7 +147,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersebc380ae5f94c7b58c30d780f064bc980ad95d026b4e753349d00efc56f40427S3VersionKeyFFD26447" + "Ref": "AssetParameters069324dd6f747a462fc08bc2701fa4e72d5776318b3bf4f27bcdb08b937e77f0S3VersionKey53ECA362" } ] } @@ -172,29 +172,29 @@ } }, "Parameters": { - "AssetParametersc850e159fa69da9edb39ca17a495c47ca137fb5ea2119efb9b01468b0a4934a2S3BucketC982114B": { + "AssetParameters684a2f752f67fdc04a3b76308d5a71acb60a190f24b6dc1e5899167f6f32ce9fS3Bucket53FFD3D0": { "Type": "String", - "Description": "S3 bucket for asset \"c850e159fa69da9edb39ca17a495c47ca137fb5ea2119efb9b01468b0a4934a2\"" + "Description": "S3 bucket for asset \"684a2f752f67fdc04a3b76308d5a71acb60a190f24b6dc1e5899167f6f32ce9f\"" }, - "AssetParametersc850e159fa69da9edb39ca17a495c47ca137fb5ea2119efb9b01468b0a4934a2S3VersionKey6D9FF4C1": { + "AssetParameters684a2f752f67fdc04a3b76308d5a71acb60a190f24b6dc1e5899167f6f32ce9fS3VersionKey7A7468A3": { "Type": "String", - "Description": "S3 key for asset version \"c850e159fa69da9edb39ca17a495c47ca137fb5ea2119efb9b01468b0a4934a2\"" + "Description": "S3 key for asset version \"684a2f752f67fdc04a3b76308d5a71acb60a190f24b6dc1e5899167f6f32ce9f\"" }, - "AssetParametersc850e159fa69da9edb39ca17a495c47ca137fb5ea2119efb9b01468b0a4934a2ArtifactHash27EECEC5": { + "AssetParameters684a2f752f67fdc04a3b76308d5a71acb60a190f24b6dc1e5899167f6f32ce9fArtifactHash18F2A416": { "Type": "String", - "Description": "Artifact hash for asset \"c850e159fa69da9edb39ca17a495c47ca137fb5ea2119efb9b01468b0a4934a2\"" + "Description": "Artifact hash for asset \"684a2f752f67fdc04a3b76308d5a71acb60a190f24b6dc1e5899167f6f32ce9f\"" }, - "AssetParametersebc380ae5f94c7b58c30d780f064bc980ad95d026b4e753349d00efc56f40427S3Bucket42FB475E": { + "AssetParameters069324dd6f747a462fc08bc2701fa4e72d5776318b3bf4f27bcdb08b937e77f0S3Bucket714A0D7D": { "Type": "String", - "Description": "S3 bucket for asset \"ebc380ae5f94c7b58c30d780f064bc980ad95d026b4e753349d00efc56f40427\"" + "Description": "S3 bucket for asset \"069324dd6f747a462fc08bc2701fa4e72d5776318b3bf4f27bcdb08b937e77f0\"" }, - "AssetParametersebc380ae5f94c7b58c30d780f064bc980ad95d026b4e753349d00efc56f40427S3VersionKeyFFD26447": { + "AssetParameters069324dd6f747a462fc08bc2701fa4e72d5776318b3bf4f27bcdb08b937e77f0S3VersionKey53ECA362": { "Type": "String", - "Description": "S3 key for asset version \"ebc380ae5f94c7b58c30d780f064bc980ad95d026b4e753349d00efc56f40427\"" + "Description": "S3 key for asset version \"069324dd6f747a462fc08bc2701fa4e72d5776318b3bf4f27bcdb08b937e77f0\"" }, - "AssetParametersebc380ae5f94c7b58c30d780f064bc980ad95d026b4e753349d00efc56f40427ArtifactHashCC6CC552": { + "AssetParameters069324dd6f747a462fc08bc2701fa4e72d5776318b3bf4f27bcdb08b937e77f0ArtifactHashA527F411": { "Type": "String", - "Description": "Artifact hash for asset \"ebc380ae5f94c7b58c30d780f064bc980ad95d026b4e753349d00efc56f40427\"" + "Description": "Artifact hash for asset \"069324dd6f747a462fc08bc2701fa4e72d5776318b3bf4f27bcdb08b937e77f0\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-python/test/integ.function.poetry.expected.json b/packages/@aws-cdk/aws-lambda-python/test/integ.function.poetry.expected.json index 868afeba6ff43..bbae8112b1807 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/integ.function.poetry.expected.json +++ b/packages/@aws-cdk/aws-lambda-python/test/integ.function.poetry.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersab7f43c80b3b659f320744f583b7bfda3605f7018c253ab2e7615cfb667cb0daS3Bucket142AE375" + "Ref": "AssetParametersb56cede4ec5df8a7b7eac0b708729b7bd41299f732fd0d287c6ac64c12626f91S3Bucket057A8A40" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersab7f43c80b3b659f320744f583b7bfda3605f7018c253ab2e7615cfb667cb0daS3VersionKeyDC1A62D5" + "Ref": "AssetParametersb56cede4ec5df8a7b7eac0b708729b7bd41299f732fd0d287c6ac64c12626f91S3VersionKey0AF7333B" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersab7f43c80b3b659f320744f583b7bfda3605f7018c253ab2e7615cfb667cb0daS3VersionKeyDC1A62D5" + "Ref": "AssetParametersb56cede4ec5df8a7b7eac0b708729b7bd41299f732fd0d287c6ac64c12626f91S3VersionKey0AF7333B" } ] } @@ -121,7 +121,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters67452e07162ae977faecaa7c71cf523f4442341f285bd53f84089624ce7fff1dS3BucketB5B7A82F" + "Ref": "AssetParametersc6ffa1649951c75afc6c302e13c762f94b8f8958c48d7cf0a0712ce381be73b2S3Bucket1B953860" }, "S3Key": { "Fn::Join": [ @@ -134,7 +134,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters67452e07162ae977faecaa7c71cf523f4442341f285bd53f84089624ce7fff1dS3VersionKey06225DD1" + "Ref": "AssetParametersc6ffa1649951c75afc6c302e13c762f94b8f8958c48d7cf0a0712ce381be73b2S3VersionKey21C3F64D" } ] } @@ -147,7 +147,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters67452e07162ae977faecaa7c71cf523f4442341f285bd53f84089624ce7fff1dS3VersionKey06225DD1" + "Ref": "AssetParametersc6ffa1649951c75afc6c302e13c762f94b8f8958c48d7cf0a0712ce381be73b2S3VersionKey21C3F64D" } ] } @@ -172,29 +172,29 @@ } }, "Parameters": { - "AssetParametersab7f43c80b3b659f320744f583b7bfda3605f7018c253ab2e7615cfb667cb0daS3Bucket142AE375": { + "AssetParametersb56cede4ec5df8a7b7eac0b708729b7bd41299f732fd0d287c6ac64c12626f91S3Bucket057A8A40": { "Type": "String", - "Description": "S3 bucket for asset \"ab7f43c80b3b659f320744f583b7bfda3605f7018c253ab2e7615cfb667cb0da\"" + "Description": "S3 bucket for asset \"b56cede4ec5df8a7b7eac0b708729b7bd41299f732fd0d287c6ac64c12626f91\"" }, - "AssetParametersab7f43c80b3b659f320744f583b7bfda3605f7018c253ab2e7615cfb667cb0daS3VersionKeyDC1A62D5": { + "AssetParametersb56cede4ec5df8a7b7eac0b708729b7bd41299f732fd0d287c6ac64c12626f91S3VersionKey0AF7333B": { "Type": "String", - "Description": "S3 key for asset version \"ab7f43c80b3b659f320744f583b7bfda3605f7018c253ab2e7615cfb667cb0da\"" + "Description": "S3 key for asset version \"b56cede4ec5df8a7b7eac0b708729b7bd41299f732fd0d287c6ac64c12626f91\"" }, - "AssetParametersab7f43c80b3b659f320744f583b7bfda3605f7018c253ab2e7615cfb667cb0daArtifactHash0EF1F0C3": { + "AssetParametersb56cede4ec5df8a7b7eac0b708729b7bd41299f732fd0d287c6ac64c12626f91ArtifactHash5E36A98B": { "Type": "String", - "Description": "Artifact hash for asset \"ab7f43c80b3b659f320744f583b7bfda3605f7018c253ab2e7615cfb667cb0da\"" + "Description": "Artifact hash for asset \"b56cede4ec5df8a7b7eac0b708729b7bd41299f732fd0d287c6ac64c12626f91\"" }, - "AssetParameters67452e07162ae977faecaa7c71cf523f4442341f285bd53f84089624ce7fff1dS3BucketB5B7A82F": { + "AssetParametersc6ffa1649951c75afc6c302e13c762f94b8f8958c48d7cf0a0712ce381be73b2S3Bucket1B953860": { "Type": "String", - "Description": "S3 bucket for asset \"67452e07162ae977faecaa7c71cf523f4442341f285bd53f84089624ce7fff1d\"" + "Description": "S3 bucket for asset \"c6ffa1649951c75afc6c302e13c762f94b8f8958c48d7cf0a0712ce381be73b2\"" }, - "AssetParameters67452e07162ae977faecaa7c71cf523f4442341f285bd53f84089624ce7fff1dS3VersionKey06225DD1": { + "AssetParametersc6ffa1649951c75afc6c302e13c762f94b8f8958c48d7cf0a0712ce381be73b2S3VersionKey21C3F64D": { "Type": "String", - "Description": "S3 key for asset version \"67452e07162ae977faecaa7c71cf523f4442341f285bd53f84089624ce7fff1d\"" + "Description": "S3 key for asset version \"c6ffa1649951c75afc6c302e13c762f94b8f8958c48d7cf0a0712ce381be73b2\"" }, - "AssetParameters67452e07162ae977faecaa7c71cf523f4442341f285bd53f84089624ce7fff1dArtifactHash253A552F": { + "AssetParametersc6ffa1649951c75afc6c302e13c762f94b8f8958c48d7cf0a0712ce381be73b2ArtifactHash267CE95E": { "Type": "String", - "Description": "Artifact hash for asset \"67452e07162ae977faecaa7c71cf523f4442341f285bd53f84089624ce7fff1d\"" + "Description": "Artifact hash for asset \"c6ffa1649951c75afc6c302e13c762f94b8f8958c48d7cf0a0712ce381be73b2\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-python/test/integ.function.project.expected.json b/packages/@aws-cdk/aws-lambda-python/test/integ.function.project.expected.json index 0f96e29246a70..faace5659fe2d 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/integ.function.project.expected.json +++ b/packages/@aws-cdk/aws-lambda-python/test/integ.function.project.expected.json @@ -5,7 +5,7 @@ "Properties": { "Content": { "S3Bucket": { - "Ref": "AssetParameters1f7d3c2f23a4820c4d01a0bce4add499802732068e570fb63c9f9ae0c2011949S3BucketE93E5D2C" + "Ref": "AssetParameters51a124c454095f3106d92ba6c988cda953780ef31f562c86bd4ca693a7fdf724S3BucketDA99AAC5" }, "S3Key": { "Fn::Join": [ @@ -18,7 +18,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters1f7d3c2f23a4820c4d01a0bce4add499802732068e570fb63c9f9ae0c2011949S3VersionKey13A824E8" + "Ref": "AssetParameters51a124c454095f3106d92ba6c988cda953780ef31f562c86bd4ca693a7fdf724S3VersionKey561281CF" } ] } @@ -31,7 +31,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters1f7d3c2f23a4820c4d01a0bce4add499802732068e570fb63c9f9ae0c2011949S3VersionKey13A824E8" + "Ref": "AssetParameters51a124c454095f3106d92ba6c988cda953780ef31f562c86bd4ca693a7fdf724S3VersionKey561281CF" } ] } @@ -82,7 +82,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters3164004f2e76531b3631d1b70c1bee3da1439011bf712a91211b8721868da676S3Bucket9F42D72A" + "Ref": "AssetParametersc5c2604faa927103df13d5a72632c7be09d3fc34b6b31039a6acec9acf0f9116S3BucketD74EF551" }, "S3Key": { "Fn::Join": [ @@ -95,7 +95,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters3164004f2e76531b3631d1b70c1bee3da1439011bf712a91211b8721868da676S3VersionKey37C5ED38" + "Ref": "AssetParametersc5c2604faa927103df13d5a72632c7be09d3fc34b6b31039a6acec9acf0f9116S3VersionKey9612D0E2" } ] } @@ -108,7 +108,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters3164004f2e76531b3631d1b70c1bee3da1439011bf712a91211b8721868da676S3VersionKey37C5ED38" + "Ref": "AssetParametersc5c2604faa927103df13d5a72632c7be09d3fc34b6b31039a6acec9acf0f9116S3VersionKey9612D0E2" } ] } @@ -138,29 +138,29 @@ } }, "Parameters": { - "AssetParameters1f7d3c2f23a4820c4d01a0bce4add499802732068e570fb63c9f9ae0c2011949S3BucketE93E5D2C": { + "AssetParameters51a124c454095f3106d92ba6c988cda953780ef31f562c86bd4ca693a7fdf724S3BucketDA99AAC5": { "Type": "String", - "Description": "S3 bucket for asset \"1f7d3c2f23a4820c4d01a0bce4add499802732068e570fb63c9f9ae0c2011949\"" + "Description": "S3 bucket for asset \"51a124c454095f3106d92ba6c988cda953780ef31f562c86bd4ca693a7fdf724\"" }, - "AssetParameters1f7d3c2f23a4820c4d01a0bce4add499802732068e570fb63c9f9ae0c2011949S3VersionKey13A824E8": { + "AssetParameters51a124c454095f3106d92ba6c988cda953780ef31f562c86bd4ca693a7fdf724S3VersionKey561281CF": { "Type": "String", - "Description": "S3 key for asset version \"1f7d3c2f23a4820c4d01a0bce4add499802732068e570fb63c9f9ae0c2011949\"" + "Description": "S3 key for asset version \"51a124c454095f3106d92ba6c988cda953780ef31f562c86bd4ca693a7fdf724\"" }, - "AssetParameters1f7d3c2f23a4820c4d01a0bce4add499802732068e570fb63c9f9ae0c2011949ArtifactHashD6269488": { + "AssetParameters51a124c454095f3106d92ba6c988cda953780ef31f562c86bd4ca693a7fdf724ArtifactHash2CDEA207": { "Type": "String", - "Description": "Artifact hash for asset \"1f7d3c2f23a4820c4d01a0bce4add499802732068e570fb63c9f9ae0c2011949\"" + "Description": "Artifact hash for asset \"51a124c454095f3106d92ba6c988cda953780ef31f562c86bd4ca693a7fdf724\"" }, - "AssetParameters3164004f2e76531b3631d1b70c1bee3da1439011bf712a91211b8721868da676S3Bucket9F42D72A": { + "AssetParametersc5c2604faa927103df13d5a72632c7be09d3fc34b6b31039a6acec9acf0f9116S3BucketD74EF551": { "Type": "String", - "Description": "S3 bucket for asset \"3164004f2e76531b3631d1b70c1bee3da1439011bf712a91211b8721868da676\"" + "Description": "S3 bucket for asset \"c5c2604faa927103df13d5a72632c7be09d3fc34b6b31039a6acec9acf0f9116\"" }, - "AssetParameters3164004f2e76531b3631d1b70c1bee3da1439011bf712a91211b8721868da676S3VersionKey37C5ED38": { + "AssetParametersc5c2604faa927103df13d5a72632c7be09d3fc34b6b31039a6acec9acf0f9116S3VersionKey9612D0E2": { "Type": "String", - "Description": "S3 key for asset version \"3164004f2e76531b3631d1b70c1bee3da1439011bf712a91211b8721868da676\"" + "Description": "S3 key for asset version \"c5c2604faa927103df13d5a72632c7be09d3fc34b6b31039a6acec9acf0f9116\"" }, - "AssetParameters3164004f2e76531b3631d1b70c1bee3da1439011bf712a91211b8721868da676ArtifactHash74C7DB3B": { + "AssetParametersc5c2604faa927103df13d5a72632c7be09d3fc34b6b31039a6acec9acf0f9116ArtifactHash1E0614B3": { "Type": "String", - "Description": "Artifact hash for asset \"3164004f2e76531b3631d1b70c1bee3da1439011bf712a91211b8721868da676\"" + "Description": "Artifact hash for asset \"c5c2604faa927103df13d5a72632c7be09d3fc34b6b31039a6acec9acf0f9116\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-python/test/integ.function.py38.expected.json b/packages/@aws-cdk/aws-lambda-python/test/integ.function.py38.expected.json index 8c028fc0afac0..8a264a6ca2058 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/integ.function.py38.expected.json +++ b/packages/@aws-cdk/aws-lambda-python/test/integ.function.py38.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters9004e881069342d6cd7cc95689e1c51eb68f9f5d8c0bdfb0c2c52d9aa301d1d6S3Bucket8DE4578D" + "Ref": "AssetParameters5e6412615f95ab4d20cbc13454e0603afb26be2b12bdd954c21a3bca6cbc6e57S3Bucket5AE0410B" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters9004e881069342d6cd7cc95689e1c51eb68f9f5d8c0bdfb0c2c52d9aa301d1d6S3VersionKey86A8985D" + "Ref": "AssetParameters5e6412615f95ab4d20cbc13454e0603afb26be2b12bdd954c21a3bca6cbc6e57S3VersionKey68880DE9" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters9004e881069342d6cd7cc95689e1c51eb68f9f5d8c0bdfb0c2c52d9aa301d1d6S3VersionKey86A8985D" + "Ref": "AssetParameters5e6412615f95ab4d20cbc13454e0603afb26be2b12bdd954c21a3bca6cbc6e57S3VersionKey68880DE9" } ] } @@ -87,17 +87,17 @@ } }, "Parameters": { - "AssetParameters9004e881069342d6cd7cc95689e1c51eb68f9f5d8c0bdfb0c2c52d9aa301d1d6S3Bucket8DE4578D": { + "AssetParameters5e6412615f95ab4d20cbc13454e0603afb26be2b12bdd954c21a3bca6cbc6e57S3Bucket5AE0410B": { "Type": "String", - "Description": "S3 bucket for asset \"9004e881069342d6cd7cc95689e1c51eb68f9f5d8c0bdfb0c2c52d9aa301d1d6\"" + "Description": "S3 bucket for asset \"5e6412615f95ab4d20cbc13454e0603afb26be2b12bdd954c21a3bca6cbc6e57\"" }, - "AssetParameters9004e881069342d6cd7cc95689e1c51eb68f9f5d8c0bdfb0c2c52d9aa301d1d6S3VersionKey86A8985D": { + "AssetParameters5e6412615f95ab4d20cbc13454e0603afb26be2b12bdd954c21a3bca6cbc6e57S3VersionKey68880DE9": { "Type": "String", - "Description": "S3 key for asset version \"9004e881069342d6cd7cc95689e1c51eb68f9f5d8c0bdfb0c2c52d9aa301d1d6\"" + "Description": "S3 key for asset version \"5e6412615f95ab4d20cbc13454e0603afb26be2b12bdd954c21a3bca6cbc6e57\"" }, - "AssetParameters9004e881069342d6cd7cc95689e1c51eb68f9f5d8c0bdfb0c2c52d9aa301d1d6ArtifactHash4E095FCC": { + "AssetParameters5e6412615f95ab4d20cbc13454e0603afb26be2b12bdd954c21a3bca6cbc6e57ArtifactHashD00E469F": { "Type": "String", - "Description": "Artifact hash for asset \"9004e881069342d6cd7cc95689e1c51eb68f9f5d8c0bdfb0c2c52d9aa301d1d6\"" + "Description": "Artifact hash for asset \"5e6412615f95ab4d20cbc13454e0603afb26be2b12bdd954c21a3bca6cbc6e57\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-python/test/integ.function.sub.expected.json b/packages/@aws-cdk/aws-lambda-python/test/integ.function.sub.expected.json index fb29f895b492e..e76e7cfb14392 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/integ.function.sub.expected.json +++ b/packages/@aws-cdk/aws-lambda-python/test/integ.function.sub.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersccd39730103b259d263418443f3d426e109312f1f147710e2e5fffc2150b8647S3Bucket11B30F21" + "Ref": "AssetParameters4427066e616276cb27bb4011d3a6a474a4e5ffb67c01234137177c6c5e44b1d0S3Bucket89FCC833" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersccd39730103b259d263418443f3d426e109312f1f147710e2e5fffc2150b8647S3VersionKey1D9AFDF5" + "Ref": "AssetParameters4427066e616276cb27bb4011d3a6a474a4e5ffb67c01234137177c6c5e44b1d0S3VersionKey3090BAB2" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersccd39730103b259d263418443f3d426e109312f1f147710e2e5fffc2150b8647S3VersionKey1D9AFDF5" + "Ref": "AssetParameters4427066e616276cb27bb4011d3a6a474a4e5ffb67c01234137177c6c5e44b1d0S3VersionKey3090BAB2" } ] } @@ -87,17 +87,17 @@ } }, "Parameters": { - "AssetParametersccd39730103b259d263418443f3d426e109312f1f147710e2e5fffc2150b8647S3Bucket11B30F21": { + "AssetParameters4427066e616276cb27bb4011d3a6a474a4e5ffb67c01234137177c6c5e44b1d0S3Bucket89FCC833": { "Type": "String", - "Description": "S3 bucket for asset \"ccd39730103b259d263418443f3d426e109312f1f147710e2e5fffc2150b8647\"" + "Description": "S3 bucket for asset \"4427066e616276cb27bb4011d3a6a474a4e5ffb67c01234137177c6c5e44b1d0\"" }, - "AssetParametersccd39730103b259d263418443f3d426e109312f1f147710e2e5fffc2150b8647S3VersionKey1D9AFDF5": { + "AssetParameters4427066e616276cb27bb4011d3a6a474a4e5ffb67c01234137177c6c5e44b1d0S3VersionKey3090BAB2": { "Type": "String", - "Description": "S3 key for asset version \"ccd39730103b259d263418443f3d426e109312f1f147710e2e5fffc2150b8647\"" + "Description": "S3 key for asset version \"4427066e616276cb27bb4011d3a6a474a4e5ffb67c01234137177c6c5e44b1d0\"" }, - "AssetParametersccd39730103b259d263418443f3d426e109312f1f147710e2e5fffc2150b8647ArtifactHash997AD273": { + "AssetParameters4427066e616276cb27bb4011d3a6a474a4e5ffb67c01234137177c6c5e44b1d0ArtifactHash862641FA": { "Type": "String", - "Description": "Artifact hash for asset \"ccd39730103b259d263418443f3d426e109312f1f147710e2e5fffc2150b8647\"" + "Description": "Artifact hash for asset \"4427066e616276cb27bb4011d3a6a474a4e5ffb67c01234137177c6c5e44b1d0\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-python/test/integ.function.vpc.expected.json b/packages/@aws-cdk/aws-lambda-python/test/integ.function.vpc.expected.json index fb5aafb8c9c75..23cf7919d5dd1 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/integ.function.vpc.expected.json +++ b/packages/@aws-cdk/aws-lambda-python/test/integ.function.vpc.expected.json @@ -296,7 +296,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters28ffbbca5292e933d802ff7c495367b0d7fddab6f52a3777f67a52f14efc6b38S3BucketF4C94740" + "Ref": "AssetParameters94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573S3Bucket5DFF2A17" }, "S3Key": { "Fn::Join": [ @@ -309,7 +309,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters28ffbbca5292e933d802ff7c495367b0d7fddab6f52a3777f67a52f14efc6b38S3VersionKey584C9092" + "Ref": "AssetParameters94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573S3VersionKey4E2330F4" } ] } @@ -322,7 +322,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters28ffbbca5292e933d802ff7c495367b0d7fddab6f52a3777f67a52f14efc6b38S3VersionKey584C9092" + "Ref": "AssetParameters94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573S3VersionKey4E2330F4" } ] } @@ -368,17 +368,17 @@ } }, "Parameters": { - "AssetParameters28ffbbca5292e933d802ff7c495367b0d7fddab6f52a3777f67a52f14efc6b38S3BucketF4C94740": { + "AssetParameters94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573S3Bucket5DFF2A17": { "Type": "String", - "Description": "S3 bucket for asset \"28ffbbca5292e933d802ff7c495367b0d7fddab6f52a3777f67a52f14efc6b38\"" + "Description": "S3 bucket for asset \"94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573\"" }, - "AssetParameters28ffbbca5292e933d802ff7c495367b0d7fddab6f52a3777f67a52f14efc6b38S3VersionKey584C9092": { + "AssetParameters94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573S3VersionKey4E2330F4": { "Type": "String", - "Description": "S3 key for asset version \"28ffbbca5292e933d802ff7c495367b0d7fddab6f52a3777f67a52f14efc6b38\"" + "Description": "S3 key for asset version \"94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573\"" }, - "AssetParameters28ffbbca5292e933d802ff7c495367b0d7fddab6f52a3777f67a52f14efc6b38ArtifactHashC0B5BADB": { + "AssetParameters94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573ArtifactHashA5E62729": { "Type": "String", - "Description": "Artifact hash for asset \"28ffbbca5292e933d802ff7c495367b0d7fddab6f52a3777f67a52f14efc6b38\"" + "Description": "Artifact hash for asset \"94754b2f276800442d199c45b0bf611b9ed8b4d1f6d2acdf6bf5cbeed6176573\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-python/test/layer.test.ts b/packages/@aws-cdk/aws-lambda-python/test/layer.test.ts index a254e82d48af6..eb12017072030 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/layer.test.ts +++ b/packages/@aws-cdk/aws-lambda-python/test/layer.test.ts @@ -63,3 +63,33 @@ test('Allows use of custom bundling image', () => { image, })); }); + +test('Skip bundling when stack does not require it', () => { + const spy = jest.spyOn(stack, 'bundlingRequired', 'get').mockReturnValue(false); + const entry = path.join(__dirname, 'lambda-handler-project'); + + new PythonLayerVersion(stack, 'layer', { + entry, + }); + + expect(Bundling.bundle).toHaveBeenCalledWith(expect.objectContaining({ + skip: true, + })); + + spy.mockRestore(); +}); + +test('Do not skip bundling when stack requires it', () => { + const spy = jest.spyOn(stack, 'bundlingRequired', 'get').mockReturnValue(true); + const entry = path.join(__dirname, 'lambda-handler-project'); + + new PythonLayerVersion(stack, 'layer', { + entry, + }); + + expect(Bundling.bundle).toHaveBeenCalledWith(expect.objectContaining({ + skip: false, + })); + + spy.mockRestore(); +}); diff --git a/packages/@aws-cdk/aws-lambda/README.md b/packages/@aws-cdk/aws-lambda/README.md index f6c95dfe0d68f..9c9182b174550 100644 --- a/packages/@aws-cdk/aws-lambda/README.md +++ b/packages/@aws-cdk/aws-lambda/README.md @@ -480,10 +480,48 @@ fn.addEventSource(new eventsources.S3EventSource(bucket, { See the documentation for the __@aws-cdk/aws-lambda-event-sources__ module for more details. +## Imported Lambdas + +When referencing an imported lambda in the CDK, use `fromFunctionArn()` for most use cases: + +```ts +const fn = lambda.Function.fromFunctionArn( + this, + 'Function', + 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', +); +``` + +The `fromFunctionAttributes()` API is available for more specific use cases: + +```ts +const fn = lambda.Function.fromFunctionAttributes(this, 'Function', { + functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', + // The following are optional properties for specific use cases and should be used with caution: + + // Use Case: imported function is in the same account as the stack. This tells the CDK that it + // can modify the function's permissions. + sameEnvironment: true, + + // Use Case: imported function is in a different account and user commits to ensuring that the + // imported function has the correct permissions outside the CDK. + skipPermissions: true, +}); +``` + +If `fromFunctionArn()` causes an error related to having to provide an account and/or region in a different construct, +and the lambda is in the same account and region as the stack you're importing it into, +you can use `Function.fromFunctionName()` instead: + +```ts +const fn = lambda.Function.fromFunctionName(this, 'Function', 'MyFn'); +``` + ## Lambda with DLQ A dead-letter queue can be automatically created for a Lambda function by -setting the `deadLetterQueueEnabled: true` configuration. +setting the `deadLetterQueueEnabled: true` configuration. In such case CDK creates +a `sqs.Queue` as `deadLetterQueue`. ```ts const fn = new lambda.Function(this, 'MyFunction', { @@ -508,6 +546,20 @@ const fn = new lambda.Function(this, 'MyFunction', { }); ``` +You can also use a `sns.Topic` instead of an `sqs.Queue` as dead-letter queue: + +```ts +import * as sns from '@aws-cdk/aws-sns'; + +const dlt = new sns.Topic(this, 'DLQ'); +const fn = new lambda.Function(this, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + code: lambda.Code.fromInline('// your code here'), + deadLetterTopic: dlt, +}); +``` + See [the AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/dlq.html) to learn more about AWS Lambdas and DLQs. diff --git a/packages/@aws-cdk/aws-lambda/lib/alias.ts b/packages/@aws-cdk/aws-lambda/lib/alias.ts index 36fdbdfcc2eaf..be92b4a3dde8f 100644 --- a/packages/@aws-cdk/aws-lambda/lib/alias.ts +++ b/packages/@aws-cdk/aws-lambda/lib/alias.ts @@ -75,7 +75,7 @@ export interface AliasProps extends AliasOptions { /** * Function version this alias refers to * - * Use lambda.addVersion() to obtain a new lambda version to refer to. + * Use lambda.currentVersion to reference a version with your latest changes. */ readonly version: IVersion; } diff --git a/packages/@aws-cdk/aws-lambda/lib/event-source-mapping.ts b/packages/@aws-cdk/aws-lambda/lib/event-source-mapping.ts index 172d681d1fef9..7840a465b87b2 100644 --- a/packages/@aws-cdk/aws-lambda/lib/event-source-mapping.ts +++ b/packages/@aws-cdk/aws-lambda/lib/event-source-mapping.ts @@ -91,7 +91,7 @@ export interface EventSourceMappingOptions { * Valid Range: Minimum value of 1. Maximum value of 10000. * * @default - Amazon Kinesis, Amazon DynamoDB, and Amazon MSK is 100 records. - * Both the default and maximum for Amazon SQS are 10 messages. + * The default for Amazon SQS is 10 messages. For standard SQS queues, the maximum is 10,000. For FIFO SQS queues, the maximum is 10. */ readonly batchSize?: number; diff --git a/packages/@aws-cdk/aws-lambda/lib/function-base.ts b/packages/@aws-cdk/aws-lambda/lib/function-base.ts index 1256383c471bd..a4c8b73b46a9a 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function-base.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function-base.ts @@ -62,6 +62,14 @@ export interface IFunction extends IResource, ec2.IConnectable, iam.IGrantable { */ readonly architecture: Architecture; + /** + * The ARN(s) to put into the resource field of the generated IAM policy for grantInvoke(). + * + * This property is for cdk modules to consume only. You should not need to use this property. + * Instead, use grantInvoke() directly. + */ + readonly resourceArnsForGrantInvoke: string[]; + /** * Adds an event source that maps to this AWS Lambda function. * @param id construct ID @@ -180,6 +188,20 @@ export interface FunctionAttributes { */ readonly sameEnvironment?: boolean; + /** + * Setting this property informs the CDK that the imported function ALREADY HAS the necessary permissions + * for what you are trying to do. When not configured, the CDK attempts to auto-determine whether or not + * additional permissions are necessary on the function when grant APIs are used. If the CDK tried to add + * permissions on an imported lambda, it will fail. + * + * Set this property *ONLY IF* you are committing to manage the imported function's permissions outside of + * CDK. You are acknowledging that your CDK code alone will have insufficient permissions to access the + * imported function. + * + * @default false + */ + readonly skipPermissions?: boolean; + /** * The architecture of this Lambda Function (this is an optional attribute and defaults to X86_64). * @default - Architecture.X86_64 @@ -228,6 +250,20 @@ export abstract class FunctionBase extends Resource implements IFunction, ec2.IC */ protected abstract readonly canCreatePermissions: boolean; + /** + * The ARN(s) to put into the resource field of the generated IAM policy for grantInvoke() + */ + public abstract readonly resourceArnsForGrantInvoke: string[]; + + /** + * Whether the user decides to skip adding permissions. + * The only use case is for cross-account, imported lambdas + * where the user commits to modifying the permisssions + * on the imported lambda outside CDK. + * @internal + */ + protected readonly _skipPermissions?: boolean; + /** * Actual connections object for this Lambda * @@ -329,7 +365,7 @@ export abstract class FunctionBase extends Resource implements IFunction, ec2.IC grant = iam.Grant.addToPrincipalOrResource({ grantee, actions: ['lambda:InvokeFunction'], - resourceArns: [this.functionArn], + resourceArns: this.resourceArnsForGrantInvoke, // Fake resource-like object on which to call addToResourcePolicy(), which actually // calls addPermission() @@ -342,9 +378,10 @@ export abstract class FunctionBase extends Resource implements IFunction, ec2.IC }); const permissionNode = this._functionNode().tryFindChild(identifier); - if (!permissionNode) { - throw new Error('Cannot modify permission to lambda function. Function is either imported or $LATEST version. ' - + 'If the function is imported from the same account use `fromFunctionAttributes()` API with the `sameEnvironment` flag.'); + if (!permissionNode && !this._skipPermissions) { + throw new Error('Cannot modify permission to lambda function. Function is either imported or $LATEST version.\n' + + 'If the function is imported from the same account use `fromFunctionAttributes()` API with the `sameEnvironment` flag.\n' + + 'If the function is imported from a different account and already has the correct permissions use `fromFunctionAttributes()` API with the `skipPermissions` flag.'); } return { statementAdded: true, policyDependable: permissionNode }; }, @@ -502,6 +539,10 @@ export abstract class QualifiedFunctionBase extends FunctionBase { return this.lambda.latestVersion; } + public get resourceArnsForGrantInvoke() { + return [this.functionArn]; + } + public configureAsyncInvoke(options: EventInvokeConfigOptions): void { if (this.node.tryFindChild('EventInvokeConfig') !== undefined) { throw new Error(`An EventInvokeConfig has already been configured for the qualified function at ${this.node.path}`); @@ -554,11 +595,15 @@ class LatestVersion extends FunctionBase implements IVersion { return this.lambda.role; } - public addAlias(aliasName: string, options: AliasOptions = {}) { - return addAlias(this, this, aliasName, options); - } - public get edgeArn(): never { throw new Error('$LATEST function version cannot be used for Lambda@Edge'); } + + public get resourceArnsForGrantInvoke() { + return [this.functionArn]; + } + + public addAlias(aliasName: string, options: AliasOptions = {}) { + return addAlias(this, this, aliasName, options); + } } diff --git a/packages/@aws-cdk/aws-lambda/lib/function-hash.ts b/packages/@aws-cdk/aws-lambda/lib/function-hash.ts index 0b7eff434ba65..0d16849763fec 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function-hash.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function-hash.ts @@ -60,6 +60,7 @@ export const VERSION_LOCKED: { [key: string]: boolean } = { DeadLetterConfig: true, Description: true, Environment: true, + EphemeralStorage: true, FileSystemConfigs: true, FunctionName: true, Handler: true, diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index 2b47aa8d7bca3..3e2c778be2891 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -4,8 +4,9 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as logs from '@aws-cdk/aws-logs'; +import * as sns from '@aws-cdk/aws-sns'; import * as sqs from '@aws-cdk/aws-sqs'; -import { Annotations, ArnFormat, CfnResource, Duration, Fn, Lazy, Names, Stack } from '@aws-cdk/core'; +import { Annotations, ArnFormat, CfnResource, Duration, Fn, Lazy, Names, Stack, Token } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { Architecture } from './architecture'; import { Code, CodeConfig } from './code'; @@ -188,11 +189,21 @@ export interface FunctionOptions extends EventInvokeConfigOptions { /** * The SQS queue to use if DLQ is enabled. + * If SNS topic is desired, specify `deadLetterTopic` property instead. * * @default - SQS queue with 14 day retention period if `deadLetterQueueEnabled` is `true` */ readonly deadLetterQueue?: sqs.IQueue; + /** + * The SNS topic to use as a DLQ. + * Note that if `deadLetterQueueEnabled` is set to `true`, an SQS queue will be created + * rather than an SNS topic. Using an SNS topic as a DLQ requires this property to be set explicitly. + * + * @default - no SNS topic + */ + readonly deadLetterTopic?: sns.ITopic; + /** * Enable AWS X-Ray Tracing for Lambda Function. * @@ -410,6 +421,10 @@ export class Function extends FunctionBase { return this._currentVersion; } + public get resourceArnsForGrantInvoke() { + return [this.functionArn, `${this.functionArn}:*`]; + } + /** @internal */ public static _VER_PROPS: { [key: string]: boolean } = {}; @@ -424,6 +439,20 @@ export class Function extends FunctionBase { this._VER_PROPS[propertyName] = locked; } + /** + * Import a lambda function into the CDK using its name + */ + public static fromFunctionName(scope: Construct, id: string, functionName: string): IFunction { + return Function.fromFunctionAttributes(scope, id, { + functionArn: Stack.of(scope).formatArn({ + service: 'lambda', + resource: 'function', + resourceName: functionName, + arnFormat: ArnFormat.COLON_RESOURCE_NAME, + }), + }); + } + /** * Import a lambda function into the CDK using its ARN */ @@ -451,8 +480,10 @@ export class Function extends FunctionBase { public readonly role = role; public readonly permissionsNode = this.node; public readonly architecture = attrs.architecture ?? Architecture.X86_64; + public readonly resourceArnsForGrantInvoke = [this.functionArn, `${this.functionArn}:*`]; protected readonly canCreatePermissions = attrs.sameEnvironment ?? this._isStackAccount(); + protected readonly _skipPermissions = attrs.skipPermissions ?? false; constructor(s: Construct, i: string) { super(s, i, { @@ -572,10 +603,15 @@ export class Function extends FunctionBase { public readonly grantPrincipal: iam.IPrincipal; /** - * The DLQ associated with this Lambda Function (this is an optional attribute). + * The DLQ (as queue) associated with this Lambda Function (this is an optional attribute). */ public readonly deadLetterQueue?: sqs.IQueue; + /** + * The DLQ (as topic) associated with this Lambda Function (this is an optional attribute). + */ + public readonly deadLetterTopic?: sns.ITopic; + /** * The architecture of this Lambda Function (this is an optional attribute and defaults to X86_64). */ @@ -610,6 +646,15 @@ export class Function extends FunctionBase { physicalName: props.functionName, }); + if (props.functionName && !Token.isUnresolved(props.functionName)) { + if (props.functionName.length > 64) { + throw new Error(`Function name can not be longer than 64 characters but has ${props.functionName.length} characters.`); + } + if (!/^[a-zA-Z0-9-_]+$/.test(props.functionName)) { + throw new Error(`Function name ${props.functionName} can contain only letters, numbers, hyphens, or underscores with no spaces.`); + } + } + const managedPolicies = new Array(); // the arn is in the form of - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole @@ -672,7 +717,15 @@ export class Function extends FunctionBase { this.addEnvironment(key, value); } - this.deadLetterQueue = this.buildDeadLetterQueue(props); + // DLQ can be either sns.ITopic or sqs.IQueue + const dlqTopicOrQueue = this.buildDeadLetterQueue(props); + if (dlqTopicOrQueue !== undefined) { + if (this.isQueue(dlqTopicOrQueue)) { + this.deadLetterQueue = dlqTopicOrQueue; + } else { + this.deadLetterTopic = dlqTopicOrQueue; + } + } let fileSystemConfigs: CfnFunction.FileSystemConfigProperty[] | undefined = undefined; if (props.filesystem) { @@ -711,7 +764,7 @@ export class Function extends FunctionBase { environment: Lazy.uncachedAny({ produce: () => this.renderEnvironment() }), memorySize: props.memorySize, vpcConfig: this.configureVpc(props), - deadLetterConfig: this.buildDeadLetterConfig(this.deadLetterQueue), + deadLetterConfig: this.buildDeadLetterConfig(dlqTopicOrQueue), tracingConfig: this.buildTracingConfig(props), reservedConcurrentExecutions: props.reservedConcurrentExecutions, imageConfig: undefinedIfNoKeys({ @@ -1030,31 +1083,45 @@ Environment variables can be marked for removal when used in Lambda@Edge by sett }; } - private buildDeadLetterQueue(props: FunctionProps) { + private isQueue(deadLetterQueue: sqs.IQueue | sns.ITopic): deadLetterQueue is sqs.IQueue { + return (deadLetterQueue).queueArn !== undefined; + } + + private buildDeadLetterQueue(props: FunctionProps): sqs.IQueue | sns.ITopic | undefined { + if (!props.deadLetterQueue && !props.deadLetterQueueEnabled && !props.deadLetterTopic) { + return undefined; + } if (props.deadLetterQueue && props.deadLetterQueueEnabled === false) { throw Error('deadLetterQueue defined but deadLetterQueueEnabled explicitly set to false'); } - - if (!props.deadLetterQueue && !props.deadLetterQueueEnabled) { - return undefined; + if (props.deadLetterTopic && (props.deadLetterQueue || props.deadLetterQueueEnabled !== undefined)) { + throw new Error('deadLetterQueue and deadLetterTopic cannot be specified together at the same time'); } - const deadLetterQueue = props.deadLetterQueue || new sqs.Queue(this, 'DeadLetterQueue', { - retentionPeriod: Duration.days(14), - }); - - this.addToRolePolicy(new iam.PolicyStatement({ - actions: ['sqs:SendMessage'], - resources: [deadLetterQueue.queueArn], - })); + let deadLetterQueue: sqs.IQueue | sns.ITopic; + if (props.deadLetterTopic) { + deadLetterQueue = props.deadLetterTopic; + this.addToRolePolicy(new iam.PolicyStatement({ + actions: ['sns:Publish'], + resources: [deadLetterQueue.topicArn], + })); + } else { + deadLetterQueue = props.deadLetterQueue || new sqs.Queue(this, 'DeadLetterQueue', { + retentionPeriod: Duration.days(14), + }); + this.addToRolePolicy(new iam.PolicyStatement({ + actions: ['sqs:SendMessage'], + resources: [deadLetterQueue.queueArn], + })); + } return deadLetterQueue; } - private buildDeadLetterConfig(deadLetterQueue?: sqs.IQueue) { + private buildDeadLetterConfig(deadLetterQueue?: sqs.IQueue | sns.ITopic) { if (deadLetterQueue) { return { - targetArn: deadLetterQueue.queueArn, + targetArn: this.isQueue(deadLetterQueue) ? deadLetterQueue.queueArn : deadLetterQueue.topicArn, }; } else { return undefined; diff --git a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts index dbbd1496d8d8c..50a3e5ade12dd 100644 --- a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts +++ b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts @@ -93,16 +93,17 @@ export interface VersionAttributes { } /** - * A single newly-deployed version of a Lambda function. + * Tag the current state of a Function with a Version number * - * This object exists to--at deploy time--query the "then-current" version of - * the Lambda function that it refers to. This Version object can then be - * used in `Alias` to refer to a particular deployment of a Lambda. + * Avoid using this resource directly. If you need a Version object, use + * `function.currentVersion` instead. That will add a Version object to your + * template, and make sure the Version is invalidated whenever the Function + * object changes. If you use the `Version` resource directly, you are + * responsible for making sure it is invalidated (by changing its + * logical ID) whenever necessary. * - * This means that for every new update you deploy to your Lambda (using the - * CDK and Aliases), you must always create a new Version object. In - * particular, it must have a different name, so that a new resource is - * created. + * Version resources can then be used in `Alias` resources to refer to a + * particular deployment of a Lambda. * * If you want to ensure that you're associating the right version with * the right deployment, specify the `codeSha256` property while diff --git a/packages/@aws-cdk/aws-lambda/lib/permission.ts b/packages/@aws-cdk/aws-lambda/lib/permission.ts index a4ca4ef3d1e7f..a22a3d53fb10b 100644 --- a/packages/@aws-cdk/aws-lambda/lib/permission.ts +++ b/packages/@aws-cdk/aws-lambda/lib/permission.ts @@ -3,7 +3,7 @@ import { Construct } from '@aws-cdk/core'; /** * Represents a permission statement that can be added to a Lambda function's - * resource policy via the `addPermissions()` method. + * resource policy via the `addPermission()` method. */ export interface Permission { /** diff --git a/packages/@aws-cdk/aws-lambda/lib/runtime.ts b/packages/@aws-cdk/aws-lambda/lib/runtime.ts index 9c0e305d4441e..5c3d918302060 100644 --- a/packages/@aws-cdk/aws-lambda/lib/runtime.ts +++ b/packages/@aws-cdk/aws-lambda/lib/runtime.ts @@ -137,6 +137,11 @@ export class Runtime { supportsCodeGuruProfiling: true, }); + /** + * The .NET 6 runtime (dotnet6) + */ + public static readonly DOTNET_6 = new Runtime('dotnet6', RuntimeFamily.DOTNET_CORE); + /** * The .NET Core 1.0 runtime (dotnetcore1.0) * Legacy runtime no longer supported by AWS Lambda. diff --git a/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts b/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts index 7ee0cf016e52d..33365c81037a4 100644 --- a/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts +++ b/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts @@ -117,6 +117,10 @@ export class SingletonFunction extends FunctionBase { return this.lambdaFunction.currentVersion; } + public get resourceArnsForGrantInvoke() { + return [this.functionArn, `${this.functionArn}:*`]; + }; + /** * Adds an environment variable to this Lambda function. * If this is a ref to a Lambda function, this operation results in a no-op. diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index 0c20400dcd01a..3476070c68ac2 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -89,10 +89,10 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cfnspec": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.92", - "@types/jest": "^27.4.0", - "@types/lodash": "^4.14.178", - "jest": "^27.4.7", + "@types/aws-lambda": "^8.10.93", + "@types/jest": "^27.4.1", + "@types/lodash": "^4.14.181", + "jest": "^27.5.1", "lodash": "^4.17.21" }, "dependencies": { @@ -110,6 +110,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-signer": "0.0.0", + "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", @@ -132,6 +133,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-signer": "0.0.0", + "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda/test/alias.test.ts b/packages/@aws-cdk/aws-lambda/test/alias.test.ts index 2a37ffb285060..4b4a5b13a8e73 100644 --- a/packages/@aws-cdk/aws-lambda/test/alias.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/alias.test.ts @@ -1,4 +1,4 @@ -import { Match, Template } from '@aws-cdk/assertions'; +import { Annotations, Match, Template } from '@aws-cdk/assertions'; import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import { testDeprecated } from '@aws-cdk/cdk-build-tools'; @@ -579,4 +579,55 @@ describe('alias', () => { ], }); }); + + test('scheduled scaling shows warning when minute is not defined in cron', () => { + // GIVEN + const stack = new Stack(); + const fn = new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('hello()'), + handler: 'index.hello', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + const alias = new lambda.Alias(stack, 'Alias', { + aliasName: 'prod', + version: fn.currentVersion, + }); + + // WHEN + const target = alias.addAutoScaling({ maxCapacity: 5 }); + target.scaleOnSchedule('Scheduling', { + schedule: appscaling.Schedule.cron({}), + maxCapacity: 10, + }); + + // THEN + Annotations.fromStack(stack).hasWarning('/Default/Alias/AliasScaling/Target', "cron: If you don't pass 'minute', by default the event runs every minute. Pass 'minute: '*'' if that's what you intend, or 'minute: 0' to run once per hour instead."); + }); + + test('scheduled scaling shows no warning when minute is * in cron', () => { + // GIVEN + const stack = new Stack(); + const fn = new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('hello()'), + handler: 'index.hello', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + const alias = new lambda.Alias(stack, 'Alias', { + aliasName: 'prod', + version: fn.currentVersion, + }); + + // WHEN + const target = alias.addAutoScaling({ maxCapacity: 5 }); + target.scaleOnSchedule('Scheduling', { + schedule: appscaling.Schedule.cron({ minute: '*' }), + maxCapacity: 10, + }); + + // THEN + const annotations = Annotations.fromStack(stack).findWarning('*', Match.anyValue()); + expect(annotations.length).toBe(0); + }); }); diff --git a/packages/@aws-cdk/aws-lambda/test/function.test.ts b/packages/@aws-cdk/aws-lambda/test/function.test.ts index d4f1af8f02cf0..81edf78b9a0e7 100644 --- a/packages/@aws-cdk/aws-lambda/test/function.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/function.test.ts @@ -8,6 +8,7 @@ import * as kms from '@aws-cdk/aws-kms'; import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; import * as signer from '@aws-cdk/aws-signer'; +import * as sns from '@aws-cdk/aws-sns'; import * as sqs from '@aws-cdk/aws-sqs'; import { testDeprecated } from '@aws-cdk/cdk-build-tools'; import * as cdk from '@aws-cdk/core'; @@ -296,6 +297,42 @@ describe('function', () => { expect(imported.functionName).toEqual('ProcessKinesisRecords'); }); + test('Function.fromFunctionName', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const imported = lambda.Function.fromFunctionName(stack, 'Imported', 'my-function'); + + // THEN + expect(stack.resolve(imported.functionArn)).toStrictEqual({ + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':lambda:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':function:my-function', + ]], + }); + expect(stack.resolve(imported.functionName)).toStrictEqual({ + 'Fn::Select': [6, { + 'Fn::Split': [':', { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':lambda:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':function:my-function', + ]], + }], + }], + }); + }); + describe('Function.fromFunctionAttributes()', () => { let stack: cdk.Stack; @@ -684,6 +721,84 @@ describe('function', () => { })).toThrow(/deadLetterQueue defined but deadLetterQueueEnabled explicitly set to false/); }); + test('default function with SNS DLQ when client provides Topic to be used as DLQ', () => { + const stack = new cdk.Stack(); + + const dlTopic = new sns.Topic(stack, 'DeadLetterTopic'); + + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + deadLetterTopic: dlTopic, + }); + + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: Match.arrayWith([ + { + Action: 'sns:Publish', + Effect: 'Allow', + Resource: { + Ref: 'DeadLetterTopicC237650B', + }, + }, + ]), + }, + }); + template.hasResourceProperties('AWS::Lambda::Function', { + DeadLetterConfig: { + TargetArn: { + Ref: 'DeadLetterTopicC237650B', + }, + }, + }); + }); + + test('error when default function with SNS DLQ when client provides Topic to be used as DLQ and deadLetterQueueEnabled set to false', () => { + const stack = new cdk.Stack(); + + const dlTopic = new sns.Topic(stack, 'DeadLetterTopic'); + + expect(() => new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + deadLetterQueueEnabled: false, + deadLetterTopic: dlTopic, + })).toThrow(/deadLetterQueue and deadLetterTopic cannot be specified together at the same time/); + }); + + test('error when default function with SNS DLQ when client provides Topic to be used as DLQ and deadLetterQueueEnabled set to true', () => { + const stack = new cdk.Stack(); + + const dlTopic = new sns.Topic(stack, 'DeadLetterTopic'); + + expect(() => new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + deadLetterQueueEnabled: true, + deadLetterTopic: dlTopic, + })).toThrow(/deadLetterQueue and deadLetterTopic cannot be specified together at the same time/); + }); + + test('error when both topic and queue are presented as DLQ', () => { + const stack = new cdk.Stack(); + + const dlQueue = new sqs.Queue(stack, 'DLQ'); + const dlTopic = new sns.Topic(stack, 'DeadLetterTopic'); + + expect(() => new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + deadLetterQueue: dlQueue, + deadLetterTopic: dlTopic, + })).toThrow(/deadLetterQueue and deadLetterTopic cannot be specified together at the same time/); + }); + test('default function with Active tracing', () => { const stack = new cdk.Stack(); @@ -845,7 +960,6 @@ describe('function', () => { }); describe('grantInvoke', () => { - test('adds iam:InvokeFunction', () => { // GIVEN const stack = new cdk.Stack(); @@ -869,7 +983,10 @@ describe('function', () => { { Action: 'lambda:InvokeFunction', Effect: 'Allow', - Resource: { 'Fn::GetAtt': ['Function76856677', 'Arn'] }, + Resource: [ + { 'Fn::GetAtt': ['Function76856677', 'Arn'] }, + { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['Function76856677', 'Arn'] }, ':*']] }, + ], }, ], }, @@ -1002,7 +1119,10 @@ describe('function', () => { { Action: 'lambda:InvokeFunction', Effect: 'Allow', - Resource: { 'Fn::GetAtt': ['Function76856677', 'Arn'] }, + Resource: [ + { 'Fn::GetAtt': ['Function76856677', 'Arn'] }, + { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['Function76856677', 'Arn'] }, ':*']] }, + ], }, ], }, @@ -1091,8 +1211,25 @@ describe('function', () => { const fn = lambda.Function.fromFunctionArn(stack, 'Function', 'arn:aws:lambda:us-east-1:123456789012:function:MyFn'); // THEN - expect(() => { fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); }) - .toThrow(/Cannot modify permission to lambda function/); + expect(() => { + fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); + }).toThrow(/Cannot modify permission to lambda function/); + }); + + test('on an imported function (different account & w/ skipPermissions', () => { + // GIVEN + const stack = new cdk.Stack(undefined, undefined, { + env: { account: '111111111111' }, // Different account + }); + const fn = lambda.Function.fromFunctionAttributes(stack, 'Function', { + functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', + skipPermissions: true, + }); + + // THEN + expect(() => { + fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); + }).not.toThrow(); }); }); @@ -1545,7 +1682,7 @@ describe('function', () => { expect(logGroup.logGroupArn).toBeDefined(); }); - test('dlq is returned when provided by user', () => { + test('dlq is returned when provided by user and is Queue', () => { const stack = new cdk.Stack(); const dlQueue = new sqs.Queue(stack, 'DeadLetterQueue', { @@ -1560,12 +1697,37 @@ describe('function', () => { deadLetterQueue: dlQueue, }); const deadLetterQueue = fn.deadLetterQueue; - expect(deadLetterQueue?.queueArn).toBeDefined(); - expect(deadLetterQueue?.queueName).toBeDefined(); - expect(deadLetterQueue?.queueUrl).toBeDefined(); + const deadLetterTopic = fn.deadLetterTopic; + + expect(deadLetterTopic).toBeUndefined(); + + expect(deadLetterQueue).toBeDefined(); + expect(deadLetterQueue).toBeInstanceOf(sqs.Queue); + }); + + test('dlq is returned when provided by user and is Topic', () => { + const stack = new cdk.Stack(); + + const dlTopic = new sns.Topic(stack, 'DeadLetterQueue', { + topicName: 'MyLambda_DLQ', + }); + + const fn = new lambda.Function(stack, 'fn', { + handler: 'foo', + runtime: lambda.Runtime.NODEJS_10_X, + code: lambda.Code.fromInline('foo'), + deadLetterTopic: dlTopic, + }); + const deadLetterQueue = fn.deadLetterQueue; + const deadLetterTopic = fn.deadLetterTopic; + + expect(deadLetterQueue).toBeUndefined(); + + expect(deadLetterTopic).toBeDefined(); + expect(deadLetterTopic).toBeInstanceOf(sns.Topic); }); - test('dlq is returned when setup by cdk', () => { + test('dlq is returned when setup by cdk and is Queue', () => { const stack = new cdk.Stack(); const fn = new lambda.Function(stack, 'fn', { handler: 'foo', @@ -1574,9 +1736,12 @@ describe('function', () => { deadLetterQueueEnabled: true, }); const deadLetterQueue = fn.deadLetterQueue; - expect(deadLetterQueue?.queueArn).toBeDefined(); - expect(deadLetterQueue?.queueName).toBeDefined(); - expect(deadLetterQueue?.queueUrl).toBeDefined(); + const deadLetterTopic = fn.deadLetterTopic; + + expect(deadLetterTopic).toBeUndefined(); + + expect(deadLetterQueue).toBeDefined(); + expect(deadLetterQueue).toBeInstanceOf(sqs.Queue); }); test('dlq is undefined when not setup', () => { @@ -1587,7 +1752,10 @@ describe('function', () => { code: lambda.Code.fromInline('foo'), }); const deadLetterQueue = fn.deadLetterQueue; + const deadLetterTopic = fn.deadLetterTopic; + expect(deadLetterQueue).toBeUndefined(); + expect(deadLetterTopic).toBeUndefined(); }); test('one and only one child LogRetention construct will be created', () => { @@ -2278,6 +2446,45 @@ describe('function', () => { }); expect(fn.architecture?.name).toEqual('arm64'); }); + + test('Error when function name is longer than 64 chars', () => { + const stack = new cdk.Stack(); + expect(() => new lambda.Function(stack, 'MyFunction', { + code: lambda.Code.fromInline('foo'), + runtime: lambda.Runtime.NODEJS_14_X, + handler: 'index.handler', + functionName: 'a'.repeat(65), + })).toThrow(/Function name can not be longer than 64 characters/); + }); + + test('Error when function name contains invalid characters', () => { + const stack = new cdk.Stack(); + [' ', '\n', '\r', '[', ']', '<', '>', '$'].forEach(invalidChar => { + expect(() => { + new lambda.Function(stack, `foo${invalidChar}`, { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_14_X, + functionName: `foo${invalidChar}`, + }); + }).toThrow(/can contain only letters, numbers, hyphens, or underscores with no spaces./); + }); + }); + + test('No error when function name is Tokenized and Unresolved', () => { + const stack = new cdk.Stack(); + expect(() => { + const realFunctionName = 'a'.repeat(141); + const tokenizedFunctionName = cdk.Token.asString(new cdk.Intrinsic(realFunctionName)); + + new lambda.Function(stack, 'foo', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_14_X, + functionName: tokenizedFunctionName, + }); + }).not.toThrow(); + }); }); function newTestLambda(scope: constructs.Construct) { diff --git a/packages/@aws-cdk/aws-lambda/test/integ.bundling.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.bundling.expected.json index 75863fbac5fab..ce5b2fbe98384 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.bundling.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.bundling.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47bS3Bucket48F36117" + "Ref": "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3BucketBF50F97C" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47bS3VersionKey5B24FA75" + "Ref": "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3VersionKeyF21AC8C1" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47bS3VersionKey5B24FA75" + "Ref": "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3VersionKeyF21AC8C1" } ] } @@ -87,17 +87,17 @@ } }, "Parameters": { - "AssetParameters4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47bS3Bucket48F36117": { + "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3BucketBF50F97C": { "Type": "String", - "Description": "S3 bucket for asset \"4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47b\"" + "Description": "S3 bucket for asset \"fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" }, - "AssetParameters4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47bS3VersionKey5B24FA75": { + "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3VersionKeyF21AC8C1": { "Type": "String", - "Description": "S3 key for asset version \"4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47b\"" + "Description": "S3 key for asset version \"fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" }, - "AssetParameters4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47bArtifactHashFE4A3131": { + "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509ArtifactHash5D8C129B": { "Type": "String", - "Description": "Artifact hash for asset \"4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47b\"" + "Description": "Artifact hash for asset \"fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda/test/integ.lambda-insights-mapping.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.lambda-insights-mapping.expected.json index a7a94e5d13ba7..824a0b3e6b8f9 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.lambda-insights-mapping.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.lambda-insights-mapping.expected.json @@ -291,7 +291,7 @@ { "Ref": "AWS::Region" }, - "1_0_98_0_x86_64" + "1x0x98x0xx86x64" ] } ], @@ -364,7 +364,7 @@ { "Ref": "AWS::Region" }, - "1_0_119_0_x86_64" + "1x0x119x0xx86x64" ] } ], @@ -457,92 +457,92 @@ "Mappings": { "CloudwatchlambdainsightsversionMap": { "af-south-1": { - "1_0_98_0_x86_64": "arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:8", - "1_0_119_0_x86_64": "arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:9" + "1x0x98x0xx86x64": "arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:8", + "1x0x119x0xx86x64": "arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:9" }, "ap-east-1": { - "1_0_98_0_x86_64": "arn:aws:lambda:ap-east-1:519774774795:layer:LambdaInsightsExtension:8", - "1_0_119_0_x86_64": "arn:aws:lambda:ap-east-1:519774774795:layer:LambdaInsightsExtension:9" + "1x0x98x0xx86x64": "arn:aws:lambda:ap-east-1:519774774795:layer:LambdaInsightsExtension:8", + "1x0x119x0xx86x64": "arn:aws:lambda:ap-east-1:519774774795:layer:LambdaInsightsExtension:9" }, "ap-northeast-1": { - "1_0_98_0_x86_64": "arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension:14", - "1_0_119_0_x86_64": "arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension:23" + "1x0x98x0xx86x64": "arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension:14", + "1x0x119x0xx86x64": "arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension:23" }, "ap-northeast-2": { - "1_0_98_0_x86_64": "arn:aws:lambda:ap-northeast-2:580247275435:layer:LambdaInsightsExtension:14", - "1_0_119_0_x86_64": "arn:aws:lambda:ap-northeast-2:580247275435:layer:LambdaInsightsExtension:16" + "1x0x98x0xx86x64": "arn:aws:lambda:ap-northeast-2:580247275435:layer:LambdaInsightsExtension:14", + "1x0x119x0xx86x64": "arn:aws:lambda:ap-northeast-2:580247275435:layer:LambdaInsightsExtension:16" }, "ap-south-1": { - "1_0_98_0_x86_64": "arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:14", - "1_0_119_0_x86_64": "arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:16" + "1x0x98x0xx86x64": "arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:14", + "1x0x119x0xx86x64": "arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:16" }, "ap-southeast-1": { - "1_0_98_0_x86_64": "arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension:14", - "1_0_119_0_x86_64": "arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension:16" + "1x0x98x0xx86x64": "arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension:14", + "1x0x119x0xx86x64": "arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension:16" }, "ap-southeast-2": { - "1_0_98_0_x86_64": "arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension:14", - "1_0_119_0_x86_64": "arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension:16" + "1x0x98x0xx86x64": "arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension:14", + "1x0x119x0xx86x64": "arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension:16" }, "ca-central-1": { - "1_0_98_0_x86_64": "arn:aws:lambda:ca-central-1:580247275435:layer:LambdaInsightsExtension:14", - "1_0_119_0_x86_64": "arn:aws:lambda:ca-central-1:580247275435:layer:LambdaInsightsExtension:16" + "1x0x98x0xx86x64": "arn:aws:lambda:ca-central-1:580247275435:layer:LambdaInsightsExtension:14", + "1x0x119x0xx86x64": "arn:aws:lambda:ca-central-1:580247275435:layer:LambdaInsightsExtension:16" }, "cn-north-1": { - "1_0_98_0_x86_64": "arn:aws-cn:lambda:cn-north-1:488211338238:layer:LambdaInsightsExtension:8", - "1_0_119_0_x86_64": "arn:aws-cn:lambda:cn-north-1:488211338238:layer:LambdaInsightsExtension:9" + "1x0x98x0xx86x64": "arn:aws-cn:lambda:cn-north-1:488211338238:layer:LambdaInsightsExtension:8", + "1x0x119x0xx86x64": "arn:aws-cn:lambda:cn-north-1:488211338238:layer:LambdaInsightsExtension:9" }, "cn-northwest-1": { - "1_0_98_0_x86_64": "arn:aws-cn:lambda:cn-northwest-1:488211338238:layer:LambdaInsightsExtension:8", - "1_0_119_0_x86_64": "arn:aws-cn:lambda:cn-northwest-1:488211338238:layer:LambdaInsightsExtension:9" + "1x0x98x0xx86x64": "arn:aws-cn:lambda:cn-northwest-1:488211338238:layer:LambdaInsightsExtension:8", + "1x0x119x0xx86x64": "arn:aws-cn:lambda:cn-northwest-1:488211338238:layer:LambdaInsightsExtension:9" }, "eu-central-1": { - "1_0_98_0_x86_64": "arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension:14", - "1_0_119_0_x86_64": "arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension:16" + "1x0x98x0xx86x64": "arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension:14", + "1x0x119x0xx86x64": "arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension:16" }, "eu-north-1": { - "1_0_98_0_x86_64": "arn:aws:lambda:eu-north-1:580247275435:layer:LambdaInsightsExtension:14", - "1_0_119_0_x86_64": "arn:aws:lambda:eu-north-1:580247275435:layer:LambdaInsightsExtension:16" + "1x0x98x0xx86x64": "arn:aws:lambda:eu-north-1:580247275435:layer:LambdaInsightsExtension:14", + "1x0x119x0xx86x64": "arn:aws:lambda:eu-north-1:580247275435:layer:LambdaInsightsExtension:16" }, "eu-south-1": { - "1_0_98_0_x86_64": "arn:aws:lambda:eu-south-1:339249233099:layer:LambdaInsightsExtension:8", - "1_0_119_0_x86_64": "arn:aws:lambda:eu-south-1:339249233099:layer:LambdaInsightsExtension:9" + "1x0x98x0xx86x64": "arn:aws:lambda:eu-south-1:339249233099:layer:LambdaInsightsExtension:8", + "1x0x119x0xx86x64": "arn:aws:lambda:eu-south-1:339249233099:layer:LambdaInsightsExtension:9" }, "eu-west-1": { - "1_0_98_0_x86_64": "arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension:14", - "1_0_119_0_x86_64": "arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension:16" + "1x0x98x0xx86x64": "arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension:14", + "1x0x119x0xx86x64": "arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension:16" }, "eu-west-2": { - "1_0_98_0_x86_64": "arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:14", - "1_0_119_0_x86_64": "arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:16" + "1x0x98x0xx86x64": "arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:14", + "1x0x119x0xx86x64": "arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:16" }, "eu-west-3": { - "1_0_98_0_x86_64": "arn:aws:lambda:eu-west-3:580247275435:layer:LambdaInsightsExtension:14", - "1_0_119_0_x86_64": "arn:aws:lambda:eu-west-3:580247275435:layer:LambdaInsightsExtension:16" + "1x0x98x0xx86x64": "arn:aws:lambda:eu-west-3:580247275435:layer:LambdaInsightsExtension:14", + "1x0x119x0xx86x64": "arn:aws:lambda:eu-west-3:580247275435:layer:LambdaInsightsExtension:16" }, "me-south-1": { - "1_0_98_0_x86_64": "arn:aws:lambda:me-south-1:285320876703:layer:LambdaInsightsExtension:8", - "1_0_119_0_x86_64": "arn:aws:lambda:me-south-1:285320876703:layer:LambdaInsightsExtension:9" + "1x0x98x0xx86x64": "arn:aws:lambda:me-south-1:285320876703:layer:LambdaInsightsExtension:8", + "1x0x119x0xx86x64": "arn:aws:lambda:me-south-1:285320876703:layer:LambdaInsightsExtension:9" }, "sa-east-1": { - "1_0_98_0_x86_64": "arn:aws:lambda:sa-east-1:580247275435:layer:LambdaInsightsExtension:14", - "1_0_119_0_x86_64": "arn:aws:lambda:sa-east-1:580247275435:layer:LambdaInsightsExtension:16" + "1x0x98x0xx86x64": "arn:aws:lambda:sa-east-1:580247275435:layer:LambdaInsightsExtension:14", + "1x0x119x0xx86x64": "arn:aws:lambda:sa-east-1:580247275435:layer:LambdaInsightsExtension:16" }, "us-east-1": { - "1_0_98_0_x86_64": "arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:14", - "1_0_119_0_x86_64": "arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:16" + "1x0x98x0xx86x64": "arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:14", + "1x0x119x0xx86x64": "arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:16" }, "us-east-2": { - "1_0_98_0_x86_64": "arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension:14", - "1_0_119_0_x86_64": "arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension:16" + "1x0x98x0xx86x64": "arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension:14", + "1x0x119x0xx86x64": "arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension:16" }, "us-west-1": { - "1_0_98_0_x86_64": "arn:aws:lambda:us-west-1:580247275435:layer:LambdaInsightsExtension:14", - "1_0_119_0_x86_64": "arn:aws:lambda:us-west-1:580247275435:layer:LambdaInsightsExtension:16" + "1x0x98x0xx86x64": "arn:aws:lambda:us-west-1:580247275435:layer:LambdaInsightsExtension:14", + "1x0x119x0xx86x64": "arn:aws:lambda:us-west-1:580247275435:layer:LambdaInsightsExtension:16" }, "us-west-2": { - "1_0_98_0_x86_64": "arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:14", - "1_0_119_0_x86_64": "arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:16" + "1x0x98x0xx86x64": "arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:14", + "1x0x119x0xx86x64": "arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:16" } } } diff --git a/packages/@aws-cdk/aws-lambda/test/integ.log-retention.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.log-retention.expected.json index ec86574496747..1765faee07465 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.log-retention.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.log-retention.expected.json @@ -37,13 +37,13 @@ "Code": { "ZipFile": "exports.handler = (event) => console.log(JSON.stringify(event));" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "OneWeekServiceRole05A6F9F8", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -111,8 +111,8 @@ "Statement": [ { "Action": [ - "logs:PutRetentionPolicy", - "logs:DeleteRetentionPolicy" + "logs:DeleteRetentionPolicy", + "logs:PutRetentionPolicy" ], "Effect": "Allow", "Resource": "*" @@ -131,9 +131,11 @@ "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aFD4BFC8A": { "Type": "AWS::Lambda::Function", "Properties": { + "Handler": "index.handler", + "Runtime": "nodejs14.x", "Code": { "S3Bucket": { - "Ref": "AssetParameters11aa2ce8971716ca7c8d28d472ab5e937131e78e136d0de8f4997fb11c4de847S3Bucket46EF559D" + "Ref": "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665S3Bucket0D8A173B" }, "S3Key": { "Fn::Join": [ @@ -146,7 +148,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters11aa2ce8971716ca7c8d28d472ab5e937131e78e136d0de8f4997fb11c4de847S3VersionKey68B7BF84" + "Ref": "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665S3VersionKeyE95BF332" } ] } @@ -159,7 +161,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters11aa2ce8971716ca7c8d28d472ab5e937131e78e136d0de8f4997fb11c4de847S3VersionKey68B7BF84" + "Ref": "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665S3VersionKeyE95BF332" } ] } @@ -169,14 +171,12 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRole9741ECFB", "Arn" ] - }, - "Runtime": "nodejs14.x" + } }, "DependsOn": [ "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB", @@ -220,13 +220,13 @@ "Code": { "ZipFile": "exports.handler = (event) => console.log(JSON.stringify(event));" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "OneMonthServiceRoleFBD1064F", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -293,13 +293,13 @@ "Code": { "ZipFile": "exports.handler = (event) => console.log(JSON.stringify(event));" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "OneYearServiceRole24D47762", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -331,17 +331,17 @@ } }, "Parameters": { - "AssetParameters11aa2ce8971716ca7c8d28d472ab5e937131e78e136d0de8f4997fb11c4de847S3Bucket46EF559D": { + "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665S3Bucket0D8A173B": { "Type": "String", - "Description": "S3 bucket for asset \"11aa2ce8971716ca7c8d28d472ab5e937131e78e136d0de8f4997fb11c4de847\"" + "Description": "S3 bucket for asset \"22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665\"" }, - "AssetParameters11aa2ce8971716ca7c8d28d472ab5e937131e78e136d0de8f4997fb11c4de847S3VersionKey68B7BF84": { + "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665S3VersionKeyE95BF332": { "Type": "String", - "Description": "S3 key for asset version \"11aa2ce8971716ca7c8d28d472ab5e937131e78e136d0de8f4997fb11c4de847\"" + "Description": "S3 key for asset version \"22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665\"" }, - "AssetParameters11aa2ce8971716ca7c8d28d472ab5e937131e78e136d0de8f4997fb11c4de847ArtifactHash27BA7171": { + "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665ArtifactHashF4A1E70E": { "Type": "String", - "Description": "Artifact hash for asset \"11aa2ce8971716ca7c8d28d472ab5e937131e78e136d0de8f4997fb11c4de847\"" + "Description": "Artifact hash for asset \"22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665\"" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts b/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts index 761d7262b412e..ac758ab4be5ad 100644 --- a/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts @@ -97,7 +97,7 @@ describe('lambda-insights', () => { { Ref: 'AWS::Region', }, - '1_0_98_0_x86_64', + '1x0x98x0xx86x64', ], }], }); @@ -117,20 +117,20 @@ describe('lambda-insights', () => { Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { FunctionName: 'MyLambda1', Layers: [{ - 'Fn::FindInMap': ['CloudwatchlambdainsightsversionMap', { Ref: 'AWS::Region' }, '1_0_98_0_x86_64'], + 'Fn::FindInMap': ['CloudwatchlambdainsightsversionMap', { Ref: 'AWS::Region' }, '1x0x98x0xx86x64'], }], }); Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { FunctionName: 'MyLambda2', Layers: [{ - 'Fn::FindInMap': ['CloudwatchlambdainsightsversionMap', { Ref: 'AWS::Region' }, '1_0_98_0_x86_64'], + 'Fn::FindInMap': ['CloudwatchlambdainsightsversionMap', { Ref: 'AWS::Region' }, '1x0x98x0xx86x64'], }], }); Template.fromStack(stack).hasMapping('CloudwatchlambdainsightsversionMap', { 'af-south-1': { - '1_0_98_0_x86_64': 'arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:8', + '1x0x98x0xx86x64': 'arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:8', }, }); @@ -218,21 +218,21 @@ describe('lambda-insights', () => { Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { FunctionName: 'MyLambda1', Layers: [{ - 'Fn::FindInMap': ['CloudwatchlambdainsightsversionMap', { Ref: 'AWS::Region' }, '1_0_119_0_x86_64'], + 'Fn::FindInMap': ['CloudwatchlambdainsightsversionMap', { Ref: 'AWS::Region' }, '1x0x119x0xx86x64'], }], }); Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { FunctionName: 'MyLambda2', Layers: [{ - 'Fn::FindInMap': ['CloudwatchlambdainsightsversionMap', { Ref: 'AWS::Region' }, '1_0_119_0_arm64'], + 'Fn::FindInMap': ['CloudwatchlambdainsightsversionMap', { Ref: 'AWS::Region' }, '1x0x119x0xarm64'], }], }); Template.fromStack(stack).hasMapping('CloudwatchlambdainsightsversionMap', { 'ap-south-1': { - '1_0_119_0_x86_64': 'arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:16', - '1_0_119_0_arm64': 'arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension-Arm64:1', + '1x0x119x0xx86x64': 'arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:16', + '1x0x119x0xarm64': 'arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension-Arm64:1', }, }); diff --git a/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts b/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts index 3e6db8d6ea422..0f0a864a4c173 100644 --- a/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts @@ -182,9 +182,10 @@ describe('singleton lambda', () => { expect(statement.action).toEqual(['lambda:InvokeFunction']); expect(statement.principal).toEqual({ Service: ['events.amazonaws.com'] }); expect(statement.effect).toEqual('Allow'); - expect(statement.resource).toEqual([{ - 'Fn::GetAtt': ['SingletonLambda84c0de93353f42179b0b45b6c993251a840BCC38', 'Arn'], - }]); + expect(statement.resource).toEqual([ + { 'Fn::GetAtt': ['SingletonLambda84c0de93353f42179b0b45b6c993251a840BCC38', 'Arn'] }, + { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['SingletonLambda84c0de93353f42179b0b45b6c993251a840BCC38', 'Arn'] }, ':*']] }, + ]); }); test('check edge compatibility', () => { diff --git a/packages/@aws-cdk/aws-licensemanager/package.json b/packages/@aws-cdk/aws-licensemanager/package.json index 2a080395c788e..7a41e125ce49d 100644 --- a/packages/@aws-cdk/aws-licensemanager/package.json +++ b/packages/@aws-cdk/aws-licensemanager/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-lightsail/package.json b/packages/@aws-cdk/aws-lightsail/package.json index c99305e2ad42c..8f71c3ebd1192 100644 --- a/packages/@aws-cdk/aws-lightsail/package.json +++ b/packages/@aws-cdk/aws-lightsail/package.json @@ -88,7 +88,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-location/package.json b/packages/@aws-cdk/aws-location/package.json index 7acaf2d81fd60..e686e64f27c41 100644 --- a/packages/@aws-cdk/aws-location/package.json +++ b/packages/@aws-cdk/aws-location/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-logs-destinations/README.md b/packages/@aws-cdk/aws-logs-destinations/README.md index 28d124c669017..4e2b4d7bedf5b 100644 --- a/packages/@aws-cdk/aws-logs-destinations/README.md +++ b/packages/@aws-cdk/aws-logs-destinations/README.md @@ -9,4 +9,7 @@ -A short description here. +This library contains destinations for AWS CloudWatch Logs SubscriptionFilters. You +can send log data to Kinesis Streams or Lambda Functions. + +See the documentation of the `logs` module for more information. diff --git a/packages/@aws-cdk/aws-logs-destinations/lib/kinesis.ts b/packages/@aws-cdk/aws-logs-destinations/lib/kinesis.ts index e4f57f5d4b33f..41aca9dea4ca5 100644 --- a/packages/@aws-cdk/aws-logs-destinations/lib/kinesis.ts +++ b/packages/@aws-cdk/aws-logs-destinations/lib/kinesis.ts @@ -3,18 +3,35 @@ import * as kinesis from '@aws-cdk/aws-kinesis'; import * as logs from '@aws-cdk/aws-logs'; import { Construct } from '@aws-cdk/core'; +/** + * Customize the Kinesis Logs Destination + */ +export interface KinesisDestinationProps { + /** + * The role to assume to write log events to the destination + * + * @default - A new Role is created + */ + readonly role?: iam.IRole; +} + /** * Use a Kinesis stream as the destination for a log subscription */ export class KinesisDestination implements logs.ILogSubscriptionDestination { - constructor(private readonly stream: kinesis.IStream) { + /** + * @param stream The Kinesis stream to use as destination + * @param props The Kinesis Destination properties + * + */ + constructor(private readonly stream: kinesis.IStream, private readonly props: KinesisDestinationProps = {}) { } public bind(scope: Construct, _sourceLogGroup: logs.ILogGroup): logs.LogSubscriptionDestinationConfig { // Following example from https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/SubscriptionFilters.html#DestinationKinesisExample // Create a role to be assumed by CWL that can write to this stream and pass itself. const id = 'CloudWatchLogsCanPutRecords'; - const role = scope.node.tryFindChild(id) as iam.IRole || new iam.Role(scope, id, { + const role = this.props.role ?? scope.node.tryFindChild(id) as iam.IRole ?? new iam.Role(scope, id, { assumedBy: new iam.ServicePrincipal('logs.amazonaws.com'), }); this.stream.grantWrite(role); diff --git a/packages/@aws-cdk/aws-logs-destinations/package.json b/packages/@aws-cdk/aws-logs-destinations/package.json index e1e43b017c992..07e783848cb15 100644 --- a/packages/@aws-cdk/aws-logs-destinations/package.json +++ b/packages/@aws-cdk/aws-logs-destinations/package.json @@ -76,8 +76,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-logs-destinations/test/kinesis.test.ts b/packages/@aws-cdk/aws-logs-destinations/test/kinesis.test.ts index 4325993406ccd..e09a58ba7dd3a 100644 --- a/packages/@aws-cdk/aws-logs-destinations/test/kinesis.test.ts +++ b/packages/@aws-cdk/aws-logs-destinations/test/kinesis.test.ts @@ -1,4 +1,5 @@ import { Template } from '@aws-cdk/assertions'; +import * as iam from '@aws-cdk/aws-iam'; import * as kinesis from '@aws-cdk/aws-kinesis'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; @@ -136,3 +137,54 @@ test('stream can be subscription destination twice, without duplicating permissi }, }); }); + +test('an existing IAM role can be passed to new destination instance instead of auto-created ', ()=> { + // GIVEN + const stack = new cdk.Stack(); + const stream = new kinesis.Stream(stack, 'MyStream'); + const logGroup = new logs.LogGroup(stack, 'LogGroup'); + + const importedRole = iam.Role.fromRoleArn(stack, 'ImportedRole', 'arn:aws:iam::123456789012:role/ImportedRoleKinesisDestinationTest'); + + const kinesisDestination = new dests.KinesisDestination(stream, { role: importedRole }); + + new logs.SubscriptionFilter(logGroup, 'MySubscriptionFilter', { + logGroup: logGroup, + destination: kinesisDestination, + filterPattern: logs.FilterPattern.allEvents(), + }); + + // THEN + const template = Template.fromStack(stack); + template.resourceCountIs('AWS::IAM::Role', 0); + template.hasResourceProperties('AWS::Logs::SubscriptionFilter', { + RoleArn: importedRole.roleArn, + }); +}); + +test('creates a new IAM Role if not passed on new destination instance', ()=> { + // GIVEN + const stack = new cdk.Stack(); + const stream = new kinesis.Stream(stack, 'MyStream'); + const logGroup = new logs.LogGroup(stack, 'LogGroup'); + + const kinesisDestination = new dests.KinesisDestination(stream); + + new logs.SubscriptionFilter(logGroup, 'MySubscriptionFilter', { + logGroup: logGroup, + destination: kinesisDestination, + filterPattern: logs.FilterPattern.allEvents(), + }); + + // THEN + const template = Template.fromStack(stack); + template.resourceCountIs('AWS::IAM::Role', 1); + template.hasResourceProperties('AWS::Logs::SubscriptionFilter', { + RoleArn: { + 'Fn::GetAtt': [ + 'LogGroupMySubscriptionFilterCloudWatchLogsCanPutRecords9112BD02', + 'Arn', + ], + }, + }); +}); diff --git a/packages/@aws-cdk/aws-logs/package.json b/packages/@aws-cdk/aws-logs/package.json index 6449ad0144d0f..37f646b394b9e 100644 --- a/packages/@aws-cdk/aws-logs/package.json +++ b/packages/@aws-cdk/aws-logs/package.json @@ -84,12 +84,12 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.92", - "@types/jest": "^27.4.0", + "@types/aws-lambda": "^8.10.93", + "@types/jest": "^27.4.1", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", "aws-sdk-mock": "5.6.0", - "jest": "^27.4.7", + "jest": "^27.5.1", "nock": "^13.2.4", "sinon": "^9.2.4" }, diff --git a/packages/@aws-cdk/aws-lookoutequipment/package.json b/packages/@aws-cdk/aws-lookoutequipment/package.json index 26dc399bb1d3d..7218c3f7fd95f 100644 --- a/packages/@aws-cdk/aws-lookoutequipment/package.json +++ b/packages/@aws-cdk/aws-lookoutequipment/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-lookoutmetrics/package.json b/packages/@aws-cdk/aws-lookoutmetrics/package.json index 257c1ccad03c5..bce07b4f9fed7 100644 --- a/packages/@aws-cdk/aws-lookoutmetrics/package.json +++ b/packages/@aws-cdk/aws-lookoutmetrics/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-lookoutvision/package.json b/packages/@aws-cdk/aws-lookoutvision/package.json index 3722553279a80..f24b9b3a26db1 100644 --- a/packages/@aws-cdk/aws-lookoutvision/package.json +++ b/packages/@aws-cdk/aws-lookoutvision/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-macie/package.json b/packages/@aws-cdk/aws-macie/package.json index 0db2eaf329169..c24dd63ebd1ba 100644 --- a/packages/@aws-cdk/aws-macie/package.json +++ b/packages/@aws-cdk/aws-macie/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-managedblockchain/package.json b/packages/@aws-cdk/aws-managedblockchain/package.json index 8f8f77907edb4..9190b3c3b9955 100644 --- a/packages/@aws-cdk/aws-managedblockchain/package.json +++ b/packages/@aws-cdk/aws-managedblockchain/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-mediaconnect/package.json b/packages/@aws-cdk/aws-mediaconnect/package.json index ca2d9a593ea5a..5a67e0a1c0942 100644 --- a/packages/@aws-cdk/aws-mediaconnect/package.json +++ b/packages/@aws-cdk/aws-mediaconnect/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-mediaconvert/package.json b/packages/@aws-cdk/aws-mediaconvert/package.json index 0ee4ec64dcbe7..637617e65843e 100644 --- a/packages/@aws-cdk/aws-mediaconvert/package.json +++ b/packages/@aws-cdk/aws-mediaconvert/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-medialive/package.json b/packages/@aws-cdk/aws-medialive/package.json index f87426fc1fd81..dbe092b4b0dfb 100644 --- a/packages/@aws-cdk/aws-medialive/package.json +++ b/packages/@aws-cdk/aws-medialive/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-mediapackage/package.json b/packages/@aws-cdk/aws-mediapackage/package.json index 31e2b39fe0c9a..23f112ba5ae80 100644 --- a/packages/@aws-cdk/aws-mediapackage/package.json +++ b/packages/@aws-cdk/aws-mediapackage/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-mediastore/package.json b/packages/@aws-cdk/aws-mediastore/package.json index ece435e1c014f..73dc4e62f8961 100644 --- a/packages/@aws-cdk/aws-mediastore/package.json +++ b/packages/@aws-cdk/aws-mediastore/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-memorydb/package.json b/packages/@aws-cdk/aws-memorydb/package.json index b85421f3713f9..5db59ada0d550 100644 --- a/packages/@aws-cdk/aws-memorydb/package.json +++ b/packages/@aws-cdk/aws-memorydb/package.json @@ -88,7 +88,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-msk/package.json b/packages/@aws-cdk/aws-msk/package.json index 37873685aa03e..e175174ae9da6 100644 --- a/packages/@aws-cdk/aws-msk/package.json +++ b/packages/@aws-cdk/aws-msk/package.json @@ -86,8 +86,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-acmpca": "0.0.0", diff --git a/packages/@aws-cdk/aws-msk/test/integ.cluster.expected.json b/packages/@aws-cdk/aws-msk/test/integ.cluster.expected.json index 2b523706bd3e2..d7ef1ebc8825f 100644 --- a/packages/@aws-cdk/aws-msk/test/integ.cluster.expected.json +++ b/packages/@aws-cdk/aws-msk/test/integ.cluster.expected.json @@ -524,7 +524,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3Bucket4C71F166" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16" }, "S3Key": { "Fn::Join": [ @@ -537,7 +537,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3VersionKey0124EFC4" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -550,7 +550,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3VersionKey0124EFC4" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -576,17 +576,17 @@ } }, "Parameters": { - "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3Bucket4C71F166": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16": { "Type": "String", - "Description": "S3 bucket for asset \"1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2d\"" + "Description": "S3 bucket for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3VersionKey0124EFC4": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B": { "Type": "String", - "Description": "S3 key for asset version \"1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2d\"" + "Description": "S3 key for asset version \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dArtifactHash6350D824": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87ArtifactHash40DDF5EE": { "Type": "String", - "Description": "Artifact hash for asset \"1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2d\"" + "Description": "Artifact hash for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-mwaa/package.json b/packages/@aws-cdk/aws-mwaa/package.json index f0a0cec6a6877..ab2d6061c871b 100644 --- a/packages/@aws-cdk/aws-mwaa/package.json +++ b/packages/@aws-cdk/aws-mwaa/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-neptune/package.json b/packages/@aws-cdk/aws-neptune/package.json index 27c8c35f6e980..73b0ac6867a50 100644 --- a/packages/@aws-cdk/aws-neptune/package.json +++ b/packages/@aws-cdk/aws-neptune/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-networkfirewall/package.json b/packages/@aws-cdk/aws-networkfirewall/package.json index 91e96fd0b3a46..937d63aa53730 100644 --- a/packages/@aws-cdk/aws-networkfirewall/package.json +++ b/packages/@aws-cdk/aws-networkfirewall/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-networkmanager/package.json b/packages/@aws-cdk/aws-networkmanager/package.json index 696efca60f8eb..c34d778bac829 100644 --- a/packages/@aws-cdk/aws-networkmanager/package.json +++ b/packages/@aws-cdk/aws-networkmanager/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-nimblestudio/package.json b/packages/@aws-cdk/aws-nimblestudio/package.json index c033e0066f94e..52ab33b43c1ca 100644 --- a/packages/@aws-cdk/aws-nimblestudio/package.json +++ b/packages/@aws-cdk/aws-nimblestudio/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-opensearchservice/README.md b/packages/@aws-cdk/aws-opensearchservice/README.md index 79d2289dcfffb..db737d1b84741 100644 --- a/packages/@aws-cdk/aws-opensearchservice/README.md +++ b/packages/@aws-cdk/aws-opensearchservice/README.md @@ -235,6 +235,61 @@ const domain = new opensearch.Domain(this, 'Domain', { const masterUserPassword = domain.masterUserPassword; ``` +## Custom access policies + +If the domain requires custom access control it can be configured either as a +constructor property, or later by means of a helper method. + +For simple permissions the `accessPolicies` constructor may be sufficient: + +```ts +const domain = new opensearch.Domain(this, 'Domain', { + version: opensearch.EngineVersion.OPENSEARCH_1_0, + accessPolicies: [ + new iam.PolicyStatement({ + actions: ['es:*ESHttpPost', 'es:ESHttpPut*'], + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('123456789012')], + resources: ['*'], + }), + ] +}); +``` + +For more complex use-cases, for example, to set the domain up to receive data from a +[cross-account Kinesis Firehose](https://aws.amazon.com/premiumsupport/knowledge-center/kinesis-firehose-cross-account-streaming/) the `addAccessPolicies` helper method +allows for policies that include the explicit domain ARN. + +```ts +const domain = new opensearch.Domain(this, 'Domain', { + version: opensearch.EngineVersion.OPENSEARCH_1_0, +}); +domain.addAccessPolicies( + new iam.PolicyStatement({ + actions: ['es:ESHttpPost', 'es:ESHttpPut'], + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('123456789012')], + resources: [domain.domainArn, `${domain.domainArn}/*`], + }), + new iam.PolicyStatement({ + actions: ['es:ESHttpGet'], + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('123456789012')], + resources: [ + `${domain.domainArn}/_all/_settings`, + `${domain.domainArn}/_cluster/stats`, + `${domain.domainArn}/index-name*/_mapping/type-name`, + `${domain.domainArn}/roletest*/_mapping/roletest`, + `${domain.domainArn}/_nodes`, + `${domain.domainArn}/_nodes/stats`, + `${domain.domainArn}/_nodes/*/stats`, + `${domain.domainArn}/_stats`, + `${domain.domainArn}/index-name*/_stats`, + `${domain.domainArn}/roletest*/_stat`, + ], + }), +); +``` ## Audit logs diff --git a/packages/@aws-cdk/aws-opensearchservice/lib/domain.ts b/packages/@aws-cdk/aws-opensearchservice/lib/domain.ts index aadf9e011b827..fbcd1d9f33d51 100644 --- a/packages/@aws-cdk/aws-opensearchservice/lib/domain.ts +++ b/packages/@aws-cdk/aws-opensearchservice/lib/domain.ts @@ -1195,6 +1195,10 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable { private readonly domain: CfnDomain; + private accessPolicy?: OpenSearchAccessPolicy + + private encryptionAtRestOptions?: EncryptionAtRestOptions + private readonly _connections: ec2.Connections | undefined; constructor(scope: Construct, id: string, props: DomainProps) { @@ -1654,33 +1658,12 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable { }); } - const accessPolicyStatements: iam.PolicyStatement[] | undefined = unsignedBasicAuthEnabled - ? (props.accessPolicies ?? []).concat(unsignedAccessPolicy) - : props.accessPolicies; - - if (accessPolicyStatements != null) { - const accessPolicy = new OpenSearchAccessPolicy(this, 'Access Policy', { - domainName: this.domainName, - domainArn: this.domainArn, - accessPolicies: accessPolicyStatements, - }); - - if (props.encryptionAtRest?.kmsKey) { - - // https://docs.aws.amazon.com/opensearch-service/latest/developerguide/encryption-at-rest.html - - // these permissions are documented as required during domain creation. - // while not strictly documented for updates as well, it stands to reason that an update - // operation might require these in case the cluster uses a kms key. - // empircal evidence shows this is indeed required: https://github.com/aws/aws-cdk/issues/11412 - accessPolicy.grantPrincipal.addToPrincipalPolicy(new iam.PolicyStatement({ - actions: ['kms:List*', 'kms:Describe*', 'kms:CreateGrant'], - resources: [props.encryptionAtRest.kmsKey.keyArn], - effect: iam.Effect.ALLOW, - })); - } - - accessPolicy.node.addDependency(this.domain); + this.encryptionAtRestOptions = props.encryptionAtRest; + if (props.accessPolicies) { + this.addAccessPolicies(...props.accessPolicies); + } + if (unsignedBasicAuthEnabled) { + this.addAccessPolicies(unsignedAccessPolicy); } } @@ -1694,6 +1677,39 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable { } return this._connections; } + + + /** + * Add policy statements to the domain access policy + */ + public addAccessPolicies(...accessPolicyStatements: iam.PolicyStatement[]) { + if (accessPolicyStatements.length > 0) { + if (!this.accessPolicy) { + // Only create the custom resource after there are statements to set. + this.accessPolicy = new OpenSearchAccessPolicy(this, 'AccessPolicy', { + domainName: this.domainName, + domainArn: this.domainArn, + accessPolicies: accessPolicyStatements, + }); + + if (this.encryptionAtRestOptions?.kmsKey) { + // https://docs.aws.amazon.com/opensearch-service/latest/developerguide/encryption-at-rest.html + + // these permissions are documented as required during domain creation. + // while not strictly documented for updates as well, it stands to reason that an update + // operation might require these in case the cluster uses a kms key. + // empircal evidence shows this is indeed required: https://github.com/aws/aws-cdk/issues/11412 + this.accessPolicy.grantPrincipal.addToPrincipalPolicy(new iam.PolicyStatement({ + actions: ['kms:List*', 'kms:Describe*', 'kms:CreateGrant'], + resources: [this.encryptionAtRestOptions.kmsKey.keyArn], + effect: iam.Effect.ALLOW, + })); + } + } else { + this.accessPolicy.addAccessPolicies(...accessPolicyStatements); + } + } + } } /** diff --git a/packages/@aws-cdk/aws-opensearchservice/lib/opensearch-access-policy.ts b/packages/@aws-cdk/aws-opensearchservice/lib/opensearch-access-policy.ts index 1eeb01fb95d78..b9e9acc3a37c6 100644 --- a/packages/@aws-cdk/aws-opensearchservice/lib/opensearch-access-policy.ts +++ b/packages/@aws-cdk/aws-opensearchservice/lib/opensearch-access-policy.ts @@ -1,9 +1,7 @@ import * as iam from '@aws-cdk/aws-iam'; +import * as cdk from '@aws-cdk/core'; import * as cr from '@aws-cdk/custom-resources'; - -// keep this import separate from other imports to reduce chance for merge conflicts with v2-main -// eslint-disable-next-line no-duplicate-imports, import/order -import { Construct } from '@aws-cdk/core'; +import { Construct } from 'constructs'; /** * Construction properties for OpenSearchAccessPolicy @@ -29,11 +27,10 @@ export interface OpenSearchAccessPolicyProps { * Creates LogGroup resource policies. */ export class OpenSearchAccessPolicy extends cr.AwsCustomResource { - constructor(scope: Construct, id: string, props: OpenSearchAccessPolicyProps) { - const policyDocument = new iam.PolicyDocument({ - statements: props.accessPolicies, - }); + private accessPolicyStatements: iam.PolicyStatement[] = []; + + constructor(scope: Construct, id: string, props: OpenSearchAccessPolicyProps) { super(scope, id, { resourceType: 'Custom::OpenSearchAccessPolicy', onUpdate: { @@ -41,7 +38,13 @@ export class OpenSearchAccessPolicy extends cr.AwsCustomResource { service: 'OpenSearch', parameters: { DomainName: props.domainName, - AccessPolicies: JSON.stringify(policyDocument.toJSON()), + AccessPolicies: cdk.Lazy.string({ + produce: () => JSON.stringify( + new iam.PolicyDocument({ + statements: this.accessPolicyStatements, + }).toJSON(), + ), + }), }, // this is needed to limit the response body, otherwise it exceeds the CFN 4k limit outputPaths: ['DomainConfig.AccessPolicies'], @@ -49,5 +52,14 @@ export class OpenSearchAccessPolicy extends cr.AwsCustomResource { }, policy: cr.AwsCustomResourcePolicy.fromStatements([new iam.PolicyStatement({ actions: ['es:UpdateDomainConfig'], resources: [props.domainArn] })]), }); + + this.addAccessPolicies(...props.accessPolicies); + } + + /** + * Add policy statements to the domain access policy + */ + public addAccessPolicies(...accessPolicyStatements: iam.PolicyStatement[]) { + this.accessPolicyStatements.push(...accessPolicyStatements); } } diff --git a/packages/@aws-cdk/aws-opensearchservice/package.json b/packages/@aws-cdk/aws-opensearchservice/package.json index f0d434006921e..1bece17b44f7a 100644 --- a/packages/@aws-cdk/aws-opensearchservice/package.json +++ b/packages/@aws-cdk/aws-opensearchservice/package.json @@ -89,7 +89,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", diff --git a/packages/@aws-cdk/aws-opensearchservice/test/domain.test.ts b/packages/@aws-cdk/aws-opensearchservice/test/domain.test.ts index 3739031d6f3b2..5ffcb3140c791 100644 --- a/packages/@aws-cdk/aws-opensearchservice/test/domain.test.ts +++ b/packages/@aws-cdk/aws-opensearchservice/test/domain.test.ts @@ -204,6 +204,66 @@ test('can enable version upgrade update policy', () => { }); }); +test('can set a self-referencing custom policy', () => { + const domain = new Domain(stack, 'Domain', { + version: defaultVersion, + }); + + domain.addAccessPolicies( + new iam.PolicyStatement({ + actions: ['es:ESHttpPost', 'es:ESHttpPut'], + effect: iam.Effect.ALLOW, + principals: [new iam.AccountPrincipal('5678')], + resources: [domain.domainArn, `${domain.domainArn}/*`], + }), + ); + + const expectedPolicy = { + 'Fn::Join': [ + '', + [ + '{"action":"updateDomainConfig","service":"OpenSearch","parameters":{"DomainName":"', + { + Ref: 'Domain66AC69E0', + }, + '","AccessPolicies":"{\\"Statement\\":[{\\"Action\\":[\\"es:ESHttpPost\\",\\"es:ESHttpPut\\"],\\"Effect\\":\\"Allow\\",\\"Principal\\":{\\"AWS\\":\\"arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::5678:root\\"},\\"Resource\\":[\\"', + { + 'Fn::GetAtt': [ + 'Domain66AC69E0', + 'Arn', + ], + }, + '\\",\\"', + { + 'Fn::GetAtt': [ + 'Domain66AC69E0', + 'Arn', + ], + }, + '/*\\"]}],\\"Version\\":\\"2012-10-17\\"}"},"outputPaths":["DomainConfig.AccessPolicies"],"physicalResourceId":{"id":"', + { + Ref: 'Domain66AC69E0', + }, + 'AccessPolicy"}}', + ], + ], + }; + Template.fromStack(stack).hasResourceProperties('Custom::OpenSearchAccessPolicy', { + ServiceToken: { + 'Fn::GetAtt': [ + 'AWS679f53fac002430cb0da5b7982bd22872D164C4C', + 'Arn', + ], + }, + Create: expectedPolicy, + Update: expectedPolicy, + }); +}); + describe('UltraWarm instances', () => { test('can enable UltraWarm instances', () => { diff --git a/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.custom-kms-key.expected.json b/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.custom-kms-key.expected.json index 63a1cb0c236d5..085298946af5d 100644 --- a/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.custom-kms-key.expected.json +++ b/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.custom-kms-key.expected.json @@ -39,8 +39,8 @@ "Type": "AWS::OpenSearchService::Domain", "Properties": { "ClusterConfig": { - "InstanceCount": 1, "DedicatedMasterEnabled": false, + "InstanceCount": 1, "InstanceType": "r5.large.search", "ZoneAwarenessEnabled": false }, @@ -53,14 +53,14 @@ }, "EBSOptions": { "EBSEnabled": true, - "VolumeType": "gp2", - "VolumeSize": 10 + "VolumeSize": 10, + "VolumeType": "gp2" }, "EncryptionAtRestOptions": { + "Enabled": true, "KmsKeyId": { "Ref": "Key961B73FD" - }, - "Enabled": true + } }, "EngineVersion": "Elasticsearch_7.1", "LogPublishingOptions": {}, @@ -71,7 +71,7 @@ "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, - "DomainAccessPolicyCustomResourcePolicy107E31EB": { + "DomainAccessPolicyCustomResourcePolicyE61F1845": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { @@ -89,18 +89,15 @@ ], "Version": "2012-10-17" }, - "PolicyName": "DomainAccessPolicyCustomResourcePolicy107E31EB", + "PolicyName": "DomainAccessPolicyCustomResourcePolicyE61F1845", "Roles": [ { "Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" } ] - }, - "DependsOn": [ - "Domain66AC69E0" - ] + } }, - "DomainAccessPolicyFCD6BE37": { + "DomainAccessPolicyEE735B04": { "Type": "Custom::OpenSearchAccessPolicy", "Properties": { "ServiceToken": { @@ -160,8 +157,7 @@ "InstallLatestAwsSdk": true }, "DependsOn": [ - "DomainAccessPolicyCustomResourcePolicy107E31EB", - "Domain66AC69E0" + "DomainAccessPolicyCustomResourcePolicyE61F1845" ], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" @@ -204,9 +200,9 @@ "Statement": [ { "Action": [ - "kms:List*", + "kms:CreateGrant", "kms:Describe*", - "kms:CreateGrant" + "kms:List*" ], "Effect": "Allow", "Resource": { @@ -232,7 +228,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16" }, "S3Key": { "Fn::Join": [ @@ -245,7 +241,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -258,7 +254,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -285,17 +281,17 @@ } }, "Parameters": { - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16": { "Type": "String", - "Description": "S3 bucket for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "S3 bucket for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B": { "Type": "String", - "Description": "S3 key for asset version \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "S3 key for asset version \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2ArtifactHash4BE92B79": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87ArtifactHash40DDF5EE": { "Type": "String", - "Description": "Artifact hash for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "Artifact hash for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.expected.json b/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.expected.json index da98a9b24ab35..50228805f44ea 100644 --- a/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.expected.json +++ b/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.expected.json @@ -22,12 +22,10 @@ "PolicyDocument": { "Statement": [ { - "Action": "logs:PutResourcePolicy", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "logs:DeleteResourcePolicy", + "Action": [ + "logs:DeleteResourcePolicy", + "logs:PutResourcePolicy" + ], "Effect": "Allow", "Resource": "*" } @@ -113,8 +111,8 @@ "indices.query.bool.max_clause_count": "2048" }, "ClusterConfig": { - "InstanceCount": 1, "DedicatedMasterEnabled": false, + "InstanceCount": 1, "InstanceType": "r5.large.search", "ZoneAwarenessEnabled": false }, @@ -127,8 +125,8 @@ }, "EBSOptions": { "EBSEnabled": true, - "VolumeType": "gp2", - "VolumeSize": 10 + "VolumeSize": 10, + "VolumeType": "gp2" }, "EncryptionAtRestOptions": { "Enabled": true @@ -165,7 +163,7 @@ "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, - "Domain1AccessPolicyCustomResourcePolicy3BDE9B82": { + "Domain1AccessPolicyCustomResourcePolicy3BA04487": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { @@ -183,18 +181,15 @@ ], "Version": "2012-10-17" }, - "PolicyName": "Domain1AccessPolicyCustomResourcePolicy3BDE9B82", + "PolicyName": "Domain1AccessPolicyCustomResourcePolicy3BA04487", "Roles": [ { "Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" } ] - }, - "DependsOn": [ - "Domain19FCBCB91" - ] + } }, - "Domain1AccessPolicy4A36C656": { + "Domain1AccessPolicy1FDDB3CF": { "Type": "Custom::OpenSearchAccessPolicy", "Properties": { "ServiceToken": { @@ -254,8 +249,7 @@ "InstallLatestAwsSdk": true }, "DependsOn": [ - "Domain1AccessPolicyCustomResourcePolicy3BDE9B82", - "Domain19FCBCB91" + "Domain1AccessPolicyCustomResourcePolicy3BA04487" ], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" @@ -296,7 +290,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16" }, "S3Key": { "Fn::Join": [ @@ -309,7 +303,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -322,7 +316,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -368,12 +362,10 @@ "PolicyDocument": { "Statement": [ { - "Action": "logs:PutResourcePolicy", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "logs:DeleteResourcePolicy", + "Action": [ + "logs:DeleteResourcePolicy", + "logs:PutResourcePolicy" + ], "Effect": "Allow", "Resource": "*" } @@ -459,8 +451,8 @@ "indices.query.bool.max_clause_count": "2048" }, "ClusterConfig": { - "InstanceCount": 1, "DedicatedMasterEnabled": false, + "InstanceCount": 1, "InstanceType": "r5.large.search", "ZoneAwarenessEnabled": false }, @@ -473,8 +465,8 @@ }, "EBSOptions": { "EBSEnabled": true, - "VolumeType": "gp2", - "VolumeSize": 10 + "VolumeSize": 10, + "VolumeType": "gp2" }, "EncryptionAtRestOptions": { "Enabled": true @@ -511,7 +503,7 @@ "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, - "Domain2AccessPolicyCustomResourcePolicy1FB37294": { + "Domain2AccessPolicyCustomResourcePolicy7C8260FD": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { @@ -529,18 +521,15 @@ ], "Version": "2012-10-17" }, - "PolicyName": "Domain2AccessPolicyCustomResourcePolicy1FB37294", + "PolicyName": "Domain2AccessPolicyCustomResourcePolicy7C8260FD", "Roles": [ { "Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" } ] - }, - "DependsOn": [ - "Domain2644FE48C" - ] + } }, - "Domain2AccessPolicy8AB4B908": { + "Domain2AccessPolicyB81CB6CE": { "Type": "Custom::OpenSearchAccessPolicy", "Properties": { "ServiceToken": { @@ -600,25 +589,24 @@ "InstallLatestAwsSdk": true }, "DependsOn": [ - "Domain2AccessPolicyCustomResourcePolicy1FB37294", - "Domain2644FE48C" + "Domain2AccessPolicyCustomResourcePolicy7C8260FD" ], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" } }, "Parameters": { - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16": { "Type": "String", - "Description": "S3 bucket for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "S3 bucket for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B": { "Type": "String", - "Description": "S3 key for asset version \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "S3 key for asset version \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2ArtifactHash4BE92B79": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87ArtifactHash40DDF5EE": { "Type": "String", - "Description": "Artifact hash for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "Artifact hash for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.unsignedbasicauth.expected.json b/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.unsignedbasicauth.expected.json index b1a9048f14dc1..e5b8703ab4b90 100644 --- a/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.unsignedbasicauth.expected.json +++ b/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.unsignedbasicauth.expected.json @@ -17,7 +17,9 @@ "Properties": { "AdvancedSecurityOptions": { "Enabled": true, + "InternalUserDatabaseEnabled": true, "MasterUserOptions": { + "MasterUserName": "admin", "MasterUserPassword": { "Fn::Join": [ "", @@ -29,14 +31,12 @@ ":SecretString:password::}}" ] ] - }, - "MasterUserName": "admin" - }, - "InternalUserDatabaseEnabled": true + } + } }, "ClusterConfig": { - "InstanceCount": 1, "DedicatedMasterEnabled": false, + "InstanceCount": 1, "InstanceType": "r5.large.search", "ZoneAwarenessEnabled": false }, @@ -49,8 +49,8 @@ }, "EBSOptions": { "EBSEnabled": true, - "VolumeType": "gp2", - "VolumeSize": 10 + "VolumeSize": 10, + "VolumeType": "gp2" }, "EncryptionAtRestOptions": { "Enabled": true @@ -64,7 +64,7 @@ "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, - "DomainAccessPolicyCustomResourcePolicy107E31EB": { + "DomainAccessPolicyCustomResourcePolicyE61F1845": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { @@ -82,18 +82,15 @@ ], "Version": "2012-10-17" }, - "PolicyName": "DomainAccessPolicyCustomResourcePolicy107E31EB", + "PolicyName": "DomainAccessPolicyCustomResourcePolicyE61F1845", "Roles": [ { "Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" } ] - }, - "DependsOn": [ - "Domain66AC69E0" - ] + } }, - "DomainAccessPolicyFCD6BE37": { + "DomainAccessPolicyEE735B04": { "Type": "Custom::OpenSearchAccessPolicy", "Properties": { "ServiceToken": { @@ -151,8 +148,7 @@ "InstallLatestAwsSdk": true }, "DependsOn": [ - "DomainAccessPolicyCustomResourcePolicy107E31EB", - "Domain66AC69E0" + "DomainAccessPolicyCustomResourcePolicyE61F1845" ], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" @@ -193,7 +189,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16" }, "S3Key": { "Fn::Join": [ @@ -206,7 +202,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -219,7 +215,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -245,17 +241,17 @@ } }, "Parameters": { - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16": { "Type": "String", - "Description": "S3 bucket for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "S3 bucket for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B": { "Type": "String", - "Description": "S3 key for asset version \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "S3 key for asset version \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2ArtifactHash4BE92B79": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87ArtifactHash40DDF5EE": { "Type": "String", - "Description": "Artifact hash for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "Artifact hash for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-opensearchservice/test/opensearch-access-policy.test.ts b/packages/@aws-cdk/aws-opensearchservice/test/opensearch-access-policy.test.ts index 6e449d3521adb..429cdca5a89cb 100644 --- a/packages/@aws-cdk/aws-opensearchservice/test/opensearch-access-policy.test.ts +++ b/packages/@aws-cdk/aws-opensearchservice/test/opensearch-access-policy.test.ts @@ -16,7 +16,7 @@ beforeEach(() => { test('minimal example renders correctly', () => { const domainArn = 'test:arn'; - new OpenSearchAccessPolicy(stack, 'ElasticsearchAccessPolicy', { + new OpenSearchAccessPolicy(stack, 'OpenSearchAccessPolicy', { domainName: 'TestDomain', domainArn: domainArn, accessPolicies: [new iam.PolicyStatement({ @@ -66,3 +66,55 @@ test('minimal example renders correctly', () => { }, }); }); + +test('support access policy added inline and later', () => { + const opensearchAccessPolicy = new OpenSearchAccessPolicy(stack, 'OpenSearchAccessPolicy', { + domainName: 'TestDomain', + domainArn: 'test:arn', + accessPolicies: [ + new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + actions: ['es:ESHttp*'], + principals: [new iam.AnyPrincipal()], + resources: ['test:arn'], + }), + ], + }); + opensearchAccessPolicy.addAccessPolicies( + new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + actions: ['*'], + principals: [new iam.AnyPrincipal()], + resources: ['test:arn'], + }), + ); + + Template.fromStack(stack).hasResourceProperties('Custom::OpenSearchAccessPolicy', { + ServiceToken: { + 'Fn::GetAtt': [ + 'AWS679f53fac002430cb0da5b7982bd22872D164C4C', + 'Arn', + ], + }, + Create: JSON.stringify({ + action: 'updateDomainConfig', + service: 'OpenSearch', + parameters: { + DomainName: 'TestDomain', + AccessPolicies: '{"Statement":[{"Action":"es:ESHttp*","Effect":"Allow","Principal":{"AWS":"*"},"Resource":"test:arn"},{"Action":"*","Effect":"Allow","Principal":{"AWS":"*"},"Resource":"test:arn"}],"Version":"2012-10-17"}', + }, + outputPaths: ['DomainConfig.AccessPolicies'], + physicalResourceId: { id: 'TestDomainAccessPolicy' }, + }), + Update: JSON.stringify({ + action: 'updateDomainConfig', + service: 'OpenSearch', + parameters: { + DomainName: 'TestDomain', + AccessPolicies: '{"Statement":[{"Action":"es:ESHttp*","Effect":"Allow","Principal":{"AWS":"*"},"Resource":"test:arn"},{"Action":"*","Effect":"Allow","Principal":{"AWS":"*"},"Resource":"test:arn"}],"Version":"2012-10-17"}', + }, + outputPaths: ['DomainConfig.AccessPolicies'], + physicalResourceId: { id: 'TestDomainAccessPolicy' }, + }), + }); +}); diff --git a/packages/@aws-cdk/aws-opsworks/package.json b/packages/@aws-cdk/aws-opsworks/package.json index 838ff7003ff62..011fa1d4d0790 100644 --- a/packages/@aws-cdk/aws-opsworks/package.json +++ b/packages/@aws-cdk/aws-opsworks/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-opsworkscm/package.json b/packages/@aws-cdk/aws-opsworkscm/package.json index 1220456e3ff0b..f429f37979df0 100644 --- a/packages/@aws-cdk/aws-opsworkscm/package.json +++ b/packages/@aws-cdk/aws-opsworkscm/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-panorama/package.json b/packages/@aws-cdk/aws-panorama/package.json index 37658a09b0c61..f766e427bbffd 100644 --- a/packages/@aws-cdk/aws-panorama/package.json +++ b/packages/@aws-cdk/aws-panorama/package.json @@ -95,7 +95,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-personalize/.eslintrc.js b/packages/@aws-cdk/aws-personalize/.eslintrc.js new file mode 100644 index 0000000000000..2658ee8727166 --- /dev/null +++ b/packages/@aws-cdk/aws-personalize/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-personalize/.gitignore b/packages/@aws-cdk/aws-personalize/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-personalize/.gitignore @@ -0,0 +1,19 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk +nyc.config.js +!.eslintrc.js +!jest.config.js +junit.xml diff --git a/packages/@aws-cdk/aws-personalize/.npmignore b/packages/@aws-cdk/aws-personalize/.npmignore new file mode 100644 index 0000000000000..f931fede67c44 --- /dev/null +++ b/packages/@aws-cdk/aws-personalize/.npmignore @@ -0,0 +1,29 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json + +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml +test/ +!*.lit.ts diff --git a/packages/@aws-cdk/aws-personalize/LICENSE b/packages/@aws-cdk/aws-personalize/LICENSE new file mode 100644 index 0000000000000..82ad00bb02d0b --- /dev/null +++ b/packages/@aws-cdk/aws-personalize/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/aws-personalize/NOTICE b/packages/@aws-cdk/aws-personalize/NOTICE new file mode 100644 index 0000000000000..1b7adbb891265 --- /dev/null +++ b/packages/@aws-cdk/aws-personalize/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-personalize/README.md b/packages/@aws-cdk/aws-personalize/README.md new file mode 100644 index 0000000000000..7a5d42638c5b5 --- /dev/null +++ b/packages/@aws-cdk/aws-personalize/README.md @@ -0,0 +1,31 @@ +# AWS::Personalize Construct Library + + +--- + +![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge) + +> All classes with the `Cfn` prefix in this module ([CFN Resources]) are always stable and safe to use. +> +> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib + +--- + + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as personalize from '@aws-cdk/aws-personalize'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Personalize](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Personalize.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-personalize/jest.config.js b/packages/@aws-cdk/aws-personalize/jest.config.js new file mode 100644 index 0000000000000..3a2fd93a1228a --- /dev/null +++ b/packages/@aws-cdk/aws-personalize/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-personalize/lib/index.ts b/packages/@aws-cdk/aws-personalize/lib/index.ts new file mode 100644 index 0000000000000..a573bd0456934 --- /dev/null +++ b/packages/@aws-cdk/aws-personalize/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::Personalize CloudFormation Resources: +export * from './personalize.generated'; diff --git a/packages/@aws-cdk/aws-personalize/package.json b/packages/@aws-cdk/aws-personalize/package.json new file mode 100644 index 0000000000000..8448bece3402f --- /dev/null +++ b/packages/@aws-cdk/aws-personalize/package.json @@ -0,0 +1,110 @@ +{ + "name": "@aws-cdk/aws-personalize", + "version": "0.0.0", + "description": "AWS::Personalize Construct Library", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.Personalize", + "packageId": "Amazon.CDK.AWS.Personalize", + "signAssembly": true, + "assemblyOriginatorKeyFile": "../../key.snk", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "java": { + "package": "software.amazon.awscdk.services.personalize", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "personalize" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-personalize", + "module": "aws_cdk.aws_personalize" + } + }, + "metadata": { + "jsii": { + "rosetta": { + "strict": true + } + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-personalize" + }, + "homepage": "https://github.com/aws/aws-cdk", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "cfn2ts": "cfn2ts", + "build+test": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "gen": "cfn2ts", + "rosetta:extract": "yarn --silent jsii-rosetta extract", + "build+extract": "yarn build && yarn rosetta:extract", + "build+test+extract": "yarn build+test && yarn rosetta:extract" + }, + "cdk-build": { + "cloudformation": "AWS::Personalize", + "jest": true, + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::Personalize", + "aws-personalize" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^27.4.1" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "experimental", + "maturity": "cfn-only", + "awscdkio": { + "announce": false + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-personalize/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-personalize/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..e208762bca03c --- /dev/null +++ b/packages/@aws-cdk/aws-personalize/rosetta/default.ts-fixture @@ -0,0 +1,8 @@ +import { Construct } from 'constructs'; +import { Stack } from '@aws-cdk/core'; + +class MyStack extends Stack { + constructor(scope: Construct, id: string) { + /// here + } +} diff --git a/packages/@aws-cdk/aws-personalize/test/personalize.test.ts b/packages/@aws-cdk/aws-personalize/test/personalize.test.ts new file mode 100644 index 0000000000000..465c7bdea0693 --- /dev/null +++ b/packages/@aws-cdk/aws-personalize/test/personalize.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assertions'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-pinpoint/package.json b/packages/@aws-cdk/aws-pinpoint/package.json index 30801027c4e06..b4f9c8565e526 100644 --- a/packages/@aws-cdk/aws-pinpoint/package.json +++ b/packages/@aws-cdk/aws-pinpoint/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-pinpointemail/package.json b/packages/@aws-cdk/aws-pinpointemail/package.json index 26486ee72627b..3c51a3c74abd1 100644 --- a/packages/@aws-cdk/aws-pinpointemail/package.json +++ b/packages/@aws-cdk/aws-pinpointemail/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-qldb/package.json b/packages/@aws-cdk/aws-qldb/package.json index a35637354c0c1..9e4e6e0c90ac0 100644 --- a/packages/@aws-cdk/aws-qldb/package.json +++ b/packages/@aws-cdk/aws-qldb/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-quicksight/package.json b/packages/@aws-cdk/aws-quicksight/package.json index 270c171d3b5cb..79d41343ab08b 100644 --- a/packages/@aws-cdk/aws-quicksight/package.json +++ b/packages/@aws-cdk/aws-quicksight/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-ram/package.json b/packages/@aws-cdk/aws-ram/package.json index 1064bb16fc89f..ddf8049356491 100644 --- a/packages/@aws-cdk/aws-ram/package.json +++ b/packages/@aws-cdk/aws-ram/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-rds/README.md b/packages/@aws-cdk/aws-rds/README.md index d97acee7ec616..2cd840e202504 100644 --- a/packages/@aws-cdk/aws-rds/README.md +++ b/packages/@aws-cdk/aws-rds/README.md @@ -326,6 +326,8 @@ You can also authenticate to a database instance using AWS Identity and Access M See for more information and a list of supported versions and limitations. +**Note**: `grantConnect()` does not currently work - see [this GitHub issue](https://github.com/aws/aws-cdk/issues/11851). + The following example shows enabling IAM authentication for a database instance and granting connection access to an IAM role. ```ts @@ -527,6 +529,51 @@ new rds.OptionGroup(this, 'Options', { }); ``` +## Parameter Groups + +Database parameters specify how the database is configured. +For example, database parameters can specify the amount of resources, such as memory, to allocate to a database. +You manage your database configuration by associating your DB instances with parameter groups. +Amazon RDS defines parameter groups with default settings. + +You can create your own parameter group for your cluster or instance and associate it with your database: + +```ts +declare const vpc: ec2.Vpc; + +const parameterGroup = new rds.ParameterGroup(this, 'ParameterGroup', { + engine: rds.DatabaseInstanceEngine.sqlServerEe({ + version: rds.SqlServerEngineVersion.VER_11, + }), + parameters: { + locks: '100', + }, +}); + +new rds.DatabaseInstance(this, 'Database', { + engine: rds.DatabaseInstanceEngine.SQL_SERVER_EE, + vpc, + parameterGroup, +}); +``` + +Another way to specify parameters is to use the inline field `parameters` that creates an RDS parameter group for you. +You can use this if you do not want to reuse the parameter group instance for different instances: + +```ts +declare const vpc: ec2.Vpc; + +new rds.DatabaseInstance(this, 'Database', { + engine: rds.DatabaseInstanceEngine.sqlServerEe({ version: rds.SqlServerEngineVersion.VER_11 }), + vpc, + parameters: { + locks: '100', + }, +}); +``` + +You cannot specify a parameter map and a parameter group at the same time. + ## Serverless [Amazon Aurora Serverless](https://aws.amazon.com/rds/aurora/serverless/) is an on-demand, auto-scaling configuration for Amazon @@ -594,7 +641,7 @@ declare const vpc: ec2.Vpc; const cluster = new rds.ServerlessCluster(this, 'AnotherCluster', { engine: rds.DatabaseClusterEngine.AURORA_MYSQL, - vpc, + vpc, // this parameter is optional for serverless Clusters enableDataApi: true, // Optional - will be automatically set if you call grantDataApiAccess() }); @@ -614,3 +661,11 @@ cluster.grantDataApiAccess(fn); **Note**: To invoke the Data API, the resource will need to read the secret associated with the cluster. To learn more about using the Data API, see the [documentation](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html). + +### Default VPC + +The `vpc` parameter is optional. + +If not provided, the cluster will be created in the default VPC of the account and region. +As this VPC is not deployed with AWS CDK, you can't configure the `vpcSubnets`, `subnetGroup` or `securityGroups` of the Aurora Serverless Cluster. +If you want to provide one of `vpcSubnets`, `subnetGroup` or `securityGroups` parameter, please provide a `vpc`. diff --git a/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts b/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts index d8d5c91f41507..65e7ed6496e97 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts @@ -177,7 +177,11 @@ abstract class MySqlClusterEngineBase extends ClusterEngineBase { }) : config.parameterGroup); if (options.s3ImportRole) { - parameterGroup?.addParameter('aurora_load_from_s3_role', options.s3ImportRole.roleArn); + // major version 8.0 uses a different name for the S3 import parameter + const s3ImportParam = this.engineVersion?.majorVersion === '8.0' + ? 'aws_default_s3_role' + : 'aurora_load_from_s3_role'; + parameterGroup?.addParameter(s3ImportParam, options.s3ImportRole.roleArn); } if (options.s3ExportRole) { parameterGroup?.addParameter('aurora_select_into_s3_role', options.s3ExportRole.roleArn); @@ -340,6 +344,8 @@ export class AuroraMysqlEngineVersion { public static readonly VER_2_10_0 = AuroraMysqlEngineVersion.builtIn_5_7('2.10.0'); /** Version "5.7.mysql_aurora.2.10.1". */ public static readonly VER_2_10_1 = AuroraMysqlEngineVersion.builtIn_5_7('2.10.1'); + /** Version "5.7.mysql_aurora.2.10.2". */ + public static readonly VER_2_10_2 = AuroraMysqlEngineVersion.builtIn_5_7('2.10.2'); /** Version "8.0.mysql_aurora.3.01.0". */ public static readonly VER_3_01_0 = AuroraMysqlEngineVersion.builtIn_8_0('3.01.0'); diff --git a/packages/@aws-cdk/aws-rds/lib/cluster.ts b/packages/@aws-cdk/aws-rds/lib/cluster.ts index 7324cacb333c2..5ac2ce91e652a 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster.ts @@ -10,8 +10,8 @@ import { Construct } from 'constructs'; import { IClusterEngine } from './cluster-engine'; import { DatabaseClusterAttributes, IDatabaseCluster } from './cluster-ref'; import { Endpoint } from './endpoint'; -import { IParameterGroup } from './parameter-group'; -import { DEFAULT_PASSWORD_EXCLUDE_CHARS, defaultDeletionProtection, renderCredentials, setupS3ImportExport, helperRemovalPolicy, renderUnless } from './private/util'; +import { IParameterGroup, ParameterGroup } from './parameter-group'; +import { applyDefaultRotationOptions, defaultDeletionProtection, renderCredentials, setupS3ImportExport, helperRemovalPolicy, renderUnless } from './private/util'; import { BackupProps, Credentials, InstanceProps, PerformanceInsightRetention, RotationSingleUserOptions, RotationMultiUserOptions } from './props'; import { DatabaseProxy, DatabaseProxyOptions, ProxyTarget } from './proxy'; import { CfnDBCluster, CfnDBClusterProps, CfnDBInstance } from './rds.generated'; @@ -116,6 +116,16 @@ interface DatabaseClusterBaseProps { */ readonly parameterGroup?: IParameterGroup; + /** + * The parameters in the DBClusterParameterGroup to create automatically + * + * You can only specify parameterGroup or parameters but not both. + * You need to use a versioned engine to auto-generate a DBClusterParameterGroup. + * + * @default - None + */ + readonly parameters?: { [key: string]: string }; + /** * The removal policy to apply when the cluster and its instances are removed * from the stack or replaced during an update. @@ -240,6 +250,21 @@ interface DatabaseClusterBaseProps { * @default false */ readonly iamAuthentication?: boolean; + + /** + * Whether to enable storage encryption. + * + * @default - true if storageEncryptionKey is provided, false otherwise + */ + readonly storageEncrypted?: boolean + + /** + * The KMS key for storage encryption. + * If specified, {@link storageEncrypted} will be set to `true`. + * + * @default - if storageEncrypted is true then the default master key, no key otherwise + */ + readonly storageEncryptionKey?: kms.IKey; } /** @@ -338,11 +363,23 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { ]; let { s3ImportRole, s3ExportRole } = setupS3ImportExport(this, props, /* combineRoles */ false); + + if (props.parameterGroup && props.parameters) { + throw new Error('You cannot specify both parameterGroup and parameters'); + } + const parameterGroup = props.parameterGroup ?? ( + props.parameters + ? new ParameterGroup(this, 'ParameterGroup', { + engine: props.engine, + parameters: props.parameters, + }) + : undefined + ); // bind the engine to the Cluster const clusterEngineBindConfig = props.engine.bindToCluster(this, { s3ImportRole, s3ExportRole, - parameterGroup: props.parameterGroup, + parameterGroup, }); const clusterAssociatedRoles: CfnDBCluster.DBClusterRoleProperty[] = []; @@ -380,6 +417,9 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { preferredMaintenanceWindow: props.preferredMaintenanceWindow, databaseName: props.defaultDatabaseName, enableCloudwatchLogsExports: props.cloudwatchLogsExports, + // Encryption + kmsKeyId: props.storageEncryptionKey?.keyArn, + storageEncrypted: props.storageEncryptionKey ? true : props.storageEncrypted, }; } } @@ -457,21 +497,6 @@ export interface DatabaseClusterProps extends DatabaseClusterBaseProps { */ readonly credentials?: Credentials; - /** - * Whether to enable storage encryption. - * - * @default - true if storageEncryptionKey is provided, false otherwise - */ - readonly storageEncrypted?: boolean - - /** - * The KMS key for storage encryption. - * If specified, {@link storageEncrypted} will be set to `true`. - * - * @default - if storageEncrypted is true then the default master key, no key otherwise - */ - readonly storageEncryptionKey?: kms.IKey; - /** * Whether to copy tags to the snapshot when a snapshot is created. * @@ -528,9 +553,7 @@ export class DatabaseCluster extends DatabaseClusterNew { // Admin masterUsername: credentials.username, masterUserPassword: credentials.password?.toString(), - // Encryption - kmsKeyId: props.storageEncryptionKey?.keyArn, - storageEncrypted: props.storageEncryptionKey ? true : props.storageEncrypted, + // Tags copyTagsToSnapshot: props.copyTagsToSnapshot ?? true, }); @@ -572,13 +595,11 @@ export class DatabaseCluster extends DatabaseClusterNew { } return new secretsmanager.SecretRotation(this, id, { + ...applyDefaultRotationOptions(options, this.vpcSubnets), secret: this.secret, application: this.singleUserRotationApplication, vpc: this.vpc, - vpcSubnets: this.vpcSubnets, target: this, - ...options, - excludeCharacters: options.excludeCharacters ?? DEFAULT_PASSWORD_EXCLUDE_CHARS, }); } @@ -589,13 +610,13 @@ export class DatabaseCluster extends DatabaseClusterNew { if (!this.secret) { throw new Error('Cannot add multi user rotation for a cluster without secret.'); } + return new secretsmanager.SecretRotation(this, id, { - ...options, - excludeCharacters: options.excludeCharacters ?? DEFAULT_PASSWORD_EXCLUDE_CHARS, + ...applyDefaultRotationOptions(options, this.vpcSubnets), + secret: options.secret, masterSecret: this.secret, application: this.multiUserRotationApplication, vpc: this.vpc, - vpcSubnets: this.vpcSubnets, target: this, }); } @@ -722,7 +743,21 @@ function createInstances(cluster: DatabaseClusterNew, props: DatabaseClusterBase } const instanceType = instanceProps.instanceType ?? ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MEDIUM); - const instanceParameterGroupConfig = instanceProps.parameterGroup?.bindToInstance({}); + + if (instanceProps.parameterGroup && instanceProps.parameters) { + throw new Error('You cannot specify both parameterGroup and parameters'); + } + + const instanceParameterGroup = instanceProps.parameterGroup ?? ( + instanceProps.parameters + ? new ParameterGroup(cluster, 'InstanceParameterGroup', { + engine: props.engine, + parameters: instanceProps.parameters, + }) + : undefined + ); + const instanceParameterGroupConfig = instanceParameterGroup?.bindToInstance({}); + for (let i = 0; i < instanceCount; i++) { const instanceIndex = i + 1; const instanceIdentifier = props.instanceIdentifierBase != null ? `${props.instanceIdentifierBase}${instanceIndex}` : diff --git a/packages/@aws-cdk/aws-rds/lib/instance-engine.ts b/packages/@aws-cdk/aws-rds/lib/instance-engine.ts index 01f2f62d7a4da..fd84f6fd17444 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance-engine.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance-engine.ts @@ -492,6 +492,12 @@ export class MysqlEngineVersion { public static readonly VER_5_7_33 = MysqlEngineVersion.of('5.7.33', '5.7'); /** Version "5.7.34". */ public static readonly VER_5_7_34 = MysqlEngineVersion.of('5.7.34', '5.7'); + /** Version "5.7.35". */ + public static readonly VER_5_7_35 = MysqlEngineVersion.of('5.7.35', '5.7'); + /** Version "5.7.36". */ + public static readonly VER_5_7_36 = MysqlEngineVersion.of('5.7.36', '5.7'); + /** Version "5.7.37". */ + public static readonly VER_5_7_37 = MysqlEngineVersion.of('5.7.37', '5.7'); /** Version "8.0" (only a major version, without a specific minor version). */ public static readonly VER_8_0 = MysqlEngineVersion.of('8.0', '8.0'); @@ -517,6 +523,10 @@ export class MysqlEngineVersion { public static readonly VER_8_0_25 = MysqlEngineVersion.of('8.0.25', '8.0'); /** Version "8.0.26". */ public static readonly VER_8_0_26 = MysqlEngineVersion.of('8.0.26', '8.0'); + /** Version "8.0.27". */ + public static readonly VER_8_0_27 = MysqlEngineVersion.of('8.0.27', '8.0'); + /** Version "8.0.28". */ + public static readonly VER_8_0_28 = MysqlEngineVersion.of('8.0.28', '8.0'); /** * Create a new MysqlEngineVersion with an arbitrary version. @@ -841,6 +851,8 @@ export class PostgresEngineVersion { public static readonly VER_10_18 = PostgresEngineVersion.of('10.18', '10', { s3Import: true, s3Export: true }); /** Version "10.19". */ public static readonly VER_10_19 = PostgresEngineVersion.of('10.19', '10', { s3Import: true, s3Export: true }); + /** Version "10.20". */ + public static readonly VER_10_20 = PostgresEngineVersion.of('10.20', '10', { s3Import: true, s3Export: true }); /** Version "11" (only a major version, without a specific minor version). */ public static readonly VER_11 = PostgresEngineVersion.of('11', '11', { s3Import: true }); @@ -870,6 +882,8 @@ export class PostgresEngineVersion { public static readonly VER_11_13 = PostgresEngineVersion.of('11.13', '11', { s3Import: true, s3Export: true }); /** Version "11.14". */ public static readonly VER_11_14 = PostgresEngineVersion.of('11.14', '11', { s3Import: true, s3Export: true }); + /** Version "11.15". */ + public static readonly VER_11_15 = PostgresEngineVersion.of('11.15', '11', { s3Import: true, s3Export: true }); /** Version "12" (only a major version, without a specific minor version). */ public static readonly VER_12 = PostgresEngineVersion.of('12', '12', { s3Import: true }); @@ -889,6 +903,8 @@ export class PostgresEngineVersion { public static readonly VER_12_8 = PostgresEngineVersion.of('12.8', '12', { s3Import: true, s3Export: true }); /** Version "12.9". */ public static readonly VER_12_9 = PostgresEngineVersion.of('12.9', '12', { s3Import: true, s3Export: true }); + /** Version "12.10". */ + public static readonly VER_12_10 = PostgresEngineVersion.of('12.10', '12', { s3Import: true, s3Export: true }); /** Version "13" (only a major version, without a specific minor version). */ public static readonly VER_13 = PostgresEngineVersion.of('13', '13', { s3Import: true, s3Export: true }); @@ -902,11 +918,15 @@ export class PostgresEngineVersion { public static readonly VER_13_4 = PostgresEngineVersion.of('13.4', '13', { s3Import: true, s3Export: true }); /** Version "13.5". */ public static readonly VER_13_5 = PostgresEngineVersion.of('13.5', '13', { s3Import: true, s3Export: true }); + /** Version "13.6". */ + public static readonly VER_13_6 = PostgresEngineVersion.of('13.6', '13', { s3Import: true, s3Export: true }); /** Version "14" (only a major version, without a specific minor version). */ public static readonly VER_14 = PostgresEngineVersion.of('14', '14', { s3Import: true, s3Export: true }); /** Version "14.1". */ public static readonly VER_14_1 = PostgresEngineVersion.of('14.1', '14', { s3Import: true, s3Export: true }); + /** Version "14.2". */ + public static readonly VER_14_2 = PostgresEngineVersion.of('14.2', '14', { s3Import: true, s3Export: true }); /** * Create a new PostgresEngineVersion with an arbitrary version. diff --git a/packages/@aws-cdk/aws-rds/lib/instance.ts b/packages/@aws-cdk/aws-rds/lib/instance.ts index 10467e0b19390..fd4d10ae7afbd 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance.ts @@ -12,8 +12,8 @@ import { DatabaseSecret } from './database-secret'; import { Endpoint } from './endpoint'; import { IInstanceEngine } from './instance-engine'; import { IOptionGroup } from './option-group'; -import { IParameterGroup } from './parameter-group'; -import { DEFAULT_PASSWORD_EXCLUDE_CHARS, defaultDeletionProtection, engineDescription, renderCredentials, setupS3ImportExport, helperRemovalPolicy, renderUnless } from './private/util'; +import { IParameterGroup, ParameterGroup } from './parameter-group'; +import { applyDefaultRotationOptions, defaultDeletionProtection, engineDescription, renderCredentials, setupS3ImportExport, helperRemovalPolicy, renderUnless } from './private/util'; import { Credentials, PerformanceInsightRetention, RotationMultiUserOptions, RotationSingleUserOptions, SnapshotCredentials } from './props'; import { DatabaseProxy, DatabaseProxyOptions, ProxyTarget } from './proxy'; import { CfnDBInstance, CfnDBInstanceProps } from './rds.generated'; @@ -66,6 +66,8 @@ export interface IDatabaseInstance extends IResource, ec2.IConnectable, secretsm /** * Grant the given identity connection access to the database. + * **Note**: this method does not currently work, see https://github.com/aws/aws-cdk/issues/11851 for details. + * @see https://github.com/aws/aws-cdk/issues/11851 */ grantConnect(grantee: iam.IGrantable): iam.Grant; @@ -822,6 +824,16 @@ export interface DatabaseInstanceSourceProps extends DatabaseInstanceNewProps { * @default - no name */ readonly databaseName?: string; + + /** + * The parameters in the DBParameterGroup to create automatically + * + * You can only specify parameterGroup or parameters but not both. + * You need to use a versioned engine to auto-generate a DBParameterGroup. + * + * @default - None + */ + readonly parameters?: { [key: string]: string }; } /** @@ -877,6 +889,17 @@ abstract class DatabaseInstanceSource extends DatabaseInstanceNew implements IDa this.instanceType = props.instanceType ?? ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.LARGE); + if (props.parameterGroup && props.parameters) { + throw new Error('You cannot specify both parameterGroup and parameters'); + } + + const dbParameterGroupName = props.parameters + ? new ParameterGroup(this, 'ParameterGroup', { + engine: props.engine, + parameters: props.parameters, + }).bindToInstance({}).parameterGroupName + : this.newCfnProps.dbParameterGroupName; + this.sourceCfnProps = { ...this.newCfnProps, associatedRoles: instanceAssociatedRoles.length > 0 ? instanceAssociatedRoles : undefined, @@ -888,6 +911,7 @@ abstract class DatabaseInstanceSource extends DatabaseInstanceNew implements IDa engineVersion: props.engine.engineVersion?.fullVersion, licenseModel: props.licenseModel, timezone: props.timezone, + dbParameterGroupName, }; } @@ -909,13 +933,11 @@ abstract class DatabaseInstanceSource extends DatabaseInstanceNew implements IDa } return new secretsmanager.SecretRotation(this, id, { + ...applyDefaultRotationOptions(options, this.vpcPlacement), secret: this.secret, application: this.singleUserRotationApplication, vpc: this.vpc, - vpcSubnets: this.vpcPlacement, target: this, - ...options, - excludeCharacters: options.excludeCharacters ?? DEFAULT_PASSWORD_EXCLUDE_CHARS, }); } @@ -926,13 +948,13 @@ abstract class DatabaseInstanceSource extends DatabaseInstanceNew implements IDa if (!this.secret) { throw new Error('Cannot add multi user rotation for an instance without secret.'); } + return new secretsmanager.SecretRotation(this, id, { - ...options, - excludeCharacters: options.excludeCharacters ?? DEFAULT_PASSWORD_EXCLUDE_CHARS, + ...applyDefaultRotationOptions(options, this.vpcPlacement), + secret: options.secret, masterSecret: this.secret, application: this.multiUserRotationApplication, vpc: this.vpc, - vpcSubnets: this.vpcPlacement, target: this, }); } @@ -1149,12 +1171,18 @@ export class DatabaseInstanceReadReplica extends DatabaseInstanceNew implements throw new Error(`Cannot set 'backupRetention', as engine '${engineDescription(props.sourceDatabaseInstance.engine)}' does not support automatic backups for read replicas`); } + // The read replica instance always uses the same engine as the source instance + // but some CF validations require the engine to be explicitely passed when some + // properties are specified. + const shouldPassEngine = props.domain != null; + const instance = new CfnDBInstance(this, 'Resource', { ...this.newCfnProps, // this must be ARN, not ID, because of https://github.com/terraform-providers/terraform-provider-aws/issues/528#issuecomment-391169012 sourceDbInstanceIdentifier: props.sourceDatabaseInstance.instanceArn, kmsKeyId: props.storageEncryptionKey?.keyArn, storageEncrypted: props.storageEncryptionKey ? true : props.storageEncrypted, + engine: shouldPassEngine ? props.sourceDatabaseInstance.engine?.engineType : undefined, }); this.instanceType = props.instanceType; diff --git a/packages/@aws-cdk/aws-rds/lib/private/util.ts b/packages/@aws-cdk/aws-rds/lib/private/util.ts index 1664647c92bd8..729744a911eaf 100644 --- a/packages/@aws-cdk/aws-rds/lib/private/util.ts +++ b/packages/@aws-cdk/aws-rds/lib/private/util.ts @@ -1,9 +1,10 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import { RemovalPolicy } from '@aws-cdk/core'; import { DatabaseSecret } from '../database-secret'; import { IEngine } from '../engine'; -import { Credentials } from '../props'; +import { CommonRotationUserOptions, Credentials } from '../props'; // keep this import separate from other imports to reduce chance for merge conflicts with v2-main // eslint-disable-next-line no-duplicate-imports, import/order @@ -134,3 +135,14 @@ export function helperRemovalPolicy(basePolicy?: RemovalPolicy): RemovalPolicy { export function renderUnless(value: A, suppressValue: A): A | undefined { return value === suppressValue ? undefined : value; } + +/** + * Applies defaults for rotation options + */ +export function applyDefaultRotationOptions(options: CommonRotationUserOptions, defaultvpcSubnets?: ec2.SubnetSelection): CommonRotationUserOptions { + return { + excludeCharacters: DEFAULT_PASSWORD_EXCLUDE_CHARS, + vpcSubnets: defaultvpcSubnets, + ...options, + }; +} diff --git a/packages/@aws-cdk/aws-rds/lib/props.ts b/packages/@aws-cdk/aws-rds/lib/props.ts index 4a8883df504e3..6338fa0368849 100644 --- a/packages/@aws-cdk/aws-rds/lib/props.ts +++ b/packages/@aws-cdk/aws-rds/lib/props.ts @@ -43,6 +43,16 @@ export interface InstanceProps { */ readonly parameterGroup?: IParameterGroup; + /** + * The parameters in the DBParameterGroup to create automatically + * + * You can only specify parameterGroup or parameters but not both. + * You need to use a versioned engine to auto-generate a DBParameterGroup. + * + * @default - None + */ + readonly parameters?: { [key: string]: string }; + /** * Whether to enable Performance Insights for the DB instance. * @@ -446,7 +456,7 @@ export abstract class SnapshotCredentials { /** * Properties common to single-user and multi-user rotation options. */ -interface CommonRotationUserOptions { +export interface CommonRotationUserOptions { /** * Specifies the number of days after the previous rotation * before Secrets Manager triggers the next automatic rotation. diff --git a/packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts b/packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts index 0365bfd98c9e9..4e8aa6d46597d 100644 --- a/packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts +++ b/packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts @@ -10,7 +10,7 @@ import { DatabaseSecret } from './database-secret'; import { Endpoint } from './endpoint'; import { IParameterGroup } from './parameter-group'; import { DATA_API_ACTIONS } from './perms'; -import { defaultDeletionProtection, DEFAULT_PASSWORD_EXCLUDE_CHARS, renderCredentials } from './private/util'; +import { applyDefaultRotationOptions, defaultDeletionProtection, renderCredentials } from './private/util'; import { Credentials, RotationMultiUserOptions, RotationSingleUserOptions, SnapshotCredentials } from './props'; import { CfnDBCluster, CfnDBClusterProps } from './rds.generated'; import { ISubnetGroup, SubnetGroup } from './subnet-group'; @@ -99,11 +99,14 @@ interface ServerlessClusterNewProps { /** * The VPC that this Aurora Serverless cluster has been created in. + * + * @default - the default VPC in the account and region will be used */ - readonly vpc: ec2.IVpc; + readonly vpc?: ec2.IVpc; /** - * Where to place the instances within the VPC + * Where to place the instances within the VPC. + * If provided, the `vpc` property must also be specified. * * @default - the VPC default strategy if not specified. */ @@ -129,7 +132,8 @@ interface ServerlessClusterNewProps { /** * Security group. * - * @default - a new security group is created. + * @default - a new security group is created if `vpc` was provided. + * If the `vpc` property was not provided, no VPC security groups will be associated with the DB cluster. */ readonly securityGroups?: ec2.ISecurityGroup[]; @@ -143,7 +147,8 @@ interface ServerlessClusterNewProps { /** * Existing subnet group for the cluster. * - * @default - a new subnet group will be created. + * @default - a new subnet group is created if `vpc` was provided. + * If the `vpc` property was not provided, no subnet group will be associated with the DB cluster */ readonly subnetGroup?: ISubnetGroup; } @@ -351,19 +356,42 @@ abstract class ServerlessClusterNew extends ServerlessClusterBase { constructor(scope: Construct, id: string, props: ServerlessClusterNewProps) { super(scope, id); - const { subnetIds } = props.vpc.selectSubnets(props.vpcSubnets); - - // Cannot test whether the subnets are in different AZs, but at least we can test the amount. - if (subnetIds.length < 2) { - Annotations.of(this).addError(`Cluster requires at least 2 subnets, got ${subnetIds.length}`); + if (props.vpc === undefined) { + if (props.vpcSubnets !== undefined) { + throw new Error('A VPC is required to use vpcSubnets in ServerlessCluster. Please add a VPC or remove vpcSubnets'); + } + if (props.subnetGroup !== undefined) { + throw new Error('A VPC is required to use subnetGroup in ServerlessCluster. Please add a VPC or remove subnetGroup'); + } + if (props.securityGroups !== undefined) { + throw new Error('A VPC is required to use securityGroups in ServerlessCluster. Please add a VPC or remove securityGroups'); + } } - const subnetGroup = props.subnetGroup ?? new SubnetGroup(this, 'Subnets', { - description: `Subnets for ${id} database`, - vpc: props.vpc, - vpcSubnets: props.vpcSubnets, - removalPolicy: props.removalPolicy === RemovalPolicy.RETAIN ? props.removalPolicy : undefined, - }); + let subnetGroup: ISubnetGroup | undefined = props.subnetGroup; + this.securityGroups = props.securityGroups ?? []; + if (props.vpc !== undefined) { + const { subnetIds } = props.vpc.selectSubnets(props.vpcSubnets); + + // Cannot test whether the subnets are in different AZs, but at least we can test the amount. + if (subnetIds.length < 2) { + Annotations.of(this).addError(`Cluster requires at least 2 subnets, got ${subnetIds.length}`); + } + + subnetGroup = props.subnetGroup ?? new SubnetGroup(this, 'Subnets', { + description: `Subnets for ${id} database`, + vpc: props.vpc, + vpcSubnets: props.vpcSubnets, + removalPolicy: props.removalPolicy === RemovalPolicy.RETAIN ? props.removalPolicy : undefined, + }); + + this.securityGroups = props.securityGroups ?? [ + new ec2.SecurityGroup(this, 'SecurityGroup', { + description: 'RDS security group', + vpc: props.vpc, + }), + ]; + } if (props.backupRetention) { const backupRetentionDays = props.backupRetention.toDays(); @@ -379,12 +407,6 @@ abstract class ServerlessClusterNew extends ServerlessClusterBase { const clusterParameterGroup = props.parameterGroup ?? clusterEngineBindConfig.parameterGroup; const clusterParameterGroupConfig = clusterParameterGroup?.bindToCluster({}); - this.securityGroups = props.securityGroups ?? [ - new ec2.SecurityGroup(this, 'SecurityGroup', { - description: 'RDS security group', - vpc: props.vpc, - }), - ]; const clusterIdentifier = FeatureFlags.of(this).isEnabled(cxapi.RDS_LOWERCASE_DB_IDENTIFIER) ? props.clusterIdentifier?.toLowerCase() @@ -395,7 +417,7 @@ abstract class ServerlessClusterNew extends ServerlessClusterBase { databaseName: props.defaultDatabaseName, dbClusterIdentifier: clusterIdentifier, dbClusterParameterGroupName: clusterParameterGroupConfig?.parameterGroupName, - dbSubnetGroupName: subnetGroup.subnetGroupName, + dbSubnetGroupName: subnetGroup?.subnetGroupName, deletionProtection: defaultDeletionProtection(props.deletionProtection, props.removalPolicy), engine: props.engine.engineType, engineVersion: props.engine.engineVersion?.fullVersion, @@ -476,7 +498,7 @@ export class ServerlessCluster extends ServerlessClusterNew { public readonly secret?: secretsmanager.ISecret; - private readonly vpc: ec2.IVpc; + private readonly vpc?: ec2.IVpc; private readonly vpcSubnets?: ec2.SubnetSelection; private readonly singleUserRotationApplication: secretsmanager.SecretRotationApplication; @@ -525,6 +547,10 @@ export class ServerlessCluster extends ServerlessClusterNew { throw new Error('Cannot add single user rotation for a cluster without secret.'); } + if (this.vpc === undefined) { + throw new Error('Cannot add single user rotation for a cluster without VPC.'); + } + const id = 'RotationSingleUser'; const existing = this.node.tryFindChild(id); if (existing) { @@ -532,13 +558,11 @@ export class ServerlessCluster extends ServerlessClusterNew { } return new secretsmanager.SecretRotation(this, id, { + ...applyDefaultRotationOptions(options, this.vpcSubnets), secret: this.secret, application: this.singleUserRotationApplication, vpc: this.vpc, - vpcSubnets: this.vpcSubnets, target: this, - ...options, - excludeCharacters: options.excludeCharacters ?? DEFAULT_PASSWORD_EXCLUDE_CHARS, }); } @@ -549,13 +573,17 @@ export class ServerlessCluster extends ServerlessClusterNew { if (!this.secret) { throw new Error('Cannot add multi user rotation for a cluster without secret.'); } + + if (this.vpc === undefined) { + throw new Error('Cannot add multi user rotation for a cluster without VPC.'); + } + return new secretsmanager.SecretRotation(this, id, { - ...options, - excludeCharacters: options.excludeCharacters ?? DEFAULT_PASSWORD_EXCLUDE_CHARS, + ...applyDefaultRotationOptions(options, this.vpcSubnets), + secret: options.secret, masterSecret: this.secret, application: this.multiUserRotationApplication, vpc: this.vpc, - vpcSubnets: this.vpcSubnets, target: this, }); } @@ -680,4 +708,4 @@ export class ServerlessClusterFromSnapshot extends ServerlessClusterNew { this.secret = secret.attach(this); } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-rds/package.json b/packages/@aws-cdk/aws-rds/package.json index 0da51c0d59691..3110738220ab1 100644 --- a/packages/@aws-cdk/aws-rds/package.json +++ b/packages/@aws-cdk/aws-rds/package.json @@ -87,8 +87,8 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-rds/test/cluster.test.ts b/packages/@aws-cdk/aws-rds/test/cluster.test.ts index aa72d19f4f7d9..a7c749e04a399 100644 --- a/packages/@aws-cdk/aws-rds/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-rds/test/cluster.test.ts @@ -1,6 +1,7 @@ import { Match, Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import { ManagedPolicy, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; +import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; @@ -10,6 +11,7 @@ import * as cxapi from '@aws-cdk/cx-api'; import { AuroraEngineVersion, AuroraMysqlEngineVersion, AuroraPostgresEngineVersion, CfnDBCluster, Credentials, DatabaseCluster, DatabaseClusterEngine, DatabaseClusterFromSnapshot, ParameterGroup, PerformanceInsightRetention, SubnetGroup, DatabaseSecret, + DatabaseInstanceEngine, SqlServerEngineVersion, } from '../lib'; describe('cluster', () => { @@ -322,6 +324,112 @@ describe('cluster', () => { }); }); + test('cluster with inline parameter group', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + parameters: { + locks: '100', + }, + instanceProps: { + vpc, + parameters: { + locks: '200', + }, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::RDS::DBCluster', { + DBClusterParameterGroupName: { + Ref: 'DatabaseParameterGroup2A921026', + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::RDS::DBClusterParameterGroup', { + Family: 'aurora5.6', + Parameters: { + locks: '100', + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::RDS::DBInstance', { + DBParameterGroupName: { + Ref: 'DatabaseInstanceParameterGroup6968C5BF', + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::RDS::DBParameterGroup', { + Family: 'aurora5.6', + Parameters: { + locks: '200', + }, + }); + }); + + test('cluster with inline parameter group and parameterGroup arg fails', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const parameterGroup = new ParameterGroup(stack, 'ParameterGroup', { + engine: DatabaseInstanceEngine.sqlServerEe({ + version: SqlServerEngineVersion.VER_11, + }), + parameters: { + locks: '50', + }, + }); + + expect(() => { + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + parameters: { + locks: '100', + }, + parameterGroup, + instanceProps: { + vpc, + parameters: { + locks: '200', + }, + }, + }); + }).toThrow(/You cannot specify both parameterGroup and parameters/); + }); + + test('instance with inline parameter group and parameterGroup arg fails', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const parameterGroup = new ParameterGroup(stack, 'ParameterGroup', { + engine: DatabaseInstanceEngine.sqlServerEe({ + version: SqlServerEngineVersion.VER_11, + }), + parameters: { + locks: '50', + }, + }); + + expect(() => { + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + parameters: { + locks: '100', + }, + instanceProps: { + vpc, + parameterGroup, + parameters: { + locks: '200', + }, + }, + }); + }).toThrow(/You cannot specify both parameterGroup and parameters/); + }); + describe('performance insights', () => { test('cluster with all performance insights properties', () => { // GIVEN @@ -781,15 +889,18 @@ describe('cluster', () => { }); }); - test('addRotationSingleUser() with options', () => { + test('addRotationSingleUser() with custom automaticallyAfter, excludeCharacters and vpcSubnets', () => { // GIVEN const stack = new cdk.Stack(); - const vpcWithIsolated = new ec2.Vpc(stack, 'Vpc', { - subnetConfiguration: [ - { name: 'public', subnetType: ec2.SubnetType.PUBLIC }, - { name: 'private', subnetType: ec2.SubnetType.PRIVATE_WITH_NAT }, - { name: 'isolated', subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, - ], + const vpcWithIsolated = ec2.Vpc.fromVpcAttributes(stack, 'Vpc', { + vpcId: 'vpc-id', + availabilityZones: ['az1'], + publicSubnetIds: ['public-subnet-id-1', 'public-subnet-id-2'], + publicSubnetNames: ['public-subnet-name-1', 'public-subnet-name-2'], + privateSubnetIds: ['private-subnet-id-1', 'private-subnet-id-2'], + privateSubnetNames: ['private-subnet-name-1', 'private-subnet-name-2'], + isolatedSubnetIds: ['isolated-subnet-id-1', 'isolated-subnet-id-2'], + isolatedSubnetNames: ['isolated-subnet-name-1', 'isolated-subnet-name-2'], }); // WHEN @@ -827,26 +938,69 @@ describe('cluster', () => { { Ref: 'AWS::URLSuffix' }, ]], }, - functionName: 'DatabaseRotationSingleUser458A45BE', - vpcSubnetIds: { + vpcSubnetIds: 'private-subnet-id-1,private-subnet-id-2', + excludeCharacters: '°_@', + }, + }); + }); + + test('addRotationMultiUser() with custom automaticallyAfter, excludeCharacters and vpcSubnets', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpcWithIsolated = ec2.Vpc.fromVpcAttributes(stack, 'Vpc', { + vpcId: 'vpc-id', + availabilityZones: ['az1'], + publicSubnetIds: ['public-subnet-id-1', 'public-subnet-id-2'], + publicSubnetNames: ['public-subnet-name-1', 'public-subnet-name-2'], + privateSubnetIds: ['private-subnet-id-1', 'private-subnet-id-2'], + privateSubnetNames: ['private-subnet-name-1', 'private-subnet-name-2'], + isolatedSubnetIds: ['isolated-subnet-id-1', 'isolated-subnet-id-2'], + isolatedSubnetNames: ['isolated-subnet-name-1', 'isolated-subnet-name-2'], + }); + const userSecret = new DatabaseSecret(stack, 'UserSecret', { username: 'user' }); + + // WHEN + // DB in isolated subnet (no internet connectivity) + const cluster = new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA_MYSQL, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc: vpcWithIsolated, + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, + }, + }); + + // Rotation in private subnet (internet via NAT) + cluster.addRotationMultiUser('user', { + secret: userSecret.attach(cluster), + automaticallyAfter: cdk.Duration.days(15), + excludeCharacters: '°_@', + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_NAT }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::RotationSchedule', { + RotationRules: { + AutomaticallyAfterDays: 15, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Serverless::Application', { + Parameters: { + endpoint: { 'Fn::Join': ['', [ - { Ref: 'VpcprivateSubnet1SubnetCEAD3716' }, - ',', - { Ref: 'VpcprivateSubnet2Subnet2DE7549C' }, + 'https://secretsmanager.', + { Ref: 'AWS::Region' }, + '.', + { Ref: 'AWS::URLSuffix' }, ]], }, - vpcSecurityGroupIds: { - 'Fn::GetAtt': [ - 'DatabaseRotationSingleUserSecurityGroupAC6E0E73', - 'GroupId', - ], - }, + vpcSubnetIds: 'private-subnet-id-1,private-subnet-id-2', excludeCharacters: '°_@', }, }); }); - test('addRotationSingleUser() with VPC interface endpoint', () => { // GIVEN const stack = new cdk.Stack(); @@ -1600,6 +1754,26 @@ describe('cluster', () => { Template.fromStack(stack).resourceCountIs('AWS::RDS::DBClusterParameterGroup', 0); }); + test('MySQL cluster in version 8.0 uses aws_default_s3_role as a Parameter for S3 import, instead of aurora_load_from_s3_role', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + instanceProps: { vpc }, + engine: DatabaseClusterEngine.auroraMysql({ version: AuroraMysqlEngineVersion.VER_3_01_0 }), + s3ImportRole: iam.Role.fromRoleArn(stack, 'S3ImportRole', 'arn:aws:iam::123456789012:role/my-role'), + }); + + Template.fromStack(stack).hasResourceProperties('AWS::RDS::DBClusterParameterGroup', { + Family: 'aurora-mysql8.0', + Parameters: { + aws_default_s3_role: 'arn:aws:iam::123456789012:role/my-role', + }, + }); + }); + test('throws when s3ExportRole and s3ExportBuckets properties are both specified', () => { // GIVEN const stack = testStack(); @@ -1847,6 +2021,27 @@ describe('cluster', () => { }); }); + test('create a cluster from a snapshot with encrypted storage', () => { + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseClusterFromSnapshot(stack, 'Database', { + engine: DatabaseClusterEngine.aurora({ version: AuroraEngineVersion.VER_1_22_2 }), + instanceProps: { + vpc, + }, + snapshotIdentifier: 'mySnapshot', + storageEncryptionKey: kms.Key.fromKeyArn(stack, 'Key', 'arn:aws:kms:us-east-1:456:key/my-key'), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::RDS::DBCluster', { + KmsKeyId: 'arn:aws:kms:us-east-1:456:key/my-key', + StorageEncrypted: true, + }); + }); + test('reuse an existing subnet group', () => { // GIVEN const stack = testStack(); diff --git a/packages/@aws-cdk/aws-rds/test/instance.test.ts b/packages/@aws-cdk/aws-rds/test/instance.test.ts index 6681f7e77aab7..d8ec0d85fa6d1 100644 --- a/packages/@aws-cdk/aws-rds/test/instance.test.ts +++ b/packages/@aws-cdk/aws-rds/test/instance.test.ts @@ -246,6 +246,52 @@ describe('instance', () => { }); }); + test('instance with inline parameter group', () => { + // WHEN + new rds.DatabaseInstance(stack, 'Database', { + engine: rds.DatabaseInstanceEngine.sqlServerEe({ version: rds.SqlServerEngineVersion.VER_11 }), + vpc, + parameters: { + locks: '100', + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::RDS::DBInstance', { + DBParameterGroupName: { + Ref: 'DatabaseParameterGroup2A921026', + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::RDS::DBParameterGroup', { + Family: 'sqlserver-ee-11.0', + Parameters: { + locks: '100', + }, + }); + }); + + test('instance with inline parameter group and parameterGroup arg fails', () => { + const parameterGroup = new rds.ParameterGroup(stack, 'ParameterGroup', { + engine: rds.DatabaseInstanceEngine.sqlServerEe({ + version: rds.SqlServerEngineVersion.VER_11, + }), + parameters: { + key: 'value', + }, + }); + + expect(() => { + new rds.DatabaseInstance(stack, 'Database', { + engine: rds.DatabaseInstanceEngine.sqlServerEe({ version: rds.SqlServerEngineVersion.VER_11 }), + vpc, + parameters: { + locks: '100', + }, + parameterGroup, + }); + }).toThrow(/You cannot specify both parameterGroup and parameters/); + }); + test('can specify subnet type', () => { new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.mysql({ @@ -751,14 +797,17 @@ describe('instance', () => { }); }); - test('addRotationSingleUser() with options', () => { + test('addRotationSingleUser() with custom automaticallyAfter, excludeCharacters and vpcSubnets', () => { // GIVEN - const vpcWithIsolated = new ec2.Vpc(stack, 'Vpc', { - subnetConfiguration: [ - { name: 'public', subnetType: ec2.SubnetType.PUBLIC }, - { name: 'private', subnetType: ec2.SubnetType.PRIVATE_WITH_NAT }, - { name: 'isolated', subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, - ], + const vpcWithIsolated = ec2.Vpc.fromVpcAttributes(stack, 'Vpc', { + vpcId: 'vpc-id', + availabilityZones: ['az1'], + publicSubnetIds: ['public-subnet-id-1', 'public-subnet-id-2'], + publicSubnetNames: ['public-subnet-name-1', 'public-subnet-name-2'], + privateSubnetIds: ['private-subnet-id-1', 'private-subnet-id-2'], + privateSubnetNames: ['private-subnet-name-1', 'private-subnet-name-2'], + isolatedSubnetIds: ['isolated-subnet-id-1', 'isolated-subnet-id-2'], + isolatedSubnetNames: ['isolated-subnet-name-1', 'isolated-subnet-name-2'], }); // WHEN @@ -793,26 +842,65 @@ describe('instance', () => { { Ref: 'AWS::URLSuffix' }, ]], }, - functionName: 'DatabaseRotationSingleUser458A45BE', - vpcSubnetIds: { + vpcSubnetIds: 'private-subnet-id-1,private-subnet-id-2', + excludeCharacters: '°_@', + }, + }); + }); + + test('addRotationMultiUser() with custom automaticallyAfter, excludeCharacters and vpcSubnets', () => { + // GIVEN + const vpcWithIsolated = ec2.Vpc.fromVpcAttributes(stack, 'Vpc', { + vpcId: 'vpc-id', + availabilityZones: ['az1'], + publicSubnetIds: ['public-subnet-id-1', 'public-subnet-id-2'], + publicSubnetNames: ['public-subnet-name-1', 'public-subnet-name-2'], + privateSubnetIds: ['private-subnet-id-1', 'private-subnet-id-2'], + privateSubnetNames: ['private-subnet-name-1', 'private-subnet-name-2'], + isolatedSubnetIds: ['isolated-subnet-id-1', 'isolated-subnet-id-2'], + isolatedSubnetNames: ['isolated-subnet-name-1', 'isolated-subnet-name-2'], + }); + const userSecret = new rds.DatabaseSecret(stack, 'UserSecret', { username: 'user' }); + + // WHEN + // DB in isolated subnet (no internet connectivity) + const instance = new rds.DatabaseInstance(stack, 'Database', { + engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_10 }), + vpc: vpcWithIsolated, + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, + }); + + // Rotation in private subnet (internet via NAT) + instance.addRotationMultiUser('user', { + secret: userSecret.attach(instance), + automaticallyAfter: cdk.Duration.days(15), + excludeCharacters: '°_@', + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_NAT }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::RotationSchedule', { + RotationRules: { + AutomaticallyAfterDays: 15, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Serverless::Application', { + Parameters: { + endpoint: { 'Fn::Join': ['', [ - { Ref: 'VpcprivateSubnet1SubnetCEAD3716' }, - ',', - { Ref: 'VpcprivateSubnet2Subnet2DE7549C' }, + 'https://secretsmanager.', + { Ref: 'AWS::Region' }, + '.', + { Ref: 'AWS::URLSuffix' }, ]], }, - vpcSecurityGroupIds: { - 'Fn::GetAtt': [ - 'DatabaseRotationSingleUserSecurityGroupAC6E0E73', - 'GroupId', - ], - }, + vpcSubnetIds: 'private-subnet-id-1,private-subnet-id-2', excludeCharacters: '°_@', }, }); }); - test('addRotationSingleUser() with VPC interface endpoint', () => { // GIVEN const vpcIsolatedOnly = new ec2.Vpc(stack, 'Vpc', { natGateways: 0 }); @@ -1571,6 +1659,31 @@ describe('instance', () => { }, }); }); + + test('engine is specified for read replica using domain', () => { + // GIVEN + const instanceType = ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.SMALL); + const engine = rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_13 }); + const source = new rds.DatabaseInstance(stack, 'Source', { + engine, + instanceType, + vpc, + }); + + // WHEN + new rds.DatabaseInstanceReadReplica(stack, 'Replica', { + sourceDatabaseInstance: source, + instanceType, + vpc, + domain: 'my-domain', + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::RDS::DBInstance', { + SourceDBInstanceIdentifier: Match.anyValue(), + Engine: 'postgres', + }); + }); }); test.each([ diff --git a/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json b/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json index 4992aa9ac3383..30db89af96b49 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json @@ -841,7 +841,7 @@ "DatabaseRotationSingleUserSARMapping9AEB3E55": { "aws": { "applicationId": "arn:aws:serverlessrepo:us-east-1:297356227824:applications/SecretsManagerRDSMySQLRotationSingleUser", - "semanticVersion": "1.1.60" + "semanticVersion": "1.1.225" }, "aws-cn": { "applicationId": "arn:aws-cn:serverlessrepo:cn-north-1:193023089310:applications/SecretsManagerRDSMySQLRotationSingleUser", diff --git a/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.expected.json b/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.expected.json index d3127f0b8fdd9..3f138a90f511b 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.expected.json @@ -95,15 +95,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VPCPublicSubnet2NATGateway3C070193": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "Tags": [ { "Key": "Name", @@ -480,8 +480,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -543,16 +543,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -614,7 +614,6 @@ "Type": "AWS::RDS::DBCluster", "Properties": { "Engine": "aurora", - "CopyTagsToSnapshot": true, "AssociatedRoles": [ { "RoleArn": { @@ -633,6 +632,7 @@ } } ], + "CopyTagsToSnapshot": true, "DBClusterParameterGroupName": { "Ref": "DatabaseClusterParameterGroupF2A52087" }, diff --git a/packages/@aws-cdk/aws-rds/test/integ.instance-s3-postgres.expected.json b/packages/@aws-cdk/aws-rds/test/integ.instance-s3-postgres.expected.json index f811978275863..b625e5f5de352 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.instance-s3-postgres.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.instance-s3-postgres.expected.json @@ -387,8 +387,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -450,16 +450,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ diff --git a/packages/@aws-cdk/aws-rds/test/integ.instance-s3.expected.json b/packages/@aws-cdk/aws-rds/test/integ.instance-s3.expected.json index f379bde6663f7..2a725ac4b7a54 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.instance-s3.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.instance-s3.expected.json @@ -419,8 +419,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -449,16 +449,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ diff --git a/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json b/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json index e5a193d0d68c4..36c5fdc654df2 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json @@ -984,8 +984,8 @@ "Statement": [ { "Action": [ - "logs:PutRetentionPolicy", - "logs:DeleteRetentionPolicy" + "logs:DeleteRetentionPolicy", + "logs:PutRetentionPolicy" ], "Effect": "Allow", "Resource": "*" @@ -1008,7 +1008,7 @@ "Runtime": "nodejs14.x", "Code": { "S3Bucket": { - "Ref": "AssetParametersdd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9S3BucketE7DA8D4B" + "Ref": "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665S3Bucket0D8A173B" }, "S3Key": { "Fn::Join": [ @@ -1021,7 +1021,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9S3VersionKey534293E7" + "Ref": "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665S3VersionKeyE95BF332" } ] } @@ -1034,7 +1034,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9S3VersionKey534293E7" + "Ref": "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665S3VersionKeyE95BF332" } ] } @@ -1131,7 +1131,7 @@ "InstanceRotationSingleUserSARMappingFEA0C86E": { "aws": { "applicationId": "arn:aws:serverlessrepo:us-east-1:297356227824:applications/SecretsManagerRDSOracleRotationSingleUser", - "semanticVersion": "1.1.60" + "semanticVersion": "1.1.225" }, "aws-cn": { "applicationId": "arn:aws-cn:serverlessrepo:cn-north-1:193023089310:applications/SecretsManagerRDSOracleRotationSingleUser", @@ -1144,17 +1144,17 @@ } }, "Parameters": { - "AssetParametersdd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9S3BucketE7DA8D4B": { + "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665S3Bucket0D8A173B": { "Type": "String", - "Description": "S3 bucket for asset \"dd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9\"" + "Description": "S3 bucket for asset \"22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665\"" }, - "AssetParametersdd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9S3VersionKey534293E7": { + "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665S3VersionKeyE95BF332": { "Type": "String", - "Description": "S3 key for asset version \"dd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9\"" + "Description": "S3 key for asset version \"22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665\"" }, - "AssetParametersdd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9ArtifactHash3CB520C3": { + "AssetParameters22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665ArtifactHashF4A1E70E": { "Type": "String", - "Description": "Artifact hash for asset \"dd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9\"" + "Description": "Artifact hash for asset \"22bb41d703c8e7a9a1712308f455fcf58cc012b0a386c9df563a6244a61e6665\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json b/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json index 8ec23ce0fe7db..a8eff4138bc50 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json @@ -524,8 +524,8 @@ "Statement": [ { "Action": [ - "secretsmanager:GetSecretValue", - "secretsmanager:DescribeSecret" + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster-no-vpc.expected.json b/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster-no-vpc.expected.json new file mode 100644 index 0000000000000..7d81d78c4e34f --- /dev/null +++ b/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster-no-vpc.expected.json @@ -0,0 +1,18 @@ +{ + "Resources": { + "ServerlessDatabaseWithoutVPC93F9A752": { + "Type": "AWS::RDS::DBCluster", + "Properties": { + "Engine": "aurora-mysql", + "DBClusterParameterGroupName": "default.aurora-mysql5.7", + "EngineMode": "serverless", + "MasterUsername": "admin", + "MasterUserPassword": "7959866cacc02c2d243ecfe177464fe6", + "StorageEncrypted": true, + "VpcSecurityGroupIds": [] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster-no-vpc.ts b/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster-no-vpc.ts new file mode 100644 index 0000000000000..807cf1a894601 --- /dev/null +++ b/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster-no-vpc.ts @@ -0,0 +1,17 @@ +import * as cdk from '@aws-cdk/core'; +import * as rds from '../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-cdk-sls-cluster-no-vpc-integ'); + +const cluster = new rds.ServerlessCluster(stack, 'Serverless Database Without VPC', { + engine: rds.DatabaseClusterEngine.AURORA_MYSQL, + credentials: { + username: 'admin', + password: cdk.SecretValue.plainText('7959866cacc02c2d243ecfe177464fe6'), + }, + removalPolicy: cdk.RemovalPolicy.DESTROY, +}); +cluster.connections.allowDefaultPortFromAnyIpv4('Open to the world'); + +app.synth(); diff --git a/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts b/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts index 3849a99cdeb02..a55a23df02421 100644 --- a/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts +++ b/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts @@ -1,10 +1,10 @@ -import { Template } from '@aws-cdk/assertions'; +import { Template, Match } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { AuroraPostgresEngineVersion, ServerlessCluster, DatabaseClusterEngine, ParameterGroup, AuroraCapacityUnit, DatabaseSecret } from '../lib'; +import { AuroraPostgresEngineVersion, ServerlessCluster, DatabaseClusterEngine, ParameterGroup, AuroraCapacityUnit, DatabaseSecret, SubnetGroup } from '../lib'; describe('serverless cluster', () => { test('can create a Serverless Cluster with Aurora Postgres database engine', () => { @@ -70,28 +70,18 @@ describe('serverless cluster', () => { }, EngineMode: 'serverless', MasterUsername: { - 'Fn::Join': [ - '', - [ - '{{resolve:secretsmanager:', - { - Ref: 'ServerlessDatabaseSecret1C9BF4F1', - }, - ':SecretString:username::}}', - ], - ], + 'Fn::Join': ['', [ + '{{resolve:secretsmanager:', + { Ref: 'ServerlessDatabaseSecret1C9BF4F1' }, + ':SecretString:username::}}', + ]], }, MasterUserPassword: { - 'Fn::Join': [ - '', - [ - '{{resolve:secretsmanager:', - { - Ref: 'ServerlessDatabaseSecret1C9BF4F1', - }, - ':SecretString:password::}}', - ], - ], + 'Fn::Join': ['', [ + '{{resolve:secretsmanager:', + { Ref: 'ServerlessDatabaseSecret1C9BF4F1' }, + ':SecretString:password::}}', + ]], }, StorageEncrypted: true, VpcSecurityGroupIds: [ @@ -131,28 +121,18 @@ describe('serverless cluster', () => { EngineMode: 'serverless', DBSubnetGroupName: { Ref: 'DatabaseSubnets56F17B9A' }, MasterUsername: { - 'Fn::Join': [ - '', - [ - '{{resolve:secretsmanager:', - { - Ref: 'DatabaseSecret3B817195', - }, - ':SecretString:username::}}', - ], - ], + 'Fn::Join': ['', [ + '{{resolve:secretsmanager:', + { Ref: 'DatabaseSecret3B817195' }, + ':SecretString:username::}}', + ]], }, MasterUserPassword: { - 'Fn::Join': [ - '', - [ - '{{resolve:secretsmanager:', - { - Ref: 'DatabaseSecret3B817195', - }, - ':SecretString:password::}}', - ], - ], + 'Fn::Join': ['', [ + '{{resolve:secretsmanager:', + { Ref: 'DatabaseSecret3B817195' }, + ':SecretString:password::}}', + ]], }, VpcSecurityGroupIds: ['SecurityGroupId12345'], }); @@ -192,28 +172,18 @@ describe('serverless cluster', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::RDS::DBCluster', { MasterUsername: { - 'Fn::Join': [ - '', - [ - '{{resolve:secretsmanager:', - { - Ref: 'DatabaseSecret3B817195', - }, - ':SecretString:username::}}', - ], - ], + 'Fn::Join': ['', [ + '{{resolve:secretsmanager:', + { Ref: 'DatabaseSecret3B817195' }, + ':SecretString:username::}}', + ]], }, MasterUserPassword: { - 'Fn::Join': [ - '', - [ - '{{resolve:secretsmanager:', - { - Ref: 'DatabaseSecret3B817195', - }, - ':SecretString:password::}}', - ], - ], + 'Fn::Join': ['', [ + '{{resolve:secretsmanager:', + { Ref: 'DatabaseSecret3B817195' }, + ':SecretString:password::}}', + ]], }, }); @@ -351,7 +321,7 @@ describe('serverless cluster', () => { expect(cluster.clusterReadEndpoint.socketAddress).toEqual('reader-address:3306'); }); - test('throws when trying to add rotation to a serverless cluster without secret', () => { + test('throws when trying to add single-user rotation to a serverless cluster without secret', () => { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -387,6 +357,39 @@ describe('serverless cluster', () => { expect(() => cluster.addRotationSingleUser()).toThrow(/A single user rotation was already added to this cluster/); }); + test('throws when trying to add single-user rotation to a serverless cluster without VPC', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const cluster = new ServerlessCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA_MYSQL, + }); + + // THEN + expect(() => { + cluster.addRotationSingleUser(); + }).toThrow(/Cannot add single user rotation for a cluster without VPC/); + }); + + test('throws when trying to add multi-user rotation to a serverless cluster without VPC', () => { + // GIVEN + const stack = new cdk.Stack(); + const secret = new DatabaseSecret(stack, 'Secret', { + username: 'admin', + }); + + // WHEN + const cluster = new ServerlessCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA_MYSQL, + }); + + // THEN + expect(() => { + cluster.addRotationMultiUser('someId', { secret }); + }).toThrow(/Cannot add multi user rotation for a cluster without VPC/); + }); + test('can set deletion protection', () => { // GIVEN const stack = testStack(); @@ -612,15 +615,12 @@ describe('serverless cluster', () => { // THEN expect(stack.resolve(cluster.clusterArn)).toEqual({ - 'Fn::Join': [ - '', - [ - 'arn:', - { Ref: 'AWS::Partition' }, - ':rds:us-test-1:12345:cluster:', - { Ref: 'DatabaseB269D8BB' }, - ], - ], + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':rds:us-test-1:12345:cluster:', + { Ref: 'DatabaseB269D8BB' }, + ]], }); }); @@ -803,6 +803,65 @@ describe('serverless cluster', () => { DBClusterIdentifier: clusterIdentifier, }); }); + + test('can create a Serverless cluster without VPC', () => { + // GIVEN + const stack = testStack(); + + // WHEN + new ServerlessCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA_MYSQL, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::RDS::DBCluster', { + Engine: 'aurora-mysql', + EngineMode: 'serverless', + DbSubnetGroupName: Match.absent(), + VpcSecurityGroupIds: [], + }); + }); + + test('cannot create a Serverless cluster without VPC but specifying a security group', () => { + // GIVEN + const stack = testStack(); + const sg = ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'SecurityGroupId12345'); + + // THEN + expect(() => new ServerlessCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA_MYSQL, + securityGroups: [sg], + })).toThrow(/A VPC is required to use securityGroups in ServerlessCluster. Please add a VPC or remove securityGroups/); + }); + + test('cannot create a Serverless cluster without VPC but specifying a subnet group', () => { + // GIVEN + const stack = testStack(); + const SubnetGroupName = 'SubnetGroupId12345'; + const subnetGroup = SubnetGroup.fromSubnetGroupName(stack, 'SubnetGroup12345', SubnetGroupName); + + // THEN + expect(() => new ServerlessCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA_MYSQL, + subnetGroup, + })).toThrow(/A VPC is required to use subnetGroup in ServerlessCluster. Please add a VPC or remove subnetGroup/); + }); + + test('cannot create a Serverless cluster without VPC but specifying VPC subnets', () => { + // GIVEN + const stack = testStack(); + + // WHEN + const vpcSubnets = { + subnetName: 'AVpcSubnet', + }; + + // THEN + expect(() => new ServerlessCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA_MYSQL, + vpcSubnets, + })).toThrow(/A VPC is required to use vpcSubnets in ServerlessCluster. Please add a VPC or remove vpcSubnets/); + }); }); function testStack(app?: cdk.App, id?: string): cdk.Stack { diff --git a/packages/@aws-cdk/aws-redshift/package.json b/packages/@aws-cdk/aws-redshift/package.json index c3f98007a8691..d6841a31195d5 100644 --- a/packages/@aws-cdk/aws-redshift/package.json +++ b/packages/@aws-cdk/aws-redshift/package.json @@ -84,9 +84,9 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "aws-sdk": "^2.848.0", - "jest": "^27.4.7" + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.expected.json b/packages/@aws-cdk/aws-redshift/test/integ.database.expected.json index 6e909192a7f3d..096fb4b074160 100644 --- a/packages/@aws-cdk/aws-redshift/test/integ.database.expected.json +++ b/packages/@aws-cdk/aws-redshift/test/integ.database.expected.json @@ -20,11 +20,11 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.0.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1a", + "CidrBlock": "10.0.0.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -129,11 +129,11 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.32.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1b", + "CidrBlock": "10.0.32.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -238,11 +238,11 @@ "VpcPublicSubnet3SubnetBE12F0B6": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.64.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1c", + "CidrBlock": "10.0.64.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -347,11 +347,11 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.96.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1a", + "CidrBlock": "10.0.96.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -417,11 +417,11 @@ "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.128.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1b", + "CidrBlock": "10.0.128.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -487,11 +487,11 @@ "VpcPrivateSubnet3SubnetF258B56E": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.160.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1c", + "CidrBlock": "10.0.160.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -800,12 +800,28 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "QueryRedshiftDatabase3de5bea727da479686625efb56431b5f3DF81997", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "QueryRedshiftDatabase3de5bea727da479686625efb56431b5f3DF81997", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "QueryRedshiftDatabase3de5bea727da479686625efb56431b5f3DF81997", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -825,7 +841,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, "S3Key": { "Fn::Join": [ @@ -838,7 +854,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -851,7 +867,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -955,12 +971,28 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "QueryRedshiftDatabase3de5bea727da479686625efb56431b5f3DF81997", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "QueryRedshiftDatabase3de5bea727da479686625efb56431b5f3DF81997", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "QueryRedshiftDatabase3de5bea727da479686625efb56431b5f3DF81997", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -980,7 +1012,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, "S3Key": { "Fn::Join": [ @@ -993,7 +1025,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -1006,7 +1038,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -1131,23 +1163,18 @@ }, { "Action": [ - "secretsmanager:GetSecretValue", - "secretsmanager:DescribeSecret" + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue" ], "Effect": "Allow", - "Resource": { - "Ref": "ClusterSecretAttachment769E6258" - } - }, - { - "Action": [ - "secretsmanager:GetSecretValue", - "secretsmanager:DescribeSecret" - ], - "Effect": "Allow", - "Resource": { - "Ref": "UserSecretAttachment02022609" - } + "Resource": [ + { + "Ref": "ClusterSecretAttachment769E6258" + }, + { + "Ref": "UserSecretAttachment02022609" + } + ] } ], "Version": "2012-10-17" @@ -1167,7 +1194,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters85597bcd6a07abd4673fe02c7e92e21df5859eee0d831e9db67f4d2e74d4d066S3Bucket0B347C2E" + "Ref": "AssetParameters104629e772240371441c4f76a71184cb01d6d09afe126b3ddc9243d03f78fb3bS3Bucket2B744261" }, "S3Key": { "Fn::Join": [ @@ -1180,7 +1207,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters85597bcd6a07abd4673fe02c7e92e21df5859eee0d831e9db67f4d2e74d4d066S3VersionKey932D0479" + "Ref": "AssetParameters104629e772240371441c4f76a71184cb01d6d09afe126b3ddc9243d03f78fb3bS3VersionKey26C2ED2C" } ] } @@ -1193,7 +1220,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters85597bcd6a07abd4673fe02c7e92e21df5859eee0d831e9db67f4d2e74d4d066S3VersionKey932D0479" + "Ref": "AssetParameters104629e772240371441c4f76a71184cb01d6d09afe126b3ddc9243d03f78fb3bS3VersionKey26C2ED2C" } ] } @@ -1261,12 +1288,28 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "QueryRedshiftDatabase3de5bea727da479686625efb56431b5f3DF81997", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "QueryRedshiftDatabase3de5bea727da479686625efb56431b5f3DF81997", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "QueryRedshiftDatabase3de5bea727da479686625efb56431b5f3DF81997", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -1286,7 +1329,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, "S3Key": { "Fn::Join": [ @@ -1299,7 +1342,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -1312,7 +1355,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -1396,29 +1439,29 @@ } }, "Parameters": { - "AssetParameters85597bcd6a07abd4673fe02c7e92e21df5859eee0d831e9db67f4d2e74d4d066S3Bucket0B347C2E": { + "AssetParameters104629e772240371441c4f76a71184cb01d6d09afe126b3ddc9243d03f78fb3bS3Bucket2B744261": { "Type": "String", - "Description": "S3 bucket for asset \"85597bcd6a07abd4673fe02c7e92e21df5859eee0d831e9db67f4d2e74d4d066\"" + "Description": "S3 bucket for asset \"104629e772240371441c4f76a71184cb01d6d09afe126b3ddc9243d03f78fb3b\"" }, - "AssetParameters85597bcd6a07abd4673fe02c7e92e21df5859eee0d831e9db67f4d2e74d4d066S3VersionKey932D0479": { + "AssetParameters104629e772240371441c4f76a71184cb01d6d09afe126b3ddc9243d03f78fb3bS3VersionKey26C2ED2C": { "Type": "String", - "Description": "S3 key for asset version \"85597bcd6a07abd4673fe02c7e92e21df5859eee0d831e9db67f4d2e74d4d066\"" + "Description": "S3 key for asset version \"104629e772240371441c4f76a71184cb01d6d09afe126b3ddc9243d03f78fb3b\"" }, - "AssetParameters85597bcd6a07abd4673fe02c7e92e21df5859eee0d831e9db67f4d2e74d4d066ArtifactHash78689978": { + "AssetParameters104629e772240371441c4f76a71184cb01d6d09afe126b3ddc9243d03f78fb3bArtifactHash00C57864": { "Type": "String", - "Description": "Artifact hash for asset \"85597bcd6a07abd4673fe02c7e92e21df5859eee0d831e9db67f4d2e74d4d066\"" + "Description": "Artifact hash for asset \"104629e772240371441c4f76a71184cb01d6d09afe126b3ddc9243d03f78fb3b\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { "Type": "String", - "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { "Type": "String", - "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { "Type": "String", - "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rekognition/package.json b/packages/@aws-cdk/aws-rekognition/package.json index 9cf5d2e0d407d..1c92e782a9e64 100644 --- a/packages/@aws-cdk/aws-rekognition/package.json +++ b/packages/@aws-cdk/aws-rekognition/package.json @@ -95,7 +95,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-resourcegroups/package.json b/packages/@aws-cdk/aws-resourcegroups/package.json index caf23fb138d50..a17a9aa169e15 100644 --- a/packages/@aws-cdk/aws-resourcegroups/package.json +++ b/packages/@aws-cdk/aws-resourcegroups/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-robomaker/package.json b/packages/@aws-cdk/aws-robomaker/package.json index d40dc417d86d6..b96c0b59e92b4 100644 --- a/packages/@aws-cdk/aws-robomaker/package.json +++ b/packages/@aws-cdk/aws-robomaker/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53-patterns/package.json b/packages/@aws-cdk/aws-route53-patterns/package.json index f4e358cde998a..2d4e248234582 100644 --- a/packages/@aws-cdk/aws-route53-patterns/package.json +++ b/packages/@aws-cdk/aws-route53-patterns/package.json @@ -77,8 +77,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53-targets/lib/elastic-beanstalk-environment-target.ts b/packages/@aws-cdk/aws-route53-targets/lib/elastic-beanstalk-environment-target.ts index ef48c2845c233..255114b773854 100644 --- a/packages/@aws-cdk/aws-route53-targets/lib/elastic-beanstalk-environment-target.ts +++ b/packages/@aws-cdk/aws-route53-targets/lib/elastic-beanstalk-environment-target.ts @@ -5,6 +5,7 @@ import { RegionInfo } from '@aws-cdk/region-info'; /** * Use an Elastic Beanstalk environment URL as an alias record target. * E.g. mysampleenvironment.xyz.us-east-1.elasticbeanstalk.com + * or mycustomcnameprefix.us-east-1.elasticbeanstalk.com * * Only supports Elastic Beanstalk environments created after 2016 that have a regional endpoint. */ @@ -18,7 +19,9 @@ export class ElasticBeanstalkEnvironmentEndpointTarget implements route53.IAlias } const dnsName = this.environmentEndpoint; - const region = cdk.Fn.select(2, cdk.Fn.split('.', dnsName)); + const subDomains = cdk.Fn.split('.', dnsName); + const regionSubdomainIndex = subDomains.length - 3; + const region = cdk.Fn.select(regionSubdomainIndex, subDomains); const { ebsEnvEndpointHostedZoneId: hostedZoneId } = RegionInfo.get(region); if (!hostedZoneId || !dnsName) { diff --git a/packages/@aws-cdk/aws-route53-targets/package.json b/packages/@aws-cdk/aws-route53-targets/package.json index c51747d33eb5e..7aca456bffc24 100644 --- a/packages/@aws-cdk/aws-route53-targets/package.json +++ b/packages/@aws-cdk/aws-route53-targets/package.json @@ -79,8 +79,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-apigateway": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53-targets/test/elastic-beanstalk-environment-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/elastic-beanstalk-environment-target.test.ts index 44cadae6e3b9f..a60fd9be58d5b 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/elastic-beanstalk-environment-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/elastic-beanstalk-environment-target.test.ts @@ -23,3 +23,25 @@ test('use EBS environment as record target', () => { }, }); }); + + +test('support 4-levels subdomain URLs for EBS environments', () => { + // GIVEN + const stack = new Stack(); + const zone = new route53.PublicHostedZone(stack, 'HostedZone', { zoneName: 'test.public' }); + + // WHEN + new route53.ARecord(stack, 'Alias', { + zone, + recordName: '_foo', + target: route53.RecordTarget.fromAlias(new targets.ElasticBeanstalkEnvironmentEndpointTarget('mycustomcnameprefix.us-east-1.elasticbeanstalk.com')), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { + AliasTarget: { + DNSName: 'mycustomcnameprefix.us-east-1.elasticbeanstalk.com', + HostedZoneId: 'Z117KPS5GTRQ2G', + }, + }); +}); diff --git a/packages/@aws-cdk/aws-route53/lib/record-set.ts b/packages/@aws-cdk/aws-route53/lib/record-set.ts index 823257f6fb576..a10cb05c37e67 100644 --- a/packages/@aws-cdk/aws-route53/lib/record-set.ts +++ b/packages/@aws-cdk/aws-route53/lib/record-set.ts @@ -690,13 +690,13 @@ export class CrossAccountZoneDelegationRecord extends CoreConstruct { const role = iam.Role.fromRoleArn(this, 'cross-account-zone-delegation-handler-role', provider.roleArn); - role.addToPrincipalPolicy(new iam.PolicyStatement({ + const addToPrinciplePolicyResult = role.addToPrincipalPolicy(new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: ['sts:AssumeRole'], resources: [props.delegationRole.roleArn], })); - new CustomResource(this, 'CrossAccountZoneDelegationCustomResource', { + const customResource = new CustomResource(this, 'CrossAccountZoneDelegationCustomResource', { resourceType: CROSS_ACCOUNT_ZONE_DELEGATION_RESOURCE_TYPE, serviceToken: provider.serviceToken, removalPolicy: props.removalPolicy, @@ -709,5 +709,9 @@ export class CrossAccountZoneDelegationRecord extends CoreConstruct { TTL: (props.ttl || Duration.days(2)).toSeconds(), }, }); + + if (addToPrinciplePolicyResult.policyDependable) { + customResource.node.addDependency(addToPrinciplePolicyResult.policyDependable); + } } } diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index 8290edcc15e60..64206dd84854b 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -84,10 +84,10 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.92", - "@types/jest": "^27.4.0", + "@types/aws-lambda": "^8.10.93", + "@types/jest": "^27.4.1", "aws-sdk": "^2.848.0", - "jest": "^27.4.7" + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53/test/integ.cross-account-zone-delegation.expected.json b/packages/@aws-cdk/aws-route53/test/integ.cross-account-zone-delegation.expected.json index d5890cda1c955..3ad72296cd685 100644 --- a/packages/@aws-cdk/aws-route53/test/integ.cross-account-zone-delegation.expected.json +++ b/packages/@aws-cdk/aws-route53/test/integ.cross-account-zone-delegation.expected.json @@ -154,6 +154,9 @@ }, "TTL": 172800 }, + "DependsOn": [ + "DelegationWithZoneIdcrossaccountzonedelegationhandlerrolePolicy5170A69B" + ], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -184,7 +187,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersd17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602S3Bucket200D9216" + "Ref": "AssetParameters7625bcc3bbd65c490a92d42790a563e31dc02c18006ef272338c8c788849bb8aS3BucketC1366C27" }, "S3Key": { "Fn::Join": [ @@ -197,7 +200,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersd17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602S3VersionKey0E5C26F0" + "Ref": "AssetParameters7625bcc3bbd65c490a92d42790a563e31dc02c18006ef272338c8c788849bb8aS3VersionKeyEE72CEF8" } ] } @@ -210,7 +213,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersd17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602S3VersionKey0E5C26F0" + "Ref": "AssetParameters7625bcc3bbd65c490a92d42790a563e31dc02c18006ef272338c8c788849bb8aS3VersionKeyEE72CEF8" } ] } @@ -315,22 +318,25 @@ }, "TTL": 172800 }, + "DependsOn": [ + "DelegationWithZoneNamecrossaccountzonedelegationhandlerrolePolicy86996882" + ], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" } }, "Parameters": { - "AssetParametersd17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602S3Bucket200D9216": { + "AssetParameters7625bcc3bbd65c490a92d42790a563e31dc02c18006ef272338c8c788849bb8aS3BucketC1366C27": { "Type": "String", - "Description": "S3 bucket for asset \"d17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602\"" + "Description": "S3 bucket for asset \"7625bcc3bbd65c490a92d42790a563e31dc02c18006ef272338c8c788849bb8a\"" }, - "AssetParametersd17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602S3VersionKey0E5C26F0": { + "AssetParameters7625bcc3bbd65c490a92d42790a563e31dc02c18006ef272338c8c788849bb8aS3VersionKeyEE72CEF8": { "Type": "String", - "Description": "S3 key for asset version \"d17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602\"" + "Description": "S3 key for asset version \"7625bcc3bbd65c490a92d42790a563e31dc02c18006ef272338c8c788849bb8a\"" }, - "AssetParametersd17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602ArtifactHash37FB4D0C": { + "AssetParameters7625bcc3bbd65c490a92d42790a563e31dc02c18006ef272338c8c788849bb8aArtifactHashAADF3168": { "Type": "String", - "Description": "Artifact hash for asset \"d17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602\"" + "Description": "Artifact hash for asset \"7625bcc3bbd65c490a92d42790a563e31dc02c18006ef272338c8c788849bb8a\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-route53/test/integ.vpc-endpoint-service-domain-name.expected.json b/packages/@aws-cdk/aws-route53/test/integ.vpc-endpoint-service-domain-name.expected.json index 030333512f860..88f5a2f51362c 100644 --- a/packages/@aws-cdk/aws-route53/test/integ.vpc-endpoint-service-domain-name.expected.json +++ b/packages/@aws-cdk/aws-route53/test/integ.vpc-endpoint-service-domain-name.expected.json @@ -95,15 +95,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VPCPublicSubnet2NATGateway3C070193": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "Tags": [ { "Key": "Name", @@ -289,15 +289,15 @@ "VPCPublicSubnet3NATGatewayD3048F5C": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet3EIPAD4BC883", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - }, "Tags": [ { "Key": "Name", @@ -936,7 +936,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3BucketD609D0D9" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16" }, "S3Key": { "Fn::Join": [ @@ -949,7 +949,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -962,7 +962,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -988,17 +988,17 @@ } }, "Parameters": { - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3BucketD609D0D9": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16": { "Type": "String", - "Description": "S3 bucket for asset \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "S3 bucket for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B": { "Type": "String", - "Description": "S3 key for asset version \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "S3 key for asset version \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cArtifactHash86CFA15D": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87ArtifactHash40DDF5EE": { "Type": "String", - "Description": "Artifact hash for asset \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "Artifact hash for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-route53/test/record-set.test.ts b/packages/@aws-cdk/aws-route53/test/record-set.test.ts index a48cb07bb5ab0..fbf3d56517d3b 100644 --- a/packages/@aws-cdk/aws-route53/test/record-set.test.ts +++ b/packages/@aws-cdk/aws-route53/test/record-set.test.ts @@ -737,33 +737,38 @@ describe('record set', () => { // THEN const childHostedZones = [ - { name: 'sub.myzone.com', id: 'ChildHostedZone4B14AC71' }, - { name: 'anothersub.myzone.com', id: 'ChildHostedZone2A37198F0' }, + { name: 'sub.myzone.com', id: 'ChildHostedZone4B14AC71', dependsOn: 'DelegationcrossaccountzonedelegationhandlerrolePolicy1E157602' }, + { name: 'anothersub.myzone.com', id: 'ChildHostedZone2A37198F0', dependsOn: 'Delegation2crossaccountzonedelegationhandlerrolePolicy713BEAC3' }, ]; for (var childHostedZone of childHostedZones) { - Template.fromStack(stack).hasResourceProperties('Custom::CrossAccountZoneDelegation', { - ServiceToken: { - 'Fn::GetAtt': [ - 'CustomCrossAccountZoneDelegationCustomResourceProviderHandler44A84265', - 'Arn', - ], - }, - AssumeRoleArn: { - 'Fn::GetAtt': [ - 'ParentHostedZoneCrossAccountZoneDelegationRole95B1C36E', - 'Arn', - ], - }, - ParentZoneName: 'myzone.com', - DelegatedZoneName: childHostedZone.name, - DelegatedZoneNameServers: { - 'Fn::GetAtt': [ - childHostedZone.id, - 'NameServers', - ], + Template.fromStack(stack).hasResource('Custom::CrossAccountZoneDelegation', { + Properties: { + ServiceToken: { + 'Fn::GetAtt': [ + 'CustomCrossAccountZoneDelegationCustomResourceProviderHandler44A84265', + 'Arn', + ], + }, + AssumeRoleArn: { + 'Fn::GetAtt': [ + 'ParentHostedZoneCrossAccountZoneDelegationRole95B1C36E', + 'Arn', + ], + }, + ParentZoneName: 'myzone.com', + DelegatedZoneName: childHostedZone.name, + DelegatedZoneNameServers: { + 'Fn::GetAtt': [ + childHostedZone.id, + 'NameServers', + ], + }, + TTL: 60, }, - TTL: 60, + DependsOn: [ + childHostedZone.dependsOn, + ], }); } }); diff --git a/packages/@aws-cdk/aws-route53recoverycontrol/package.json b/packages/@aws-cdk/aws-route53recoverycontrol/package.json index 0ec2546ada38d..cde17f02ec86e 100644 --- a/packages/@aws-cdk/aws-route53recoverycontrol/package.json +++ b/packages/@aws-cdk/aws-route53recoverycontrol/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-route53recoveryreadiness/package.json b/packages/@aws-cdk/aws-route53recoveryreadiness/package.json index 6dcaed6cb8433..8feeeca412adb 100644 --- a/packages/@aws-cdk/aws-route53recoveryreadiness/package.json +++ b/packages/@aws-cdk/aws-route53recoveryreadiness/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-route53resolver/package.json b/packages/@aws-cdk/aws-route53resolver/package.json index 851453eb1279c..be0c3e79cea04 100644 --- a/packages/@aws-cdk/aws-route53resolver/package.json +++ b/packages/@aws-cdk/aws-route53resolver/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3-assets/package.json b/packages/@aws-cdk/aws-s3-assets/package.json index 80996d4ebc255..5291ae6cb726e 100644 --- a/packages/@aws-cdk/aws-s3-assets/package.json +++ b/packages/@aws-cdk/aws-s3-assets/package.json @@ -82,7 +82,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/assets": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts b/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts index f04218f95929d..23666d832f7e2 100644 --- a/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts +++ b/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts @@ -275,7 +275,7 @@ test('nested assemblies share assets: default synth edition', () => { // Read the asset manifests to verify the file paths for (const stageName of ['Stage1', 'Stage2']) { - const manifestArtifact = assembly.getNestedAssembly(`assembly-${stageName}`).artifacts.filter(isAssetManifestArtifact)[0]; + const manifestArtifact = assembly.getNestedAssembly(`assembly-${stageName}`).artifacts.filter(cxapi.AssetManifestArtifact.isAssetManifestArtifact)[0]; const manifest = JSON.parse(fs.readFileSync(manifestArtifact.file, { encoding: 'utf-8' })); expect(manifest.files[SAMPLE_ASSET_HASH].source).toEqual({ @@ -410,7 +410,3 @@ function mkdtempSync() { function isStackArtifact(x: any): x is cxapi.CloudFormationStackArtifact { return x instanceof cxapi.CloudFormationStackArtifact; } - -function isAssetManifestArtifact(x: any): x is cxapi.AssetManifestArtifact { - return x instanceof cxapi.AssetManifestArtifact; -} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3-assets/test/integ.assets.bundling.lit.expected.json b/packages/@aws-cdk/aws-s3-assets/test/integ.assets.bundling.lit.expected.json index 3f1cef1b0c4f4..fe8410cd1f63b 100644 --- a/packages/@aws-cdk/aws-s3-assets/test/integ.assets.bundling.lit.expected.json +++ b/packages/@aws-cdk/aws-s3-assets/test/integ.assets.bundling.lit.expected.json @@ -24,8 +24,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -41,7 +41,8 @@ ":s3:::", { "Ref": "AssetParameters8995e9405bdcae88dc6fc76b4fc224fecfd00ef93663cb759b491c6a13cc59c2S3Bucket32756583" - } + }, + "/*" ] ] }, @@ -56,8 +57,7 @@ ":s3:::", { "Ref": "AssetParameters8995e9405bdcae88dc6fc76b4fc224fecfd00ef93663cb759b491c6a13cc59c2S3Bucket32756583" - }, - "/*" + } ] ] } diff --git a/packages/@aws-cdk/aws-s3-assets/test/integ.assets.directory.lit.expected.json b/packages/@aws-cdk/aws-s3-assets/test/integ.assets.directory.lit.expected.json index 867d0a2430be4..d034243acc5b6 100644 --- a/packages/@aws-cdk/aws-s3-assets/test/integ.assets.directory.lit.expected.json +++ b/packages/@aws-cdk/aws-s3-assets/test/integ.assets.directory.lit.expected.json @@ -24,8 +24,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -41,7 +41,8 @@ ":s3:::", { "Ref": "AssetParameters6b84b87243a4a01c592d78e1fd3855c4bfef39328cd0a450cc97e81717fea2a2S3Bucket50B5A10B" - } + }, + "/*" ] ] }, @@ -56,8 +57,7 @@ ":s3:::", { "Ref": "AssetParameters6b84b87243a4a01c592d78e1fd3855c4bfef39328cd0a450cc97e81717fea2a2S3Bucket50B5A10B" - }, - "/*" + } ] ] } diff --git a/packages/@aws-cdk/aws-s3-assets/test/integ.assets.file.lit.expected.json b/packages/@aws-cdk/aws-s3-assets/test/integ.assets.file.lit.expected.json index 4548468d9a80a..2c3894cefd893 100644 --- a/packages/@aws-cdk/aws-s3-assets/test/integ.assets.file.lit.expected.json +++ b/packages/@aws-cdk/aws-s3-assets/test/integ.assets.file.lit.expected.json @@ -24,8 +24,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -41,7 +41,8 @@ ":s3:::", { "Ref": "AssetParameters78add9eaf468dfa2191da44a7da92a21baba4c686cf6053d772556768ef21197S3Bucket2C60F94A" - } + }, + "/*" ] ] }, @@ -56,8 +57,7 @@ ":s3:::", { "Ref": "AssetParameters78add9eaf468dfa2191da44a7da92a21baba4c686cf6053d772556768ef21197S3Bucket2C60F94A" - }, - "/*" + } ] ] } diff --git a/packages/@aws-cdk/aws-s3-assets/test/integ.assets.permissions.lit.expected.json b/packages/@aws-cdk/aws-s3-assets/test/integ.assets.permissions.lit.expected.json index df2a4a5f73e9b..cf48b76027050 100644 --- a/packages/@aws-cdk/aws-s3-assets/test/integ.assets.permissions.lit.expected.json +++ b/packages/@aws-cdk/aws-s3-assets/test/integ.assets.permissions.lit.expected.json @@ -24,8 +24,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -41,7 +41,8 @@ ":s3:::", { "Ref": "AssetParameters78add9eaf468dfa2191da44a7da92a21baba4c686cf6053d772556768ef21197S3Bucket2C60F94A" - } + }, + "/*" ] ] }, @@ -56,8 +57,7 @@ ":s3:::", { "Ref": "AssetParameters78add9eaf468dfa2191da44a7da92a21baba4c686cf6053d772556768ef21197S3Bucket2C60F94A" - }, - "/*" + } ] ] } diff --git a/packages/@aws-cdk/aws-s3-assets/test/integ.assets.refs.lit.expected.json b/packages/@aws-cdk/aws-s3-assets/test/integ.assets.refs.lit.expected.json index 76aecf1148218..49c2b9550834b 100644 --- a/packages/@aws-cdk/aws-s3-assets/test/integ.assets.refs.lit.expected.json +++ b/packages/@aws-cdk/aws-s3-assets/test/integ.assets.refs.lit.expected.json @@ -154,8 +154,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -171,7 +171,8 @@ ":s3:::", { "Ref": "AssetParameters6b84b87243a4a01c592d78e1fd3855c4bfef39328cd0a450cc97e81717fea2a2S3Bucket50B5A10B" - } + }, + "/*" ] ] }, @@ -186,8 +187,7 @@ ":s3:::", { "Ref": "AssetParameters6b84b87243a4a01c592d78e1fd3855c4bfef39328cd0a450cc97e81717fea2a2S3Bucket50B5A10B" - }, - "/*" + } ] ] } diff --git a/packages/@aws-cdk/aws-s3-deployment/README.md b/packages/@aws-cdk/aws-s3-deployment/README.md index 62595042f652a..84ccec9e23c55 100644 --- a/packages/@aws-cdk/aws-s3-deployment/README.md +++ b/packages/@aws-cdk/aws-s3-deployment/README.md @@ -42,6 +42,25 @@ This is what happens under the hood: `websiteBucket`). If there is more than one source, the sources will be downloaded and merged pre-deployment at this step. +If you are referencing the filled bucket in another construct that depends on +the files already be there, be sure to use `deployment.deployedBucket`. This +will ensure the bucket deployment has finished before the resource that uses +the bucket is created: + +```ts +declare const websiteBucket: s3.Bucket; + +const deployment = new s3deploy.BucketDeployment(this, 'DeployWebsite', { + sources: [s3deploy.Source.asset(path.join(__dirname, 'my-website'))], + destinationBucket: websiteBucket, +}); + +new ConstructThatReadsFromTheBucket(this, 'Consumer', { + // Use 'deployment.deployedBucket' instead of 'websiteBucket' here + bucket: deployment.deployedBucket, +}); +``` + ## Supported sources The following source types are supported for bucket deployments: @@ -302,7 +321,7 @@ substituting it when its deployed to the destination with the actual value. ## Notes -- This library uses an AWS CloudFormation custom resource which about 10MiB in +- This library uses an AWS CloudFormation custom resource which is about 10MiB in size. The code of this resource is bundled with this library. - AWS Lambda execution time is limited to 15min. This limits the amount of data which can be deployed into the bucket by this timeout. diff --git a/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts b/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts index b08011866f7ea..31a7ec92e2db5 100644 --- a/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts +++ b/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts @@ -239,6 +239,10 @@ export interface BucketDeploymentProps { * other S3 buckets or from local disk */ export class BucketDeployment extends CoreConstruct { + private readonly cr: cdk.CustomResource; + private _deployedBucket?: s3.IBucket; + private requestDestinationArn: boolean = false; + constructor(scope: Construct, id: string, props: BucketDeploymentProps) { super(scope, id); @@ -328,7 +332,7 @@ export class BucketDeployment extends CoreConstruct { const hasMarkers = sources.some(source => source.markers); const crUniqueId = `CustomResource${this.renderUniqueId(props.memoryLimit, props.vpc)}`; - const cr = new cdk.CustomResource(this, crUniqueId, { + this.cr = new cdk.CustomResource(this, crUniqueId, { serviceToken: handler.functionArn, resourceType: 'Custom::CDKBucketDeployment', properties: { @@ -345,13 +349,15 @@ export class BucketDeployment extends CoreConstruct { SystemMetadata: mapSystemMetadata(props), DistributionId: props.distribution?.distributionId, DistributionPaths: props.distributionPaths, + // Passing through the ARN sequences dependencees on the deployment + DestinationBucketArn: cdk.Lazy.string({ produce: () => this.requestDestinationArn ? props.destinationBucket.bucketArn : undefined }), }, }); let prefix: string = props.destinationKeyPrefix ? `:${props.destinationKeyPrefix}` : ''; - prefix += `:${cr.node.addr.substr(-8)}`; + prefix += `:${this.cr.node.addr.substr(-8)}`; const tagKey = CUSTOM_RESOURCE_OWNER_TAG + prefix; // destinationKeyPrefix can be 104 characters before we hit @@ -405,6 +411,21 @@ export class BucketDeployment extends CoreConstruct { } + /** + * The bucket after the deployment + * + * If you want to reference the destination bucket in another construct and make sure the + * bucket deployment has happened before the next operation is started, pass the other construct + * a reference to `deployment.deployedBucket`. + * + * Doing this replaces calling `otherResource.node.addDependency(deployment)`. + */ + public get deployedBucket(): s3.IBucket { + this.requestDestinationArn = true; + this._deployedBucket = this._deployedBucket ?? s3.Bucket.fromBucketArn(this, 'DestinationBucket', cdk.Token.asString(this.cr.getAtt('DestinationBucketArn'))); + return this._deployedBucket; + } + private renderUniqueId(memoryLimit?: number, vpc?: ec2.IVpc) { let uuid = ''; diff --git a/packages/@aws-cdk/aws-s3-deployment/lib/lambda/index.py b/packages/@aws-cdk/aws-s3-deployment/lib/lambda/index.py index 14b1cc479e9d8..877b78a8452ee 100644 --- a/packages/@aws-cdk/aws-s3-deployment/lib/lambda/index.py +++ b/packages/@aws-cdk/aws-s3-deployment/lib/lambda/index.py @@ -118,7 +118,10 @@ def cfn_error(message=None): if distribution_id: cloudfront_invalidate(distribution_id, distribution_paths) - cfn_send(event, context, CFN_SUCCESS, physicalResourceId=physical_id) + cfn_send(event, context, CFN_SUCCESS, physicalResourceId=physical_id, responseData={ + # Passing through the ARN sequences dependencees on the deployment + 'DestinationBucketArn': props.get('DestinationBucketArn') + }) except KeyError as e: cfn_error("invalid request. Missing key %s" % str(e)) except Exception as e: diff --git a/packages/@aws-cdk/aws-s3-deployment/package.json b/packages/@aws-cdk/aws-s3-deployment/package.json index 70adaaac2ff88..104ff0bc223d2 100644 --- a/packages/@aws-cdk/aws-s3-deployment/package.json +++ b/packages/@aws-cdk/aws-s3-deployment/package.json @@ -90,8 +90,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-cloudfront": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3-deployment/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-s3-deployment/rosetta/default.ts-fixture index 75a435a142566..8733f436c5e29 100644 --- a/packages/@aws-cdk/aws-s3-deployment/rosetta/default.ts-fixture +++ b/packages/@aws-cdk/aws-s3-deployment/rosetta/default.ts-fixture @@ -13,3 +13,8 @@ class Fixture extends Stack { /// here } } + +class ConstructThatReadsFromTheBucket { + constructor(...args: any[]) { + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts b/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts index cff1a509c9b5b..9706f9d9d33f1 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts +++ b/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts @@ -945,6 +945,68 @@ test('deployment allows vpc and subnets to be implicitly supplied to lambda', () }); }); +test('s3 deployment bucket is identical to destination bucket', () => { + // GIVEN + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'Dest'); + + // WHEN + const bd = new s3deploy.BucketDeployment(stack, 'Deployment', { + destinationBucket: bucket, + sources: [s3deploy.Source.asset(path.join(__dirname, 'my-website'))], + }); + + // Call this function + void(bd.deployedBucket); + + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('Custom::CDKBucketDeployment', { + // Since this utilizes GetAtt, we know CFN will deploy the bucket first + // before deploying other resources that rely call the destination bucket. + DestinationBucketArn: { 'Fn::GetAtt': ['DestC383B82A', 'Arn'] }, + }); +}); + +test('using deployment bucket references the destination bucket by means of the CustomResource', () => { + // GIVEN + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'Dest'); + const deployment = new s3deploy.BucketDeployment(stack, 'Deployment', { + destinationBucket: bucket, + sources: [s3deploy.Source.asset(path.join(__dirname, 'my-website'))], + }); + + // WHEN + new cdk.CfnOutput(stack, 'DestinationArn', { + value: deployment.deployedBucket.bucketArn, + }); + new cdk.CfnOutput(stack, 'DestinationName', { + value: deployment.deployedBucket.bucketName, + }); + + // THEN + + const template = Template.fromStack(stack); + expect(template.findOutputs('*')).toEqual({ + DestinationArn: { + Value: { 'Fn::GetAtt': ['DeploymentCustomResource47E8B2E6', 'DestinationBucketArn'] }, + }, + DestinationName: { + Value: { + 'Fn::Select': [0, { + 'Fn::Split': ['/', { + 'Fn::Select': [5, { + 'Fn::Split': [':', + { 'Fn::GetAtt': ['DeploymentCustomResource47E8B2E6', 'DestinationBucketArn'] }], + }], + }], + }], + }, + }, + }); +}); + test('resource id includes memory and vpc', () => { // GIVEN @@ -1139,4 +1201,4 @@ function readDataFile(casm: cxapi.CloudAssembly, assetId: string, filePath: stri const asset = casm.stacks[0].assets.find(a => a.id === assetId); if (!asset) { throw new Error('Asset not found'); } return readFileSync(path.join(casm.directory, asset.path, filePath), 'utf-8'); -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json index 54fa70b01ed7f..f0447996bff9d 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json @@ -27,9 +27,9 @@ "Statement": [ { "Action": [ + "s3:DeleteObject*", "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*" + "s3:List*" ], "Effect": "Allow", "Principal": { @@ -230,7 +230,7 @@ "Properties": { "Content": { "S3Bucket": { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3Bucket59E5CFEF" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" }, "S3Key": { "Fn::Join": [ @@ -243,7 +243,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -256,7 +256,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -371,8 +371,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -388,7 +388,8 @@ ":s3:::", { "Ref": "AssetParametersfc4481abf279255619ff7418faa5d24456fef3432ea0da59c95542578ff0222eS3Bucket9CD8B20A" - } + }, + "/*" ] ] }, @@ -403,8 +404,7 @@ ":s3:::", { "Ref": "AssetParametersfc4481abf279255619ff7418faa5d24456fef3432ea0da59c95542578ff0222eS3Bucket9CD8B20A" - }, - "/*" + } ] ] } @@ -412,16 +412,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -449,8 +449,8 @@ }, { "Action": [ - "cloudfront:GetInvalidation", - "cloudfront:CreateInvalidation" + "cloudfront:CreateInvalidation", + "cloudfront:GetInvalidation" ], "Effect": "Allow", "Resource": "*" @@ -471,7 +471,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3BucketC3F9EAA2" + "Ref": "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3BucketF23C0DE7" }, "S3Key": { "Fn::Join": [ @@ -484,7 +484,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3VersionKey030ACBFF" + "Ref": "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3VersionKey5E97B17D" } ] } @@ -497,7 +497,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3VersionKey030ACBFF" + "Ref": "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3VersionKey5E97B17D" } ] } @@ -541,29 +541,29 @@ "Type": "String", "Description": "Artifact hash for asset \"be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824\"" }, - "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3Bucket59E5CFEF": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488": { "Type": "String", - "Description": "S3 bucket for asset \"187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0\"" + "Description": "S3 bucket for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2": { "Type": "String", - "Description": "S3 key for asset version \"187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0\"" + "Description": "S3 key for asset version \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0ArtifactHash8F73A2B0": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95ArtifactHash16B60F6C": { "Type": "String", - "Description": "Artifact hash for asset \"187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0\"" + "Description": "Artifact hash for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3BucketC3F9EAA2": { + "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3BucketF23C0DE7": { "Type": "String", - "Description": "S3 bucket for asset \"4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282e\"" + "Description": "S3 bucket for asset \"f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da\"" }, - "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3VersionKey030ACBFF": { + "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3VersionKey5E97B17D": { "Type": "String", - "Description": "S3 key for asset version \"4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282e\"" + "Description": "S3 key for asset version \"f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da\"" }, - "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eArtifactHashE8052809": { + "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daArtifactHashD85D28D8": { "Type": "String", - "Description": "Artifact hash for asset \"4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282e\"" + "Description": "Artifact hash for asset \"f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da\"" }, "AssetParametersfc4481abf279255619ff7418faa5d24456fef3432ea0da59c95542578ff0222eS3Bucket9CD8B20A": { "Type": "String", diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.expected.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.expected.json index 51b9a179e65c5..f8b42aa2fbd9b 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.expected.json +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.expected.json @@ -18,7 +18,7 @@ "Properties": { "Content": { "S3Bucket": { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3Bucket59E5CFEF" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" }, "S3Key": { "Fn::Join": [ @@ -31,7 +31,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -44,7 +44,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -241,8 +241,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -257,8 +257,9 @@ }, ":s3:::", { - "Ref": "AssetParametersd09271be89b6cb0398f793b40c1531fd9b076aa92ba80b5e436914b1808fe18dS3BucketBC52CF96" - } + "Ref": "AssetParameters0d7be86c2a7d62be64fcbe2cbaa36c912a72d445022cc17c37af4f99f1b97a5aS3Bucket485B8F98" + }, + "/*" ] ] }, @@ -272,22 +273,11 @@ }, ":s3:::", { - "Ref": "AssetParametersd09271be89b6cb0398f793b40c1531fd9b076aa92ba80b5e436914b1808fe18dS3BucketBC52CF96" - }, - "/*" + "Ref": "AssetParameters0d7be86c2a7d62be64fcbe2cbaa36c912a72d445022cc17c37af4f99f1b97a5aS3Bucket485B8F98" + } ] ] - } - ] - }, - { - "Action": [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*" - ], - "Effect": "Allow", - "Resource": [ + }, { "Fn::Join": [ "", @@ -299,7 +289,8 @@ ":s3:::", { "Ref": "AssetParameters0f14dedeaf4386031c978375cbda0f65d7b52b29452cabb8873eb8f0d0fa936bS3BucketE46D7C76" - } + }, + "/*" ] ] }, @@ -314,21 +305,10 @@ ":s3:::", { "Ref": "AssetParameters0f14dedeaf4386031c978375cbda0f65d7b52b29452cabb8873eb8f0d0fa936bS3BucketE46D7C76" - }, - "/*" + } ] ] - } - ] - }, - { - "Action": [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*" - ], - "Effect": "Allow", - "Resource": [ + }, { "Fn::Join": [ "", @@ -339,8 +319,9 @@ }, ":s3:::", { - "Ref": "AssetParameters0d7be86c2a7d62be64fcbe2cbaa36c912a72d445022cc17c37af4f99f1b97a5aS3Bucket485B8F98" - } + "Ref": "AssetParametersd09271be89b6cb0398f793b40c1531fd9b076aa92ba80b5e436914b1808fe18dS3BucketBC52CF96" + }, + "/*" ] ] }, @@ -354,9 +335,8 @@ }, ":s3:::", { - "Ref": "AssetParameters0d7be86c2a7d62be64fcbe2cbaa36c912a72d445022cc17c37af4f99f1b97a5aS3Bucket485B8F98" - }, - "/*" + "Ref": "AssetParametersd09271be89b6cb0398f793b40c1531fd9b076aa92ba80b5e436914b1808fe18dS3BucketBC52CF96" + } ] ] } @@ -364,16 +344,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -415,7 +395,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3BucketC3F9EAA2" + "Ref": "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3BucketF23C0DE7" }, "S3Key": { "Fn::Join": [ @@ -428,7 +408,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3VersionKey030ACBFF" + "Ref": "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3VersionKey5E97B17D" } ] } @@ -441,7 +421,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3VersionKey030ACBFF" + "Ref": "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3VersionKey5E97B17D" } ] } @@ -473,29 +453,29 @@ } }, "Parameters": { - "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3Bucket59E5CFEF": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488": { "Type": "String", - "Description": "S3 bucket for asset \"187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0\"" + "Description": "S3 bucket for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2": { "Type": "String", - "Description": "S3 key for asset version \"187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0\"" + "Description": "S3 key for asset version \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0ArtifactHash8F73A2B0": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95ArtifactHash16B60F6C": { "Type": "String", - "Description": "Artifact hash for asset \"187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0\"" + "Description": "Artifact hash for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3BucketC3F9EAA2": { + "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3BucketF23C0DE7": { "Type": "String", - "Description": "S3 bucket for asset \"4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282e\"" + "Description": "S3 bucket for asset \"f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da\"" }, - "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3VersionKey030ACBFF": { + "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3VersionKey5E97B17D": { "Type": "String", - "Description": "S3 key for asset version \"4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282e\"" + "Description": "S3 key for asset version \"f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da\"" }, - "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eArtifactHashE8052809": { + "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daArtifactHashD85D28D8": { "Type": "String", - "Description": "Artifact hash for asset \"4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282e\"" + "Description": "Artifact hash for asset \"f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da\"" }, "AssetParametersd09271be89b6cb0398f793b40c1531fd9b076aa92ba80b5e436914b1808fe18dS3BucketBC52CF96": { "Type": "String", diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment.expected.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment.expected.json index bf4c180c9b559..d1d5576423ee4 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment.expected.json +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment.expected.json @@ -42,9 +42,9 @@ "Statement": [ { "Action": [ + "s3:DeleteObject*", "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*" + "s3:List*" ], "Effect": "Allow", "Principal": { @@ -197,7 +197,7 @@ "Properties": { "Content": { "S3Bucket": { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3Bucket59E5CFEF" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" }, "S3Key": { "Fn::Join": [ @@ -210,7 +210,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -223,7 +223,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -332,8 +332,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -349,7 +349,8 @@ ":s3:::", { "Ref": "AssetParametersfc4481abf279255619ff7418faa5d24456fef3432ea0da59c95542578ff0222eS3Bucket9CD8B20A" - } + }, + "/*" ] ] }, @@ -364,8 +365,7 @@ ":s3:::", { "Ref": "AssetParametersfc4481abf279255619ff7418faa5d24456fef3432ea0da59c95542578ff0222eS3Bucket9CD8B20A" - }, - "/*" + } ] ] } @@ -373,19 +373,31 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ + { + "Fn::GetAtt": [ + "Destination281A09BDF", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "Destination3E3DC043D", + "Arn" + ] + }, { "Fn::GetAtt": [ "Destination920A3C57", @@ -398,36 +410,13 @@ [ { "Fn::GetAtt": [ - "Destination920A3C57", + "Destination281A09BDF", "Arn" ] }, "/*" ] ] - } - ] - }, - { - "Action": [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*", - "s3:PutObject", - "s3:PutObjectLegalHold", - "s3:PutObjectRetention", - "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::GetAtt": [ - "Destination281A09BDF", - "Arn" - ] }, { "Fn::Join": [ @@ -435,36 +424,13 @@ [ { "Fn::GetAtt": [ - "Destination281A09BDF", + "Destination3E3DC043D", "Arn" ] }, "/*" ] ] - } - ] - }, - { - "Action": [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*", - "s3:PutObject", - "s3:PutObjectLegalHold", - "s3:PutObjectRetention", - "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::GetAtt": [ - "Destination3E3DC043D", - "Arn" - ] }, { "Fn::Join": [ @@ -472,7 +438,7 @@ [ { "Fn::GetAtt": [ - "Destination3E3DC043D", + "Destination920A3C57", "Arn" ] }, @@ -498,7 +464,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3BucketC3F9EAA2" + "Ref": "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3BucketF23C0DE7" }, "S3Key": { "Fn::Join": [ @@ -511,7 +477,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3VersionKey030ACBFF" + "Ref": "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3VersionKey5E97B17D" } ] } @@ -524,7 +490,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3VersionKey030ACBFF" + "Ref": "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3VersionKey5E97B17D" } ] } @@ -1073,7 +1039,7 @@ "Properties": { "Content": { "S3Bucket": { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3Bucket59E5CFEF" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" }, "S3Key": { "Fn::Join": [ @@ -1086,7 +1052,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -1099,7 +1065,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -1494,8 +1460,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -1511,7 +1477,8 @@ ":s3:::", { "Ref": "AssetParametersfc4481abf279255619ff7418faa5d24456fef3432ea0da59c95542578ff0222eS3Bucket9CD8B20A" - } + }, + "/*" ] ] }, @@ -1526,8 +1493,7 @@ ":s3:::", { "Ref": "AssetParametersfc4481abf279255619ff7418faa5d24456fef3432ea0da59c95542578ff0222eS3Bucket9CD8B20A" - }, - "/*" + } ] ] } @@ -1535,16 +1501,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -1612,7 +1578,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3BucketC3F9EAA2" + "Ref": "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3BucketF23C0DE7" }, "S3Key": { "Fn::Join": [ @@ -1625,7 +1591,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3VersionKey030ACBFF" + "Ref": "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3VersionKey5E97B17D" } ] } @@ -1638,7 +1604,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3VersionKey030ACBFF" + "Ref": "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3VersionKey5E97B17D" } ] } @@ -1753,9 +1719,9 @@ "Statement": [ { "Action": [ + "s3:DeleteObject*", "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*" + "s3:List*" ], "Effect": "Allow", "Principal": { @@ -1818,7 +1784,7 @@ "Properties": { "Content": { "S3Bucket": { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3Bucket59E5CFEF" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" }, "S3Key": { "Fn::Join": [ @@ -1831,7 +1797,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -1844,7 +1810,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -1943,9 +1909,9 @@ "Statement": [ { "Action": [ + "s3:DeleteObject*", "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*" + "s3:List*" ], "Effect": "Allow", "Principal": { @@ -2008,7 +1974,7 @@ "Properties": { "Content": { "S3Bucket": { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3Bucket59E5CFEF" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" }, "S3Key": { "Fn::Join": [ @@ -2021,7 +1987,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -2034,7 +2000,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -2119,7 +2085,7 @@ "Properties": { "Content": { "S3Bucket": { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3Bucket59E5CFEF" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" }, "S3Key": { "Fn::Join": [ @@ -2132,7 +2098,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -2145,7 +2111,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -2221,7 +2187,7 @@ "Properties": { "Content": { "S3Bucket": { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3Bucket59E5CFEF" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" }, "S3Key": { "Fn::Join": [ @@ -2234,7 +2200,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -2247,7 +2213,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C" + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" } ] } @@ -2335,29 +2301,29 @@ "Type": "String", "Description": "Artifact hash for asset \"be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824\"" }, - "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3Bucket59E5CFEF": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488": { "Type": "String", - "Description": "S3 bucket for asset \"187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0\"" + "Description": "S3 bucket for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0S3VersionKey7EE70F5C": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2": { "Type": "String", - "Description": "S3 key for asset version \"187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0\"" + "Description": "S3 key for asset version \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameters187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0ArtifactHash8F73A2B0": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95ArtifactHash16B60F6C": { "Type": "String", - "Description": "Artifact hash for asset \"187e7a21dd5d55d36f1f45007ff6bbc5713cb0866ca86224c0f1f86b3d1e76a0\"" + "Description": "Artifact hash for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3BucketC3F9EAA2": { + "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3BucketF23C0DE7": { "Type": "String", - "Description": "S3 bucket for asset \"4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282e\"" + "Description": "S3 bucket for asset \"f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da\"" }, - "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eS3VersionKey030ACBFF": { + "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daS3VersionKey5E97B17D": { "Type": "String", - "Description": "S3 key for asset version \"4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282e\"" + "Description": "S3 key for asset version \"f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da\"" }, - "AssetParameters4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282eArtifactHashE8052809": { + "AssetParametersf98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711daArtifactHashD85D28D8": { "Type": "String", - "Description": "Artifact hash for asset \"4e09e63403b235ffda9db09367996f2d4c9fe1f7aa19b402908d8221614a282e\"" + "Description": "Artifact hash for asset \"f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da\"" }, "AssetParametersfc4481abf279255619ff7418faa5d24456fef3432ea0da59c95542578ff0222eS3Bucket9CD8B20A": { "Type": "String", diff --git a/packages/@aws-cdk/aws-s3-notifications/README.md b/packages/@aws-cdk/aws-s3-notifications/README.md index 0b57126001cf8..75fba9152e2b8 100644 --- a/packages/@aws-cdk/aws-s3-notifications/README.md +++ b/packages/@aws-cdk/aws-s3-notifications/README.md @@ -26,6 +26,18 @@ const topic = new sns.Topic(this, 'Topic'); bucket.addEventNotification(s3.EventType.OBJECT_CREATED_PUT, new s3n.SnsDestination(topic)); ``` +The following example shows how to send a notification to an SQS queue +when an object is created in an S3 bucket: + +```ts +import * as sqs from '@aws-cdk/aws-sqs'; + +const bucket = new s3.Bucket(this, 'Bucket'); +const queue = new sqs.Queue(this, 'Queue'); + +bucket.addEventNotification(s3.EventType.OBJECT_CREATED_PUT, new s3n.SqsDestination(queue)); +``` + The following example shows how to send a notification to a Lambda function when an object is created in an S3 bucket: ```ts diff --git a/packages/@aws-cdk/aws-s3-notifications/lib/sqs.ts b/packages/@aws-cdk/aws-s3-notifications/lib/sqs.ts index 330a941a9ae86..5562a07c5182a 100644 --- a/packages/@aws-cdk/aws-s3-notifications/lib/sqs.ts +++ b/packages/@aws-cdk/aws-s3-notifications/lib/sqs.ts @@ -1,6 +1,10 @@ import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import * as sqs from '@aws-cdk/aws-sqs'; +import { Annotations } from '@aws-cdk/core'; + +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order import { Construct } from '@aws-cdk/core'; /** @@ -24,11 +28,15 @@ export class SqsDestination implements s3.IBucketNotificationDestination { // if this queue is encrypted, we need to allow S3 to read messages since that's how // it verifies that the notification destination configuration is valid. if (this.queue.encryptionMasterKey) { - this.queue.encryptionMasterKey.addToResourcePolicy(new iam.PolicyStatement({ + const statement = new iam.PolicyStatement({ principals: [new iam.ServicePrincipal('s3.amazonaws.com')], actions: ['kms:GenerateDataKey*', 'kms:Decrypt'], resources: ['*'], - }), /* allowNoOp */ false); + }); + const addResult = this.queue.encryptionMasterKey.addToResourcePolicy(statement, /* allowNoOp */ true); + if (!addResult.statementAdded) { + Annotations.of(this.queue.encryptionMasterKey).addWarning(`Can not change key policy of imported kms key. Ensure that your key policy contains the following permissions: \n${JSON.stringify(statement.toJSON(), null, 2)}`); + } } return { diff --git a/packages/@aws-cdk/aws-s3-notifications/package.json b/packages/@aws-cdk/aws-s3-notifications/package.json index f40467d02c99d..32738cd1b0d93 100644 --- a/packages/@aws-cdk/aws-s3-notifications/package.json +++ b/packages/@aws-cdk/aws-s3-notifications/package.json @@ -75,11 +75,12 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", @@ -90,6 +91,7 @@ "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3-notifications/test/integ.notifications.expected.json b/packages/@aws-cdk/aws-s3-notifications/test/integ.notifications.expected.json index 9026931306ab4..472b3b55a72b7 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/integ.notifications.expected.json +++ b/packages/@aws-cdk/aws-s3-notifications/test/integ.notifications.expected.json @@ -1,5 +1,10 @@ { "Resources": { + "Bucket83908E77": { + "Type": "AWS::S3::Bucket", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, "BucketNotifications8F2E257D": { "Type": "Custom::S3BucketNotifications", "Properties": { @@ -51,11 +56,6 @@ "Topic3DEAE47A7" ] }, - "Bucket83908E77": { - "Type": "AWS::S3::Bucket", - "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete" - }, "TopicBFC7AF6E": { "Type": "AWS::SNS::Topic" }, @@ -222,12 +222,10 @@ "PolicyDocument": { "Statement": [ { - "Action": "s3:PutBucketNotification", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "s3:GetBucketNotification", + "Action": [ + "s3:GetBucketNotification", + "s3:PutBucketNotification" + ], "Effect": "Allow", "Resource": "*" } @@ -264,6 +262,11 @@ "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleB6FB88EC" ] }, + "Bucket25524B414": { + "Type": "AWS::S3::Bucket", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, "Bucket2NotificationsD9BA2A77": { "Type": "Custom::S3BucketNotifications", "Properties": { @@ -309,11 +312,6 @@ "Topic3DEAE47A7" ] }, - "Bucket25524B414": { - "Type": "AWS::S3::Bucket", - "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete" - }, "Bucket3NotificationsAFEFF359": { "Type": "Custom::S3BucketNotifications", "Properties": { diff --git a/packages/@aws-cdk/aws-s3-notifications/test/queue.test.ts b/packages/@aws-cdk/aws-s3-notifications/test/queue.test.ts index b1ae15e895a7c..44404de1b1d79 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/queue.test.ts +++ b/packages/@aws-cdk/aws-s3-notifications/test/queue.test.ts @@ -1,4 +1,5 @@ -import { Match, Template } from '@aws-cdk/assertions'; +import { Match, Template, Annotations } from '@aws-cdk/assertions'; +import * as kms from '@aws-cdk/aws-kms'; import * as s3 from '@aws-cdk/aws-s3'; import * as sqs from '@aws-cdk/aws-sqs'; import { Stack } from '@aws-cdk/core'; @@ -96,3 +97,27 @@ test('if the queue is encrypted with a custom kms key, the key resource policy i }, }); }); + +test('if the queue is encrypted with a imported kms key, printout warning', () => { + const stack = new Stack(); + const bucket = new s3.Bucket(stack, 'Bucket'); + const key = kms.Key.fromKeyArn(stack, 'ImportedKey', 'arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab'); + const queue = new sqs.Queue(stack, 'Queue', { + encryption: sqs.QueueEncryption.KMS, + encryptionMasterKey: key, + }); + + bucket.addObjectCreatedNotification(new notif.SqsDestination(queue)); + + Annotations.fromStack(stack).hasWarning('/Default/ImportedKey', `Can not change key policy of imported kms key. Ensure that your key policy contains the following permissions: \n${JSON.stringify({ + Action: [ + 'kms:GenerateDataKey*', + 'kms:Decrypt', + ], + Effect: 'Allow', + Principal: { + Service: 's3.amazonaws.com', + }, + Resource: '*', + }, null, 2)}`); +}); diff --git a/packages/@aws-cdk/aws-s3-notifications/test/sqs/integ.bucket-notifications.expected.json b/packages/@aws-cdk/aws-s3-notifications/test/sqs/integ.bucket-notifications.expected.json index 229b916beac4b..de109b272d9bb 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/sqs/integ.bucket-notifications.expected.json +++ b/packages/@aws-cdk/aws-s3-notifications/test/sqs/integ.bucket-notifications.expected.json @@ -1,5 +1,10 @@ { "Resources": { + "Bucket12520700A": { + "Type": "AWS::S3::Bucket", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, "Bucket1NotificationsBC5D9A45": { "Type": "Custom::S3BucketNotifications", "Properties": { @@ -48,11 +53,6 @@ "MyQueueE6CA6235" ] }, - "Bucket12520700A": { - "Type": "AWS::S3::Bucket", - "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete" - }, "MyQueueE6CA6235": { "Type": "AWS::SQS::Queue", "UpdateReplacePolicy": "Delete", @@ -65,9 +65,9 @@ "Statement": [ { "Action": [ - "sqs:SendMessage", "sqs:GetQueueAttributes", - "sqs:GetQueueUrl" + "sqs:GetQueueUrl", + "sqs:SendMessage" ], "Condition": { "ArnLike": { @@ -92,9 +92,9 @@ }, { "Action": [ - "sqs:SendMessage", "sqs:GetQueueAttributes", - "sqs:GetQueueUrl" + "sqs:GetQueueUrl", + "sqs:SendMessage" ], "Condition": { "ArnLike": { @@ -201,6 +201,11 @@ "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleB6FB88EC" ] }, + "Bucket25524B414": { + "Type": "AWS::S3::Bucket", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, "Bucket2NotificationsD9BA2A77": { "Type": "Custom::S3BucketNotifications", "Properties": { @@ -245,11 +250,6 @@ "MyQueueE6CA6235" ] }, - "Bucket25524B414": { - "Type": "AWS::S3::Bucket", - "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete" - }, "EncryptedQueueKey6F4FD304": { "Type": "AWS::KMS::Key", "Properties": { @@ -282,8 +282,8 @@ "Action": [ "kms:Decrypt", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Condition": { "ArnLike": { @@ -303,8 +303,8 @@ }, { "Action": [ - "kms:GenerateDataKey*", - "kms:Decrypt" + "kms:Decrypt", + "kms:GenerateDataKey*" ], "Effect": "Allow", "Principal": { @@ -340,9 +340,9 @@ "Statement": [ { "Action": [ - "sqs:SendMessage", "sqs:GetQueueAttributes", - "sqs:GetQueueUrl" + "sqs:GetQueueUrl", + "sqs:SendMessage" ], "Condition": { "ArnLike": { diff --git a/packages/@aws-cdk/aws-s3/lib/bucket.ts b/packages/@aws-cdk/aws-s3/lib/bucket.ts index 42d6a84bdc18b..321f65603c14c 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket.ts @@ -2297,6 +2297,16 @@ export enum EventType { */ OBJECT_RESTORE_COMPLETED = 's3:ObjectRestore:Completed', + /** + * Using restore object event types you can receive notifications for + * initiation and completion when restoring objects from the S3 Glacier + * storage class. + * + * You use s3:ObjectRestore:Delete to request notification of + * restoration completion. + */ + OBJECT_RESTORE_DELETE = 's3:ObjectRestore:Delete', + /** * You can use this event type to request Amazon S3 to send a notification * message when Amazon S3 detects that an object of the RRS storage class is diff --git a/packages/@aws-cdk/aws-s3/package.json b/packages/@aws-cdk/aws-s3/package.json index 7e3a9f89448e0..adff6efa3f93e 100644 --- a/packages/@aws-cdk/aws-s3/package.json +++ b/packages/@aws-cdk/aws-s3/package.json @@ -84,9 +84,9 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.92", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/aws-lambda": "^8.10.93", + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3/test/aspect.test.ts b/packages/@aws-cdk/aws-s3/test/aspect.test.ts index 5a3732bfbe70a..dd0acd0b8a65e 100644 --- a/packages/@aws-cdk/aws-s3/test/aspect.test.ts +++ b/packages/@aws-cdk/aws-s3/test/aspect.test.ts @@ -1,3 +1,4 @@ +import { Annotations } from '@aws-cdk/assertions'; import * as cdk from '@aws-cdk/core'; import { IConstruct } from 'constructs'; import * as s3 from '../lib'; @@ -13,9 +14,7 @@ describe('aspect', () => { cdk.Aspects.of(stack).add(new BucketVersioningChecker()); // THEN - const assembly = app.synth().getStackArtifact(stack.artifactId); - const errorMessage = assembly.messages.find(m => m.entry.data === 'Bucket versioning is not enabled'); - expect(errorMessage).toBeDefined(); + Annotations.fromStack(stack).hasError('/Default/MyBucket/Resource', 'Bucket versioning is not enabled'); }); test('bucket must have versioning: success', () => { @@ -30,8 +29,7 @@ describe('aspect', () => { cdk.Aspects.of(stack).add(new BucketVersioningChecker()); // THEN - const assembly = app.synth().getStackArtifact(stack.artifactId); - expect(assembly.messages.length).toEqual(0); + Annotations.fromStack(stack).hasNoError('/Default/MyBucket/Resource', 'Bucket versioning is not enabled'); }); }); diff --git a/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.expected.json b/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.expected.json index da2c8cf503fe6..c50af59d25b5c 100644 --- a/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.expected.json +++ b/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.expected.json @@ -23,9 +23,9 @@ "Statement": [ { "Action": [ + "s3:DeleteObject*", "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*" + "s3:List*" ], "Effect": "Allow", "Principal": { diff --git a/packages/@aws-cdk/aws-s3/test/integ.bucket-sharing.lit.expected.json b/packages/@aws-cdk/aws-s3/test/integ.bucket-sharing.lit.expected.json index d3f68abaf02b5..50df7b97b9f05 100644 --- a/packages/@aws-cdk/aws-s3/test/integ.bucket-sharing.lit.expected.json +++ b/packages/@aws-cdk/aws-s3/test/integ.bucket-sharing.lit.expected.json @@ -33,16 +33,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ diff --git a/packages/@aws-cdk/aws-s3/test/integ.bucket.expected.json b/packages/@aws-cdk/aws-s3/test/integ.bucket.expected.json index 4352395e831c2..fbe9cea592664 100644 --- a/packages/@aws-cdk/aws-s3/test/integ.bucket.expected.json +++ b/packages/@aws-cdk/aws-s3/test/integ.bucket.expected.json @@ -84,16 +84,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -124,8 +124,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -137,8 +137,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", diff --git a/packages/@aws-cdk/aws-s3objectlambda/README.md b/packages/@aws-cdk/aws-s3objectlambda/README.md index 60a5c42835925..35deed15685a9 100644 --- a/packages/@aws-cdk/aws-s3objectlambda/README.md +++ b/packages/@aws-cdk/aws-s3objectlambda/README.md @@ -9,23 +9,92 @@ > > [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib +![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) + +> The APIs of higher level constructs in this module are experimental and under active development. +> They are subject to non-backward compatible changes or removal in any future version. These are +> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be +> announced in the release notes. This means that while you may use them, you may need to update +> your source code when upgrading to a newer version of this package. + --- -This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. +This construct library allows you to define S3 object lambda access points. -```ts nofixture +```ts +import * as lambda from '@aws-cdk/aws-lambda'; +import * as s3 from '@aws-cdk/aws-s3'; import * as s3objectlambda from '@aws-cdk/aws-s3objectlambda'; +import * as cdk from '@aws-cdk/core'; + +const stack = new cdk.Stack(); +const bucket = new s3.Bucket(stack, 'MyBucket'); +const handler = new lambda.Function(stack, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_14_X, + handler: 'index.handler', + code: lambda.Code.fromAsset('lambda.zip'), +}); +new s3objectlambda.AccessPoint(stack, 'MyObjectLambda', { + bucket, + handler, + accessPointName: 'my-access-point', + payload: { + prop: "value", + }, +}); ``` - +## Handling range and part number requests + +Lambdas are currently limited to only transforming `GetObject` requests. However, they can additionally support `GetObject-Range` and `GetObject-PartNumber` requests, which needs to be specified in the access point configuration: + +```ts +import * as lambda from '@aws-cdk/aws-lambda'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as s3objectlambda from '@aws-cdk/aws-s3objectlambda'; +import * as cdk from '@aws-cdk/core'; -There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. -However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. +const stack = new cdk.Stack(); +const bucket = new s3.Bucket(stack, 'MyBucket'); +const handler = new lambda.Function(stack, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_14_X, + handler: 'index.handler', + code: lambda.Code.fromAsset('lambda.zip'), +}); +new s3objectlambda.AccessPoint(stack, 'MyObjectLambda', { + bucket, + handler, + accessPointName: 'my-access-point', + supportsGetObjectRange: true, + supportsGetObjectPartNumber: true, +}); +``` -For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::S3ObjectLambda](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_S3ObjectLambda.html). +## Pass additional data to Lambda function -(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) +You can specify an additional object that provides supplemental data to the Lambda function used to transform objects. The data is delivered as a JSON payload to the Lambda: - +```ts +import * as lambda from '@aws-cdk/aws-lambda'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as s3objectlambda from '@aws-cdk/aws-s3objectlambda'; +import * as cdk from '@aws-cdk/core'; + +const stack = new cdk.Stack(); +const bucket = new s3.Bucket(stack, 'MyBucket'); +const handler = new lambda.Function(stack, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_14_X, + handler: 'index.handler', + code: lambda.Code.fromAsset('lambda.zip'), +}); +new s3objectlambda.AccessPoint(stack, 'MyObjectLambda', { + bucket, + handler, + accessPointName: 'my-access-point', + payload: { + prop: "value", + }, +}); +``` diff --git a/packages/@aws-cdk/aws-s3objectlambda/lib/access-point.ts b/packages/@aws-cdk/aws-s3objectlambda/lib/access-point.ts new file mode 100644 index 0000000000000..a99fd64669f81 --- /dev/null +++ b/packages/@aws-cdk/aws-s3objectlambda/lib/access-point.ts @@ -0,0 +1,255 @@ +import * as iam from '@aws-cdk/aws-iam'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as core from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { CfnAccessPoint } from './s3objectlambda.generated'; + +/** + * The interface that represents the AccessPoint resource. + */ +export interface IAccessPoint extends core.IResource { + /** + * The ARN of the access point. + * @attribute + */ + readonly accessPointArn: string; + + /** + * The creation data of the access point. + * @attribute + */ + readonly accessPointCreationDate: string; + + /** + * The IPv4 DNS name of the access point. + */ + readonly domainName: string; + + /** + * The regional domain name of the access point. + */ + readonly regionalDomainName: string; + + /** + * The virtual hosted-style URL of an S3 object through this access point. + * Specify `regional: false` at the options for non-regional URL. + * @param key The S3 key of the object. If not specified, the URL of the + * bucket is returned. + * @param options Options for generating URL. + * @returns an ObjectS3Url token + */ + virtualHostedUrlForObject(key?: string, options?: s3.VirtualHostedStyleUrlOptions): string; +} + +/** + * The S3 object lambda access point configuration. + */ +export interface AccessPointProps { + /** + * The bucket to which this access point belongs. + */ + readonly bucket: s3.IBucket; + + /** + * The Lambda function used to transform objects. + */ + readonly handler: lambda.IFunction; + + /** + * The name of the S3 object lambda access point. + * + * @default a unique name will be generated + */ + readonly accessPointName?: string; + + /** + * Whether CloudWatch metrics are enabled for the access point. + * + * @default false + */ + readonly cloudWatchMetricsEnabled?: boolean; + + /** + * Whether the Lambda function can process `GetObject-Range` requests. + * + * @default false + */ + readonly supportsGetObjectRange?: boolean; + + /** + * Whether the Lambda function can process `GetObject-PartNumber` requests. + * + * @default false + */ + readonly supportsGetObjectPartNumber?: boolean; + + /** + * Additional JSON that provides supplemental data passed to the + * Lambda function on every request. + * + * @default - No data. + */ + readonly payload?: { [key: string]: any }; +} + +abstract class AccessPointBase extends core.Resource implements IAccessPoint { + public abstract readonly accessPointArn: string; + public abstract readonly accessPointCreationDate: string; + public abstract readonly accessPointName: string; + + /** Implement the {@link IAccessPoint.domainName} field. */ + get domainName(): string { + const urlSuffix = this.stack.urlSuffix; + return `${this.accessPointName}-${this.stack.account}.s3-object-lambda.${urlSuffix}`; + } + + /** Implement the {@link IAccessPoint.regionalDomainName} field. */ + get regionalDomainName(): string { + const urlSuffix = this.stack.urlSuffix; + const region = this.stack.region; + return `${this.accessPointName}-${this.stack.account}.s3-object-lambda.${region}.${urlSuffix}`; + } + + /** Implement the {@link IAccessPoint.virtualHostedUrlForObject} method. */ + public virtualHostedUrlForObject(key?: string, options?: s3.VirtualHostedStyleUrlOptions): string { + const domainName = options?.regional ?? true ? this.regionalDomainName : this.domainName; + const prefix = `https://${domainName}`; + if (!key) { + return prefix; + } + if (key.startsWith('/')) { + key = key.slice(1); + } + if (key.endsWith('/')) { + key = key.slice(0, -1); + } + return `${prefix}/${key}`; + } +} + +/** + * The access point resource attributes. + */ +export interface AccessPointAttributes { + /** + * The ARN of the access point. + */ + readonly accessPointArn: string + + /** + * The creation data of the access point. + */ + readonly accessPointCreationDate: string; +} + +/** + * Checks the access point name against the rules in https://docs.aws.amazon.com/AmazonS3/latest/userguide/creating-access-points.html#access-points-names + * @param name The name of the access point + */ +function validateAccessPointName(name: string): void { + if (name.length < 3 || name.length > 50) { + throw new Error('Access point name must be between 3 and 50 characters long'); + } + if (name.endsWith('-s3alias')) { + throw new Error('Access point name cannot end with the suffix -s3alias'); + } + if (name[0] === '-' || name[name.length - 1] === '-') { + throw new Error('Access point name cannot begin or end with a dash'); + } + if (!/^[0-9a-z](.(?![\.A-Z_]))+[0-9a-z]$/.test(name)) { + throw new Error('Access point name must begin with a number or lowercase letter and not contain underscores, uppercase letters, or periods'); + } +} + +/** + * An S3 object lambda access point for intercepting and + * transforming `GetObject` requests. + */ +export class AccessPoint extends AccessPointBase { + /** + * Reference an existing AccessPoint defined outside of the CDK code. + */ + public static fromAccessPointAttributes(scope: Construct, id: string, attrs: AccessPointAttributes): IAccessPoint { + const arn = core.Arn.split(attrs.accessPointArn, core.ArnFormat.SLASH_RESOURCE_NAME); + if (!arn.resourceName) { + throw new Error('Unable to parse acess point name'); + } + const name = arn.resourceName; + class Import extends AccessPointBase { + public readonly accessPointArn: string = attrs.accessPointArn; + public readonly accessPointCreationDate: string = attrs.accessPointCreationDate; + public readonly accessPointName: string = name; + } + return new Import(scope, id); + } + + /** + * The ARN of the access point. + */ + public readonly accessPointName: string + + /** + * The ARN of the access point. + * @attribute + */ + public readonly accessPointArn: string + + /** + * The creation data of the access point. + * @attribute + */ + public readonly accessPointCreationDate: string + + constructor(scope: Construct, id: string, props: AccessPointProps) { + super(scope, id, { + physicalName: props.accessPointName, + }); + + if (props.accessPointName) { + validateAccessPointName(props.accessPointName); + } + + const supporting = new s3.CfnAccessPoint(this, 'SupportingAccessPoint', { + bucket: props.bucket.bucketName, + }); + + const allowedFeatures = []; + if (props.supportsGetObjectPartNumber) { + allowedFeatures.push('GetObject-PartNumber'); + } + if (props.supportsGetObjectRange) { + allowedFeatures.push('GetObject-Range'); + } + + const accessPoint = new CfnAccessPoint(this, id, { + name: this.physicalName, + objectLambdaConfiguration: { + allowedFeatures, + cloudWatchMetricsEnabled: props.cloudWatchMetricsEnabled, + supportingAccessPoint: supporting.attrArn, + transformationConfigurations: [ + { + actions: ['GetObject'], + contentTransformation: { + AwsLambda: { + FunctionArn: props.handler.functionArn, + FunctionPayload: props.payload ? JSON.stringify(props.payload) : undefined, + }, + }, + }, + ], + }, + }); + this.accessPointName = accessPoint.ref; + this.accessPointArn = accessPoint.attrArn; + this.accessPointCreationDate = accessPoint.attrCreationDate; + + props.handler.addToRolePolicy( + new iam.PolicyStatement({ + actions: ['s3-object-lambda:WriteGetObjectResponse'], + resources: ['*'], + }), + ); + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3objectlambda/lib/index.ts b/packages/@aws-cdk/aws-s3objectlambda/lib/index.ts index 791ddcf126933..e3c96c8d8be85 100644 --- a/packages/@aws-cdk/aws-s3objectlambda/lib/index.ts +++ b/packages/@aws-cdk/aws-s3objectlambda/lib/index.ts @@ -1,2 +1,4 @@ +export * from './access-point'; + // AWS::S3ObjectLambda CloudFormation Resources: export * from './s3objectlambda.generated'; diff --git a/packages/@aws-cdk/aws-s3objectlambda/package.json b/packages/@aws-cdk/aws-s3objectlambda/package.json index 0e1020f5e6dc1..97ccfc93dfff9 100644 --- a/packages/@aws-cdk/aws-s3objectlambda/package.json +++ b/packages/@aws-cdk/aws-s3objectlambda/package.json @@ -85,25 +85,40 @@ "devDependencies": { "@aws-cdk/assertions": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { - "@aws-cdk/core": "0.0.0" + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" }, "peerDependencies": { - "@aws-cdk/core": "0.0.0" + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", - "maturity": "cfn-only", + "maturity": "experimental", "awscdkio": { "announce": false }, "publishConfig": { "tag": "latest" + }, + "awslint": { + "exclude": [ + "attribute-tag:@aws-cdk/aws-s3objectlambda.AccessPoint.accessPointName" + ] } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3objectlambda/test/integ.s3objectlambda.expected.json b/packages/@aws-cdk/aws-s3objectlambda/test/integ.s3objectlambda.expected.json new file mode 100644 index 0000000000000..c53bfb57cd719 --- /dev/null +++ b/packages/@aws-cdk/aws-s3objectlambda/test/integ.s3objectlambda.expected.json @@ -0,0 +1,239 @@ +{ + "Resources": { + "MyBucketF68F3FF0": { + "Type": "AWS::S3::Bucket", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "MyFunction1ServiceRole9852B06B": { + "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" + ] + ] + } + ] + } + }, + "MyFunction1ServiceRoleDefaultPolicy39556460": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3-object-lambda:WriteGetObjectResponse", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyFunction1ServiceRoleDefaultPolicy39556460", + "Roles": [ + { + "Ref": "MyFunction1ServiceRole9852B06B" + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRoleDefaultPolicy39556460", + "MyFunction1ServiceRole9852B06B" + ] + }, + "MyFunction2ServiceRole07E5BE0E": { + "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" + ] + ] + } + ] + } + }, + "MyFunction2ServiceRoleDefaultPolicyA79C693E": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3-object-lambda:WriteGetObjectResponse", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyFunction2ServiceRoleDefaultPolicyA79C693E", + "Roles": [ + { + "Ref": "MyFunction2ServiceRole07E5BE0E" + } + ] + } + }, + "MyFunction2F2A964CA": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction2ServiceRole07E5BE0E", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction2ServiceRoleDefaultPolicyA79C693E", + "MyFunction2ServiceRole07E5BE0E" + ] + }, + "MyObjectLambda1SupportingAccessPoint223B719B": { + "Type": "AWS::S3::AccessPoint", + "Properties": { + "Bucket": { + "Ref": "MyBucketF68F3FF0" + } + } + }, + "MyObjectLambda17554FEF4": { + "Type": "AWS::S3ObjectLambda::AccessPoint", + "Properties": { + "Name": "obj-lambda-1", + "ObjectLambdaConfiguration": { + "AllowedFeatures": [ + "GetObject-PartNumber" + ], + "CloudWatchMetricsEnabled": true, + "SupportingAccessPoint": { + "Fn::GetAtt": [ + "MyObjectLambda1SupportingAccessPoint223B719B", + "Arn" + ] + }, + "TransformationConfigurations": [ + { + "Actions": [ + "GetObject" + ], + "ContentTransformation": { + "AwsLambda": { + "FunctionArn": { + "Fn::GetAtt": [ + "MyFunction12A744C2E", + "Arn" + ] + } + } + } + } + ] + } + } + }, + "MyObjectLambda2SupportingAccessPoint6C54778F": { + "Type": "AWS::S3::AccessPoint", + "Properties": { + "Bucket": { + "Ref": "MyBucketF68F3FF0" + } + } + }, + "MyObjectLambda2CCBCAAF7": { + "Type": "AWS::S3ObjectLambda::AccessPoint", + "Properties": { + "Name": "obj-lambda-1", + "ObjectLambdaConfiguration": { + "AllowedFeatures": [ + "GetObject-Range" + ], + "SupportingAccessPoint": { + "Fn::GetAtt": [ + "MyObjectLambda2SupportingAccessPoint6C54778F", + "Arn" + ] + }, + "TransformationConfigurations": [ + { + "Actions": [ + "GetObject" + ], + "ContentTransformation": { + "AwsLambda": { + "FunctionArn": { + "Fn::GetAtt": [ + "MyFunction2F2A964CA", + "Arn" + ] + }, + "FunctionPayload": "{\"foo\":10}" + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3objectlambda/test/integ.s3objectlambda.ts b/packages/@aws-cdk/aws-s3objectlambda/test/integ.s3objectlambda.ts new file mode 100644 index 0000000000000..e840de6367479 --- /dev/null +++ b/packages/@aws-cdk/aws-s3objectlambda/test/integ.s3objectlambda.ts @@ -0,0 +1,45 @@ +import * as lambda from '@aws-cdk/aws-lambda'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; +import { AccessPoint } from '../lib'; + +class TestStack extends cdk.Stack { + constructor(scope: cdk.App, id: string) { + super(scope, id); + + const bucket = new s3.Bucket(this, 'MyBucket'); + const handler1 = new lambda.Function(this, 'MyFunction1', { + runtime: lambda.Runtime.NODEJS_14_X, + handler: 'index.handler', + code: lambda.Code.fromInline('foo'), + }); + + const handler2 = new lambda.Function(this, 'MyFunction2', { + runtime: lambda.Runtime.NODEJS_14_X, + handler: 'index.handler', + code: lambda.Code.fromInline('foo'), + }); + + new AccessPoint(this, 'MyObjectLambda1', { + bucket, + handler: handler1, + accessPointName: 'obj-lambda-1', + cloudWatchMetricsEnabled: true, + supportsGetObjectPartNumber: true, + }); + + new AccessPoint(this, 'MyObjectLambda2', { + bucket, + handler: handler2, + accessPointName: 'obj-lambda-1', + supportsGetObjectRange: true, + payload: { foo: 10 }, + }); + } +} + +const app = new cdk.App(); + +new TestStack(app, 'aws-s3-object-lambda'); + +app.synth(); diff --git a/packages/@aws-cdk/aws-s3objectlambda/test/s3objectlambda.test.ts b/packages/@aws-cdk/aws-s3objectlambda/test/s3objectlambda.test.ts index 465c7bdea0693..3e62fd370f039 100644 --- a/packages/@aws-cdk/aws-s3objectlambda/test/s3objectlambda.test.ts +++ b/packages/@aws-cdk/aws-s3objectlambda/test/s3objectlambda.test.ts @@ -1,6 +1,338 @@ -import '@aws-cdk/assertions'; -import {} from '../lib'; +import { Template } from '@aws-cdk/assertions'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; +import { AccessPoint } from '../lib'; -test('No tests are specified for this package', () => { - expect(true).toBe(true); +let stack: cdk.Stack; +let bucket: s3.Bucket; +let handler: lambda.Function; + +beforeEach(() => { + stack = new cdk.Stack(); + bucket = new s3.Bucket(stack, 'MyBucket'); + handler = new lambda.Function(stack, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_14_X, + handler: 'index.hello', + code: new lambda.InlineCode('def hello(): pass'), + }); +}); + +test('Can create a valid access point', () => { + const accessPoint = new AccessPoint(stack, 'MyObjectLambda', { + bucket, + handler, + accessPointName: 'obj-lambda', + supportsGetObjectRange: true, + supportsGetObjectPartNumber: true, + payload: { foo: 10 }, + }); + new cdk.CfnOutput(stack, 'AccessPointName', { + value: accessPoint.accessPointName, + }); + new cdk.CfnOutput(stack, 'DomainName', { + value: accessPoint.domainName, + }); + new cdk.CfnOutput(stack, 'RegionalDomainName', { + value: accessPoint.regionalDomainName, + }); + new cdk.CfnOutput(stack, 'VirtualHostedUrl', { + value: accessPoint.virtualHostedUrlForObject('key', { + regional: true, + }), + }); + new cdk.CfnOutput(stack, 'VirtualHostedRegionalUrl', { + value: accessPoint.virtualHostedUrlForObject('key', { + regional: false, + }), + }); + + expect(Template.fromStack(stack).findOutputs('*')).toEqual( + { + AccessPointName: { + Value: { + Ref: 'MyObjectLambda3F9602DC', + }, + }, + DomainName: { + Value: { + 'Fn::Join': [ + '', + [ + { + Ref: 'MyObjectLambda3F9602DC', + }, + '-', + { + Ref: 'AWS::AccountId', + }, + '.s3-object-lambda.', + { + Ref: 'AWS::URLSuffix', + }, + ], + ], + }, + }, + RegionalDomainName: { + Value: { + 'Fn::Join': [ + '', + [ + { + Ref: 'MyObjectLambda3F9602DC', + }, + '-', + { + Ref: 'AWS::AccountId', + }, + '.s3-object-lambda.', + { + Ref: 'AWS::Region', + }, + '.', + { + Ref: 'AWS::URLSuffix', + }, + ], + ], + }, + }, + VirtualHostedRegionalUrl: { + Value: { + 'Fn::Join': [ + '', + [ + 'https://', + { + Ref: 'MyObjectLambda3F9602DC', + }, + '-', + { + Ref: 'AWS::AccountId', + }, + '.s3-object-lambda.', + { + Ref: 'AWS::URLSuffix', + }, + '/key', + ], + ], + }, + }, + VirtualHostedUrl: { + Value: { + 'Fn::Join': [ + '', + [ + 'https://', + { + Ref: 'MyObjectLambda3F9602DC', + }, + '-', + { + Ref: 'AWS::AccountId', + }, + '.s3-object-lambda.', + { + Ref: 'AWS::Region', + }, + '.', + { + Ref: 'AWS::URLSuffix', + }, + '/key', + ], + ], + }, + }, + }, + ); + + Template.fromStack(stack).hasResourceProperties('AWS::S3ObjectLambda::AccessPoint', { + ObjectLambdaConfiguration: { + AllowedFeatures: [ + 'GetObject-PartNumber', + 'GetObject-Range', + ], + TransformationConfigurations: [ + { + Actions: [ + 'GetObject', + ], + ContentTransformation: { + AwsLambda: { + FunctionArn: { + 'Fn::GetAtt': [ + 'MyFunction3BAA72D1', + 'Arn', + ], + }, + FunctionPayload: '{"foo":10}', + }, + }, + }, + ], + }, + }); +}); + +test('Can create an access point without specifying the name', () => { + new AccessPoint(stack, 'MyObjectLambda', { + bucket, + handler, + }); + Template.fromStack(stack).hasResourceProperties('AWS::S3ObjectLambda::AccessPoint', { + ObjectLambdaConfiguration: { + AllowedFeatures: [], + }, + }); +}); + +test('Slashes are removed from the virtual hosted url', () => { + const accessPoint = new AccessPoint(stack, 'MyObjectLambda', { + bucket, + handler, + }); + new cdk.CfnOutput(stack, 'VirtualHostedUrlNoKey', { + value: accessPoint.virtualHostedUrlForObject(), + }); + new cdk.CfnOutput(stack, 'VirtualHostedUrlKeyBeginsSlash', { + value: accessPoint.virtualHostedUrlForObject('/key1/key2'), + }); + new cdk.CfnOutput(stack, 'VirtualHostedUrlKeyEndsSlash', { + value: accessPoint.virtualHostedUrlForObject('key1/key2/'), + }); + expect(Template.fromStack(stack).findOutputs('*')).toEqual( { + VirtualHostedUrlKeyBeginsSlash: { + Value: { + 'Fn::Join': [ + '', + [ + 'https://', + { + Ref: 'MyObjectLambda3F9602DC', + }, + '-', + { + Ref: 'AWS::AccountId', + }, + '.s3-object-lambda.', + { + Ref: 'AWS::Region', + }, + '.', + { + Ref: 'AWS::URLSuffix', + }, + '/key1/key2', + ], + ], + }, + }, + VirtualHostedUrlKeyEndsSlash: { + Value: { + 'Fn::Join': [ + '', + [ + 'https://', + { + Ref: 'MyObjectLambda3F9602DC', + }, + '-', + { + Ref: 'AWS::AccountId', + }, + '.s3-object-lambda.', + { + Ref: 'AWS::Region', + }, + '.', + { + Ref: 'AWS::URLSuffix', + }, + '/key1/key2', + ], + ], + }, + }, + VirtualHostedUrlNoKey: { + Value: { + 'Fn::Join': [ + '', + [ + 'https://', + { + Ref: 'MyObjectLambda3F9602DC', + }, + '-', + { + Ref: 'AWS::AccountId', + }, + '.s3-object-lambda.', + { + Ref: 'AWS::Region', + }, + '.', + { + Ref: 'AWS::URLSuffix', + }, + ], + ], + }, + }, + }); +}); + +test('Validates the access point name', () => { + expect(() => new AccessPoint(stack, 'MyObjectLambda1', { + bucket, + handler, + accessPointName: 'aa', + })).toThrowError(/name must be between 3 and 50 characters long/); + expect(() => new AccessPoint(stack, 'MyObjectLambda2', { + bucket, + handler, + accessPointName: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + })).toThrowError(/name must be between 3 and 50 characters long/); + expect(() => new AccessPoint(stack, 'MyObjectLambda3', { + bucket, + handler, + accessPointName: 'aaaa-s3alias', + })).toThrowError(/name cannot end with the suffix -s3alias/); + expect(() => new AccessPoint(stack, 'MyObjectLambda4', { + bucket, + handler, + accessPointName: '-aaaaa', + })).toThrowError(/name cannot begin or end with a dash/); + expect(() => new AccessPoint(stack, 'MyObjectLambda5', { + bucket, + handler, + accessPointName: 'aaaaa-', + })).toThrowError(/name cannot begin or end with a dash/); + expect(() => new AccessPoint(stack, 'MyObjectLambda6', { + bucket, + handler, + accessPointName: 'Aaaaa', + })).toThrowError(/name must begin with a number or lowercase letter and not contain underscores, uppercase letters, or periods/); + expect(() => new AccessPoint(stack, 'MyObjectLambda7', { + bucket, + handler, + accessPointName: '$aaaaa', + })).toThrowError(/name must begin with a number or lowercase letter and not contain underscores, uppercase letters, or periods/); + expect(() => new AccessPoint(stack, 'MyObjectLambda8', { + bucket, + handler, + accessPointName: 'aaaAaaa', + })).toThrowError(/name must begin with a number or lowercase letter and not contain underscores, uppercase letters, or periods/); + expect(() => new AccessPoint(stack, 'MyObjectLambda9', { + bucket, + handler, + accessPointName: 'aaa_aaa', + })).toThrowError(/name must begin with a number or lowercase letter and not contain underscores, uppercase letters, or periods/); + expect(() => new AccessPoint(stack, 'MyObjectLambda10', { + bucket, + handler, + accessPointName: 'aaa.aaa', + })).toThrowError(/name must begin with a number or lowercase letter and not contain underscores, uppercase letters, or periods/); }); diff --git a/packages/@aws-cdk/aws-s3outposts/package.json b/packages/@aws-cdk/aws-s3outposts/package.json index 9c1b9dc830771..0ad8877061133 100644 --- a/packages/@aws-cdk/aws-s3outposts/package.json +++ b/packages/@aws-cdk/aws-s3outposts/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-sagemaker/package.json b/packages/@aws-cdk/aws-sagemaker/package.json index 9741c8b8d96a3..cb5332a56fc47 100644 --- a/packages/@aws-cdk/aws-sagemaker/package.json +++ b/packages/@aws-cdk/aws-sagemaker/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-sam/package.json b/packages/@aws-cdk/aws-sam/package.json index 7b955ade95a3f..d8295d5f1aef8 100644 --- a/packages/@aws-cdk/aws-sam/package.json +++ b/packages/@aws-cdk/aws-sam/package.json @@ -84,9 +84,9 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7", - "ts-jest": "^27.1.3" + "@types/jest": "^27.4.1", + "jest": "^27.5.1", + "ts-jest": "^27.1.4" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-sdb/package.json b/packages/@aws-cdk/aws-sdb/package.json index 4636ae5160146..a4072de0aa01c 100644 --- a/packages/@aws-cdk/aws-sdb/package.json +++ b/packages/@aws-cdk/aws-sdb/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-secretsmanager/README.md b/packages/@aws-cdk/aws-secretsmanager/README.md index 8ff23ea3ba01d..5b88885e863a5 100644 --- a/packages/@aws-cdk/aws-secretsmanager/README.md +++ b/packages/@aws-cdk/aws-secretsmanager/README.md @@ -63,7 +63,7 @@ A secret can set `RemovalPolicy`. If it set to `RETAIN`, that removing a secret ## Grant permission to use the secret to a role You must grant permission to a resource for that resource to be allowed to -use a secret. This can be achieved with the `Secret.grantRead` and/or `Secret.grantUpdate` +use a secret. This can be achieved with the `Secret.grantRead` and/or `Secret.grantWrite` method, depending on your need: ```ts diff --git a/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts b/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts index 3519616fe1308..370641de3c548 100644 --- a/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts +++ b/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts @@ -28,84 +28,84 @@ export class SecretRotationApplication { /** * Conducts an AWS SecretsManager secret rotation for RDS MariaDB using the single user rotation scheme */ - public static readonly MARIADB_ROTATION_SINGLE_USER = new SecretRotationApplication('SecretsManagerRDSMariaDBRotationSingleUser', '1.1.60'); + public static readonly MARIADB_ROTATION_SINGLE_USER = new SecretRotationApplication('SecretsManagerRDSMariaDBRotationSingleUser', '1.1.225'); /** * Conducts an AWS SecretsManager secret rotation for RDS MariaDB using the multi user rotation scheme */ - public static readonly MARIADB_ROTATION_MULTI_USER = new SecretRotationApplication('SecretsManagerRDSMariaDBRotationMultiUser', '1.1.60', { + public static readonly MARIADB_ROTATION_MULTI_USER = new SecretRotationApplication('SecretsManagerRDSMariaDBRotationMultiUser', '1.1.225', { isMultiUser: true, }); /** * Conducts an AWS SecretsManager secret rotation for RDS MySQL using the single user rotation scheme */ - public static readonly MYSQL_ROTATION_SINGLE_USER = new SecretRotationApplication('SecretsManagerRDSMySQLRotationSingleUser', '1.1.60'); + public static readonly MYSQL_ROTATION_SINGLE_USER = new SecretRotationApplication('SecretsManagerRDSMySQLRotationSingleUser', '1.1.225'); /** * Conducts an AWS SecretsManager secret rotation for RDS MySQL using the multi user rotation scheme */ - public static readonly MYSQL_ROTATION_MULTI_USER = new SecretRotationApplication('SecretsManagerRDSMySQLRotationMultiUser', '1.1.60', { + public static readonly MYSQL_ROTATION_MULTI_USER = new SecretRotationApplication('SecretsManagerRDSMySQLRotationMultiUser', '1.1.225', { isMultiUser: true, }); /** * Conducts an AWS SecretsManager secret rotation for RDS Oracle using the single user rotation scheme */ - public static readonly ORACLE_ROTATION_SINGLE_USER = new SecretRotationApplication('SecretsManagerRDSOracleRotationSingleUser', '1.1.60'); + public static readonly ORACLE_ROTATION_SINGLE_USER = new SecretRotationApplication('SecretsManagerRDSOracleRotationSingleUser', '1.1.225'); /** * Conducts an AWS SecretsManager secret rotation for RDS Oracle using the multi user rotation scheme */ - public static readonly ORACLE_ROTATION_MULTI_USER = new SecretRotationApplication('SecretsManagerRDSOracleRotationMultiUser', '1.1.60', { + public static readonly ORACLE_ROTATION_MULTI_USER = new SecretRotationApplication('SecretsManagerRDSOracleRotationMultiUser', '1.1.225', { isMultiUser: true, }); /** * Conducts an AWS SecretsManager secret rotation for RDS PostgreSQL using the single user rotation scheme */ - public static readonly POSTGRES_ROTATION_SINGLE_USER = new SecretRotationApplication('SecretsManagerRDSPostgreSQLRotationSingleUser', '1.1.60'); + public static readonly POSTGRES_ROTATION_SINGLE_USER = new SecretRotationApplication('SecretsManagerRDSPostgreSQLRotationSingleUser', '1.1.225'); /** * Conducts an AWS SecretsManager secret rotation for RDS PostgreSQL using the multi user rotation scheme */ - public static readonly POSTGRES_ROTATION_MULTI_USER = new SecretRotationApplication('SecretsManagerRDSPostgreSQLRotationMultiUser', '1.1.60', { + public static readonly POSTGRES_ROTATION_MULTI_USER = new SecretRotationApplication('SecretsManagerRDSPostgreSQLRotationMultiUser', '1.1.225', { isMultiUser: true, }); /** * Conducts an AWS SecretsManager secret rotation for RDS SQL Server using the single user rotation scheme */ - public static readonly SQLSERVER_ROTATION_SINGLE_USER = new SecretRotationApplication('SecretsManagerRDSSQLServerRotationSingleUser', '1.1.60'); + public static readonly SQLSERVER_ROTATION_SINGLE_USER = new SecretRotationApplication('SecretsManagerRDSSQLServerRotationSingleUser', '1.1.225'); /** * Conducts an AWS SecretsManager secret rotation for RDS SQL Server using the multi user rotation scheme */ - public static readonly SQLSERVER_ROTATION_MULTI_USER = new SecretRotationApplication('SecretsManagerRDSSQLServerRotationMultiUser', '1.1.60', { + public static readonly SQLSERVER_ROTATION_MULTI_USER = new SecretRotationApplication('SecretsManagerRDSSQLServerRotationMultiUser', '1.1.225', { isMultiUser: true, }); /** * Conducts an AWS SecretsManager secret rotation for Amazon Redshift using the single user rotation scheme */ - public static readonly REDSHIFT_ROTATION_SINGLE_USER = new SecretRotationApplication('SecretsManagerRedshiftRotationSingleUser', '1.1.60'); + public static readonly REDSHIFT_ROTATION_SINGLE_USER = new SecretRotationApplication('SecretsManagerRedshiftRotationSingleUser', '1.1.225'); /** * Conducts an AWS SecretsManager secret rotation for Amazon Redshift using the multi user rotation scheme */ - public static readonly REDSHIFT_ROTATION_MULTI_USER = new SecretRotationApplication('SecretsManagerRedshiftRotationMultiUser', '1.1.60', { + public static readonly REDSHIFT_ROTATION_MULTI_USER = new SecretRotationApplication('SecretsManagerRedshiftRotationMultiUser', '1.1.225', { isMultiUser: true, }); /** * Conducts an AWS SecretsManager secret rotation for MongoDB using the single user rotation scheme */ - public static readonly MONGODB_ROTATION_SINGLE_USER = new SecretRotationApplication('SecretsManagerMongoDBRotationSingleUser', '1.1.60'); + public static readonly MONGODB_ROTATION_SINGLE_USER = new SecretRotationApplication('SecretsManagerMongoDBRotationSingleUser', '1.1.225'); /** * Conducts an AWS SecretsManager secret rotation for MongoDB using the multi user rotation scheme */ - public static readonly MONGODB_ROTATION_MULTI_USER = new SecretRotationApplication('SecretsManagerMongoDBRotationMultiUser', '1.1.60', { + public static readonly MONGODB_ROTATION_MULTI_USER = new SecretRotationApplication('SecretsManagerMongoDBRotationMultiUser', '1.1.225', { isMultiUser: true, }); diff --git a/packages/@aws-cdk/aws-secretsmanager/package.json b/packages/@aws-cdk/aws-secretsmanager/package.json index a289566a2728c..abf808fed6a01 100644 --- a/packages/@aws-cdk/aws-secretsmanager/package.json +++ b/packages/@aws-cdk/aws-secretsmanager/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-secretsmanager/test/integ.lambda-rotation.expected.json b/packages/@aws-cdk/aws-secretsmanager/test/integ.lambda-rotation.expected.json index f1d540cbd42a7..7e903c33b48af 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/integ.lambda-rotation.expected.json +++ b/packages/@aws-cdk/aws-secretsmanager/test/integ.lambda-rotation.expected.json @@ -30,52 +30,12 @@ }, { "Action": [ + "kms:CreateGrant", "kms:Decrypt", + "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Condition": { - "StringEquals": { - "kms:ViaService": { - "Fn::Join": [ - "", - [ - "secretsmanager.", - { - "Ref": "AWS::Region" - }, - ".amazonaws.com" - ] - ] - } - } - }, - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::", - { - "Ref": "AWS::AccountId" - }, - ":root" - ] - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:CreateGrant", - "kms:DescribeKey" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Condition": { "StringEquals": { @@ -118,8 +78,8 @@ "Action": [ "kms:Decrypt", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Condition": { "StringEquals": { diff --git a/packages/@aws-cdk/aws-secretsmanager/test/integ.secret-name-parsed.expected.json b/packages/@aws-cdk/aws-secretsmanager/test/integ.secret-name-parsed.expected.json index 01e9e10d4eed9..b4a3687322701 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/integ.secret-name-parsed.expected.json +++ b/packages/@aws-cdk/aws-secretsmanager/test/integ.secret-name-parsed.expected.json @@ -91,7 +91,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters2a2da33f11dc6085a4843d85898c13b2798393e7650fbb994d866555e23f79e9S3BucketED542E1C" + "Ref": "AssetParameters7452e934e8e327a54ba0c8e462065f22bf095d0722d22cc4c29d2ed4c2f2ff33S3Bucket499DB3A2" }, "S3Key": { "Fn::Join": [ @@ -104,7 +104,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters2a2da33f11dc6085a4843d85898c13b2798393e7650fbb994d866555e23f79e9S3VersionKey10487FD6" + "Ref": "AssetParameters7452e934e8e327a54ba0c8e462065f22bf095d0722d22cc4c29d2ed4c2f2ff33S3VersionKey8F35128C" } ] } @@ -117,7 +117,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters2a2da33f11dc6085a4843d85898c13b2798393e7650fbb994d866555e23f79e9S3VersionKey10487FD6" + "Ref": "AssetParameters7452e934e8e327a54ba0c8e462065f22bf095d0722d22cc4c29d2ed4c2f2ff33S3VersionKey8F35128C" } ] } @@ -384,17 +384,17 @@ } }, "Parameters": { - "AssetParameters2a2da33f11dc6085a4843d85898c13b2798393e7650fbb994d866555e23f79e9S3BucketED542E1C": { + "AssetParameters7452e934e8e327a54ba0c8e462065f22bf095d0722d22cc4c29d2ed4c2f2ff33S3Bucket499DB3A2": { "Type": "String", - "Description": "S3 bucket for asset \"2a2da33f11dc6085a4843d85898c13b2798393e7650fbb994d866555e23f79e9\"" + "Description": "S3 bucket for asset \"7452e934e8e327a54ba0c8e462065f22bf095d0722d22cc4c29d2ed4c2f2ff33\"" }, - "AssetParameters2a2da33f11dc6085a4843d85898c13b2798393e7650fbb994d866555e23f79e9S3VersionKey10487FD6": { + "AssetParameters7452e934e8e327a54ba0c8e462065f22bf095d0722d22cc4c29d2ed4c2f2ff33S3VersionKey8F35128C": { "Type": "String", - "Description": "S3 key for asset version \"2a2da33f11dc6085a4843d85898c13b2798393e7650fbb994d866555e23f79e9\"" + "Description": "S3 key for asset version \"7452e934e8e327a54ba0c8e462065f22bf095d0722d22cc4c29d2ed4c2f2ff33\"" }, - "AssetParameters2a2da33f11dc6085a4843d85898c13b2798393e7650fbb994d866555e23f79e9ArtifactHashB26239A1": { + "AssetParameters7452e934e8e327a54ba0c8e462065f22bf095d0722d22cc4c29d2ed4c2f2ff33ArtifactHashD7AC58BE": { "Type": "String", - "Description": "Artifact hash for asset \"2a2da33f11dc6085a4843d85898c13b2798393e7650fbb994d866555e23f79e9\"" + "Description": "Artifact hash for asset \"7452e934e8e327a54ba0c8e462065f22bf095d0722d22cc4c29d2ed4c2f2ff33\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-secretsmanager/test/integ.secret.lit.expected.json b/packages/@aws-cdk/aws-secretsmanager/test/integ.secret.lit.expected.json index e72f363ac687f..62a4980a4548a 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/integ.secret.lit.expected.json +++ b/packages/@aws-cdk/aws-secretsmanager/test/integ.secret.lit.expected.json @@ -39,8 +39,8 @@ "Statement": [ { "Action": [ - "secretsmanager:GetSecretValue", - "secretsmanager:DescribeSecret" + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-securityhub/package.json b/packages/@aws-cdk/aws-securityhub/package.json index 7c542fa20395b..2be17327b22a1 100644 --- a/packages/@aws-cdk/aws-securityhub/package.json +++ b/packages/@aws-cdk/aws-securityhub/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-servicecatalog/README.md b/packages/@aws-cdk/aws-servicecatalog/README.md index 12e57cbc200ee..54c28a0b46201 100644 --- a/packages/@aws-cdk/aws-servicecatalog/README.md +++ b/packages/@aws-cdk/aws-servicecatalog/README.md @@ -9,13 +9,13 @@ > > [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib -![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) +![cdk-constructs: Developer Preview](https://img.shields.io/badge/cdk--constructs-developer--preview-informational.svg?style=for-the-badge) -> The APIs of higher level constructs in this module are experimental and under active development. -> They are subject to non-backward compatible changes or removal in any future version. These are -> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be -> announced in the release notes. This means that while you may use them, you may need to update -> your source code when upgrading to a newer version of this package. +> The APIs of higher level constructs in this module are in **developer preview** before they +> become stable. We will only make breaking changes to address unforeseen API issues. Therefore, +> these APIs are not subject to [Semantic Versioning](https://semver.org/), and breaking changes +> will be announced in release notes. This means that while you may use them, you may need to +> update your source code when upgrading to a newer version of this package. --- @@ -37,7 +37,7 @@ enables organizations to create and manage catalogs of products for their end us - [Constraints](#constraints) - [Tag update constraint](#tag-update-constraint) - [Notify on stack events](#notify-on-stack-events) - - [CloudFormation parameters constraint](#cloudformation-parameters-constraint) + - [CloudFormation template parameters constraint](#cloudformation-template-parameters-constraint) - [Set launch role](#set-launch-role) - [Deploy with StackSets](#deploy-with-stacksets) @@ -50,23 +50,23 @@ import * as servicecatalog from '@aws-cdk/aws-servicecatalog'; ## Portfolio -AWS Service Catalog portfolios allow admins to manage products that their end users have access to. +AWS Service Catalog portfolios allow administrators to organize, manage, and distribute cloud resources for their end users. Using the CDK, a new portfolio can be created with the `Portfolio` construct: ```ts -new servicecatalog.Portfolio(this, 'MyFirstPortfolio', { - displayName: 'MyFirstPortfolio', +new servicecatalog.Portfolio(this, 'Portfolio', { + displayName: 'MyPortfolio', providerName: 'MyTeam', }); ``` -You can also specify properties such as `description` and `acceptLanguage` +You can also specify optional metadata properties such as `description` and `messageLanguage` to help better catalog and manage your portfolios. ```ts -new servicecatalog.Portfolio(this, 'MyFirstPortfolio', { +new servicecatalog.Portfolio(this, 'Portfolio', { displayName: 'MyFirstPortfolio', - providerName: 'MyTeam', + providerName: 'SCAdmin', description: 'Portfolio for a project', messageLanguage: servicecatalog.MessageLanguage.EN, }); @@ -74,37 +74,39 @@ new servicecatalog.Portfolio(this, 'MyFirstPortfolio', { Read more at [Creating and Managing Portfolios](https://docs.aws.amazon.com/servicecatalog/latest/adminguide/catalogs_portfolios.html). -A portfolio that has been created outside the stack can be imported into your CDK app. -Portfolios can be imported by their ARN via the `Portfolio.fromPortfolioArn()` API: +To import an existing portfolio into your CDK application, use the `Portfolio.fromPortfolioArn()` factory method: ```ts -const portfolio = servicecatalog.Portfolio.fromPortfolioArn(this, 'MyImportedPortfolio', +const portfolio = servicecatalog.Portfolio.fromPortfolioArn(this, 'ImportedPortfolio', 'arn:aws:catalog:region:account-id:portfolio/port-abcdefghi'); ``` ### Granting access to a portfolio -You can manage end user access to a portfolio by granting permissions to `IAM` entities like a user, group, or role. +You can grant access to and manage the `IAM` users, groups, or roles that have access to the products within a portfolio. +Entities with granted access will be able to utilize the portfolios resources and products via the console or AWS CLI. Once resources are deployed end users will be able to access them via the console or service catalog CLI. ```ts fixture=basic-portfolio import * as iam from '@aws-cdk/aws-iam'; -const user = new iam.User(this, 'MyUser'); +const user = new iam.User(this, 'User'); portfolio.giveAccessToUser(user); -const role = new iam.Role(this, 'MyRole', { +const role = new iam.Role(this, 'Role', { assumedBy: new iam.AccountRootPrincipal(), }); portfolio.giveAccessToRole(role); -const group = new iam.Group(this, 'MyGroup'); +const group = new iam.Group(this, 'Group'); portfolio.giveAccessToGroup(group); ``` ### Sharing a portfolio with another AWS account -A portfolio can be programatically shared with other accounts so that specified users can also access it: +You can use account-to-account sharing to distribute a reference to your portfolio to other AWS accounts by passing the recipient account number. +After the share is initiated, the recipient account can accept the share via CLI or console by importing the portfolio ID. +Changes made to the shared portfolio will automatically propagate to recipients. ```ts fixture=basic-portfolio portfolio.shareWithAccount('012345678901'); @@ -112,10 +114,10 @@ portfolio.shareWithAccount('012345678901'); ## Product -Products are the resources you are allowing end users to provision and utilize. +Products are version friendly infrastructure-as-code templates that admins create and add to portfolios for end users to provision and create AWS resources. The CDK currently only supports adding products of type Cloudformation product. Using the CDK, a new Product can be created with the `CloudFormationProduct` construct. -`CloudFormationTemplate.fromUrl` can be utilized to create a Product using a Cloudformation template directly from an URL: +You can use `CloudFormationTemplate.fromUrl` to create a Product from a CloudFormation template directly from a URL that points to the template in S3, GitHub, or CodeCommit: ```ts const product = new servicecatalog.CloudFormationProduct(this, 'MyFirstProduct', { @@ -133,14 +135,14 @@ const product = new servicecatalog.CloudFormationProduct(this, 'MyFirstProduct', ### Creating a product from a local asset -A `CloudFormationProduct` can also be created using a Cloudformation template from an Asset. +A `CloudFormationProduct` can also be created by using a CloudFormation template held locally on disk using Assets. Assets are files that are uploaded to an S3 Bucket before deployment. `CloudFormationTemplate.fromAsset` can be utilized to create a Product by passing the path to a local template file on your disk: ```ts import * as path from 'path'; -const product = new servicecatalog.CloudFormationProduct(this, 'MyFirstProduct', { +const product = new servicecatalog.CloudFormationProduct(this, 'Product', { productName: "My Product", owner: "Product Owner", productVersions: [ @@ -159,10 +161,10 @@ const product = new servicecatalog.CloudFormationProduct(this, 'MyFirstProduct', ### Creating a product from a stack -You can define a service catalog `CloudFormationProduct` entirely within CDK using a service catalog `ProductStack`. +You can create a Service Catalog `CloudFormationProduct` entirely defined with CDK code using a service catalog `ProductStack`. A separate child stack for your product is created and you can add resources like you would for any other CDK stack, such as an S3 Bucket, IAM roles, and EC2 instances. This stack is passed in as a product version to your -product. This will not create a separate stack during deployment. +product. This will not create a separate CloudFormation stack during deployment. ```ts import * as s3 from '@aws-cdk/aws-s3'; @@ -176,7 +178,7 @@ class S3BucketProduct extends servicecatalog.ProductStack { } } -const product = new servicecatalog.CloudFormationProduct(this, 'MyFirstProduct', { +const product = new servicecatalog.CloudFormationProduct(this, 'Product', { productName: "My Product", owner: "Product Owner", productVersions: [ @@ -190,9 +192,9 @@ const product = new servicecatalog.CloudFormationProduct(this, 'MyFirstProduct', ### Adding a product to a portfolio -You add products to a portfolio to manage your resources at scale. After adding a product to a portfolio, -it creates a portfolio-product association, and will become visible from the portfolio side in both the console and service catalog CLI. -A product can be added to multiple portfolios depending on your resource and organizational needs. +You add products to a portfolio to organize and distribute your catalog at scale. Adding a product to a portfolio creates an association, +and the product will become visible within the portfolio side in both the Service Catalog console and AWS CLI. +You can add a product to multiple portfolios depending on your organizational structure and how you would like to group access to products. ```ts fixture=portfolio-product portfolio.addProduct(product); @@ -200,11 +202,11 @@ portfolio.addProduct(product); ## Tag Options -TagOptions allow administrators to easily manage tags on provisioned products by creating a selection of tags for end users to choose from. -TagOptions are created by specifying a tag key with a selection of allowed values and can be associated with both portfolios and products. +TagOptions allow administrators to easily manage tags on provisioned products by providing a template for a selection of tags that end users choose from. +TagOptions are created by specifying a tag key with a set of allowed values and can be associated with both portfolios and products. When launching a product, both the TagOptions associated with the product and the containing portfolio are made available. -At the moment, TagOptions can only be disabled in the console. +At the moment, TagOptions can only be deactivated in the console. ```ts fixture=portfolio-product const tagOptionsForPortfolio = new servicecatalog.TagOptions(this, 'OrgTagOptions', { @@ -225,12 +227,11 @@ product.associateTagOptions(tagOptionsForProduct); ## Constraints -Constraints define governance mechanisms that allow you to manage permissions, notifications, and options related to actions end users can perform on products, -Constraints are applied on a portfolio-product association. +Constraints are governance gestures that you place on product-portfolio associations that allow you to manage minimal launch permissions, notifications, and other optional actions that end users can perform on products. Using the CDK, if you do not explicitly associate a product to a portfolio and add a constraint, it will automatically add an association for you. -There are rules around plurariliites of constraints for a portfolio and product. -For example, you can only have a single "tag update" constraint applied to a portfolio-product association. +There are rules around how constraints are applied to portfolio-product associations. +For example, you can only have a single "launch role" constraint applied to a portfolio-product association. If a misconfigured constraint is added, `synth` will fail with an error message. Read more at [Service Catalog Constraints](https://docs.aws.amazon.com/servicecatalog/latest/adminguide/constraints.html). @@ -238,7 +239,7 @@ Read more at [Service Catalog Constraints](https://docs.aws.amazon.com/serviceca ### Tag update constraint Tag update constraints allow or disallow end users to update tags on resources associated with an AWS Service Catalog product upon provisioning. -By default, tag updating is not permitted. +By default, if a Tag Update constraint is not configured, tag updating is not permitted. If tag updating is allowed, then new tags associated with the product or portfolio will be applied to provisioned resources during a provisioned product update. ```ts fixture=portfolio-product @@ -258,30 +259,30 @@ portfolio.constrainTagUpdates(product, { ### Notify on stack events -Allows users to subscribe an AWS `SNS` topic to the stack events of the product. -When an end user provisions a product it creates a product stack that notifies the subscribed topic on creation, edit, and delete events. -An individual `SNS` topic may only be subscribed once to a portfolio-product association. +Allows users to subscribe an AWS `SNS` topic to a provisioned product's CloudFormation stack events. +When an end user provisions a product it creates a CloudFormation stack that notifies the subscribed topic on creation, edit, and delete events. +An individual `SNS` topic may only have a single subscription to any given portfolio-product association. ```ts fixture=portfolio-product import * as sns from '@aws-cdk/aws-sns'; -const topic1 = new sns.Topic(this, 'MyTopic1'); +const topic1 = new sns.Topic(this, 'Topic1'); portfolio.notifyOnStackEvents(product, topic1); -const topic2 = new sns.Topic(this, 'MyTopic2'); +const topic2 = new sns.Topic(this, 'Topic2'); portfolio.notifyOnStackEvents(product, topic2, { - description: 'description for this topic2', // description is an optional field. + description: 'description for topic2', // description is an optional field. }); ``` -### CloudFormation parameters constraint +### CloudFormation template parameters constraint -CloudFormation parameters constraints allow you to configure the that are available to end users when they launch a product via defined rules. -A rule consists of one or more assertions that narrow the allowable values for parameters in a product. -You can configure multiple parameter constraints to govern the different parameters and parameter options in your products. -For example, a rule might define the various instance types that users can choose from when launching a stack that includes EC2 instances. -A parameter rule has an optional `condition` field that allows ability to configure when rules are applied. -If a `condition` is specified, all the assertions will be applied if the condition evalutates to true. +CloudFormation template parameter constraints allow you to configure the provisioning parameters that are available to end users when they launch a product. +Template constraint rules consist of one or more assertions that define the default and/or allowable values for a product’s provisioning parameters. +You can configure multiple parameter constraints to govern the different provisioning parameters within your products. +For example, a rule might define the `EC2` instance types that users can choose from when launching a product that includes one or more `EC2` instances. +Parameter rules have an optional `condition` field that allow for rule application to consider conditional evaluations. +If a `condition` is specified, all assertions will be applied if the condition evaluates to true. For information on rule-specific intrinsic functions to define rule conditions and assertions, see [AWS Rule Functions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-rules.html). @@ -302,10 +303,12 @@ portfolio.constrainCloudFormationParameters(product, { ### Set launch role -Allows you to configure a specific AWS `IAM` role that a user must assume when launching a product. -By setting this launch role, you can control what policies and privileges end users can have. -The launch role must be assumed by the service catalog principal. -You can only have one launch role set for a portfolio-product association, and you cannot set a launch role if a StackSets deployment has been configured. +Allows you to configure a specific `IAM` role that Service Catalog assumes on behalf of the end user when launching a product. +By setting a launch role constraint, you can maintain least permissions for an end user when launching a product. +For example, a launch role can grant permissions for specific resource creation like an `S3` bucket that the user. +The launch role must be assumed by the Service Catalog principal. +You can only have one launch role set for a portfolio-product association, +and you cannot set a launch role on a product that already has a StackSets deployment configured. ```ts fixture=portfolio-product import * as iam from '@aws-cdk/aws-iam'; @@ -346,16 +349,16 @@ const launchRole: iam.IRole = portfolio.setLocalLaunchRoleName(product, roleName ``` See [Launch Constraint](https://docs.aws.amazon.com/servicecatalog/latest/adminguide/constraints-launch.html) documentation -to understand the permissions roles need. +to understand the permissions that launch roles need. ### Deploy with StackSets A StackSets deployment constraint allows you to configure product deployment options using [AWS CloudFormation StackSets](https://docs.aws.amazon.com/servicecatalog/latest/adminguide/using-stacksets.html). -You can specify multiple accounts and regions for the product launch following StackSets conventions. -There is an additional field `allowStackSetInstanceOperations` that configures ability for end users to create, edit, or delete the stacks. +You can specify one or more accounts and regions into which stack instances will launch when the product is provisioned. +There is an additional field `allowStackSetInstanceOperations` that sets ability for end users to create, edit, or delete the stacks created by the StackSet. By default, this field is set to `false`. -End users can manage those accounts and determine where products deploy and the order of deployment. +When launching a StackSets product, end users can select from the list of accounts and regions configured in the constraint to determine where the Stack Instances will deploy and the order of deployment. You can only define one StackSets deployment configuration per portfolio-product association, and you cannot both set a launch role and StackSets deployment configuration for an assocation. diff --git a/packages/@aws-cdk/aws-servicecatalog/package.json b/packages/@aws-cdk/aws-servicecatalog/package.json index d5493a3813974..57c961ef8f68d 100644 --- a/packages/@aws-cdk/aws-servicecatalog/package.json +++ b/packages/@aws-cdk/aws-servicecatalog/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -121,7 +121,7 @@ "ref-via-interface:@aws-cdk/aws-servicecatalog.PortfolioProps.tagOptions" ] }, - "maturity": "experimental", + "maturity": "developer-preview", "stability": "experimental", "awscdkio": { "announce": false diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry/package.json b/packages/@aws-cdk/aws-servicecatalogappregistry/package.json index 1db1a743a5952..96e9d4dd7967c 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry/package.json +++ b/packages/@aws-cdk/aws-servicecatalogappregistry/package.json @@ -88,7 +88,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-servicediscovery/package.json b/packages/@aws-cdk/aws-servicediscovery/package.json index ba4ab174a807e..98567a421aa13 100644 --- a/packages/@aws-cdk/aws-servicediscovery/package.json +++ b/packages/@aws-cdk/aws-servicediscovery/package.json @@ -87,8 +87,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-ses-actions/package.json b/packages/@aws-cdk/aws-ses-actions/package.json index 0165754b44065..92c00efabcbcb 100644 --- a/packages/@aws-cdk/aws-ses-actions/package.json +++ b/packages/@aws-cdk/aws-ses-actions/package.json @@ -77,8 +77,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-ses/package.json b/packages/@aws-cdk/aws-ses/package.json index f7419dafe0ba7..133d6cf10ccf3 100644 --- a/packages/@aws-cdk/aws-ses/package.json +++ b/packages/@aws-cdk/aws-ses/package.json @@ -84,9 +84,9 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.92", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/aws-lambda": "^8.10.93", + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-signer/package.json b/packages/@aws-cdk/aws-signer/package.json index 7f44205727a9b..0bc0f4f9d9522 100644 --- a/packages/@aws-cdk/aws-signer/package.json +++ b/packages/@aws-cdk/aws-signer/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-sns-subscriptions/package.json b/packages/@aws-cdk/aws-sns-subscriptions/package.json index 68dd03f7ecc6c..f295805a8b389 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/package.json +++ b/packages/@aws-cdk/aws-sns-subscriptions/package.json @@ -76,8 +76,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-sns/lib/topic-base.ts b/packages/@aws-cdk/aws-sns/lib/topic-base.ts index b867670474177..70dff8b8572df 100644 --- a/packages/@aws-cdk/aws-sns/lib/topic-base.ts +++ b/packages/@aws-cdk/aws-sns/lib/topic-base.ts @@ -28,6 +28,13 @@ export interface ITopic extends IResource, notifications.INotificationRuleTarget */ readonly topicName: string; + /** + * Whether this topic is an Amazon SNS FIFO queue. If false, this is a standard topic. + * + * @attribute + */ + readonly fifo: boolean; + /** * Subscribe some endpoint to this topic */ @@ -56,6 +63,8 @@ export abstract class TopicBase extends Resource implements ITopic { public abstract readonly topicName: string; + public abstract readonly fifo: boolean; + /** * Controls automatic creation of policy objects. * diff --git a/packages/@aws-cdk/aws-sns/lib/topic.ts b/packages/@aws-cdk/aws-sns/lib/topic.ts index aa78dcfee6b80..0525e832181a2 100644 --- a/packages/@aws-cdk/aws-sns/lib/topic.ts +++ b/packages/@aws-cdk/aws-sns/lib/topic.ts @@ -64,6 +64,7 @@ export class Topic extends TopicBase { class Import extends TopicBase { public readonly topicArn = topicArn; public readonly topicName = Stack.of(scope).splitArn(topicArn, ArnFormat.NO_RESOURCE_NAME).resource; + public readonly fifo = this.topicName.endsWith('.fifo'); protected autoCreatePolicy: boolean = false; } @@ -72,6 +73,7 @@ export class Topic extends TopicBase { public readonly topicArn: string; public readonly topicName: string; + public readonly fifo: boolean; protected readonly autoCreatePolicy: boolean = true; @@ -110,5 +112,6 @@ export class Topic extends TopicBase { resource: this.physicalName, }); this.topicName = this.getResourceNameAttribute(resource.attrTopicName); + this.fifo = props.fifo || false; } } diff --git a/packages/@aws-cdk/aws-sns/package.json b/packages/@aws-cdk/aws-sns/package.json index 21b150d9e834b..b1664ed712223 100644 --- a/packages/@aws-cdk/aws-sns/package.json +++ b/packages/@aws-cdk/aws-sns/package.json @@ -88,8 +88,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-sns/test/sns.test.ts b/packages/@aws-cdk/aws-sns/test/sns.test.ts index 950aef6cbcef1..c39f6d709587b 100644 --- a/packages/@aws-cdk/aws-sns/test/sns.test.ts +++ b/packages/@aws-cdk/aws-sns/test/sns.test.ts @@ -343,9 +343,23 @@ describe('Topic', () => { // THEN expect(imported.topicName).toEqual('my_corporate_topic'); expect(imported.topicArn).toEqual('arn:aws:sns:*:123456789012:my_corporate_topic'); + expect(imported.fifo).toEqual(false); }); + test('fromTopicArn fifo', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const imported = sns.Topic.fromTopicArn(stack, 'Imported', 'arn:aws:sns:*:123456789012:mytopic.fifo'); + + // THEN + expect(imported.topicName).toEqual('mytopic.fifo'); + expect(imported.topicArn).toEqual('arn:aws:sns:*:123456789012:mytopic.fifo'); + expect(imported.fifo).toEqual(true); + }); + test('test metrics', () => { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-sqs/lib/queue.ts b/packages/@aws-cdk/aws-sqs/lib/queue.ts index b56500407167f..980185f5b7810 100644 --- a/packages/@aws-cdk/aws-sqs/lib/queue.ts +++ b/packages/@aws-cdk/aws-sqs/lib/queue.ts @@ -159,7 +159,7 @@ export interface QueueProps { readonly fifoThroughputLimit?: FifoThroughputLimit; /** - * Policy to apply when the user pool is removed from the stack + * Policy to apply when the queue is removed from the stack * * Even though queues are technically stateful, their contents are transient and it * is common to add and remove Queues while rearchitecting your application. The diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index d318be9283996..a6b12eaf10285 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -85,9 +85,9 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "aws-sdk": "^2.848.0", - "jest": "^27.4.7" + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-sqs/test/integ.sqs.expected.json b/packages/@aws-cdk/aws-sqs/test/integ.sqs.expected.json index 6dc7b035309d7..a25e39dc58a03 100644 --- a/packages/@aws-cdk/aws-sqs/test/integ.sqs.expected.json +++ b/packages/@aws-cdk/aws-sqs/test/integ.sqs.expected.json @@ -120,51 +120,39 @@ "Statement": [ { "Action": [ - "sqs:ReceiveMessage", "sqs:ChangeMessageVisibility", - "sqs:GetQueueUrl", "sqs:DeleteMessage", - "sqs:GetQueueAttributes" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "DeadLetterQueue9F481546", - "Arn" - ] - } - }, - { - "Action": [ - "sqs:ReceiveMessage", - "sqs:ChangeMessageVisibility", + "sqs:GetQueueAttributes", "sqs:GetQueueUrl", - "sqs:DeleteMessage", - "sqs:GetQueueAttributes" + "sqs:ReceiveMessage" ], "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "Queue4A7E3555", - "Arn" - ] - } - }, - { - "Action": [ - "sqs:ReceiveMessage", - "sqs:ChangeMessageVisibility", - "sqs:GetQueueUrl", - "sqs:DeleteMessage", - "sqs:GetQueueAttributes" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "FifoQueueE5FF7273", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "DeadLetterQueue9F481546", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "FifoQueueE5FF7273", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "HighThroughputFifoQueue40A0EEE4", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "Queue4A7E3555", + "Arn" + ] + } + ] }, { "Action": "kms:Decrypt", @@ -175,22 +163,6 @@ "Arn" ] } - }, - { - "Action": [ - "sqs:ReceiveMessage", - "sqs:ChangeMessageVisibility", - "sqs:GetQueueUrl", - "sqs:DeleteMessage", - "sqs:GetQueueAttributes" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "HighThroughputFifoQueue40A0EEE4", - "Arn" - ] - } } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-ssm/package.json b/packages/@aws-cdk/aws-ssm/package.json index 674b3633a1128..65caf4f4c5873 100644 --- a/packages/@aws-cdk/aws-ssm/package.json +++ b/packages/@aws-cdk/aws-ssm/package.json @@ -84,8 +84,8 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.expected.json b/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.expected.json index 2068dd41957f6..475071ea04823 100644 --- a/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.expected.json +++ b/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.expected.json @@ -40,9 +40,9 @@ { "Action": [ "ssm:DescribeParameters", - "ssm:GetParameters", "ssm:GetParameter", - "ssm:GetParameterHistory" + "ssm:GetParameterHistory", + "ssm:GetParameters" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-ssmcontacts/package.json b/packages/@aws-cdk/aws-ssmcontacts/package.json index ff883b494f4a9..bfce82c5f9d0a 100644 --- a/packages/@aws-cdk/aws-ssmcontacts/package.json +++ b/packages/@aws-cdk/aws-ssmcontacts/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-ssmincidents/package.json b/packages/@aws-cdk/aws-ssmincidents/package.json index a0663b40f9cd1..f014c6fc4ef38 100644 --- a/packages/@aws-cdk/aws-ssmincidents/package.json +++ b/packages/@aws-cdk/aws-ssmincidents/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-sso/package.json b/packages/@aws-cdk/aws-sso/package.json index 5a3e38bd255d2..349b3f7ef235a 100644 --- a/packages/@aws-cdk/aws-sso/package.json +++ b/packages/@aws-cdk/aws-sso/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md index 17948bc1112f4..ad4c2a365c38b 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md @@ -1167,6 +1167,8 @@ If your training job or model uses resources from AWS Marketplace, [network isolation is required](https://docs.aws.amazon.com/sagemaker/latest/dg/mkt-algo-model-internet-free.html). To do so, set the `enableNetworkIsolation` property to `true` for `SageMakerCreateModel` or `SageMakerCreateTrainingJob`. +To set environment variables for the Docker container use the `environment` property. + ### Create Training Job You can call the [`CreateTrainingJob`](https://docs.aws.amazon.com/sagemaker/latest/dg/API_CreateTrainingJob.html) API from a `Task` state. diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/aws-sdk/call-aws-service.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/aws-sdk/call-aws-service.ts index f3987cc0677ae..34f1bd78fe3c2 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/aws-sdk/call-aws-service.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/aws-sdk/call-aws-service.ts @@ -64,6 +64,10 @@ export class CallAwsService extends sfn.TaskStateBase { constructor(scope: Construct, id: string, private readonly props: CallAwsServiceProps) { super(scope, id, props); + if (this.props.integrationPattern === sfn.IntegrationPattern.RUN_JOB) { + throw new Error('The RUN_JOB integration pattern is not supported for CallAwsService'); + } + this.taskPolicies = [ new iam.PolicyStatement({ resources: props.iamResources, diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/submit-job.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/submit-job.ts index 0fe43f42e21ac..e0780b0b26b09 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/submit-job.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/submit-job.ts @@ -291,23 +291,37 @@ export class BatchSubmitJob extends sfn.TaskStateBase { ); } - let resources; + let resources: Array = []; if (containerOverrides.gpuCount) { - resources = [ + resources.push( { Type: 'GPU', Value: `${containerOverrides.gpuCount}`, }, - ]; + ); + } + if (containerOverrides.memory) { + resources.push( + { + Type: 'MEMORY', + Value: `${containerOverrides.memory.toMebibytes()}`, + }, + ); + } + if (containerOverrides.vcpus) { + resources.push( + { + Type: 'VCPU', + Value: `${containerOverrides.vcpus}`, + }, + ); } return { Command: containerOverrides.command, Environment: environment, InstanceType: containerOverrides.instanceType?.toString(), - Memory: containerOverrides.memory?.toMebibytes(), - ResourceRequirements: resources, - Vcpus: containerOverrides.vcpus, + ResourceRequirements: resources.length ? resources : undefined, }; } } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-create-cluster.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-create-cluster.ts index 9c4f53ca3b927..e223988059c52 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-create-cluster.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-create-cluster.ts @@ -206,7 +206,7 @@ export class EmrCreateCluster extends sfn.TaskStateBase { this.validateReleaseLabel(this.props.releaseLabel); } - if (this.props.stepConcurrencyLevel !== undefined) { + if (this.props.stepConcurrencyLevel !== undefined && !cdk.Token.isUnresolved(this.props.stepConcurrencyLevel)) { if (this.props.stepConcurrencyLevel < 1 || this.props.stepConcurrencyLevel > 256) { throw new Error(`Step concurrency level must be in range [1, 256], but got ${this.props.stepConcurrencyLevel}.`); } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/evaluate-expression.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/evaluate-expression.ts index 5b90ce066c70d..654c13320372c 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/evaluate-expression.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/evaluate-expression.ts @@ -60,7 +60,7 @@ export class EvaluateExpression extends sfn.TaskStateBase { this.taskPolicies = [ new iam.PolicyStatement({ - resources: [this.evalFn.functionArn], + resources: this.evalFn.resourceArnsForGrantInvoke, actions: ['lambda:InvokeFunction'], }), ]; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/lambda/invoke-function.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/lambda/invoke-function.ts index 8644f94ba7de8..7df2b839f63c7 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/lambda/invoke-function.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/lambda/invoke-function.ts @@ -35,7 +35,7 @@ export class InvokeFunction implements sfn.IStepFunctionsTask { return { resourceArn: this.lambdaFunction.functionArn, policyStatements: [new iam.PolicyStatement({ - resources: [this.lambdaFunction.functionArn], + resources: this.lambdaFunction.resourceArnsForGrantInvoke, actions: ['lambda:InvokeFunction'], })], metricPrefixSingular: 'LambdaFunction', diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/lambda/invoke.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/lambda/invoke.ts index aea7ef4335ae4..1d682e7db1cdf 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/lambda/invoke.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/lambda/invoke.ts @@ -45,6 +45,7 @@ export interface LambdaInvokeProps extends sfn.TaskStateBaseProps { * directly as the `lambdaFunction` argument. * * @default - Version or alias inherent to the `lambdaFunction` object. + * @deprecated pass a Version or Alias object as lambdaFunction instead */ readonly qualifier?: string; @@ -119,7 +120,7 @@ export class LambdaInvoke extends sfn.TaskStateBase { this.taskPolicies = [ new iam.PolicyStatement({ - resources: [this.props.lambdaFunction.functionArn], + resources: this.props.lambdaFunction.resourceArnsForGrantInvoke, actions: ['lambda:InvokeFunction'], }), ]; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/lambda/run-lambda-task.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/lambda/run-lambda-task.ts index a2623bb8c5d1a..830b30cc4ae3e 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/lambda/run-lambda-task.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/lambda/run-lambda-task.ts @@ -48,6 +48,7 @@ export interface RunLambdaTaskProps { * Version or alias of the function to be invoked * * @default - No qualifier + * @deprecated pass a Version or Alias object as lambdaFunction instead */ readonly qualifier?: string; } @@ -87,7 +88,7 @@ export class RunLambdaTask implements sfn.IStepFunctionsTask { return { resourceArn: getResourceArn('lambda', 'invoke', this.integrationPattern), policyStatements: [new iam.PolicyStatement({ - resources: [this.lambdaFunction.functionArn], + resources: this.lambdaFunction.resourceArnsForGrantInvoke, actions: ['lambda:InvokeFunction'], })], metricPrefixSingular: 'LambdaFunction', diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-training-job.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-training-job.ts index 64680dc357747..ba3274579eb37 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-training-job.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-training-job.ts @@ -5,7 +5,7 @@ import { Duration, Lazy, Size, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { integrationResourceArn, validatePatternSupported } from '../private/task-utils'; import { AlgorithmSpecification, Channel, InputMode, OutputDataConfig, ResourceConfig, S3DataType, StoppingCondition, VpcConfig } from './base-types'; -import { renderTags } from './private/utils'; +import { renderEnvironment, renderTags } from './private/utils'; /** * Properties for creating an Amazon SageMaker training job @@ -85,6 +85,13 @@ export interface SageMakerCreateTrainingJobProps extends sfn.TaskStateBaseProps * @default - No VPC */ readonly vpcConfig?: VpcConfig; + + /** + * Environment variables to set in the Docker container. + * + * @default - No environment variables + */ + readonly environment?: { [key: string]: string }; } /** @@ -234,6 +241,7 @@ export class SageMakerCreateTrainingJob extends sfn.TaskStateBase implements iam ...this.renderHyperparameters(this.props.hyperparameters), ...renderTags(this.props.tags), ...this.renderVpcConfig(this.props.vpcConfig), + ...renderEnvironment(this.props.environment), }; } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-transform-job.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-transform-job.ts index cc108c45e4439..84c08fa22529d 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-transform-job.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-transform-job.ts @@ -5,7 +5,7 @@ import { Size, Stack, Token } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { integrationResourceArn, validatePatternSupported } from '../private/task-utils'; import { BatchStrategy, ModelClientOptions, S3DataType, TransformInput, TransformOutput, TransformResources } from './base-types'; -import { renderTags } from './private/utils'; +import { renderEnvironment, renderTags } from './private/utils'; /** * Properties for creating an Amazon SageMaker transform job task @@ -166,7 +166,7 @@ export class SageMakerCreateTransformJob extends sfn.TaskStateBase { private renderParameters(): { [key: string]: any } { return { ...(this.props.batchStrategy ? { BatchStrategy: this.props.batchStrategy } : {}), - ...this.renderEnvironment(this.props.environment), + ...renderEnvironment(this.props.environment), ...(this.props.maxConcurrentTransforms ? { MaxConcurrentTransforms: this.props.maxConcurrentTransforms } : {}), ...(this.props.maxPayload ? { MaxPayloadInMB: this.props.maxPayload.toMebibytes() } : {}), ...this.props.modelClientOptions ? this.renderModelClientOptions(this.props.modelClientOptions) : {}, @@ -234,10 +234,6 @@ export class SageMakerCreateTransformJob extends sfn.TaskStateBase { }; } - private renderEnvironment(environment: { [key: string]: any } | undefined): { [key: string]: any } { - return environment ? { Environment: environment } : {}; - } - private makePolicyStatements(): iam.PolicyStatement[] { const stack = Stack.of(this); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/private/utils.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/private/utils.ts index e308fd890864c..bbcaed118a083 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/private/utils.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/private/utils.ts @@ -1,4 +1,7 @@ - export function renderTags(tags: { [key: string]: any } | undefined): { [key: string]: any } { return tags ? { Tags: Object.keys(tags).map((key) => ({ Key: key, Value: tags[key] })) } : {}; -} \ No newline at end of file +} + +export function renderEnvironment(environment: { [key: string]: any } | undefined): { [key: string]: any } { + return environment ? { Environment: environment } : {}; +} diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json index a00268d152555..0bbda5a9263c7 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json @@ -90,8 +90,8 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-apigateway": "0.0.0", diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-http-api.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-http-api.expected.json index 6f0435b70af0b..37195febe4b9f 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-http-api.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-http-api.expected.json @@ -17,6 +17,22 @@ "AutoDeploy": true } }, + "MyHttpApiANYDefaultIntegration5FAD8850": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "MyHttpApi8AEAAC21" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::GetAtt": [ + "HelloHandler2E4FBA4D", + "Arn" + ] + }, + "PayloadFormatVersion": "2.0" + } + }, "MyHttpApiANYDefaultIntegrationPermissionAB8301EF": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -54,22 +70,6 @@ } } }, - "MyHttpApiANYDefaultIntegration5FAD8850": { - "Type": "AWS::ApiGatewayV2::Integration", - "Properties": { - "ApiId": { - "Ref": "MyHttpApi8AEAAC21" - }, - "IntegrationType": "AWS_PROXY", - "IntegrationUri": { - "Fn::GetAtt": [ - "HelloHandler2E4FBA4D", - "Arn" - ] - }, - "PayloadFormatVersion": "2.0" - } - }, "MyHttpApiANYC3543576": { "Type": "AWS::ApiGatewayV2::Route", "Properties": { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-rest-api.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-rest-api.expected.json index b4d8eb2a4a6e7..29b6885931a63 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-rest-api.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-rest-api.expected.json @@ -74,7 +74,9 @@ }, "StageName": "prod" }, - "DependsOn": ["MyRestApiAccount2FB6DB7A"] + "DependsOn": [ + "MyRestApiAccount2FB6DB7A" + ] }, "MyRestApiANYApiPermissionCallRestApiIntegMyRestApiB570839CANY0C27C1E3": { "Type": "AWS::Lambda::Permission", diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/athena/integ.get-query-execution.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/athena/integ.get-query-execution.expected.json index 2e06603d20af1..edd7f6559e4d0 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/athena/integ.get-query-execution.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/athena/integ.get-query-execution.expected.json @@ -36,8 +36,8 @@ { "Action": [ "athena:getDataCatalog", - "athena:startQueryExecution", - "athena:getQueryExecution" + "athena:getQueryExecution", + "athena:startQueryExecution" ], "Effect": "Allow", "Resource": [ @@ -85,17 +85,13 @@ }, { "Action": [ + "athena:getQueryExecution", + "lakeformation:GetDataAccess", + "s3:AbortMultipartUpload", "s3:CreateBucket", - "s3:ListBucket", "s3:GetBucketLocation", - "s3:GetObject" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "s3:AbortMultipartUpload", + "s3:GetObject", + "s3:ListBucket", "s3:ListBucketMultipartUploads", "s3:ListMultipartUploadParts", "s3:PutObject" @@ -103,11 +99,6 @@ "Effect": "Allow", "Resource": "*" }, - { - "Action": "lakeformation:GetDataAccess", - "Effect": "Allow", - "Resource": "*" - }, { "Action": [ "glue:BatchCreatePartition", @@ -213,11 +204,6 @@ ] } ] - }, - { - "Action": "athena:getQueryExecution", - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/athena/integ.get-query-results.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/athena/integ.get-query-results.expected.json index 444c2edcf72de..cb59d216df916 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/athena/integ.get-query-results.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/athena/integ.get-query-results.expected.json @@ -36,8 +36,8 @@ { "Action": [ "athena:getDataCatalog", - "athena:startQueryExecution", - "athena:getQueryExecution" + "athena:getQueryExecution", + "athena:startQueryExecution" ], "Effect": "Allow", "Resource": [ @@ -85,17 +85,13 @@ }, { "Action": [ + "athena:getQueryResults", + "lakeformation:GetDataAccess", + "s3:AbortMultipartUpload", "s3:CreateBucket", - "s3:ListBucket", "s3:GetBucketLocation", - "s3:GetObject" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "s3:AbortMultipartUpload", + "s3:GetObject", + "s3:ListBucket", "s3:ListBucketMultipartUploads", "s3:ListMultipartUploadParts", "s3:PutObject" @@ -103,11 +99,6 @@ "Effect": "Allow", "Resource": "*" }, - { - "Action": "lakeformation:GetDataAccess", - "Effect": "Allow", - "Resource": "*" - }, { "Action": [ "glue:BatchCreatePartition", @@ -213,16 +204,6 @@ ] } ] - }, - { - "Action": "athena:getQueryResults", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "s3:GetObject", - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/athena/integ.start-query-execution.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/athena/integ.start-query-execution.expected.json index fb4d0e0169f51..e424f520cd722 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/athena/integ.start-query-execution.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/athena/integ.start-query-execution.expected.json @@ -36,8 +36,8 @@ { "Action": [ "athena:getDataCatalog", - "athena:startQueryExecution", - "athena:getQueryExecution" + "athena:getQueryExecution", + "athena:startQueryExecution" ], "Effect": "Allow", "Resource": [ @@ -85,17 +85,12 @@ }, { "Action": [ + "lakeformation:GetDataAccess", + "s3:AbortMultipartUpload", "s3:CreateBucket", - "s3:ListBucket", "s3:GetBucketLocation", - "s3:GetObject" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "s3:AbortMultipartUpload", + "s3:GetObject", + "s3:ListBucket", "s3:ListBucketMultipartUploads", "s3:ListMultipartUploadParts", "s3:PutObject" @@ -103,11 +98,6 @@ "Effect": "Allow", "Resource": "*" }, - { - "Action": "lakeformation:GetDataAccess", - "Effect": "Allow", - "Resource": "*" - }, { "Action": [ "glue:BatchCreatePartition", diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/athena/integ.stop-query-execution.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/athena/integ.stop-query-execution.expected.json index aa90bd274d85f..21d7d19a3251e 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/athena/integ.stop-query-execution.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/athena/integ.stop-query-execution.expected.json @@ -36,8 +36,8 @@ { "Action": [ "athena:getDataCatalog", - "athena:startQueryExecution", - "athena:getQueryExecution" + "athena:getQueryExecution", + "athena:startQueryExecution" ], "Effect": "Allow", "Resource": [ @@ -85,17 +85,13 @@ }, { "Action": [ + "athena:stopQueryExecution", + "lakeformation:GetDataAccess", + "s3:AbortMultipartUpload", "s3:CreateBucket", - "s3:ListBucket", "s3:GetBucketLocation", - "s3:GetObject" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "s3:AbortMultipartUpload", + "s3:GetObject", + "s3:ListBucket", "s3:ListBucketMultipartUploads", "s3:ListMultipartUploadParts", "s3:PutObject" @@ -103,11 +99,6 @@ "Effect": "Allow", "Resource": "*" }, - { - "Action": "lakeformation:GetDataAccess", - "Effect": "Allow", - "Resource": "*" - }, { "Action": [ "glue:BatchCreatePartition", @@ -213,11 +204,6 @@ ] } ] - }, - { - "Action": "athena:stopQueryExecution", - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/aws-sdk/call-aws-service.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/aws-sdk/call-aws-service.test.ts index d3b9e3e0d42ba..da26dc7d8450e 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/aws-sdk/call-aws-service.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/aws-sdk/call-aws-service.test.ts @@ -146,3 +146,16 @@ test('with unresolved tokens', () => { Parameters: {}, }); }); + +test('throws with invalid integration pattern', () => { + expect(() => new tasks.CallAwsService(stack, 'GetObject', { + integrationPattern: sfn.IntegrationPattern.RUN_JOB, + service: 's3', + action: 'getObject', + parameters: { + Bucket: 'my-bucket', + Key: sfn.JsonPath.stringAt('$.key'), + }, + iamResources: ['*'], + })).toThrow(/The RUN_JOB integration pattern is not supported for CallAwsService/); +}); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/aws-sdk/integ.call-aws-service.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/aws-sdk/integ.call-aws-service.expected.json index 38f975ca5ec03..fb1387f0f9980 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/aws-sdk/integ.call-aws-service.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/aws-sdk/integ.call-aws-service.expected.json @@ -39,43 +39,11 @@ "PolicyDocument": { "Statement": [ { - "Action": "s3:putObject", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" - ] - }, - "/*" - ] - ] - } - }, - { - "Action": "s3:getObject", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" - ] - }, - "/*" - ] - ] - } - }, - { - "Action": "s3:deleteObject", + "Action": [ + "s3:deleteObject", + "s3:getObject", + "s3:putObject" + ], "Effect": "Allow", "Resource": { "Fn::Join": [ diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.run-batch-job.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.run-batch-job.expected.json index f37bcd6e520f6..94145f863083d 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.run-batch-job.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.run-batch-job.expected.json @@ -95,15 +95,15 @@ "vpcPublicSubnet1NATGateway9C16659E": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "vpcPublicSubnet1Subnet2E65531E" + }, "AllocationId": { "Fn::GetAtt": [ "vpcPublicSubnet1EIPDA49DCBE", "AllocationId" ] }, - "SubnetId": { - "Ref": "vpcPublicSubnet1Subnet2E65531E" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "vpcPublicSubnet2NATGateway9B8AE11A": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "vpcPublicSubnet2Subnet009B674F" + }, "AllocationId": { "Fn::GetAtt": [ "vpcPublicSubnet2EIP9B3743B1", "AllocationId" ] }, - "SubnetId": { - "Ref": "vpcPublicSubnet2Subnet009B674F" - }, "Tags": [ { "Key": "Name", @@ -289,15 +289,15 @@ "vpcPublicSubnet3NATGateway82F6CA9E": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "vpcPublicSubnet3Subnet11B92D7C" + }, "AllocationId": { "Fn::GetAtt": [ "vpcPublicSubnet3EIP2C3B9D91", "AllocationId" ] }, - "SubnetId": { - "Ref": "vpcPublicSubnet3Subnet11B92D7C" - }, "Tags": [ { "Key": "Name", @@ -514,45 +514,20 @@ } } }, - "ComputeEnvEcsInstanceRoleCFB290F9": { - "Type": "AWS::IAM::Role", + "ComputeEnvResourceSecurityGroupB84CF86B": { + "Type": "AWS::EC2::SecurityGroup", "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "ec2.", - { - "Ref": "AWS::URLSuffix" - } - ] - ] - } - } - } - ], - "Version": "2012-10-17" - }, - "ManagedPolicyArns": [ + "GroupDescription": "aws-stepfunctions-integ/ComputeEnv/Resource-Security-Group", + "SecurityGroupEgress": [ { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role" - ] - ] + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" } - ] + ], + "VpcId": { + "Ref": "vpcA2121C38" + } }, "DependsOn": [ "vpcIGWE57CBDCA", @@ -590,12 +565,43 @@ "vpcVPCGW7984C166" ] }, - "ComputeEnvInstanceProfile81AFCCF2": { - "Type": "AWS::IAM::InstanceProfile", + "ComputeEnvEcsInstanceRoleCFB290F9": { + "Type": "AWS::IAM::Role", "Properties": { - "Roles": [ + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ { - "Ref": "ComputeEnvEcsInstanceRoleCFB290F9" + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role" + ] + ] } ] }, @@ -635,20 +641,14 @@ "vpcVPCGW7984C166" ] }, - "ComputeEnvResourceSecurityGroupB84CF86B": { - "Type": "AWS::EC2::SecurityGroup", + "ComputeEnvInstanceProfile81AFCCF2": { + "Type": "AWS::IAM::InstanceProfile", "Properties": { - "GroupDescription": "aws-stepfunctions-integ/ComputeEnv/Resource-Security-Group", - "SecurityGroupEgress": [ + "Roles": [ { - "CidrIp": "0.0.0.0/0", - "Description": "Allow all outbound traffic by default", - "IpProtocol": "-1" + "Ref": "ComputeEnvEcsInstanceRoleCFB290F9" } - ], - "VpcId": { - "Ref": "vpcA2121C38" - } + ] }, "DependsOn": [ "vpcIGWE57CBDCA", @@ -755,12 +755,6 @@ "ComputeEnv2C40ACC2": { "Type": "AWS::Batch::ComputeEnvironment", "Properties": { - "ServiceRole": { - "Fn::GetAtt": [ - "ComputeEnvResourceServiceInstanceRoleCF89E9E1", - "Arn" - ] - }, "Type": "MANAGED", "ComputeResources": { "AllocationStrategy": "BEST_FIT", @@ -796,6 +790,12 @@ ], "Type": "EC2" }, + "ServiceRole": { + "Fn::GetAtt": [ + "ComputeEnvResourceServiceInstanceRoleCF89E9E1", + "Arn" + ] + }, "State": "ENABLED" }, "DependsOn": [ @@ -876,8 +876,14 @@ "Privileged": false, "ReadonlyRootFilesystem": false, "ResourceRequirements": [ - { "Type": "VCPU", "Value": "1" }, - { "Type": "MEMORY", "Value": "4" } + { + "Type": "VCPU", + "Value": "1" + }, + { + "Type": "MEMORY", + "Value": "4" + } ] }, "PlatformCapabilities": [ @@ -953,9 +959,9 @@ }, { "Action": [ - "events:PutTargets", + "events:DescribeRule", "events:PutRule", - "events:DescribeRule" + "events:PutTargets" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.submit-job.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.submit-job.expected.json index a3851fd3fb5b7..7f48977f12e6c 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.submit-job.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.submit-job.expected.json @@ -95,15 +95,15 @@ "vpcPublicSubnet1NATGateway9C16659E": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "vpcPublicSubnet1Subnet2E65531E" + }, "AllocationId": { "Fn::GetAtt": [ "vpcPublicSubnet1EIPDA49DCBE", "AllocationId" ] }, - "SubnetId": { - "Ref": "vpcPublicSubnet1Subnet2E65531E" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "vpcPublicSubnet2NATGateway9B8AE11A": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "vpcPublicSubnet2Subnet009B674F" + }, "AllocationId": { "Fn::GetAtt": [ "vpcPublicSubnet2EIP9B3743B1", "AllocationId" ] }, - "SubnetId": { - "Ref": "vpcPublicSubnet2Subnet009B674F" - }, "Tags": [ { "Key": "Name", @@ -289,15 +289,15 @@ "vpcPublicSubnet3NATGateway82F6CA9E": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "vpcPublicSubnet3Subnet11B92D7C" + }, "AllocationId": { "Fn::GetAtt": [ "vpcPublicSubnet3EIP2C3B9D91", "AllocationId" ] }, - "SubnetId": { - "Ref": "vpcPublicSubnet3Subnet11B92D7C" - }, "Tags": [ { "Key": "Name", @@ -514,45 +514,20 @@ } } }, - "ComputeEnvEcsInstanceRoleCFB290F9": { - "Type": "AWS::IAM::Role", + "ComputeEnvResourceSecurityGroupB84CF86B": { + "Type": "AWS::EC2::SecurityGroup", "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "ec2.", - { - "Ref": "AWS::URLSuffix" - } - ] - ] - } - } - } - ], - "Version": "2012-10-17" - }, - "ManagedPolicyArns": [ + "GroupDescription": "aws-stepfunctions-integ/ComputeEnv/Resource-Security-Group", + "SecurityGroupEgress": [ { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role" - ] - ] + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" } - ] + ], + "VpcId": { + "Ref": "vpcA2121C38" + } }, "DependsOn": [ "vpcIGWE57CBDCA", @@ -590,12 +565,43 @@ "vpcVPCGW7984C166" ] }, - "ComputeEnvInstanceProfile81AFCCF2": { - "Type": "AWS::IAM::InstanceProfile", + "ComputeEnvEcsInstanceRoleCFB290F9": { + "Type": "AWS::IAM::Role", "Properties": { - "Roles": [ + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ { - "Ref": "ComputeEnvEcsInstanceRoleCFB290F9" + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role" + ] + ] } ] }, @@ -635,20 +641,14 @@ "vpcVPCGW7984C166" ] }, - "ComputeEnvResourceSecurityGroupB84CF86B": { - "Type": "AWS::EC2::SecurityGroup", + "ComputeEnvInstanceProfile81AFCCF2": { + "Type": "AWS::IAM::InstanceProfile", "Properties": { - "GroupDescription": "aws-stepfunctions-integ/ComputeEnv/Resource-Security-Group", - "SecurityGroupEgress": [ + "Roles": [ { - "CidrIp": "0.0.0.0/0", - "Description": "Allow all outbound traffic by default", - "IpProtocol": "-1" + "Ref": "ComputeEnvEcsInstanceRoleCFB290F9" } - ], - "VpcId": { - "Ref": "vpcA2121C38" - } + ] }, "DependsOn": [ "vpcIGWE57CBDCA", @@ -755,12 +755,6 @@ "ComputeEnv2C40ACC2": { "Type": "AWS::Batch::ComputeEnvironment", "Properties": { - "ServiceRole": { - "Fn::GetAtt": [ - "ComputeEnvResourceServiceInstanceRoleCF89E9E1", - "Arn" - ] - }, "Type": "MANAGED", "ComputeResources": { "AllocationStrategy": "BEST_FIT", @@ -796,6 +790,12 @@ ], "Type": "EC2" }, + "ServiceRole": { + "Fn::GetAtt": [ + "ComputeEnvResourceServiceInstanceRoleCF89E9E1", + "Arn" + ] + }, "State": "ENABLED" }, "DependsOn": [ @@ -876,8 +876,14 @@ "Privileged": false, "ReadonlyRootFilesystem": false, "ResourceRequirements": [ - { "Type": "VCPU", "Value": "1" }, - { "Type": "MEMORY", "Value": "4" } + { + "Type": "VCPU", + "Value": "1" + }, + { + "Type": "MEMORY", + "Value": "4" + } ] }, "PlatformCapabilities": [ @@ -953,9 +959,9 @@ }, { "Action": [ - "events:PutTargets", + "events:DescribeRule", "events:PutRule", - "events:DescribeRule" + "events:PutTargets" ], "Effect": "Allow", "Resource": { @@ -1015,7 +1021,7 @@ { "Ref": "JobQueueEE3AD499" }, - "\",\"Parameters\":{\"foo.$\":\"$.bar\"},\"ContainerOverrides\":{\"Environment\":[{\"Name\":\"key\",\"Value\":\"value\"}],\"Memory\":256,\"Vcpus\":1},\"RetryStrategy\":{\"Attempts\":3},\"Timeout\":{\"AttemptDurationSeconds\":60}}}}}" + "\",\"Parameters\":{\"foo.$\":\"$.bar\"},\"ContainerOverrides\":{\"Environment\":[{\"Name\":\"key\",\"Value\":\"value\"}],\"ResourceRequirements\":[{\"Type\":\"MEMORY\",\"Value\":\"256\"},{\"Type\":\"VCPU\",\"Value\":\"1\"}]},\"RetryStrategy\":{\"Attempts\":3},\"Timeout\":{\"AttemptDurationSeconds\":60}}}}}" ] ] } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/submit-job.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/submit-job.test.ts index 828fcdb41c7dc..0885dcfb55930 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/submit-job.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/submit-job.test.ts @@ -115,9 +115,7 @@ test('Task with all the parameters', () => { Command: ['sudo', 'rm'], Environment: [{ Name: 'key', Value: 'value' }], InstanceType: 'MULTI', - Memory: 1024, - ResourceRequirements: [{ Type: 'GPU', Value: '1' }], - Vcpus: 10, + ResourceRequirements: [{ Type: 'GPU', Value: '1' }, { Type: 'MEMORY', Value: '1024' }, { Type: 'VCPU', Value: '10' }], }, DependsOn: [{ JobId: '1234', Type: 'some_type' }], Parameters: { 'foo.$': '$.bar' }, diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/codebuild/integ.start-build.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/codebuild/integ.start-build.expected.json index 58f98f8505b8e..7b9ec9d7b7ac5 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/codebuild/integ.start-build.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/codebuild/integ.start-build.expected.json @@ -49,7 +49,8 @@ ":log-group:/aws/codebuild/", { "Ref": "ProjectC78D97AD" - } + }, + ":*" ] ] }, @@ -72,8 +73,7 @@ ":log-group:/aws/codebuild/", { "Ref": "ProjectC78D97AD" - }, - ":*" + } ] ] } @@ -81,11 +81,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -196,10 +196,10 @@ "Statement": [ { "Action": [ - "codebuild:StartBuild", - "codebuild:StopBuild", "codebuild:BatchGetBuilds", - "codebuild:BatchGetReports" + "codebuild:BatchGetReports", + "codebuild:StartBuild", + "codebuild:StopBuild" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/databrew/integ.start-job-run.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/databrew/integ.start-job-run.expected.json index 4b0dedef27b9b..6f177f7a4f522 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/databrew/integ.start-job-run.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/databrew/integ.start-job-run.expected.json @@ -30,15 +30,21 @@ "Statement": [ { "Action": [ - "s3:GetObject", - "s3:PutObject", "s3:DeleteObject", - "s3:ListBucket" + "s3:GetObject", + "s3:ListBucket", + "s3:PutObject" ], "Effect": "Allow", "Resource": [ - "arn:aws:s3:::databrew-public-datasets-test-region/*", "arn:aws:s3:::databrew-public-datasets-test-region", + "arn:aws:s3:::databrew-public-datasets-test-region/*", + { + "Fn::GetAtt": [ + "JobOutputBucketACE3BC7B", + "Arn" + ] + }, { "Fn::Join": [ "", @@ -52,12 +58,6 @@ "/*" ] ] - }, - { - "Fn::GetAtt": [ - "JobOutputBucketACE3BC7B", - "Arn" - ] } ] } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/dynamodb/integ.call-dynamodb.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/dynamodb/integ.call-dynamodb.expected.json index a8b7510287767..53a09ed1a9974 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/dynamodb/integ.call-dynamodb.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/dynamodb/integ.call-dynamodb.expected.json @@ -58,88 +58,12 @@ "PolicyDocument": { "Statement": [ { - "Action": "dynamodb:PutItem", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":dynamodb:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":table/", - { - "Ref": "Messages804FA4EB" - } - ] - ] - } - }, - { - "Action": "dynamodb:GetItem", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":dynamodb:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":table/", - { - "Ref": "Messages804FA4EB" - } - ] - ] - } - }, - { - "Action": "dynamodb:UpdateItem", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":dynamodb:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":table/", - { - "Ref": "Messages804FA4EB" - } - ] - ] - } - }, - { - "Action": "dynamodb:DeleteItem", + "Action": [ + "dynamodb:DeleteItem", + "dynamodb:GetItem", + "dynamodb:PutItem", + "dynamodb:UpdateItem" + ], "Effect": "Allow", "Resource": { "Fn::Join": [ diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.expected.json index 737459f21b68a..4dcc2e6776cca 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.expected.json @@ -95,8 +95,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -236,10 +236,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -266,7 +266,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -294,24 +296,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "Ec2ClusterEE43E89D", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -389,6 +373,17 @@ } } }, + "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup" + } + ] + } + }, "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookRole71045ED7": { "Type": "AWS::IAM::Role", "Properties": { @@ -435,17 +430,6 @@ ] } }, - "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup" - } - ] - } - }, "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHook5CB1467E": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { @@ -568,8 +552,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { @@ -753,8 +737,8 @@ }, { "Action": [ - "ecs:StopTask", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:StopTask" ], "Effect": "Allow", "Resource": "*" @@ -765,13 +749,13 @@ "Resource": [ { "Fn::GetAtt": [ - "TaskDefTaskRole1EDB4A67", + "TaskDefExecutionRoleB4775C97", "Arn" ] }, { "Fn::GetAtt": [ - "TaskDefExecutionRoleB4775C97", + "TaskDefTaskRole1EDB4A67", "Arn" ] } @@ -779,9 +763,9 @@ }, { "Action": [ - "events:PutTargets", + "events:DescribeRule", "events:PutRule", - "events:DescribeRule" + "events:PutTargets" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.expected.json index bfd53444e81b3..558b81faa2897 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.expected.json @@ -95,8 +95,8 @@ }, { "Action": [ - "ecs:DiscoverPollEndpoint", "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", "logs:CreateLogStream", "logs:PutLogEvents" ], @@ -236,10 +236,10 @@ "Statement": [ { "Action": [ - "ec2:DescribeInstances", + "ec2:DescribeHosts", "ec2:DescribeInstanceAttribute", "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" + "ec2:DescribeInstances" ], "Effect": "Allow", "Resource": "*" @@ -266,7 +266,9 @@ { "Action": [ "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" ], "Condition": { "ArnEquals": { @@ -294,24 +296,6 @@ "Arn" ] } - }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "FargateCluster7CCD5F93", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -389,6 +373,17 @@ } } }, + "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic49146C10": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup" + } + ] + } + }, "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookRole410D556D": { "Type": "AWS::IAM::Role", "Properties": { @@ -435,17 +430,6 @@ ] } }, - "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic49146C10": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup" - } - ] - } - }, "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHook2AE13680": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { @@ -568,8 +552,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { @@ -645,8 +629,8 @@ }, { "Action": [ - "ecs:StopTask", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:StopTask" ], "Effect": "Allow", "Resource": "*" @@ -657,13 +641,13 @@ "Resource": [ { "Fn::GetAtt": [ - "TaskDefTaskRole1EDB4A67", + "TaskDefExecutionRoleB4775C97", "Arn" ] }, { "Fn::GetAtt": [ - "TaskDefExecutionRoleB4775C97", + "TaskDefTaskRole1EDB4A67", "Arn" ] } @@ -671,9 +655,9 @@ }, { "Action": [ - "events:PutTargets", + "events:DescribeRule", "events:PutRule", - "events:DescribeRule" + "events:PutTargets" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.fargate-run-task.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.fargate-run-task.expected.json index ab2cb02fd8d0c..ca30cca5b1beb 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.fargate-run-task.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.fargate-run-task.expected.json @@ -103,8 +103,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { @@ -302,8 +302,8 @@ }, { "Action": [ - "ecs:StopTask", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:StopTask" ], "Effect": "Allow", "Resource": "*" @@ -314,13 +314,13 @@ "Resource": [ { "Fn::GetAtt": [ - "TaskDefTaskRole1EDB4A67", + "TaskDefExecutionRoleB4775C97", "Arn" ] }, { "Fn::GetAtt": [ - "TaskDefExecutionRoleB4775C97", + "TaskDefTaskRole1EDB4A67", "Arn" ] } @@ -328,9 +328,9 @@ }, { "Action": [ - "events:PutTargets", + "events:DescribeRule", "events:PutRule", - "events:DescribeRule" + "events:PutTargets" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.fargate-task.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.fargate-task.expected.json index 84c678d4c2806..d6e61df69d806 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.fargate-task.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.fargate-task.expected.json @@ -103,8 +103,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" ], "Effect": "Allow", "Resource": { @@ -194,8 +194,8 @@ }, { "Action": [ - "ecs:StopTask", - "ecs:DescribeTasks" + "ecs:DescribeTasks", + "ecs:StopTask" ], "Effect": "Allow", "Resource": "*" @@ -206,13 +206,13 @@ "Resource": [ { "Fn::GetAtt": [ - "TaskDefTaskRole1EDB4A67", + "TaskDefExecutionRoleB4775C97", "Arn" ] }, { "Fn::GetAtt": [ - "TaskDefExecutionRoleB4775C97", + "TaskDefTaskRole1EDB4A67", "Arn" ] } @@ -220,9 +220,9 @@ }, { "Action": [ - "events:PutTargets", + "events:DescribeRule", "events:PutRule", - "events:DescribeRule" + "events:PutTargets" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json index 8e3bc703cbde7..fd29689fa4b2e 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json @@ -84,7 +84,9 @@ "Ref": "EksClusterDefaultVpcIGWCA6A3220" } }, - "DependsOn": ["EksClusterDefaultVpcVPCGW0E4A5673"] + "DependsOn": [ + "EksClusterDefaultVpcVPCGW0E4A5673" + ] }, "EksClusterDefaultVpcPublicSubnet1EIPF53713C9": { "Type": "AWS::EC2::EIP", @@ -195,7 +197,9 @@ "Ref": "EksClusterDefaultVpcIGWCA6A3220" } }, - "DependsOn": ["EksClusterDefaultVpcVPCGW0E4A5673"] + "DependsOn": [ + "EksClusterDefaultVpcVPCGW0E4A5673" + ] }, "EksClusterDefaultVpcPublicSubnet2EIP16D41D80": { "Type": "AWS::EC2::EIP", @@ -306,7 +310,9 @@ "Ref": "EksClusterDefaultVpcIGWCA6A3220" } }, - "DependsOn": ["EksClusterDefaultVpcVPCGW0E4A5673"] + "DependsOn": [ + "EksClusterDefaultVpcVPCGW0E4A5673" + ] }, "EksClusterDefaultVpcPublicSubnet3EIPF8D34EDE": { "Type": "AWS::EC2::EIP", @@ -703,20 +709,23 @@ "Action": "iam:PassRole", "Effect": "Allow", "Resource": { - "Fn::GetAtt": ["EksClusterRoleC84B376F", "Arn"] + "Fn::GetAtt": [ + "EksClusterRoleC84B376F", + "Arn" + ] } }, { "Action": [ "eks:CreateCluster", + "eks:CreateFargateProfile", + "eks:DeleteCluster", "eks:DescribeCluster", "eks:DescribeUpdate", - "eks:DeleteCluster", - "eks:UpdateClusterVersion", - "eks:UpdateClusterConfig", - "eks:CreateFargateProfile", "eks:TagResource", - "eks:UntagResource" + "eks:UntagResource", + "eks:UpdateClusterConfig", + "eks:UpdateClusterVersion" ], "Effect": "Allow", "Resource": [ @@ -764,8 +773,8 @@ }, { "Action": [ - "eks:DescribeFargateProfile", - "eks:DeleteFargateProfile" + "eks:DeleteFargateProfile", + "eks:DescribeFargateProfile" ], "Effect": "Allow", "Resource": { @@ -789,25 +798,18 @@ ] } }, - { - "Action": ["iam:GetRole", "iam:listAttachedRolePolicies"], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "iam:CreateServiceLinkedRole", - "Effect": "Allow", - "Resource": "*" - }, { "Action": [ + "ec2:DescribeDhcpOptions", "ec2:DescribeInstances", "ec2:DescribeNetworkInterfaces", + "ec2:DescribeRouteTables", "ec2:DescribeSecurityGroups", "ec2:DescribeSubnets", - "ec2:DescribeRouteTables", - "ec2:DescribeDhcpOptions", - "ec2:DescribeVpcs" + "ec2:DescribeVpcs", + "iam:CreateServiceLinkedRole", + "iam:GetRole", + "iam:listAttachedRolePolicies" ], "Effect": "Allow", "Resource": "*" @@ -871,7 +873,10 @@ "name": "eksCluster", "version": "1.18", "roleArn": { - "Fn::GetAtt": ["EksClusterRoleC84B376F", "Arn"] + "Fn::GetAtt": [ + "EksClusterRoleC84B376F", + "Arn" + ] }, "resourcesVpcConfig": { "subnetIds": [ @@ -907,7 +912,10 @@ } }, "AssumeRoleArn": { - "Fn::GetAtt": ["EksClusterCreationRole75AABE42", "Arn"] + "Fn::GetAtt": [ + "EksClusterCreationRole75AABE42", + "Arn" + ] }, "AttributesRevision": 2 }, @@ -1010,11 +1018,17 @@ [ "[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"aws-auth\",\"namespace\":\"kube-system\",\"labels\":{\"aws.cdk.eks/prune-c8f58087a1a3e6c10f65d847befda9c1aa2145a8fc\":\"\"}},\"data\":{\"mapRoles\":\"[{\\\"rolearn\\\":\\\"", { - "Fn::GetAtt": ["EksClusterMastersRole3F49FAC3", "Arn"] + "Fn::GetAtt": [ + "EksClusterMastersRole3F49FAC3", + "Arn" + ] }, "\\\",\\\"username\\\":\\\"", { - "Fn::GetAtt": ["EksClusterMastersRole3F49FAC3", "Arn"] + "Fn::GetAtt": [ + "EksClusterMastersRole3F49FAC3", + "Arn" + ] }, "\\\",\\\"groups\\\":[\\\"system:masters\\\"]},{\\\"rolearn\\\":\\\"", { @@ -1025,11 +1039,17 @@ }, "\\\",\\\"username\\\":\\\"system:node:{{EC2PrivateDNSName}}\\\",\\\"groups\\\":[\\\"system:bootstrappers\\\",\\\"system:nodes\\\"]},{\\\"rolearn\\\":\\\"", { - "Fn::GetAtt": ["Role1ABCC5F0", "Arn"] + "Fn::GetAtt": [ + "Role1ABCC5F0", + "Arn" + ] }, "\\\",\\\"username\\\":\\\"", { - "Fn::GetAtt": ["Role1ABCC5F0", "Arn"] + "Fn::GetAtt": [ + "Role1ABCC5F0", + "Arn" + ] }, "\\\",\\\"groups\\\":[\\\"system:masters\\\"]}]\",\"mapUsers\":\"[]\",\"mapAccounts\":\"[]\"}}]" ] @@ -1039,12 +1059,17 @@ "Ref": "EksClusterFAB68BDB" }, "RoleArn": { - "Fn::GetAtt": ["EksClusterCreationRole75AABE42", "Arn"] + "Fn::GetAtt": [ + "EksClusterCreationRole75AABE42", + "Arn" + ] }, "PruneLabel": "aws.cdk.eks/prune-c8f58087a1a3e6c10f65d847befda9c1aa2145a8fc", "Overwrite": true }, - "DependsOn": ["EksClusterKubectlReadyBarrier502B0E83"], + "DependsOn": [ + "EksClusterKubectlReadyBarrier502B0E83" + ], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -1138,7 +1163,9 @@ ], "AmiType": "AL2_x86_64", "ForceUpdateEnabled": true, - "InstanceTypes": ["m5.large"], + "InstanceTypes": [ + "m5.large" + ], "ScalingConfig": { "DesiredSize": 2, "MaxSize": 2, @@ -1163,7 +1190,7 @@ }, "/", { - "Ref": "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8S3Bucket0CDB4070" + "Ref": "AssetParametersccf7ba5dd6e4a143970849e29cd4f0b5e83779a4229ae89c9a281dfb8129b695S3Bucket28E1275C" }, "/", { @@ -1173,7 +1200,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8S3VersionKey9304E721" + "Ref": "AssetParametersccf7ba5dd6e4a143970849e29cd4f0b5e83779a4229ae89c9a281dfb8129b695S3VersionKeyF39C35C5" } ] } @@ -1186,7 +1213,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8S3VersionKey9304E721" + "Ref": "AssetParametersccf7ba5dd6e4a143970849e29cd4f0b5e83779a4229ae89c9a281dfb8129b695S3VersionKeyF39C35C5" } ] } @@ -1196,26 +1223,29 @@ ] }, "Parameters": { - "referencetoawsstepfunctionstasksekscallintegEksClusterCreationRole00B486C4Arn": { - "Fn::GetAtt": ["EksClusterCreationRole75AABE42", "Arn"] + "referencetoawsstepfunctionstasksekscallintegAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket00B4958CRef": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097" }, - "referencetoawsstepfunctionstasksekscallintegAssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3Bucket7F9374E5Ref": { - "Ref": "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3Bucket575E2F4C" + "referencetoawsstepfunctionstasksekscallintegAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey361D9C06Ref": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224" }, - "referencetoawsstepfunctionstasksekscallintegAssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3VersionKey43EAF22DRef": { - "Ref": "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3VersionKeyFB3EB544" + "referencetoawsstepfunctionstasksekscallintegEksClusterCreationRole00B486C4Arn": { + "Fn::GetAtt": [ + "EksClusterCreationRole75AABE42", + "Arn" + ] }, - "referencetoawsstepfunctionstasksekscallintegAssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3Bucket32160528Ref": { - "Ref": "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3Bucket04F6B25B" + "referencetoawsstepfunctionstasksekscallintegAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket0B5E022ERef": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E" }, - "referencetoawsstepfunctionstasksekscallintegAssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3VersionKeyCEEE7AF3Ref": { - "Ref": "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3VersionKey6A7508AF" + "referencetoawsstepfunctionstasksekscallintegAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKeyFC16B266Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF" }, - "referencetoawsstepfunctionstasksekscallintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketCF9FB24DRef": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawsstepfunctionstasksekscallintegAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket060661ABRef": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawsstepfunctionstasksekscallintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey4B465A75Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawsstepfunctionstasksekscallintegAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyEAB94B97Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1239,7 +1269,7 @@ }, "/", { - "Ref": "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5S3BucketEC7134BF" + "Ref": "AssetParametersd2e7fbc583da5b26abfdeeddf4a017fe8ea21cc7708079de0f67dc762bd14b45S3Bucket9880C2B9" }, "/", { @@ -1249,7 +1279,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5S3VersionKey3EC7EA95" + "Ref": "AssetParametersd2e7fbc583da5b26abfdeeddf4a017fe8ea21cc7708079de0f67dc762bd14b45S3VersionKey02679A48" } ] } @@ -1262,7 +1292,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5S3VersionKey3EC7EA95" + "Ref": "AssetParametersd2e7fbc583da5b26abfdeeddf4a017fe8ea21cc7708079de0f67dc762bd14b45S3VersionKey02679A48" } ] } @@ -1273,16 +1303,22 @@ }, "Parameters": { "referencetoawsstepfunctionstasksekscallintegEksClusterCA674174Arn": { - "Fn::GetAtt": ["EksClusterFAB68BDB", "Arn"] + "Fn::GetAtt": [ + "EksClusterFAB68BDB", + "Arn" + ] }, "referencetoawsstepfunctionstasksekscallintegEksClusterCreationRole00B486C4Arn": { - "Fn::GetAtt": ["EksClusterCreationRole75AABE42", "Arn"] + "Fn::GetAtt": [ + "EksClusterCreationRole75AABE42", + "Arn" + ] }, - "referencetoawsstepfunctionstasksekscallintegAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketF4AF10B8Ref": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" + "referencetoawsstepfunctionstasksekscallintegAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3BucketE7B0B7E5Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3" }, - "referencetoawsstepfunctionstasksekscallintegAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey04C67745Ref": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" + "referencetoawsstepfunctionstasksekscallintegAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyCD195549Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291" }, "referencetoawsstepfunctionstasksekscallintegEksClusterDefaultVpcPrivateSubnet1Subnet3A6964EARef": { "Ref": "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F" @@ -1294,13 +1330,16 @@ "Ref": "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07" }, "referencetoawsstepfunctionstasksekscallintegEksClusterCA674174ClusterSecurityGroupId": { - "Fn::GetAtt": ["EksClusterFAB68BDB", "ClusterSecurityGroupId"] + "Fn::GetAtt": [ + "EksClusterFAB68BDB", + "ClusterSecurityGroupId" + ] }, - "referencetoawsstepfunctionstasksekscallintegAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3Bucket3F56B6C0Ref": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" + "referencetoawsstepfunctionstasksekscallintegAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketF5A5D7D1Ref": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" }, - "referencetoawsstepfunctionstasksekscallintegAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKey14F73D88Ref": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + "referencetoawsstepfunctionstasksekscallintegAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKeyB1080616Ref": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" }, "referencetoawsstepfunctionstasksekscallintegAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket91831D54Ref": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" @@ -1308,11 +1347,11 @@ "referencetoawsstepfunctionstasksekscallintegAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyAFE7B9F9Ref": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, - "referencetoawsstepfunctionstasksekscallintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketCF9FB24DRef": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawsstepfunctionstasksekscallintegAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket060661ABRef": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawsstepfunctionstasksekscallintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey4B465A75Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawsstepfunctionstasksekscallintegAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyEAB94B97Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1352,7 +1391,10 @@ "Type": "AWS::StepFunctions::StateMachine", "Properties": { "RoleArn": { - "Fn::GetAtt": ["Role1ABCC5F0", "Arn"] + "Fn::GetAtt": [ + "Role1ABCC5F0", + "Arn" + ] }, "DefinitionString": { "Fn::Join": [ @@ -1368,18 +1410,26 @@ }, "\",\"CertificateAuthority\":\"", { - "Fn::GetAtt": ["EksClusterFAB68BDB", "CertificateAuthorityData"] + "Fn::GetAtt": [ + "EksClusterFAB68BDB", + "CertificateAuthorityData" + ] }, "\",\"Endpoint\":\"", { - "Fn::GetAtt": ["EksClusterFAB68BDB", "Endpoint"] + "Fn::GetAtt": [ + "EksClusterFAB68BDB", + "Endpoint" + ] }, "\",\"Method\":\"GET\",\"Path\":\"/api/v1/namespaces/default/pods\"}}},\"TimeoutSeconds\":30}" ] ] } }, - "DependsOn": ["Role1ABCC5F0"] + "DependsOn": [ + "Role1ABCC5F0" + ] } }, "Outputs": { @@ -1398,7 +1448,10 @@ }, " --role-arn ", { - "Fn::GetAtt": ["EksClusterMastersRole3F49FAC3", "Arn"] + "Fn::GetAtt": [ + "EksClusterMastersRole3F49FAC3", + "Arn" + ] } ] ] @@ -1419,7 +1472,10 @@ }, " --role-arn ", { - "Fn::GetAtt": ["EksClusterMastersRole3F49FAC3", "Arn"] + "Fn::GetAtt": [ + "EksClusterMastersRole3F49FAC3", + "Arn" + ] } ] ] @@ -1432,65 +1488,65 @@ } }, "Parameters": { - "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3Bucket575E2F4C": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097": { "Type": "String", - "Description": "S3 bucket for asset \"2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7e\"" + "Description": "S3 bucket for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3VersionKeyFB3EB544": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224": { "Type": "String", - "Description": "S3 key for asset version \"2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7e\"" + "Description": "S3 key for asset version \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eArtifactHashDB8E8B5A": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeArtifactHash515E16AE": { "Type": "String", - "Description": "Artifact hash for asset \"2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7e\"" + "Description": "Artifact hash for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3Bucket04F6B25B": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E": { "Type": "String", - "Description": "S3 bucket for asset \"d1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6\"" + "Description": "S3 bucket for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3VersionKey6A7508AF": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF": { "Type": "String", - "Description": "S3 key for asset version \"d1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6\"" + "Description": "S3 key for asset version \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6ArtifactHashF7473C14": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647ArtifactHashE94F67E3": { "Type": "String", - "Description": "Artifact hash for asset \"d1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6\"" + "Description": "Artifact hash for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { "Type": "String", - "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { "Type": "String", - "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { "Type": "String", - "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3": { "Type": "String", - "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 bucket for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291": { "Type": "String", - "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 key for asset version \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8ArtifactHashA4AB6609": { "Type": "String", - "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "Artifact hash for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488": { "Type": "String", - "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 bucket for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2": { "Type": "String", - "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 key for asset version \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95ArtifactHash16B60F6C": { "Type": "String", - "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "Artifact hash for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", @@ -1504,29 +1560,29 @@ "Type": "String", "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8S3Bucket0CDB4070": { + "AssetParametersccf7ba5dd6e4a143970849e29cd4f0b5e83779a4229ae89c9a281dfb8129b695S3Bucket28E1275C": { "Type": "String", - "Description": "S3 bucket for asset \"0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8\"" + "Description": "S3 bucket for asset \"ccf7ba5dd6e4a143970849e29cd4f0b5e83779a4229ae89c9a281dfb8129b695\"" }, - "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8S3VersionKey9304E721": { + "AssetParametersccf7ba5dd6e4a143970849e29cd4f0b5e83779a4229ae89c9a281dfb8129b695S3VersionKeyF39C35C5": { "Type": "String", - "Description": "S3 key for asset version \"0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8\"" + "Description": "S3 key for asset version \"ccf7ba5dd6e4a143970849e29cd4f0b5e83779a4229ae89c9a281dfb8129b695\"" }, - "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8ArtifactHash27112E89": { + "AssetParametersccf7ba5dd6e4a143970849e29cd4f0b5e83779a4229ae89c9a281dfb8129b695ArtifactHashB1AF64BD": { "Type": "String", - "Description": "Artifact hash for asset \"0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8\"" + "Description": "Artifact hash for asset \"ccf7ba5dd6e4a143970849e29cd4f0b5e83779a4229ae89c9a281dfb8129b695\"" }, - "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5S3BucketEC7134BF": { + "AssetParametersd2e7fbc583da5b26abfdeeddf4a017fe8ea21cc7708079de0f67dc762bd14b45S3Bucket9880C2B9": { "Type": "String", - "Description": "S3 bucket for asset \"71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5\"" + "Description": "S3 bucket for asset \"d2e7fbc583da5b26abfdeeddf4a017fe8ea21cc7708079de0f67dc762bd14b45\"" }, - "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5S3VersionKey3EC7EA95": { + "AssetParametersd2e7fbc583da5b26abfdeeddf4a017fe8ea21cc7708079de0f67dc762bd14b45S3VersionKey02679A48": { "Type": "String", - "Description": "S3 key for asset version \"71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5\"" + "Description": "S3 key for asset version \"d2e7fbc583da5b26abfdeeddf4a017fe8ea21cc7708079de0f67dc762bd14b45\"" }, - "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5ArtifactHashCD2D1888": { + "AssetParametersd2e7fbc583da5b26abfdeeddf4a017fe8ea21cc7708079de0f67dc762bd14b45ArtifactHash172B8CCD": { "Type": "String", - "Description": "Artifact hash for asset \"71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5\"" + "Description": "Artifact hash for asset \"d2e7fbc583da5b26abfdeeddf4a017fe8ea21cc7708079de0f67dc762bd14b45\"" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-create-cluster.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-create-cluster.test.ts index 4e185710e2413..67a745bd16e2a 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-create-cluster.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-create-cluster.test.ts @@ -202,6 +202,27 @@ describe('Cluster with StepConcurrencyLevel', () => { }); }); + test('can be set dynamically through JsonPath', async () => { + // WHEN + const task = new EmrCreateCluster(stack, 'Task', { + instances: {}, + clusterRole, + name: 'Cluster', + serviceRole, + autoScalingRole, + stepConcurrencyLevel: sfn.JsonPath.numberAt('$.foo.bar'), + integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE, + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Parameters: { + 'Name': 'Cluster', + 'StepConcurrencyLevel.$': '$.foo.bar', + }, + }); + }); + test('throws if < 1 or > 256', async () => { expect(() => new EmrCreateCluster(stack, 'Task1', { instances: {}, diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.job-submission-workflow.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.job-submission-workflow.expected.json index ad853185040b4..632be9f6d5ea6 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.job-submission-workflow.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.job-submission-workflow.expected.json @@ -717,54 +717,30 @@ }, { "Action": [ + "ec2:DescribeDhcpOptions", + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeRouteTables", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeVpcs", "eks:CreateCluster", + "eks:CreateFargateProfile", + "eks:DeleteCluster", + "eks:DeleteFargateProfile", "eks:DescribeCluster", + "eks:DescribeFargateProfile", "eks:DescribeUpdate", - "eks:DeleteCluster", - "eks:UpdateClusterVersion", - "eks:UpdateClusterConfig", - "eks:CreateFargateProfile", "eks:TagResource", - "eks:UntagResource" - ], - "Effect": "Allow", - "Resource": [ - "*" - ] - }, - { - "Action": [ - "eks:DescribeFargateProfile", - "eks:DeleteFargateProfile" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ + "eks:UntagResource", + "eks:UpdateClusterConfig", + "eks:UpdateClusterVersion", + "iam:CreateServiceLinkedRole", "iam:GetRole", "iam:listAttachedRolePolicies" ], "Effect": "Allow", "Resource": "*" - }, - { - "Action": "iam:CreateServiceLinkedRole", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ec2:DescribeInstances", - "ec2:DescribeNetworkInterfaces", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSubnets", - "ec2:DescribeRouteTables", - "ec2:DescribeDhcpOptions", - "ec2:DescribeVpcs" - ], - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -1127,7 +1103,7 @@ }, "/", { - "Ref": "AssetParameters5ec12699a2590c6c682ce53d895ebfe56ed437e75e4f28b0b1aebe2941d96f81S3BucketD82D4551" + "Ref": "AssetParameters2a5ab35f4420d68f96a6e36cc4fc8d320de3bcf01199547acb57af0530db174aS3Bucket2F5D4D08" }, "/", { @@ -1137,7 +1113,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5ec12699a2590c6c682ce53d895ebfe56ed437e75e4f28b0b1aebe2941d96f81S3VersionKey897D64BB" + "Ref": "AssetParameters2a5ab35f4420d68f96a6e36cc4fc8d320de3bcf01199547acb57af0530db174aS3VersionKeyA75A8D2B" } ] } @@ -1150,7 +1126,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5ec12699a2590c6c682ce53d895ebfe56ed437e75e4f28b0b1aebe2941d96f81S3VersionKey897D64BB" + "Ref": "AssetParameters2a5ab35f4420d68f96a6e36cc4fc8d320de3bcf01199547acb57af0530db174aS3VersionKeyA75A8D2B" } ] } @@ -1160,11 +1136,11 @@ ] }, "Parameters": { - "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket780F031ARef": { - "Ref": "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1B280681" + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3BucketE001F8ECRef": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097" }, - "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKey8DCA7AE1Ref": { - "Ref": "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB1E02791" + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey112AFD6DRef": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224" }, "referencetoawsstepfunctionstasksemrcontainersallservicesintegintegrationtesteksclusterCreationRole78F8A91EArn": { "Fn::GetAtt": [ @@ -1172,17 +1148,17 @@ "Arn" ] }, - "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3Bucket1AC4E28ARef": { - "Ref": "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3Bucket9AE1EC0F" + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket970D47D8Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E" }, - "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3VersionKeyEFDBE51DRef": { - "Ref": "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3VersionKey451EAA56" + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey130969C4Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF" }, - "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket5978B8B5Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket3AEB52A5Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey9D9F3D17Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKey7B083B20Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1206,7 +1182,7 @@ }, "/", { - "Ref": "AssetParameters249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50S3BucketDBE4A868" + "Ref": "AssetParameters55ab944087ff7fca11470005814dff76a703d8bf01b6f1569046163522029e67S3Bucket7A7690F3" }, "/", { @@ -1216,7 +1192,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50S3VersionKeyDA4E6828" + "Ref": "AssetParameters55ab944087ff7fca11470005814dff76a703d8bf01b6f1569046163522029e67S3VersionKeyC21848A0" } ] } @@ -1229,7 +1205,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50S3VersionKeyDA4E6828" + "Ref": "AssetParameters55ab944087ff7fca11470005814dff76a703d8bf01b6f1569046163522029e67S3VersionKeyC21848A0" } ] } @@ -1251,11 +1227,11 @@ "Arn" ] }, - "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketFB7BE533Ref": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3BucketA20ABE41Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3" }, - "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey533AB384Ref": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKey968B9973Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291" }, "referencetoawsstepfunctionstasksemrcontainersallservicesintegintegrationtesteksclusterDefaultVpcPrivateSubnet1SubnetFBC220C4Ref": { "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB" @@ -1272,11 +1248,11 @@ "ClusterSecurityGroupId" ] }, - "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3Bucket5E7D98B4Ref": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketC3A07F1BRef": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488" }, - "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyC4C659E7Ref": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey9350B036Ref": { + "Ref": "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2" }, "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket8CD29A22Ref": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" @@ -1284,11 +1260,11 @@ "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyE130152FRef": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, - "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket5978B8B5Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3Bucket3AEB52A5Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey9D9F3D17Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKey7B083B20Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1304,25 +1280,21 @@ "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { - "Service": "emr-containers.amazonaws.com" - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "states.", - { - "Ref": "AWS::Region" - }, - ".amazonaws.com" + "Service": [ + "emr-containers.amazonaws.com", + { + "Fn::Join": [ + "", + [ + "states.", + { + "Ref": "AWS::Region" + }, + ".amazonaws.com" + ] ] - ] - } + } + ] } } ], @@ -1337,16 +1309,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -1375,6 +1347,7 @@ { "Action": [ "logs:CreateLogStream", + "logs:DescribeLogStreams", "logs:PutLogEvents" ], "Effect": "Allow", @@ -1385,16 +1358,6 @@ ] } }, - { - "Action": "logs:DescribeLogStreams", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "StartaJobRunMonitoringLogGroupD033B7AF", - "Arn" - ] - } - }, { "Action": "logs:DescribeLogGroups", "Effect": "Allow", @@ -1546,8 +1509,9 @@ }, { "Action": [ - "emr-containers:DescribeJobRun", - "emr-containers:CancelJobRun" + "emr-containers:CancelJobRun", + "emr-containers:DeleteVirtualCluster", + "emr-containers:DescribeJobRun" ], "Effect": "Allow", "Resource": { @@ -1570,30 +1534,6 @@ ] ] } - }, - { - "Action": "emr-containers:DeleteVirtualCluster", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":emr-containers:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":/virtualclusters/*" - ] - ] - } } ], "Version": "2012-10-17" @@ -1717,65 +1657,65 @@ } }, "Parameters": { - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1B280681": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097": { "Type": "String", - "Description": "S3 bucket for asset \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "S3 bucket for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB1E02791": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224": { "Type": "String", - "Description": "S3 key for asset version \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "S3 key for asset version \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665ArtifactHash9EA5AC29": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeArtifactHash515E16AE": { "Type": "String", - "Description": "Artifact hash for asset \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "Artifact hash for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3Bucket9AE1EC0F": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E": { "Type": "String", - "Description": "S3 bucket for asset \"00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5af\"" + "Description": "S3 bucket for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3VersionKey451EAA56": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF": { "Type": "String", - "Description": "S3 key for asset version \"00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5af\"" + "Description": "S3 key for asset version \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afArtifactHash761F4689": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647ArtifactHashE94F67E3": { "Type": "String", - "Description": "Artifact hash for asset \"00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5af\"" + "Description": "Artifact hash for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { "Type": "String", - "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { "Type": "String", - "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { "Type": "String", - "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3": { "Type": "String", - "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 bucket for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291": { "Type": "String", - "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 key for asset version \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8ArtifactHashA4AB6609": { "Type": "String", - "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "Artifact hash for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3BucketE02B5488": { "Type": "String", - "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 bucket for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95S3VersionKey4D8E71F2": { "Type": "String", - "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 key for asset version \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { + "AssetParametersf331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95ArtifactHash16B60F6C": { "Type": "String", - "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "Artifact hash for asset \"f331b32a8ad8983464106a58e420e7bc7e6341ba2ffb8ac9ad350d7e32845d95\"" }, "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", @@ -1789,29 +1729,29 @@ "Type": "String", "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameters5ec12699a2590c6c682ce53d895ebfe56ed437e75e4f28b0b1aebe2941d96f81S3BucketD82D4551": { + "AssetParameters2a5ab35f4420d68f96a6e36cc4fc8d320de3bcf01199547acb57af0530db174aS3Bucket2F5D4D08": { "Type": "String", - "Description": "S3 bucket for asset \"5ec12699a2590c6c682ce53d895ebfe56ed437e75e4f28b0b1aebe2941d96f81\"" + "Description": "S3 bucket for asset \"2a5ab35f4420d68f96a6e36cc4fc8d320de3bcf01199547acb57af0530db174a\"" }, - "AssetParameters5ec12699a2590c6c682ce53d895ebfe56ed437e75e4f28b0b1aebe2941d96f81S3VersionKey897D64BB": { + "AssetParameters2a5ab35f4420d68f96a6e36cc4fc8d320de3bcf01199547acb57af0530db174aS3VersionKeyA75A8D2B": { "Type": "String", - "Description": "S3 key for asset version \"5ec12699a2590c6c682ce53d895ebfe56ed437e75e4f28b0b1aebe2941d96f81\"" + "Description": "S3 key for asset version \"2a5ab35f4420d68f96a6e36cc4fc8d320de3bcf01199547acb57af0530db174a\"" }, - "AssetParameters5ec12699a2590c6c682ce53d895ebfe56ed437e75e4f28b0b1aebe2941d96f81ArtifactHash8B07F4C4": { + "AssetParameters2a5ab35f4420d68f96a6e36cc4fc8d320de3bcf01199547acb57af0530db174aArtifactHash7B798644": { "Type": "String", - "Description": "Artifact hash for asset \"5ec12699a2590c6c682ce53d895ebfe56ed437e75e4f28b0b1aebe2941d96f81\"" + "Description": "Artifact hash for asset \"2a5ab35f4420d68f96a6e36cc4fc8d320de3bcf01199547acb57af0530db174a\"" }, - "AssetParameters249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50S3BucketDBE4A868": { + "AssetParameters55ab944087ff7fca11470005814dff76a703d8bf01b6f1569046163522029e67S3Bucket7A7690F3": { "Type": "String", - "Description": "S3 bucket for asset \"249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50\"" + "Description": "S3 bucket for asset \"55ab944087ff7fca11470005814dff76a703d8bf01b6f1569046163522029e67\"" }, - "AssetParameters249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50S3VersionKeyDA4E6828": { + "AssetParameters55ab944087ff7fca11470005814dff76a703d8bf01b6f1569046163522029e67S3VersionKeyC21848A0": { "Type": "String", - "Description": "S3 key for asset version \"249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50\"" + "Description": "S3 key for asset version \"55ab944087ff7fca11470005814dff76a703d8bf01b6f1569046163522029e67\"" }, - "AssetParameters249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50ArtifactHashB10F4A4B": { + "AssetParameters55ab944087ff7fca11470005814dff76a703d8bf01b6f1569046163522029e67ArtifactHash7C23762C": { "Type": "String", - "Description": "Artifact hash for asset \"249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50\"" + "Description": "Artifact hash for asset \"55ab944087ff7fca11470005814dff76a703d8bf01b6f1569046163522029e67\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.start-job-run.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.start-job-run.expected.json index 1cd5ed999f0b5..50ea79608b669 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.start-job-run.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.start-job-run.expected.json @@ -717,54 +717,30 @@ }, { "Action": [ + "ec2:DescribeDhcpOptions", + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeRouteTables", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeVpcs", "eks:CreateCluster", + "eks:CreateFargateProfile", + "eks:DeleteCluster", + "eks:DeleteFargateProfile", "eks:DescribeCluster", + "eks:DescribeFargateProfile", "eks:DescribeUpdate", - "eks:DeleteCluster", - "eks:UpdateClusterVersion", - "eks:UpdateClusterConfig", - "eks:CreateFargateProfile", "eks:TagResource", - "eks:UntagResource" - ], - "Effect": "Allow", - "Resource": [ - "*" - ] - }, - { - "Action": [ - "eks:DescribeFargateProfile", - "eks:DeleteFargateProfile" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ + "eks:UntagResource", + "eks:UpdateClusterConfig", + "eks:UpdateClusterVersion", + "iam:CreateServiceLinkedRole", "iam:GetRole", "iam:listAttachedRolePolicies" ], "Effect": "Allow", "Resource": "*" - }, - { - "Action": "iam:CreateServiceLinkedRole", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ec2:DescribeInstances", - "ec2:DescribeNetworkInterfaces", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSubnets", - "ec2:DescribeRouteTables", - "ec2:DescribeDhcpOptions", - "ec2:DescribeVpcs" - ], - "Effect": "Allow", - "Resource": "*" } ], "Version": "2012-10-17" @@ -1186,7 +1162,7 @@ }, "/", { - "Ref": "AssetParameters8d4e2482ff0cc6756dec9686c2446eea35c5a917ce2a8d56d8b83bc148894d35S3Bucket37C1382F" + "Ref": "AssetParameters2daac167596520ae78884b19c51078420864f0dbaed10dc7d68927e0f9f8f3d1S3Bucket5BEEED81" }, "/", { @@ -1196,7 +1172,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters8d4e2482ff0cc6756dec9686c2446eea35c5a917ce2a8d56d8b83bc148894d35S3VersionKey5D044A85" + "Ref": "AssetParameters2daac167596520ae78884b19c51078420864f0dbaed10dc7d68927e0f9f8f3d1S3VersionKeyD7F17160" } ] } @@ -1209,7 +1185,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters8d4e2482ff0cc6756dec9686c2446eea35c5a917ce2a8d56d8b83bc148894d35S3VersionKey5D044A85" + "Ref": "AssetParameters2daac167596520ae78884b19c51078420864f0dbaed10dc7d68927e0f9f8f3d1S3VersionKeyD7F17160" } ] } @@ -1219,11 +1195,11 @@ ] }, "Parameters": { - "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket47FE5F69Ref": { - "Ref": "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1B280681" + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket3302917DRef": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097" }, - "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB5CD57E0Ref": { - "Ref": "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB1E02791" + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey910A3B24Ref": { + "Ref": "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224" }, "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestintegrationtesteksclusterCreationRole19DB152EArn": { "Fn::GetAtt": [ @@ -1231,17 +1207,17 @@ "Arn" ] }, - "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3Bucket90E6B403Ref": { - "Ref": "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3Bucket9AE1EC0F" + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket2A349F05Ref": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E" }, - "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3VersionKeyAD902FD9Ref": { - "Ref": "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3VersionKey451EAA56" + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey33F19E9BRef": { + "Ref": "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF" }, - "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket977A6FD0Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketACB46494Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey9A35F1EFRef": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKey4099BBC8Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1265,7 +1241,7 @@ }, "/", { - "Ref": "AssetParameters922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882bS3Bucket6FC76F07" + "Ref": "AssetParametersa0c3cdfbc06ef95d340baf52d0c1a88f573ee45813d1552c057f6c6017b5e47eS3Bucket91C98648" }, "/", { @@ -1275,7 +1251,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882bS3VersionKey396AB4CB" + "Ref": "AssetParametersa0c3cdfbc06ef95d340baf52d0c1a88f573ee45813d1552c057f6c6017b5e47eS3VersionKey8051CFBE" } ] } @@ -1288,7 +1264,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882bS3VersionKey396AB4CB" + "Ref": "AssetParametersa0c3cdfbc06ef95d340baf52d0c1a88f573ee45813d1552c057f6c6017b5e47eS3VersionKey8051CFBE" } ] } @@ -1310,11 +1286,11 @@ "Arn" ] }, - "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3Bucket266CDCEARef": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3BucketDB162633Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3" }, - "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey06C0AAD8Ref": { - "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKey428A28B8Ref": { + "Ref": "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291" }, "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestintegrationtesteksclusterDefaultVpcPrivateSubnet1SubnetDFF56EB6Ref": { "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB" @@ -1331,11 +1307,11 @@ "ClusterSecurityGroupId" ] }, - "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketFE6FEB31Ref": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3Bucket694141C5Ref": { + "Ref": "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3Bucket940CB35D" }, - "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyBE97CFCARef": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3VersionKey89E46F11Ref": { + "Ref": "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3VersionKey248C9936" }, "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketF38DB26BRef": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" @@ -1343,11 +1319,11 @@ "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKey1E1E9DA8Ref": { "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, - "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket977A6FD0Ref": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketACB46494Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, - "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey9A35F1EFRef": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKey4099BBC8Ref": { + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } } }, @@ -1384,25 +1360,21 @@ "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { - "Service": "emr-containers.amazonaws.com" - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "states.", - { - "Ref": "AWS::Region" - }, - ".amazonaws.com" + "Service": [ + "emr-containers.amazonaws.com", + { + "Fn::Join": [ + "", + [ + "states.", + { + "Ref": "AWS::Region" + }, + ".amazonaws.com" + ] ] - ] - } + } + ] } } ], @@ -1489,7 +1461,7 @@ "Properties": { "Content": { "S3Bucket": { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" + "Ref": "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3Bucket940CB35D" }, "S3Key": { "Fn::Join": [ @@ -1502,7 +1474,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + "Ref": "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3VersionKey248C9936" } ] } @@ -1515,7 +1487,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + "Ref": "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3VersionKey248C9936" } ] } @@ -1567,12 +1539,28 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "SingletonLambda8693BB64968944B69AAFB0CC9EB8757CB6182A5B", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "SingletonLambda8693BB64968944B69AAFB0CC9EB8757CB6182A5B", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "SingletonLambda8693BB64968944B69AAFB0CC9EB8757CB6182A5B", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -1590,7 +1578,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, "S3Key": { "Fn::Join": [ @@ -1603,7 +1591,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -1616,7 +1604,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -1993,8 +1981,8 @@ }, { "Action": [ - "emr-containers:DescribeJobRun", - "emr-containers:CancelJobRun" + "emr-containers:CancelJobRun", + "emr-containers:DescribeJobRun" ], "Effect": "Allow", "Resource": { @@ -2134,65 +2122,65 @@ } }, "Parameters": { - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1B280681": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3Bucket4E7CD097": { "Type": "String", - "Description": "S3 bucket for asset \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "S3 bucket for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB1E02791": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeS3VersionKey93D16224": { "Type": "String", - "Description": "S3 key for asset version \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "S3 key for asset version \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665ArtifactHash9EA5AC29": { + "AssetParameters4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06eeArtifactHash515E16AE": { "Type": "String", - "Description": "Artifact hash for asset \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + "Description": "Artifact hash for asset \"4288ebb3652acdf2d828b7db7ca44a7162a401ace50ebb4026e84b18a02a06ee\"" }, - "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3Bucket9AE1EC0F": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3Bucket05488C5E": { "Type": "String", - "Description": "S3 bucket for asset \"00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5af\"" + "Description": "S3 bucket for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afS3VersionKey451EAA56": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647S3VersionKey174B23DF": { "Type": "String", - "Description": "S3 key for asset version \"00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5af\"" + "Description": "S3 key for asset version \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParameters00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5afArtifactHash761F4689": { + "AssetParameters8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647ArtifactHashE94F67E3": { "Type": "String", - "Description": "Artifact hash for asset \"00d62edb46d4e11942f8a3afeca5526ec56ff1d63eb753bd46ceecff8b01f5af\"" + "Description": "Artifact hash for asset \"8b11ea303df4b9db9feef6ed5f901a2d1185023a40c80c9630cf5c36559ae647\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { "Type": "String", - "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { "Type": "String", - "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { "Type": "String", - "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3Bucket4CD5FFC3": { "Type": "String", - "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 bucket for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8S3VersionKeyE06BA291": { "Type": "String", - "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "S3 key for asset version \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { + "AssetParametersa70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8ArtifactHashA4AB6609": { "Type": "String", - "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + "Description": "Artifact hash for asset \"a70c48e7047fb793b2378668accb1dc2d92f2d7b1fff80c9c718f4964dc69cb8\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { + "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3Bucket940CB35D": { "Type": "String", - "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 bucket for asset \"d78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { + "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3VersionKey248C9936": { "Type": "String", - "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "S3 key for asset version \"d78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27\"" }, - "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { + "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27ArtifactHash934284DB": { "Type": "String", - "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + "Description": "Artifact hash for asset \"d78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27\"" }, "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", @@ -2230,29 +2218,29 @@ "Type": "String", "Description": "Artifact hash for asset \"b866fb0fd5a9b4215d1e23188632d74c01f3195f6f9d706134b197b400afb680\"" }, - "AssetParameters8d4e2482ff0cc6756dec9686c2446eea35c5a917ce2a8d56d8b83bc148894d35S3Bucket37C1382F": { + "AssetParameters2daac167596520ae78884b19c51078420864f0dbaed10dc7d68927e0f9f8f3d1S3Bucket5BEEED81": { "Type": "String", - "Description": "S3 bucket for asset \"8d4e2482ff0cc6756dec9686c2446eea35c5a917ce2a8d56d8b83bc148894d35\"" + "Description": "S3 bucket for asset \"2daac167596520ae78884b19c51078420864f0dbaed10dc7d68927e0f9f8f3d1\"" }, - "AssetParameters8d4e2482ff0cc6756dec9686c2446eea35c5a917ce2a8d56d8b83bc148894d35S3VersionKey5D044A85": { + "AssetParameters2daac167596520ae78884b19c51078420864f0dbaed10dc7d68927e0f9f8f3d1S3VersionKeyD7F17160": { "Type": "String", - "Description": "S3 key for asset version \"8d4e2482ff0cc6756dec9686c2446eea35c5a917ce2a8d56d8b83bc148894d35\"" + "Description": "S3 key for asset version \"2daac167596520ae78884b19c51078420864f0dbaed10dc7d68927e0f9f8f3d1\"" }, - "AssetParameters8d4e2482ff0cc6756dec9686c2446eea35c5a917ce2a8d56d8b83bc148894d35ArtifactHash907D4CC2": { + "AssetParameters2daac167596520ae78884b19c51078420864f0dbaed10dc7d68927e0f9f8f3d1ArtifactHash74CF0762": { "Type": "String", - "Description": "Artifact hash for asset \"8d4e2482ff0cc6756dec9686c2446eea35c5a917ce2a8d56d8b83bc148894d35\"" + "Description": "Artifact hash for asset \"2daac167596520ae78884b19c51078420864f0dbaed10dc7d68927e0f9f8f3d1\"" }, - "AssetParameters922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882bS3Bucket6FC76F07": { + "AssetParametersa0c3cdfbc06ef95d340baf52d0c1a88f573ee45813d1552c057f6c6017b5e47eS3Bucket91C98648": { "Type": "String", - "Description": "S3 bucket for asset \"922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882b\"" + "Description": "S3 bucket for asset \"a0c3cdfbc06ef95d340baf52d0c1a88f573ee45813d1552c057f6c6017b5e47e\"" }, - "AssetParameters922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882bS3VersionKey396AB4CB": { + "AssetParametersa0c3cdfbc06ef95d340baf52d0c1a88f573ee45813d1552c057f6c6017b5e47eS3VersionKey8051CFBE": { "Type": "String", - "Description": "S3 key for asset version \"922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882b\"" + "Description": "S3 key for asset version \"a0c3cdfbc06ef95d340baf52d0c1a88f573ee45813d1552c057f6c6017b5e47e\"" }, - "AssetParameters922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882bArtifactHash2918634A": { + "AssetParametersa0c3cdfbc06ef95d340baf52d0c1a88f573ee45813d1552c057f6c6017b5e47eArtifactHash6EFA2AF6": { "Type": "String", - "Description": "Artifact hash for asset \"922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882b\"" + "Description": "Artifact hash for asset \"a0c3cdfbc06ef95d340baf52d0c1a88f573ee45813d1552c057f6c6017b5e47e\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/eventbridge/integ.put-events.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eventbridge/integ.put-events.expected.json index 9e4fe6ff2ae21..c02d4d5afa789 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/eventbridge/integ.put-events.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eventbridge/integ.put-events.expected.json @@ -43,6 +43,12 @@ "Action": "events:PutEvents", "Effect": "Allow", "Resource": [ + { + "Fn::GetAtt": [ + "EventBus7B8748AA", + "Arn" + ] + }, { "Fn::Join": [ "", @@ -62,12 +68,6 @@ ":event-bus/default" ] ] - }, - { - "Fn::GetAtt": [ - "EventBus7B8748AA", - "Arn" - ] } ] } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/glue/integ.glue-task.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/glue/integ.glue-task.expected.json index 150ecb4c32161..7214c2b028f1b 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/glue/integ.glue-task.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/glue/integ.glue-task.expected.json @@ -52,8 +52,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -69,7 +69,8 @@ ":s3:::", { "Ref": "AssetParametersd030bb7913ca422df69f29b2ea678ab4e5085bb3cbb17029e4b101d2dc4e3e0dS3BucketB8F6851B" - } + }, + "/*" ] ] }, @@ -84,8 +85,7 @@ ":s3:::", { "Ref": "AssetParametersd030bb7913ca422df69f29b2ea678ab4e5085bb3cbb17029e4b101d2dc4e3e0dS3BucketB8F6851B" - }, - "/*" + } ] ] } @@ -192,10 +192,10 @@ "Statement": [ { "Action": [ - "glue:StartJobRun", + "glue:BatchStopJobRun", "glue:GetJobRun", "glue:GetJobRuns", - "glue:BatchStopJobRun" + "glue:StartJobRun" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/glue/integ.start-job-run.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/glue/integ.start-job-run.expected.json index 217b47176d936..a35e42ab649d9 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/glue/integ.start-job-run.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/glue/integ.start-job-run.expected.json @@ -52,8 +52,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -69,7 +69,8 @@ ":s3:::", { "Ref": "AssetParametersd030bb7913ca422df69f29b2ea678ab4e5085bb3cbb17029e4b101d2dc4e3e0dS3BucketB8F6851B" - } + }, + "/*" ] ] }, @@ -84,8 +85,7 @@ ":s3:::", { "Ref": "AssetParametersd030bb7913ca422df69f29b2ea678ab4e5085bb3cbb17029e4b101d2dc4e3e0dS3BucketB8F6851B" - }, - "/*" + } ] ] } @@ -192,10 +192,10 @@ "Statement": [ { "Action": [ - "glue:StartJobRun", + "glue:BatchStopJobRun", "glue:GetJobRun", "glue:GetJobRuns", - "glue:BatchStopJobRun" + "glue:StartJobRun" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.evaluate-expression.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.evaluate-expression.expected.json index 39a3502ba6c80..9a5de368628cd 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.evaluate-expression.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.evaluate-expression.expected.json @@ -121,12 +121,28 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "Evalda2d1181604e4a4586941a6abd7fe42dF371675D", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "Evalda2d1181604e4a4586941a6abd7fe42dF371675D", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Evalda2d1181604e4a4586941a6abd7fe42dF371675D", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.start-execution.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.start-execution.expected.json index 7916ba084ade1..f7bf0fa42dc2e 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.start-execution.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.start-execution.expected.json @@ -126,9 +126,9 @@ }, { "Action": [ - "events:PutTargets", + "events:DescribeRule", "events:PutRule", - "events:DescribeRule" + "events:PutTargets" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke-function.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke-function.expected.json index dec16cb9e6ba8..70549c1ed2ef2 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke-function.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke-function.expected.json @@ -206,22 +206,48 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "Handler886CB40B", - "Arn" - ] - } - }, - { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "CallbackHandler4434C38D", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "CallbackHandler4434C38D", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "Handler886CB40B", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "CallbackHandler4434C38D", + "Arn" + ] + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Handler886CB40B", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke.expected.json index fe1262610ffd2..06d010a158e56 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke.expected.json @@ -136,22 +136,48 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "submitJobLambdaEFB00F3C", - "Arn" - ] - } - }, - { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "checkJobStateLambda4618B7B7", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "checkJobStateLambda4618B7B7", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "submitJobLambdaEFB00F3C", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "checkJobStateLambda4618B7B7", + "Arn" + ] + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "submitJobLambdaEFB00F3C", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke.payload.only.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke.payload.only.expected.json index d0a6cdda262dc..0853de4a89c45 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke.payload.only.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke.payload.only.expected.json @@ -136,22 +136,48 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "submitJobLambdaEFB00F3C", - "Arn" - ] - } - }, - { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "checkJobStateLambda4618B7B7", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "checkJobStateLambda4618B7B7", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "submitJobLambdaEFB00F3C", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "checkJobStateLambda4618B7B7", + "Arn" + ] + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "submitJobLambdaEFB00F3C", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.run-lambda.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.run-lambda.expected.json index 6c483349d059b..1023c2caf6167 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.run-lambda.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.run-lambda.expected.json @@ -136,22 +136,48 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "submitJobLambdaEFB00F3C", - "Arn" - ] - } - }, - { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "checkJobStateLambda4618B7B7", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "checkJobStateLambda4618B7B7", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "submitJobLambdaEFB00F3C", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "checkJobStateLambda4618B7B7", + "Arn" + ] + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "submitJobLambdaEFB00F3C", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/invoke.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/invoke.test.ts index cbbd0092706ab..f588a8e7d129a 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/invoke.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/invoke.test.ts @@ -2,6 +2,7 @@ import * as lambda from '@aws-cdk/aws-lambda'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import { Stack } from '@aws-cdk/core'; import { LambdaInvocationType, LambdaInvoke } from '../../lib'; +import { testDeprecated } from '@aws-cdk/cdk-build-tools'; /* eslint-disable quote-props */ @@ -66,7 +67,7 @@ describe('LambdaInvoke', () => { }); }); - test('optional settings', () => { + testDeprecated('optional settings', () => { // WHEN const task = new LambdaInvoke(stack, 'Task', { lambdaFunction, @@ -163,7 +164,7 @@ describe('LambdaInvoke', () => { })); }); - test('invoke Lambda function and wait for task token', () => { + testDeprecated('invoke Lambda function and wait for task token', () => { // GIVEN const task = new LambdaInvoke(stack, 'Task', { lambdaFunction, @@ -360,7 +361,7 @@ describe('LambdaInvoke', () => { }).toThrow(/The 'payloadResponseOnly' property cannot be used if 'integrationPattern', 'invocationType', 'clientContext', or 'qualifier' are specified./); }); - test('fails when qualifier used with payloadResponseOnly', () => { + testDeprecated('fails when qualifier used with payloadResponseOnly', () => { expect(() => { new LambdaInvoke(stack, 'Task', { lambdaFunction, diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-training-job.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-training-job.test.ts index 7e7a5eff26348..9d5ebb1f9711a 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-training-job.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-training-job.test.ts @@ -192,6 +192,9 @@ test('create complex training job', () => { vpcConfig: { vpc, }, + environment: { + SOMEVAR: 'myvalue', + }, }); trainTask.addSecurityGroup(securityGroup); @@ -285,6 +288,9 @@ test('create complex training job', () => { { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, ], }, + Environment: { + SOMEVAR: 'myvalue', + }, }, }); }); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/integ.call-sagemaker.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/integ.call-sagemaker.expected.json index 942f72ba3d41b..d8d68cf762861 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/integ.call-sagemaker.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/integ.call-sagemaker.expected.json @@ -79,11 +79,11 @@ { "Action": [ "cloudwatch:PutMetricData", - "logs:CreateLogStream", - "logs:PutLogEvents", + "ecr:GetAuthorizationToken", "logs:CreateLogGroup", + "logs:CreateLogStream", "logs:DescribeLogStreams", - "ecr:GetAuthorizationToken" + "logs:PutLogEvents" ], "Effect": "Allow", "Resource": "*" @@ -103,8 +103,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -134,7 +134,10 @@ { "Action": [ "kms:Decrypt", - "kms:DescribeKey" + "kms:DescribeKey", + "kms:Encrypt", + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -146,13 +149,13 @@ }, { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -177,21 +180,6 @@ ] } ] - }, - { - "Action": [ - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - "kms:Decrypt" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "EncryptionKey1B843E66", - "Arn" - ] - } } ], "Version": "2012-10-17" @@ -226,11 +214,11 @@ { "Action": [ "cloudwatch:PutMetricData", - "logs:CreateLogStream", + "ecr:GetAuthorizationToken", "logs:CreateLogGroup", - "logs:PutLogEvents", + "logs:CreateLogStream", "logs:DescribeLogStreams", - "ecr:GetAuthorizationToken" + "logs:PutLogEvents" ], "Effect": "Allow", "Resource": "*" @@ -251,14 +239,8 @@ { "Action": [ "ecr:BatchCheckLayerAvailability", + "ecr:BatchGetImage", "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ "s3:GetObject", "s3:ListBucket" ], @@ -350,12 +332,20 @@ } }, "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "TrainTaskSagemakerRoleD5A6F967", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "CreateModelSagemakerRoleC2E07FC0", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "TrainTaskSagemakerRoleD5A6F967", + "Arn" + ] + } + ] }, { "Action": "sagemaker:CreateModel", @@ -381,21 +371,6 @@ ] } }, - { - "Action": "iam:PassRole", - "Condition": { - "StringEquals": { - "iam:PassedToService": "sagemaker.amazonaws.com" - } - }, - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "CreateModelSagemakerRoleC2E07FC0", - "Arn" - ] - } - }, { "Action": "sagemaker:CreateEndpointConfig", "Effect": "Allow", @@ -421,29 +396,12 @@ } }, { - "Action": "sagemaker:createEndpoint", + "Action": [ + "sagemaker:createEndpoint", + "sagemaker:updateEndpoint" + ], "Effect": "Allow", "Resource": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":sagemaker:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":endpoint/*" - ] - ] - }, { "Fn::Join": [ "", @@ -463,32 +421,6 @@ ":endpoint-config/*" ] ] - } - ] - }, - { - "Action": "sagemaker:updateEndpoint", - "Effect": "Allow", - "Resource": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":sagemaker:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":endpoint/*" - ] - ] }, { "Fn::Join": [ @@ -506,7 +438,7 @@ { "Ref": "AWS::AccountId" }, - ":endpoint-config/*" + ":endpoint/*" ] ] } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/integ.create-training-job.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/integ.create-training-job.expected.json index 3e069a953f03a..72d830f466baa 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/integ.create-training-job.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/integ.create-training-job.expected.json @@ -79,11 +79,11 @@ { "Action": [ "cloudwatch:PutMetricData", - "logs:CreateLogStream", - "logs:PutLogEvents", + "ecr:GetAuthorizationToken", "logs:CreateLogGroup", + "logs:CreateLogStream", "logs:DescribeLogStreams", - "ecr:GetAuthorizationToken" + "logs:PutLogEvents" ], "Effect": "Allow", "Resource": "*" @@ -103,8 +103,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -134,7 +134,10 @@ { "Action": [ "kms:Decrypt", - "kms:DescribeKey" + "kms:DescribeKey", + "kms:Encrypt", + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -146,13 +149,13 @@ }, { "Action": [ + "s3:Abort*", "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -177,21 +180,6 @@ ] } ] - }, - { - "Action": [ - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - "kms:Decrypt" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "EncryptionKey1B843E66", - "Arn" - ] - } } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/integ.start-execution.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/integ.start-execution.expected.json index cd4621ee4c7f1..966eb60ddfe35 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/integ.start-execution.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/integ.start-execution.expected.json @@ -126,9 +126,9 @@ }, { "Action": [ - "events:PutTargets", + "events:DescribeRule", "events:PutRule", - "events:DescribeRule" + "events:PutTargets" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts index 4143e4bba6601..7fe4423b8a310 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts @@ -142,7 +142,9 @@ abstract class StateMachineBase extends Resource implements IStateMachine { public readonly stateMachineArn = stateMachineArn; public readonly grantPrincipal = new iam.UnknownPrincipal({ resource: this }); } - return new Import(scope, id); + return new Import(scope, id, { + environmentFromArn: stateMachineArn, + }); } public abstract readonly stateMachineArn: string; diff --git a/packages/@aws-cdk/aws-stepfunctions/package.json b/packages/@aws-cdk/aws-stepfunctions/package.json index f9018098cd4d6..c901ae4980ad4 100644 --- a/packages/@aws-cdk/aws-stepfunctions/package.json +++ b/packages/@aws-cdk/aws-stepfunctions/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-stepfunctions/test/integ.state-machine.expected.json b/packages/@aws-cdk/aws-stepfunctions/test/integ.state-machine.expected.json index 3899a0ed71b99..971b1de2ed585 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/integ.state-machine.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions/test/integ.state-machine.expected.json @@ -25,7 +25,8 @@ { "Action": [ "states:ListExecutions", - "states:ListStateMachines" + "states:ListStateMachines", + "states:SendTaskSuccess" ], "Effect": "Allow", "Resource": { @@ -76,19 +77,12 @@ }, { "Action": [ - "states:ListActivities", + "states:DescribeActivity", "states:DescribeStateMachine", - "states:DescribeActivity" + "states:ListActivities" ], "Effect": "Allow", "Resource": "*" - }, - { - "Action": "states:SendTaskSuccess", - "Effect": "Allow", - "Resource": { - "Ref": "StateMachine2E01A3A5" - } } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-stepfunctions/test/state-machine.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/state-machine.test.ts index f60c0b756e66a..f99cc479c9975 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/state-machine.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/state-machine.test.ts @@ -277,4 +277,35 @@ describe('State Machine', () => { ], }); }); + + describe('StateMachine.fromStateMachineArn()', () => { + let stack: cdk.Stack; + + beforeEach(() => { + const app = new cdk.App(); + stack = new cdk.Stack(app, 'Base', { + env: { account: '111111111111', region: 'stack-region' }, + }); + }); + + describe('for a state machine in a different account and region', () => { + let mach: stepfunctions.IStateMachine; + + beforeEach(() => { + mach = stepfunctions.StateMachine.fromStateMachineArn( + stack, + 'iMach', + 'arn:aws:states:machine-region:222222222222:stateMachine:machine-name', + ); + }); + + test("the state machine's region is taken from the ARN", () => { + expect(mach.env.region).toBe('machine-region'); + }); + + test("the state machine's account is taken from the ARN", () => { + expect(mach.env.account).toBe('222222222222'); + }); + }); + }); }); diff --git a/packages/@aws-cdk/aws-synthetics/README.md b/packages/@aws-cdk/aws-synthetics/README.md index cdb5aaa6dff47..77e0b90640d81 100644 --- a/packages/@aws-cdk/aws-synthetics/README.md +++ b/packages/@aws-cdk/aws-synthetics/README.md @@ -129,7 +129,7 @@ new synthetics.Canary(this, 'Inline Canary', { code: synthetics.Code.fromInline('/* Synthetics handler code */'), handler: 'index.handler', // must be 'index.handler' }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_3, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_4, }); // To supply the code from your local filesystem: @@ -138,7 +138,7 @@ new synthetics.Canary(this, 'Asset Canary', { code: synthetics.Code.fromAsset(path.join(__dirname, 'canary')), handler: 'index.handler', // must end with '.handler' }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_3, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_4, }); // To supply the code from a S3 bucket: @@ -149,7 +149,7 @@ new synthetics.Canary(this, 'Bucket Canary', { code: synthetics.Code.fromBucket(bucket, 'canary.zip'), handler: 'index.handler', // must end with '.handler' }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_3, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_4, }); ``` @@ -173,6 +173,32 @@ new synthetics.Canary(this, 'Bucket Canary', { > > See Synthetics [docs](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_WritingCanary.html). +### Running a canary on a VPC + +You can specify what [VPC a canary executes in](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_VPC.html). +This can allow for monitoring services that may be internal to a specific VPC. To place a canary within a VPC, you can specify the `vpc` property with the desired `VPC` to place then canary in. +This will automatically attach the appropriate IAM permissions to attach to the VPC. This will also create a Security Group and attach to the default subnets for the VPC unless specified via `vpcSubnets` and `securityGroups`. + +```ts +import * as ec2 from '@aws-cdk/aws-ec2'; + +declare const vpc: ec2.IVpc; +new synthetics.Canary(this, 'Vpc Canary', { + test: synthetics.Test.custom({ + code: synthetics.Code.fromAsset(path.join(__dirname, 'canary')), + handler: 'index.handler', + }), + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_4, + vpc, +}); +``` + +> **Note:** By default, the Synthetics runtime needs access to the S3 and CloudWatch APIs, which will fail in a private subnet without internet access enabled (e.g. an isolated subnnet). +> +> Ensure that the Canary is placed in a VPC either with internet connectivity or with VPC Endpoints for S3 and CloudWatch enabled and configured. +> +> See [Synthetics VPC docs](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_VPC.html). + ### Alarms You can configure a CloudWatch Alarm on a canary metric. Metrics are emitted by CloudWatch automatically and can be accessed by the following APIs: diff --git a/packages/@aws-cdk/aws-synthetics/lib/canary.ts b/packages/@aws-cdk/aws-synthetics/lib/canary.ts index c078fd0718ce7..717bfcbe6082d 100644 --- a/packages/@aws-cdk/aws-synthetics/lib/canary.ts +++ b/packages/@aws-cdk/aws-synthetics/lib/canary.ts @@ -1,5 +1,6 @@ import * as crypto from 'crypto'; import { Metric, MetricOptions, MetricProps } from '@aws-cdk/aws-cloudwatch'; +import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; @@ -179,12 +180,36 @@ export interface CanaryProps { * @default - No environment variables. */ readonly environmentVariables?: { [key: string]: string }; + + /** + * The VPC where this canary is run. + * + * Specify this if the canary needs to access resources in a VPC. + * + * @default - Not in VPC + */ + readonly vpc?: ec2.IVpc; + + /** + * Where to place the network interfaces within the VPC. You must provide `vpc` when using this prop. + * + * @default - the Vpc default strategy if not specified + */ + readonly vpcSubnets?: ec2.SubnetSelection; + + /** + * The list of security groups to associate with the canary's network interfaces. You must provide `vpc` when using this prop. + * + * @default - If the canary is placed within a VPC and a security group is + * not specified a dedicated security group will be created for this canary. + */ + readonly securityGroups?: ec2.ISecurityGroup[]; } /** * Define a new Canary */ -export class Canary extends cdk.Resource { +export class Canary extends cdk.Resource implements ec2.IConnectable { /** * Execution role associated with this Canary. */ @@ -213,6 +238,14 @@ export class Canary extends cdk.Resource { */ public readonly artifactsBucket: s3.IBucket; + /** + * Actual connections object for the underlying Lambda + * + * May be unset, in which case the canary Lambda is not configured for use in a VPC. + * @internal + */ + private readonly _connections?: ec2.Connections; + public constructor(scope: Construct, id: string, props: CanaryProps) { if (props.canaryName && !cdk.Token.isUnresolved(props.canaryName)) { validateName(props.canaryName); @@ -229,7 +262,12 @@ export class Canary extends cdk.Resource { enforceSSL: true, }); - this.role = props.role ?? this.createDefaultRole(props.artifactsBucketLocation?.prefix); + this.role = props.role ?? this.createDefaultRole(props); + + if (props.vpc) { + // Security Groups are created and/or appended in `createVpcConfig`. + this._connections = new ec2.Connections({}); + } const resource: CfnCanary = new CfnCanary(this, 'Resource', { artifactS3Location: this.artifactsBucket.s3UrlForObject(props.artifactsBucketLocation?.prefix), @@ -242,6 +280,7 @@ export class Canary extends cdk.Resource { successRetentionPeriod: props.successRetentionPeriod?.toDays(), code: this.createCode(props), runConfig: this.createRunConfig(props), + vpcConfig: this.createVpcConfig(props), }); this.canaryId = resource.attrId; @@ -249,6 +288,19 @@ export class Canary extends cdk.Resource { this.canaryName = this.getResourceNameAttribute(resource.ref); } + /** + * Access the Connections object + * + * Will fail if not a VPC-enabled Canary + */ + public get connections(): ec2.Connections { + if (!this._connections) { + // eslint-disable-next-line max-len + throw new Error('Only VPC-associated Canaries have security groups to manage. Supply the "vpc" parameter when creating the Canary.'); + } + return this._connections; + } + /** * Measure the Duration of a single canary run, in seconds. * @@ -289,8 +341,9 @@ export class Canary extends cdk.Resource { /** * Returns a default role for the canary */ - private createDefaultRole(prefix?: string): iam.IRole { - const { partition } = cdk.Stack.of(this); + private createDefaultRole(props: CanaryProps): iam.IRole { + const prefix = props.artifactsBucketLocation?.prefix; + // Created role will need these policies to run the Canary. // https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-synthetics-canary.html#cfn-synthetics-canary-executionrolearn const policy = new iam.PolicyDocument({ @@ -313,17 +366,34 @@ export class Canary extends cdk.Resource { conditions: { StringEquals: { 'cloudwatch:namespace': 'CloudWatchSynthetics' } }, }), new iam.PolicyStatement({ - resources: [`arn:${partition}:logs:::*`], + resources: [this.logGroupArn()], actions: ['logs:CreateLogStream', 'logs:CreateLogGroup', 'logs:PutLogEvents'], }), ], }); + const managedPolicies: iam.IManagedPolicy[] = []; + + if (props.vpc) { + // Policy that will have ENI creation permissions + managedPolicies.push(iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaVPCAccessExecutionRole')); + } + return new iam.Role(this, 'ServiceRole', { assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), inlinePolicies: { canaryPolicy: policy, }, + managedPolicies, + }); + } + + private logGroupArn() { + return cdk.Stack.of(this).formatArn({ + service: 'logs', + resource: 'log-group', + arnFormat: cdk.ArnFormat.COLON_RESOURCE_NAME, + resourceName: '/aws/lambda/cwsyn-*', }); } @@ -344,6 +414,15 @@ export class Canary extends cdk.Resource { }; } + private createRunConfig(props: CanaryProps): CfnCanary.RunConfigProperty | undefined { + if (!props.environmentVariables) { + return undefined; + } + return { + environmentVariables: props.environmentVariables, + }; + } + /** * Returns a canary schedule object */ @@ -354,12 +433,36 @@ export class Canary extends cdk.Resource { }; } - private createRunConfig(props: CanaryProps): CfnCanary.RunConfigProperty | undefined { - if (!props.environmentVariables) { + private createVpcConfig(props: CanaryProps): CfnCanary.VPCConfigProperty | undefined { + if (!props.vpc) { + if (props.vpcSubnets != null || props.securityGroups != null) { + throw new Error("You must provide the 'vpc' prop when using VPC-related properties."); + } + return undefined; } + + const { subnetIds } = props.vpc.selectSubnets(props.vpcSubnets); + if (subnetIds.length < 1) { + throw new Error('No matching subnets found in the VPC.'); + } + + let securityGroups: ec2.ISecurityGroup[]; + if (props.securityGroups && props.securityGroups.length > 0) { + securityGroups = props.securityGroups; + } else { + const securityGroup = new ec2.SecurityGroup(this, 'SecurityGroup', { + vpc: props.vpc, + description: 'Automatic security group for Canary ' + cdk.Names.uniqueId(this), + }); + securityGroups = [securityGroup]; + } + this._connections!.addSecurityGroup(...securityGroups); + return { - environmentVariables: props.environmentVariables, + vpcId: props.vpc.vpcId, + subnetIds, + securityGroupIds: cdk.Lazy.list({ produce: () => this.connections.securityGroups.map(sg => sg.securityGroupId) }), }; } diff --git a/packages/@aws-cdk/aws-synthetics/lib/runtime.ts b/packages/@aws-cdk/aws-synthetics/lib/runtime.ts index 81ac1a857e6db..10c7fb566a2e6 100644 --- a/packages/@aws-cdk/aws-synthetics/lib/runtime.ts +++ b/packages/@aws-cdk/aws-synthetics/lib/runtime.ts @@ -114,6 +114,16 @@ export class Runtime { */ public static readonly SYNTHETICS_NODEJS_PUPPETEER_3_3 = new Runtime('syn-nodejs-puppeteer-3.3', RuntimeFamily.NODEJS); + /** + * `syn-nodejs-puppeteer-3.4` includes the following: + * - Lambda runtime Node.js 12.x + * - Puppeteer-core version 5.5.0 + * - Chromium version 88.0.4298.0 + * + * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Library_nodejs_puppeteer.html#CloudWatch_Synthetics_runtimeversion-nodejs-puppeteer-3.4 + */ + public static readonly SYNTHETICS_NODEJS_PUPPETEER_3_4 = new Runtime('syn-nodejs-puppeteer-3.4', RuntimeFamily.NODEJS); + /** * `syn-python-selenium-1.0` includes the following: * - Lambda runtime Python 3.8 @@ -130,4 +140,4 @@ export class Runtime { */ public constructor(public readonly name: string, public readonly family: RuntimeFamily) { } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-synthetics/package.json b/packages/@aws-cdk/aws-synthetics/package.json index 66eb03b85dd8b..ac5406e1117eb 100644 --- a/packages/@aws-cdk/aws-synthetics/package.json +++ b/packages/@aws-cdk/aws-synthetics/package.json @@ -86,10 +86,11 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", @@ -98,6 +99,7 @@ }, "peerDependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", diff --git a/packages/@aws-cdk/aws-synthetics/test/canary.test.ts b/packages/@aws-cdk/aws-synthetics/test/canary.test.ts index 83ba173562834..aee1ba78cd134 100644 --- a/packages/@aws-cdk/aws-synthetics/test/canary.test.ts +++ b/packages/@aws-cdk/aws-synthetics/test/canary.test.ts @@ -1,4 +1,5 @@ import { Match, Template } from '@aws-cdk/assertions'; +import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import { Duration, Lazy, Stack } from '@aws-cdk/core'; @@ -440,3 +441,216 @@ test('can specify custom test', () => { }, }); }); + +describe('canary in a vpc', () => { + test('can specify vpc', () => { + // GIVEN + const stack = new Stack(); + const vpc = new ec2.Vpc(stack, 'VPC', { maxAzs: 2 }); + + // WHEN + new synthetics.Canary(stack, 'Canary', { + test: synthetics.Test.custom({ + handler: 'index.handler', + code: synthetics.Code.fromInline(` + exports.handler = async () => { + console.log(\'hello world\'); + };`), + }), + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_2_0, + vpc, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Synthetics::Canary', { + Code: { + Handler: 'index.handler', + Script: ` + exports.handler = async () => { + console.log(\'hello world\'); + };`, + }, + VPCConfig: { + VpcId: { + Ref: Match.anyValue(), + }, + }, + }); + }); + + test('default security group and subnets', () => { + // GIVEN + const stack = new Stack(); + const vpc = new ec2.Vpc(stack, 'VPC', { maxAzs: 2 }); + + // WHEN + new synthetics.Canary(stack, 'Canary', { + test: synthetics.Test.custom({ + handler: 'index.handler', + code: synthetics.Code.fromInline(` + exports.handler = async () => { + console.log(\'hello world\'); + };`), + }), + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_2_0, + vpc, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Synthetics::Canary', { + Code: { + Handler: 'index.handler', + Script: ` + exports.handler = async () => { + console.log(\'hello world\'); + };`, + }, + VPCConfig: { + VpcId: { + Ref: Match.anyValue(), + }, + SecurityGroupIds: Match.anyValue(), + SubnetIds: [...vpc.privateSubnets.map(subnet => ({ Ref: Match.stringLikeRegexp(subnet.node.id) }))], + }, + }); + }); + + test('provided security group', () => { + // GIVEN + const stack = new Stack(); + const vpc = new ec2.Vpc(stack, 'VPC', { maxAzs: 2 }); + const sg = new ec2.SecurityGroup(stack, 'Sg', { vpc }); + + // WHEN + new synthetics.Canary(stack, 'Canary', { + test: synthetics.Test.custom({ + handler: 'index.handler', + code: synthetics.Code.fromInline(` + exports.handler = async () => { + console.log(\'hello world\'); + };`), + }), + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_2_0, + vpc, + securityGroups: [sg], + }); + + // THEN + const template = Template.fromStack(stack); + const sgTemplate = template.findResources('AWS::EC2::SecurityGroup'); + const sgIds = Object.keys(sgTemplate); + + expect(sgIds).toHaveLength(1); + + template.hasResourceProperties('AWS::Synthetics::Canary', { + Code: { + Handler: 'index.handler', + Script: ` + exports.handler = async () => { + console.log(\'hello world\'); + };`, + }, + VPCConfig: { + VpcId: { + Ref: Match.anyValue(), + }, + SecurityGroupIds: [{ 'Fn::GetAtt': [sgIds[0], 'GroupId'] }], + }, + }); + }); +}); + +test('Role policy generated as expected', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new synthetics.Canary(stack, 'Canary', { + test: synthetics.Test.custom({ + handler: 'index.handler', + code: synthetics.Code.fromInline('/* Synthetics handler code */'), + }), + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_3, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { + Policies: [{ + PolicyDocument: { + Statement: [ + { + Action: 's3:ListAllMyBuckets', + Effect: 'Allow', + Resource: '*', + }, + { + Action: 's3:GetBucketLocation', + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'CanaryArtifactsBucket4A60D32B', + 'Arn', + ], + }, + }, + { + Action: 's3:PutObject', + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + { + 'Fn::GetAtt': [ + 'CanaryArtifactsBucket4A60D32B', + 'Arn', + ], + }, + '/*', + ], + ], + }, + }, + { + Action: 'cloudwatch:PutMetricData', + Condition: { + StringEquals: { + 'cloudwatch:namespace': 'CloudWatchSynthetics', + }, + }, + Effect: 'Allow', + Resource: '*', + }, + { + Action: [ + 'logs:CreateLogStream', + 'logs:CreateLogGroup', + 'logs:PutLogEvents', + ], + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':logs:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':log-group:/aws/lambda/cwsyn-*', + ], + ], + }, + }, + ], + }, + }], + }); +}); diff --git a/packages/@aws-cdk/aws-synthetics/test/integ.asset.expected.json b/packages/@aws-cdk/aws-synthetics/test/integ.asset.expected.json deleted file mode 100644 index 256de95e7be25..0000000000000 --- a/packages/@aws-cdk/aws-synthetics/test/integ.asset.expected.json +++ /dev/null @@ -1,356 +0,0 @@ -{ - "Resources": { - "MyCanaryArtifactsBucket89975E6D": { - "Type": "AWS::S3::Bucket", - "Properties": { - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "aws:kms" - } - } - ] - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "MyCanaryServiceRole593F9DD9": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "lambda.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "Policies": [ - { - "PolicyDocument": { - "Statement": [ - { - "Action": "s3:ListAllMyBuckets", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "s3:GetBucketLocation", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyCanaryArtifactsBucket89975E6D", - "Arn" - ] - } - }, - { - "Action": "s3:PutObject", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "MyCanaryArtifactsBucket89975E6D", - "Arn" - ] - }, - "/*" - ] - ] - } - }, - { - "Action": "cloudwatch:PutMetricData", - "Condition": { - "StringEquals": { - "cloudwatch:namespace": "CloudWatchSynthetics" - } - }, - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "logs:CreateLogStream", - "logs:CreateLogGroup", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": "arn:aws:logs:::*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "canaryPolicy" - } - ] - } - }, - "MyCanary1A94CAFA": { - "Type": "AWS::Synthetics::Canary", - "Properties": { - "ArtifactS3Location": { - "Fn::Join": [ - "", - [ - "s3://", - { - "Ref": "MyCanaryArtifactsBucket89975E6D" - } - ] - ] - }, - "Code": { - "Handler": "canary.handler", - "S3Bucket": { - "Ref": "AssetParameters5bf46c83158ab3b336aba1449c21b02cbac2ccea621f17d842593bb39e3e529bS3Bucket58589EB6" - }, - "S3Key": { - "Fn::Join": [ - "", - [ - { - "Fn::Select": [ - 0, - { - "Fn::Split": [ - "||", - { - "Ref": "AssetParameters5bf46c83158ab3b336aba1449c21b02cbac2ccea621f17d842593bb39e3e529bS3VersionKey8FF13E90" - } - ] - } - ] - }, - { - "Fn::Select": [ - 1, - { - "Fn::Split": [ - "||", - { - "Ref": "AssetParameters5bf46c83158ab3b336aba1449c21b02cbac2ccea621f17d842593bb39e3e529bS3VersionKey8FF13E90" - } - ] - } - ] - } - ] - ] - } - }, - "ExecutionRoleArn": { - "Fn::GetAtt": [ - "MyCanaryServiceRole593F9DD9", - "Arn" - ] - }, - "Name": "assetcanary-one", - "RuntimeVersion": "syn-nodejs-2.0", - "Schedule": { - "DurationInSeconds": "0", - "Expression": "rate(5 minutes)" - }, - "StartCanaryAfterCreation": true - } - }, - "MyCanaryTwoArtifactsBucket79B179B6": { - "Type": "AWS::S3::Bucket", - "Properties": { - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "aws:kms" - } - } - ] - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "MyCanaryTwoServiceRole041E85D4": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "lambda.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "Policies": [ - { - "PolicyDocument": { - "Statement": [ - { - "Action": "s3:ListAllMyBuckets", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "s3:GetBucketLocation", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyCanaryArtifactsBucket89975E6D", - "Arn" - ] - } - }, - { - "Action": "s3:PutObject", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "MyCanaryTwoArtifactsBucket79B179B6", - "Arn" - ] - }, - "/*" - ] - ] - } - }, - { - "Action": "cloudwatch:PutMetricData", - "Condition": { - "StringEquals": { - "cloudwatch:namespace": "CloudWatchSynthetics" - } - }, - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "logs:CreateLogStream", - "logs:CreateLogGroup", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": "arn:aws:logs:::*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "canaryPolicy" - } - ] - } - }, - "MyCanaryTwo6501D55F": { - "Type": "AWS::Synthetics::Canary", - "Properties": { - "ArtifactS3Location": { - "Fn::Join": [ - "", - [ - "s3://", - { - "Ref": "MyCanaryTwoArtifactsBucket79B179B6" - } - ] - ] - }, - "Code": { - "Handler": "canary.handler", - "S3Bucket": { - "Ref": "AssetParametersb1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820S3Bucket705C3761" - }, - "S3Key": { - "Fn::Join": [ - "", - [ - { - "Fn::Select": [ - 0, - { - "Fn::Split": [ - "||", - { - "Ref": "AssetParametersb1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820S3VersionKeyE546342B" - } - ] - } - ] - }, - { - "Fn::Select": [ - 1, - { - "Fn::Split": [ - "||", - { - "Ref": "AssetParametersb1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820S3VersionKeyE546342B" - } - ] - } - ] - } - ] - ] - } - }, - "ExecutionRoleArn": { - "Fn::GetAtt": [ - "MyCanaryTwoServiceRole041E85D4", - "Arn" - ] - }, - "Name": "assetcanary-two", - "RuntimeVersion": "syn-nodejs-2.0", - "Schedule": { - "DurationInSeconds": "0", - "Expression": "rate(5 minutes)" - }, - "StartCanaryAfterCreation": true - } - } - }, - "Parameters": { - "AssetParameters5bf46c83158ab3b336aba1449c21b02cbac2ccea621f17d842593bb39e3e529bS3Bucket58589EB6": { - "Type": "String", - "Description": "S3 bucket for asset \"5bf46c83158ab3b336aba1449c21b02cbac2ccea621f17d842593bb39e3e529b\"" - }, - "AssetParameters5bf46c83158ab3b336aba1449c21b02cbac2ccea621f17d842593bb39e3e529bS3VersionKey8FF13E90": { - "Type": "String", - "Description": "S3 key for asset version \"5bf46c83158ab3b336aba1449c21b02cbac2ccea621f17d842593bb39e3e529b\"" - }, - "AssetParameters5bf46c83158ab3b336aba1449c21b02cbac2ccea621f17d842593bb39e3e529bArtifactHash74DCED3D": { - "Type": "String", - "Description": "Artifact hash for asset \"5bf46c83158ab3b336aba1449c21b02cbac2ccea621f17d842593bb39e3e529b\"" - }, - "AssetParametersb1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820S3Bucket705C3761": { - "Type": "String", - "Description": "S3 bucket for asset \"b1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820\"" - }, - "AssetParametersb1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820S3VersionKeyE546342B": { - "Type": "String", - "Description": "S3 key for asset version \"b1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820\"" - }, - "AssetParametersb1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820ArtifactHash536FDCC3": { - "Type": "String", - "Description": "Artifact hash for asset \"b1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820\"" - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-synthetics/test/integ.canary.expected.json b/packages/@aws-cdk/aws-synthetics/test/integ.canary.expected.json index 2425fad01de67..9667f7720b948 100644 --- a/packages/@aws-cdk/aws-synthetics/test/integ.canary.expected.json +++ b/packages/@aws-cdk/aws-synthetics/test/integ.canary.expected.json @@ -69,8 +69,8 @@ }, { "Action": [ - "logs:CreateLogStream", "logs:CreateLogGroup", + "logs:CreateLogStream", "logs:PutLogEvents" ], "Effect": "Allow", @@ -82,7 +82,15 @@ { "Ref": "AWS::Partition" }, - ":logs:::*" + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/cwsyn-*" ] ] } @@ -256,8 +264,8 @@ }, { "Action": [ - "logs:CreateLogStream", "logs:CreateLogGroup", + "logs:CreateLogStream", "logs:PutLogEvents" ], "Effect": "Allow", @@ -269,7 +277,15 @@ { "Ref": "AWS::Partition" }, - ":logs:::*" + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/cwsyn-*" ] ] } @@ -477,8 +493,8 @@ }, { "Action": [ - "logs:CreateLogStream", "logs:CreateLogGroup", + "logs:CreateLogStream", "logs:PutLogEvents" ], "Effect": "Allow", @@ -490,7 +506,15 @@ { "Ref": "AWS::Partition" }, - ":logs:::*" + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/cwsyn-*" ] ] } @@ -698,8 +722,8 @@ }, { "Action": [ - "logs:CreateLogStream", "logs:CreateLogGroup", + "logs:CreateLogStream", "logs:PutLogEvents" ], "Effect": "Allow", @@ -711,7 +735,15 @@ { "Ref": "AWS::Partition" }, - ":logs:::*" + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/cwsyn-*" ] ] } @@ -919,8 +951,8 @@ }, { "Action": [ - "logs:CreateLogStream", "logs:CreateLogGroup", + "logs:CreateLogStream", "logs:PutLogEvents" ], "Effect": "Allow", @@ -932,7 +964,15 @@ { "Ref": "AWS::Partition" }, - ":logs:::*" + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/cwsyn-*" ] ] } diff --git a/packages/@aws-cdk/aws-synthetics/test/integ.vpc.expected.json b/packages/@aws-cdk/aws-synthetics/test/integ.vpc.expected.json new file mode 100644 index 0000000000000..ca373b57bae03 --- /dev/null +++ b/packages/@aws-cdk/aws-synthetics/test/integ.vpc.expected.json @@ -0,0 +1,653 @@ +{ + "Resources": { + "MyVpcF9F0CA6F": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "canary-vpc/MyVpc" + } + ] + } + }, + "MyVpcPublicSubnet1SubnetF6608456": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "MyVpcF9F0CA6F" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "canary-vpc/MyVpc/PublicSubnet1" + } + ] + } + }, + "MyVpcPublicSubnet1RouteTableC46AB2F4": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "MyVpcF9F0CA6F" + }, + "Tags": [ + { + "Key": "Name", + "Value": "canary-vpc/MyVpc/PublicSubnet1" + } + ] + } + }, + "MyVpcPublicSubnet1RouteTableAssociation2ECEE1CB": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "MyVpcPublicSubnet1RouteTableC46AB2F4" + }, + "SubnetId": { + "Ref": "MyVpcPublicSubnet1SubnetF6608456" + } + } + }, + "MyVpcPublicSubnet1DefaultRoute95FDF9EB": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "MyVpcPublicSubnet1RouteTableC46AB2F4" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "MyVpcIGW5C4A4F63" + } + }, + "DependsOn": [ + "MyVpcVPCGW488ACE0D" + ] + }, + "MyVpcPublicSubnet1EIP096967CB": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "canary-vpc/MyVpc/PublicSubnet1" + } + ] + } + }, + "MyVpcPublicSubnet1NATGatewayAD3400C1": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "MyVpcPublicSubnet1SubnetF6608456" + }, + "AllocationId": { + "Fn::GetAtt": [ + "MyVpcPublicSubnet1EIP096967CB", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "canary-vpc/MyVpc/PublicSubnet1" + } + ] + } + }, + "MyVpcPublicSubnet2Subnet492B6BFB": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "MyVpcF9F0CA6F" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "canary-vpc/MyVpc/PublicSubnet2" + } + ] + } + }, + "MyVpcPublicSubnet2RouteTable1DF17386": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "MyVpcF9F0CA6F" + }, + "Tags": [ + { + "Key": "Name", + "Value": "canary-vpc/MyVpc/PublicSubnet2" + } + ] + } + }, + "MyVpcPublicSubnet2RouteTableAssociation227DE78D": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "MyVpcPublicSubnet2RouteTable1DF17386" + }, + "SubnetId": { + "Ref": "MyVpcPublicSubnet2Subnet492B6BFB" + } + } + }, + "MyVpcPublicSubnet2DefaultRoute052936F6": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "MyVpcPublicSubnet2RouteTable1DF17386" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "MyVpcIGW5C4A4F63" + } + }, + "DependsOn": [ + "MyVpcVPCGW488ACE0D" + ] + }, + "MyVpcPublicSubnet2EIP8CCBA239": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "canary-vpc/MyVpc/PublicSubnet2" + } + ] + } + }, + "MyVpcPublicSubnet2NATGateway91BFBEC9": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "MyVpcPublicSubnet2Subnet492B6BFB" + }, + "AllocationId": { + "Fn::GetAtt": [ + "MyVpcPublicSubnet2EIP8CCBA239", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "canary-vpc/MyVpc/PublicSubnet2" + } + ] + } + }, + "MyVpcPrivateSubnet1Subnet5057CF7E": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "MyVpcF9F0CA6F" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "canary-vpc/MyVpc/PrivateSubnet1" + } + ] + } + }, + "MyVpcPrivateSubnet1RouteTable8819E6E2": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "MyVpcF9F0CA6F" + }, + "Tags": [ + { + "Key": "Name", + "Value": "canary-vpc/MyVpc/PrivateSubnet1" + } + ] + } + }, + "MyVpcPrivateSubnet1RouteTableAssociation56D38C7E": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "MyVpcPrivateSubnet1RouteTable8819E6E2" + }, + "SubnetId": { + "Ref": "MyVpcPrivateSubnet1Subnet5057CF7E" + } + } + }, + "MyVpcPrivateSubnet1DefaultRouteA8CDE2FA": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "MyVpcPrivateSubnet1RouteTable8819E6E2" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "MyVpcPublicSubnet1NATGatewayAD3400C1" + } + } + }, + "MyVpcPrivateSubnet2Subnet0040C983": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "MyVpcF9F0CA6F" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "canary-vpc/MyVpc/PrivateSubnet2" + } + ] + } + }, + "MyVpcPrivateSubnet2RouteTableCEDCEECE": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "MyVpcF9F0CA6F" + }, + "Tags": [ + { + "Key": "Name", + "Value": "canary-vpc/MyVpc/PrivateSubnet2" + } + ] + } + }, + "MyVpcPrivateSubnet2RouteTableAssociation86A610DA": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "MyVpcPrivateSubnet2RouteTableCEDCEECE" + }, + "SubnetId": { + "Ref": "MyVpcPrivateSubnet2Subnet0040C983" + } + } + }, + "MyVpcPrivateSubnet2DefaultRoute9CE96294": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "MyVpcPrivateSubnet2RouteTableCEDCEECE" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "MyVpcPublicSubnet2NATGateway91BFBEC9" + } + } + }, + "MyVpcIGW5C4A4F63": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "canary-vpc/MyVpc" + } + ] + } + }, + "MyVpcVPCGW488ACE0D": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "MyVpcF9F0CA6F" + }, + "InternetGatewayId": { + "Ref": "MyVpcIGW5C4A4F63" + } + } + }, + "MyVpcCanaryArtifactsBucketDC69853C": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "aws:kms" + } + } + ] + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "MyVpcCanaryArtifactsBucketPolicy27806F2C": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "MyVpcCanaryArtifactsBucketDC69853C" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "MyVpcCanaryArtifactsBucketDC69853C", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "MyVpcCanaryArtifactsBucketDC69853C", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "MyVpcCanaryServiceRole2B1BBDE8": { + "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/AWSLambdaVPCAccessExecutionRole" + ] + ] + } + ], + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:ListAllMyBuckets", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "s3:GetBucketLocation", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyVpcCanaryArtifactsBucketDC69853C", + "Arn" + ] + } + }, + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "MyVpcCanaryArtifactsBucketDC69853C", + "Arn" + ] + }, + "/*" + ] + ] + } + }, + { + "Action": "cloudwatch:PutMetricData", + "Condition": { + "StringEquals": { + "cloudwatch:namespace": "CloudWatchSynthetics" + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/cwsyn-*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "canaryPolicy" + } + ] + } + }, + "MyVpcCanarySecurityGroupEA9564AA": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Automatic security group for Canary canaryvpcMyVpcCanaryDEF63B1A", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "MyVpcF9F0CA6F" + } + } + }, + "MyVpcCanary8C70C179": { + "Type": "AWS::Synthetics::Canary", + "Properties": { + "ArtifactS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Ref": "MyVpcCanaryArtifactsBucketDC69853C" + } + ] + ] + }, + "Code": { + "Handler": "canary.handler", + "S3Bucket": { + "Ref": "AssetParametersb1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820S3Bucket705C3761" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersb1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820S3VersionKeyE546342B" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersb1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820S3VersionKeyE546342B" + } + ] + } + ] + } + ] + ] + } + }, + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "MyVpcCanaryServiceRole2B1BBDE8", + "Arn" + ] + }, + "Name": "canary-vpc", + "RuntimeVersion": "syn-nodejs-puppeteer-3.3", + "Schedule": { + "DurationInSeconds": "0", + "Expression": "rate(5 minutes)" + }, + "StartCanaryAfterCreation": true, + "VPCConfig": { + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "MyVpcCanarySecurityGroupEA9564AA", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "MyVpcPrivateSubnet1Subnet5057CF7E" + }, + { + "Ref": "MyVpcPrivateSubnet2Subnet0040C983" + } + ], + "VpcId": { + "Ref": "MyVpcF9F0CA6F" + } + } + } + } + }, + "Parameters": { + "AssetParametersb1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820S3Bucket705C3761": { + "Type": "String", + "Description": "S3 bucket for asset \"b1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820\"" + }, + "AssetParametersb1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820S3VersionKeyE546342B": { + "Type": "String", + "Description": "S3 key for asset version \"b1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820\"" + }, + "AssetParametersb1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820ArtifactHash536FDCC3": { + "Type": "String", + "Description": "Artifact hash for asset \"b1b777dcb79a2fa2790059927207d10bf5f4747d6dd1516e2780726d9d6fa820\"" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-synthetics/test/integ.vpc.ts b/packages/@aws-cdk/aws-synthetics/test/integ.vpc.ts new file mode 100644 index 0000000000000..e31f75817e68b --- /dev/null +++ b/packages/@aws-cdk/aws-synthetics/test/integ.vpc.ts @@ -0,0 +1,29 @@ +/// !cdk-integ canary-vpc + +import * as path from 'path'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import * as synthetics from '../lib'; + +/* + * Stack verification steps: + * + * -- aws synthetics get-canary --name canary-vpc has state of 'RUNNING' + * -- aws synthetics get-canary --name canary-vpc has VpcId + */ +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'canary-vpc'); + +const vpc = new ec2.Vpc(stack, 'MyVpc', { maxAzs: 2 }); + +new synthetics.Canary(stack, 'MyVpcCanary', { + canaryName: 'canary-vpc', + test: synthetics.Test.custom({ + handler: 'canary.handler', + code: synthetics.Code.fromAsset(path.join(__dirname, 'canary.zip')), + }), + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_3, + vpc, +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-timestream/package.json b/packages/@aws-cdk/aws-timestream/package.json index 35305de3ba407..d630d3f2f818f 100644 --- a/packages/@aws-cdk/aws-timestream/package.json +++ b/packages/@aws-cdk/aws-timestream/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-transfer/package.json b/packages/@aws-cdk/aws-transfer/package.json index 5c6fefa69391a..efeddaba3fff8 100644 --- a/packages/@aws-cdk/aws-transfer/package.json +++ b/packages/@aws-cdk/aws-transfer/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-waf/package.json b/packages/@aws-cdk/aws-waf/package.json index 8aaf46f4b625f..20c6e3c1a8896 100644 --- a/packages/@aws-cdk/aws-waf/package.json +++ b/packages/@aws-cdk/aws-waf/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-wafregional/package.json b/packages/@aws-cdk/aws-wafregional/package.json index 485d9962f8424..aa4997b25435f 100644 --- a/packages/@aws-cdk/aws-wafregional/package.json +++ b/packages/@aws-cdk/aws-wafregional/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-wafv2/package.json b/packages/@aws-cdk/aws-wafv2/package.json index 331e6229ca89b..3f6fa8ac9d3ff 100644 --- a/packages/@aws-cdk/aws-wafv2/package.json +++ b/packages/@aws-cdk/aws-wafv2/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-wisdom/package.json b/packages/@aws-cdk/aws-wisdom/package.json index 376daf9bdaaa8..f641345d8e7ea 100644 --- a/packages/@aws-cdk/aws-wisdom/package.json +++ b/packages/@aws-cdk/aws-wisdom/package.json @@ -88,7 +88,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-workspaces/package.json b/packages/@aws-cdk/aws-workspaces/package.json index 95758a0601e75..8f0da7bbbfc03 100644 --- a/packages/@aws-cdk/aws-workspaces/package.json +++ b/packages/@aws-cdk/aws-workspaces/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-xray/package.json b/packages/@aws-cdk/aws-xray/package.json index b41a6bb35eb27..83f4d9e17dfed 100644 --- a/packages/@aws-cdk/aws-xray/package.json +++ b/packages/@aws-cdk/aws-xray/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0" + "@types/jest": "^27.4.1" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/cdk-assets-schema/package.json b/packages/@aws-cdk/cdk-assets-schema/package.json index 682764dae229f..abec52ee08000 100644 --- a/packages/@aws-cdk/cdk-assets-schema/package.json +++ b/packages/@aws-cdk/cdk-assets-schema/package.json @@ -61,8 +61,8 @@ "devDependencies": { "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", diff --git a/packages/@aws-cdk/cfnspec/CHANGELOG.md b/packages/@aws-cdk/cfnspec/CHANGELOG.md index ea8486a5cc0d5..6fd6a19ec06f5 100644 --- a/packages/@aws-cdk/cfnspec/CHANGELOG.md +++ b/packages/@aws-cdk/cfnspec/CHANGELOG.md @@ -1,3 +1,722 @@ +# CloudFormation Resource Specification v62.0.0 + +## New Resource Types + +* AWS::FSx::Snapshot +* AWS::FSx::StorageVirtualMachine +* AWS::FSx::Volume +* AWS::IoTEvents::AlarmModel + +## Attribute Changes + + +## Property Changes + +* AWS::DocDB::DBInstance EnablePerformanceInsights (__added__) +* AWS::Lambda::Function EphemeralStorage (__added__) +* AWS::Lambda::Permission PrincipalOrgID (__added__) +* AWS::Lex::Bot TestBotAliasSettings (__added__) + +## Property Type Changes + +* AWS::DevOpsGuru::ResourceCollection.TagCollection (__added__) +* AWS::EC2::LaunchTemplate.Ipv4PrefixSpecification (__added__) +* AWS::EC2::LaunchTemplate.Ipv6PrefixSpecification (__added__) +* AWS::Lambda::Function.EphemeralStorage (__added__) +* AWS::Lex::Bot.AdvancedRecognitionSetting (__added__) +* AWS::Lex::Bot.AudioLogDestination (__added__) +* AWS::Lex::Bot.AudioLogSetting (__added__) +* AWS::Lex::Bot.BotAliasLocaleSettings (__added__) +* AWS::Lex::Bot.BotAliasLocaleSettingsItem (__added__) +* AWS::Lex::Bot.CloudWatchLogGroupLogDestination (__added__) +* AWS::Lex::Bot.CodeHookSpecification (__added__) +* AWS::Lex::Bot.ConversationLogSettings (__added__) +* AWS::Lex::Bot.CustomVocabulary (__added__) +* AWS::Lex::Bot.CustomVocabularyItem (__added__) +* AWS::Lex::Bot.LambdaCodeHook (__added__) +* AWS::Lex::Bot.S3BucketLogDestination (__added__) +* AWS::Lex::Bot.TestBotAliasSettings (__added__) +* AWS::Lex::Bot.TextLogDestination (__added__) +* AWS::Lex::Bot.TextLogSetting (__added__) +* AWS::MediaPackage::OriginEndpoint.EncryptionContractConfiguration (__added__) +* AWS::DevOpsGuru::ResourceCollection.ResourceCollectionFilter Tags (__added__) +* AWS::EC2::LaunchTemplate.NetworkInterface Ipv4PrefixCount (__added__) +* AWS::EC2::LaunchTemplate.NetworkInterface Ipv4Prefixes (__added__) +* AWS::EC2::LaunchTemplate.NetworkInterface Ipv6PrefixCount (__added__) +* AWS::EC2::LaunchTemplate.NetworkInterface Ipv6Prefixes (__added__) +* AWS::Lex::Bot.BotLocale CustomVocabulary (__added__) +* AWS::Lex::Bot.SlotValueSelectionSetting AdvancedRecognitionSetting (__added__) +* AWS::MediaPackage::OriginEndpoint.SpekeKeyProvider EncryptionContractConfiguration (__added__) + + +# CloudFormation Resource Specification v61.0.0 + +## New Resource Types + +* AWS::BillingConductor::BillingGroup +* AWS::BillingConductor::CustomLineItem +* AWS::BillingConductor::PricingPlan +* AWS::BillingConductor::PricingRule + +## Attribute Changes + +* AWS::DMS::ReplicationInstance ReplicationInstancePrivateIpAddresses.PrimitiveItemType (__deleted__) +* AWS::DMS::ReplicationInstance ReplicationInstancePrivateIpAddresses.Type (__deleted__) +* AWS::DMS::ReplicationInstance ReplicationInstancePrivateIpAddresses.PrimitiveType (__added__) +* AWS::DMS::ReplicationInstance ReplicationInstancePublicIpAddresses.PrimitiveItemType (__deleted__) +* AWS::DMS::ReplicationInstance ReplicationInstancePublicIpAddresses.Type (__deleted__) +* AWS::DMS::ReplicationInstance ReplicationInstancePublicIpAddresses.PrimitiveType (__added__) +* AWS::EC2::Subnet Id (__deleted__) +* AWS::EC2::Subnet SubnetId (__added__) + +## Property Changes + +* AWS::CodeDeploy::DeploymentGroup OutdatedInstancesStrategy (__added__) +* AWS::CodeDeploy::DeploymentGroup Tags (__added__) +* AWS::DMS::Endpoint Tags.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::DMS::ReplicationSubnetGroup Tags.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::EC2::Subnet AvailabilityZoneId (__added__) +* AWS::EC2::Subnet EnableDns64 (__added__) +* AWS::EC2::Subnet Ipv6Native (__added__) +* AWS::EC2::Subnet PrivateDnsNameOptionsOnLaunch (__added__) +* AWS::EC2::Subnet CidrBlock.Required (__changed__) + * Old: true + * New: false +* AWS::Inspector::AssessmentTemplate RulesPackageArns.DuplicatesAllowed (__added__) +* AWS::Inspector::AssessmentTemplate UserAttributesForFindings.DuplicatesAllowed (__added__) +* AWS::Inspector::ResourceGroup ResourceGroupTags.DuplicatesAllowed (__added__) + +## Property Type Changes + +* AWS::ACMPCA::Certificate.CustomAttribute (__added__) +* AWS::ACMPCA::Certificate.CustomExtension (__added__) +* AWS::ACMPCA::CertificateAuthority.CustomAttribute (__added__) +* AWS::CodeDeploy::DeploymentGroup.TargetGroupPairInfo (__added__) +* AWS::CodeDeploy::DeploymentGroup.TrafficRoute (__added__) +* AWS::ACMPCA::Certificate.Extensions CustomExtensions (__added__) +* AWS::ACMPCA::Certificate.Subject CustomAttributes (__added__) +* AWS::ACMPCA::CertificateAuthority.Subject CustomAttributes (__added__) +* AWS::CodeDeploy::DeploymentGroup.LoadBalancerInfo TargetGroupPairInfoList (__added__) +* AWS::FSx::FileSystem.OpenZFSConfiguration Options (__added__) +* AWS::FSx::FileSystem.RootVolumeConfiguration RecordSizeKiB (__added__) + + +# CloudFormation Resource Specification v60.0.0 + +## New Resource Types + +* AWS::Personalize::Dataset +* AWS::Personalize::DatasetGroup +* AWS::Personalize::Schema +* AWS::Personalize::Solution + +## Attribute Changes + +* AWS::EC2::Subnet Id (__added__) +* AWS::EC2::Subnet Ipv6CidrBlocks.DuplicatesAllowed (__added__) + +## Property Changes + +* AWS::EC2::Subnet AvailabilityZoneId (__deleted__) +* AWS::EC2::Subnet EnableDns64 (__deleted__) +* AWS::EC2::Subnet Ipv6Native (__deleted__) +* AWS::EC2::Subnet PrivateDnsNameOptionsOnLaunch (__deleted__) +* AWS::EC2::Subnet Ipv6CidrBlock.UpdateType (__changed__) + * Old: Conditional + * New: Mutable +* AWS::EC2::Subnet VpcId.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html#cfn-awsec2subnet-prop-vpcid + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html#cfn-ec2-subnet-vpcid +* AWS::EC2::TransitGatewayPeeringAttachment Options (__deleted__) +* AWS::ECS::Service EnableECSManagedTags.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::ECS::Service LoadBalancers.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::ECS::Service PropagateTags.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::ECS::Service ServiceRegistries.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::FIS::ExperimentTemplate LogConfiguration (__added__) + +## Property Type Changes + +* AWS::EC2::Subnet.PrivateDnsNameOptionsOnLaunch (__removed__) +* AWS::EC2::TransitGatewayPeeringAttachment.TransitGatewayPeeringAttachmentOptions (__removed__) +* AWS::AppFlow::Flow.MarketoDestinationProperties (__added__) +* AWS::AutoScaling::ScalingPolicy.Metric (__added__) +* AWS::AutoScaling::ScalingPolicy.MetricDataQuery (__added__) +* AWS::AutoScaling::ScalingPolicy.MetricStat (__added__) +* AWS::AutoScaling::ScalingPolicy.PredictiveScalingCustomizedCapacityMetric (__added__) +* AWS::AutoScaling::ScalingPolicy.PredictiveScalingCustomizedLoadMetric (__added__) +* AWS::AutoScaling::ScalingPolicy.PredictiveScalingCustomizedScalingMetric (__added__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateLogConfiguration (__added__) +* AWS::AppFlow::Flow.DestinationConnectorProperties Marketo (__added__) +* AWS::AutoScaling::ScalingPolicy.PredictiveScalingMetricSpecification CustomizedCapacityMetricSpecification (__added__) +* AWS::AutoScaling::ScalingPolicy.PredictiveScalingMetricSpecification CustomizedLoadMetricSpecification (__added__) +* AWS::AutoScaling::ScalingPolicy.PredictiveScalingMetricSpecification CustomizedScalingMetricSpecification (__added__) +* AWS::ECS::Service.LoadBalancer ContainerName.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::ECS::Service.LoadBalancer ContainerPort.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::ECS::Service.LoadBalancer LoadBalancerName.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::ECS::Service.LoadBalancer TargetGroupArn.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::ECS::Service.ServiceRegistry ContainerName.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::ECS::Service.ServiceRegistry ContainerPort.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::ECS::Service.ServiceRegistry Port.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::ECS::Service.ServiceRegistry RegistryArn.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::FIS::ExperimentTemplate.ExperimentTemplateTarget Parameters (__added__) +* AWS::Lex::BotAlias.AudioLogDestination S3Bucket.Required (__changed__) + * Old: false + * New: true +* AWS::Lex::BotAlias.TextLogDestination CloudWatch.Required (__changed__) + * Old: false + * New: true +* AWS::Lex::BotAlias.TextLogSetting Destination.Required (__changed__) + * Old: false + * New: true +* AWS::Lex::BotAlias.TextLogSetting Enabled.Required (__changed__) + * Old: false + * New: true + + +# CloudFormation Resource Specification v59.0.0 + +## New Resource Types + +* AWS::EKS::IdentityProviderConfig +* AWS::MSK::BatchScramSecret +* AWS::MSK::Configuration + +## Attribute Changes + +* AWS::ImageBuilder::Image ImageUri (__added__) +* AWS::MSK::Cluster Arn (__added__) + +## Property Changes + +* AWS::AmplifyUIBuilder::Component SchemaVersion (__added__) +* AWS::ApiGateway::BasePathMapping Id (__added__) +* AWS::EC2::TransitGatewayVpcAttachment SubnetIds.Required (__changed__) + * Old: false + * New: true +* AWS::EC2::TransitGatewayVpcAttachment TransitGatewayId.Required (__changed__) + * Old: false + * New: true +* AWS::EC2::TransitGatewayVpcAttachment VpcId.Required (__changed__) + * Old: false + * New: true +* AWS::ImageBuilder::Image ContainerRecipeArn.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::MSK::Cluster CurrentVersion (__added__) +* AWS::MSK::Cluster Tags.PrimitiveType (__deleted__) +* AWS::MSK::Cluster Tags.PrimitiveItemType (__added__) +* AWS::MSK::Cluster Tags.Type (__added__) + +## Property Type Changes + +* AWS::DataBrew::Job.Output MaxOutputFiles (__added__) +* AWS::MSK::Cluster.BrokerNodeGroupInfo ClientSubnets.DuplicatesAllowed (__added__) +* AWS::MSK::Cluster.BrokerNodeGroupInfo SecurityGroups.DuplicatesAllowed (__added__) +* AWS::MSK::Cluster.Tls CertificateAuthorityArnList.DuplicatesAllowed (__added__) + + +# CloudFormation Resource Specification v58.0.0 + +## New Resource Types + +* AWS::AppIntegrations::DataIntegration +* AWS::DataSync::LocationFSxLustre + +## Attribute Changes + +* AWS::AmplifyUIBuilder::Component CreatedAt (__deleted__) +* AWS::AmplifyUIBuilder::Component ModifiedAt (__deleted__) + +## Property Changes + +* AWS::AmplifyUIBuilder::Component Events (__added__) +* AWS::AmplifyUIBuilder::Component BindingProperties.Required (__changed__) + * Old: false + * New: true +* AWS::AmplifyUIBuilder::Component ComponentType.Required (__changed__) + * Old: false + * New: true +* AWS::AmplifyUIBuilder::Component Name.Required (__changed__) + * Old: false + * New: true +* AWS::AmplifyUIBuilder::Component Overrides.Required (__changed__) + * Old: false + * New: true +* AWS::AmplifyUIBuilder::Component Properties.Required (__changed__) + * Old: false + * New: true +* AWS::AmplifyUIBuilder::Component Variants.Required (__changed__) + * Old: false + * New: true +* AWS::Events::Connection AuthParameters.PrimitiveType (__deleted__) +* AWS::Events::Connection AuthParameters.Type (__added__) +* AWS::Transfer::Server PostAuthenticationLoginBanner (__added__) +* AWS::Transfer::Server PreAuthenticationLoginBanner (__added__) + +## Property Type Changes + +* AWS::AmplifyUIBuilder::Component.ActionParameters (__added__) +* AWS::AmplifyUIBuilder::Component.ComponentEvent (__added__) +* AWS::AmplifyUIBuilder::Component.ComponentEvents (__added__) +* AWS::AmplifyUIBuilder::Component.MutationActionSetStateParameter (__added__) +* AWS::AppFlow::Flow.SAPODataDestinationProperties (__added__) +* AWS::AppFlow::Flow.SuccessResponseHandlingConfig (__added__) +* AWS::AppMesh::Mesh.MeshServiceDiscovery (__added__) +* AWS::Events::Connection.ApiKeyAuthParameters (__added__) +* AWS::Events::Connection.AuthParameters (__added__) +* AWS::Events::Connection.BasicAuthParameters (__added__) +* AWS::Events::Connection.ClientParameters (__added__) +* AWS::Events::Connection.ConnectionHttpParameters (__added__) +* AWS::Events::Connection.OAuthParameters (__added__) +* AWS::Events::Connection.Parameter (__added__) +* AWS::AmplifyUIBuilder::Component.ComponentChild Events (__added__) +* AWS::AmplifyUIBuilder::Component.ComponentConditionProperty OperandType (__added__) +* AWS::AmplifyUIBuilder::Component.ComponentProperty ComponentName (__added__) +* AWS::AmplifyUIBuilder::Component.ComponentProperty Property (__added__) +* AWS::AppFlow::Flow.DestinationConnectorProperties SAPOData (__added__) + + +# CloudFormation Resource Specification v57.0.0 + +## New Resource Types + +* AWS::ECR::PullThroughCacheRule + +## Attribute Changes + +* AWS::Batch::ComputeEnvironment ComputeEnvironmentArn (__added__) +* AWS::Batch::JobQueue JobQueueArn (__added__) +* AWS::SES::ConfigurationSetEventDestination Id (__added__) + +## Property Changes + +* AWS::Batch::ComputeEnvironment Tags.PrimitiveType (__deleted__) +* AWS::Batch::ComputeEnvironment Tags.PrimitiveItemType (__added__) +* AWS::Batch::ComputeEnvironment Tags.Type (__added__) +* AWS::Batch::JobQueue ComputeEnvironmentOrder.DuplicatesAllowed (__added__) +* AWS::Batch::JobQueue Tags.PrimitiveType (__deleted__) +* AWS::Batch::JobQueue Tags.PrimitiveItemType (__added__) +* AWS::Batch::JobQueue Tags.Type (__added__) +* AWS::DocDB::DBCluster MasterUserPassword.Required (__changed__) + * Old: true + * New: false +* AWS::DocDB::DBCluster MasterUsername.Required (__changed__) + * Old: true + * New: false +* AWS::EC2::Instance PrivateDnsNameOptions (__added__) +* AWS::IoT::Authorizer EnableCachingForHttp (__added__) +* AWS::Kendra::DataSource CustomDocumentEnrichmentConfiguration (__added__) +* AWS::Lambda::EventSourceMapping FilterCriteria.PrimitiveType (__deleted__) +* AWS::Lambda::EventSourceMapping FilterCriteria.Type (__added__) +* AWS::Lambda::EventSourceMapping StartingPositionTimestamp.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::StepFunctions::StateMachine StateMachineType.UpdateType (__changed__) + * Old: Mutable + * New: Immutable + +## Property Type Changes + +* AWS::EC2::Instance.PrivateDnsNameOptions (__added__) +* AWS::Kendra::DataSource.CustomDocumentEnrichmentConfiguration (__added__) +* AWS::Kendra::DataSource.DocumentAttributeCondition (__added__) +* AWS::Kendra::DataSource.DocumentAttributeTarget (__added__) +* AWS::Kendra::DataSource.DocumentAttributeValue (__added__) +* AWS::Kendra::DataSource.HookConfiguration (__added__) +* AWS::Kendra::DataSource.InlineCustomDocumentEnrichmentConfiguration (__added__) +* AWS::Lambda::EventSourceMapping.Filter (__added__) +* AWS::Lambda::EventSourceMapping.FilterCriteria (__added__) +* AWS::WAFv2::WebACL.FieldIdentifier (__added__) +* AWS::WAFv2::WebACL.ManagedRuleGroupConfig (__added__) +* AWS::Batch::ComputeEnvironment.ComputeResources Ec2Configuration.DuplicatesAllowed (__added__) +* AWS::Batch::ComputeEnvironment.ComputeResources InstanceTypes.DuplicatesAllowed (__added__) +* AWS::Batch::ComputeEnvironment.ComputeResources SecurityGroupIds.DuplicatesAllowed (__added__) +* AWS::Batch::ComputeEnvironment.ComputeResources Subnets.DuplicatesAllowed (__added__) +* AWS::Batch::ComputeEnvironment.ComputeResources Tags.PrimitiveType (__deleted__) +* AWS::Batch::ComputeEnvironment.ComputeResources Tags.PrimitiveItemType (__added__) +* AWS::Batch::ComputeEnvironment.ComputeResources Tags.Type (__added__) +* AWS::EC2::SpotFleet.LaunchTemplateOverrides Priority (__added__) +* AWS::IoTAnalytics::Dataset.RetentionPeriod NumberOfDays.Required (__changed__) + * Old: true + * New: false +* AWS::IoTAnalytics::Dataset.RetentionPeriod Unlimited.Required (__changed__) + * Old: true + * New: false +* AWS::NetworkFirewall::FirewallPolicy.FirewallPolicy StatefulDefaultActions.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::FirewallPolicy.FirewallPolicy StatefulRuleGroupReferences.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::FirewallPolicy.FirewallPolicy StatelessCustomActions.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::FirewallPolicy.FirewallPolicy StatelessDefaultActions.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::FirewallPolicy.FirewallPolicy StatelessFragmentDefaultActions.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::FirewallPolicy.FirewallPolicy StatelessRuleGroupReferences.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::FirewallPolicy.PublishMetricAction Dimensions.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.IPSet Definition.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.MatchAttributes DestinationPorts.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.MatchAttributes Destinations.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.MatchAttributes Protocols.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.MatchAttributes SourcePorts.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.MatchAttributes Sources.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.MatchAttributes TCPFlags.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.PortSet Definition.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.PublishMetricAction Dimensions.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.RuleDefinition Actions.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.RuleOption Settings.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.RulesSource StatefulRules.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.RulesSourceList TargetTypes.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.RulesSourceList Targets.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.StatefulRule RuleOptions.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.StatelessRulesAndCustomActions CustomActions.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.StatelessRulesAndCustomActions StatelessRules.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.TCPFlagField Flags.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::RuleGroup.TCPFlagField Masks.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::SES::ConfigurationSetEventDestination.CloudWatchDestination DimensionConfigurations.DuplicatesAllowed (__added__) +* AWS::SES::ConfigurationSetEventDestination.EventDestination MatchingEventTypes.DuplicatesAllowed (__added__) +* AWS::WAFv2::WebACL.ManagedRuleGroupStatement ManagedRuleGroupConfigs (__added__) + +## Unapplied changes + +* AWS::AppIntegrations is at 53.1.0 + +# CloudFormation Resource Specification v56.0.0 + +## New Resource Types + +* AWS::AppRunner::VpcConnector +* AWS::CloudFormation::HookDefaultVersion +* AWS::CloudFormation::HookTypeConfig +* AWS::CloudFormation::HookVersion + +## Attribute Changes + +* AWS::AutoScaling::LaunchConfiguration Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html +* AWS::EKS::Nodegroup Id (__added__) +* AWS::SES::Template Id (__added__) +* AWS::SQS::Queue QueueUrl (__added__) +* AWS::SQS::Queue Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html + +## Property Changes + +* AWS::AppRunner::Service NetworkConfiguration (__added__) +* AWS::AutoScaling::LaunchConfiguration AssociatePublicIpAddress.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cf-as-launchconfig-associatepubip + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-associatepublicipaddress +* AWS::AutoScaling::LaunchConfiguration BlockDeviceMappings.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-blockdevicemappings + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-blockdevicemappings +* AWS::AutoScaling::LaunchConfiguration ClassicLinkVPCId.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-classiclinkvpcid + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-classiclinkvpcid +* AWS::AutoScaling::LaunchConfiguration ClassicLinkVPCSecurityGroups.DuplicatesAllowed (__deleted__) +* AWS::AutoScaling::LaunchConfiguration ClassicLinkVPCSecurityGroups.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-classiclinkvpcsecuritygroups + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-classiclinkvpcsecuritygroups +* AWS::AutoScaling::LaunchConfiguration EbsOptimized.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-ebsoptimized + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-ebsoptimized +* AWS::AutoScaling::LaunchConfiguration IamInstanceProfile.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-iaminstanceprofile + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-iaminstanceprofile +* AWS::AutoScaling::LaunchConfiguration ImageId.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-imageid + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-imageid +* AWS::AutoScaling::LaunchConfiguration InstanceId.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-instanceid + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-instanceid +* AWS::AutoScaling::LaunchConfiguration InstanceMonitoring.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-instancemonitoring + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-instancemonitoring +* AWS::AutoScaling::LaunchConfiguration InstanceType.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-instancetype + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-instancetype +* AWS::AutoScaling::LaunchConfiguration KernelId.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-kernelid + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-kernelid +* AWS::AutoScaling::LaunchConfiguration KeyName.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-keyname + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-keyname +* AWS::AutoScaling::LaunchConfiguration LaunchConfigurationName.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-autoscaling-launchconfig-launchconfigurationname + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-launchconfigurationname +* AWS::AutoScaling::LaunchConfiguration MetadataOptions.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-autoscaling-launchconfig-metadataoptions + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-metadataoptions +* AWS::AutoScaling::LaunchConfiguration PlacementTenancy.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-placementtenancy + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-placementtenancy +* AWS::AutoScaling::LaunchConfiguration RamDiskId.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-ramdiskid + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-ramdiskid +* AWS::AutoScaling::LaunchConfiguration SecurityGroups.DuplicatesAllowed (__deleted__) +* AWS::AutoScaling::LaunchConfiguration SecurityGroups.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-securitygroups + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-securitygroups +* AWS::AutoScaling::LaunchConfiguration SpotPrice.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-spotprice + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-spotprice +* AWS::AutoScaling::LaunchConfiguration UserData.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-userdata + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-userdata +* AWS::CustomerProfiles::Integration ObjectTypeNames (__added__) +* AWS::CustomerProfiles::Integration ObjectTypeName.Required (__changed__) + * Old: true + * New: false +* AWS::DocDB::DBCluster CopyTagsToSnapshot (__added__) +* AWS::EC2::Subnet AvailabilityZoneId (__added__) +* AWS::EC2::Subnet EnableDns64 (__added__) +* AWS::EC2::Subnet Ipv6Native (__added__) +* AWS::EC2::Subnet PrivateDnsNameOptionsOnLaunch (__added__) +* AWS::EC2::Subnet Ipv6CidrBlock.UpdateType (__changed__) + * Old: Mutable + * New: Conditional +* AWS::EC2::VPC Ipv4IpamPoolId (__added__) +* AWS::EC2::VPC Ipv4NetmaskLength (__added__) +* AWS::EC2::VPCCidrBlock Ipv4IpamPoolId (__added__) +* AWS::EC2::VPCCidrBlock Ipv4NetmaskLength (__added__) +* AWS::EC2::VPCCidrBlock Ipv6IpamPoolId (__added__) +* AWS::EC2::VPCCidrBlock Ipv6NetmaskLength (__added__) +* AWS::EKS::Nodegroup DiskSize.PrimitiveType (__changed__) + * Old: Double + * New: Integer +* AWS::EKS::Nodegroup InstanceTypes.DuplicatesAllowed (__added__) +* AWS::EKS::Nodegroup Subnets.DuplicatesAllowed (__added__) +* AWS::SQS::Queue ContentBasedDeduplication.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-contentbaseddeduplication + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-contentbaseddeduplication +* AWS::SQS::Queue DeduplicationScope.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-deduplicationscope + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-deduplicationscope +* AWS::SQS::Queue DelaySeconds.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-delayseconds + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-delayseconds +* AWS::SQS::Queue FifoQueue.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-fifoqueue + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-fifoqueue +* AWS::SQS::Queue FifoThroughputLimit.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-fifothroughputlimit + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-fifothroughputlimit +* AWS::SQS::Queue KmsDataKeyReusePeriodSeconds.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-kmsdatakeyreuseperiodseconds + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-kmsdatakeyreuseperiodseconds +* AWS::SQS::Queue KmsMasterKeyId.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-kmsmasterkeyid + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-kmsmasterkeyid +* AWS::SQS::Queue MaximumMessageSize.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-maxmesgsize + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-maximummessagesize +* AWS::SQS::Queue MessageRetentionPeriod.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-msgretentionperiod + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-messageretentionperiod +* AWS::SQS::Queue QueueName.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-name + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-queuename +* AWS::SQS::Queue ReceiveMessageWaitTimeSeconds.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-receivemsgwaittime + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-receivemessagewaittimeseconds +* AWS::SQS::Queue RedriveAllowPolicy.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-redriveallowpolicy + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-redriveallowpolicy +* AWS::SQS::Queue RedrivePolicy.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-redrive + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-redrivepolicy +* AWS::SQS::Queue Tags.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#cfn-sqs-queue-tags + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-tags +* AWS::SQS::Queue VisibilityTimeout.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-visiblitytimeout + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-visibilitytimeout + +## Property Type Changes + +* AWS::AppRunner::Service.EgressConfiguration (__added__) +* AWS::AppRunner::Service.NetworkConfiguration (__added__) +* AWS::CustomerProfiles::Integration.ObjectTypeMapping (__added__) +* AWS::EC2::Subnet.PrivateDnsNameOptionsOnLaunch (__added__) +* AWS::AutoScaling::LaunchConfiguration.BlockDevice DeleteOnTermination.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-template.html#cfn-as-launchconfig-blockdev-template-deleteonterm + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevice.html#cfn-autoscaling-launchconfiguration-blockdevice-deleteontermination +* AWS::AutoScaling::LaunchConfiguration.BlockDevice DeleteOnTermination.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::AutoScaling::LaunchConfiguration.BlockDevice Encrypted.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-template.html#cfn-as-launchconfig-blockdev-template-encrypted + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevice.html#cfn-autoscaling-launchconfiguration-blockdevice-encrypted +* AWS::AutoScaling::LaunchConfiguration.BlockDevice Encrypted.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::AutoScaling::LaunchConfiguration.BlockDevice Iops.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-template.html#cfn-as-launchconfig-blockdev-template-iops + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevice.html#cfn-autoscaling-launchconfiguration-blockdevice-iops +* AWS::AutoScaling::LaunchConfiguration.BlockDevice Iops.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::AutoScaling::LaunchConfiguration.BlockDevice SnapshotId.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-template.html#cfn-as-launchconfig-blockdev-template-snapshotid + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevice.html#cfn-autoscaling-launchconfiguration-blockdevice-snapshotid +* AWS::AutoScaling::LaunchConfiguration.BlockDevice SnapshotId.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::AutoScaling::LaunchConfiguration.BlockDevice Throughput.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-template.html#cfn-as-launchconfig-blockdev-template-throughput + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevice.html#cfn-autoscaling-launchconfiguration-blockdevice-throughput +* AWS::AutoScaling::LaunchConfiguration.BlockDevice Throughput.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::AutoScaling::LaunchConfiguration.BlockDevice VolumeSize.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-template.html#cfn-as-launchconfig-blockdev-template-volumesize + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevice.html#cfn-autoscaling-launchconfiguration-blockdevice-volumesize +* AWS::AutoScaling::LaunchConfiguration.BlockDevice VolumeSize.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::AutoScaling::LaunchConfiguration.BlockDevice VolumeType.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-template.html#cfn-as-launchconfig-blockdev-template-volumetype + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevice.html#cfn-autoscaling-launchconfiguration-blockdevice-volumetype +* AWS::AutoScaling::LaunchConfiguration.BlockDevice VolumeType.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::AutoScaling::LaunchConfiguration.BlockDeviceMapping DeviceName.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-mapping.html#cfn-as-launchconfig-blockdev-mapping-devicename + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevicemapping.html#cfn-autoscaling-launchconfiguration-blockdevicemapping-devicename +* AWS::AutoScaling::LaunchConfiguration.BlockDeviceMapping DeviceName.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::AutoScaling::LaunchConfiguration.BlockDeviceMapping Ebs.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-mapping.html#cfn-as-launchconfig-blockdev-mapping-ebs + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevicemapping.html#cfn-autoscaling-launchconfiguration-blockdevicemapping-ebs +* AWS::AutoScaling::LaunchConfiguration.BlockDeviceMapping Ebs.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::AutoScaling::LaunchConfiguration.BlockDeviceMapping NoDevice.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-mapping.html#cfn-as-launchconfig-blockdev-mapping-nodevice + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevicemapping.html#cfn-autoscaling-launchconfiguration-blockdevicemapping-nodevice +* AWS::AutoScaling::LaunchConfiguration.BlockDeviceMapping NoDevice.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::AutoScaling::LaunchConfiguration.BlockDeviceMapping VirtualName.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-mapping.html#cfn-as-launchconfig-blockdev-mapping-virtualname + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevicemapping.html#cfn-autoscaling-launchconfiguration-blockdevicemapping-virtualname +* AWS::AutoScaling::LaunchConfiguration.BlockDeviceMapping VirtualName.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::AutoScaling::LaunchConfiguration.MetadataOptions HttpEndpoint.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfig-metadataoptions.html#cfn-autoscaling-launchconfig-metadataoptions-httpendpoint + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-metadataoptions.html#cfn-autoscaling-launchconfiguration-metadataoptions-httpendpoint +* AWS::AutoScaling::LaunchConfiguration.MetadataOptions HttpEndpoint.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::AutoScaling::LaunchConfiguration.MetadataOptions HttpPutResponseHopLimit.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfig-metadataoptions.html#cfn-autoscaling-launchconfig-metadataoptions-httpputresponsehoplimit + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-metadataoptions.html#cfn-autoscaling-launchconfiguration-metadataoptions-httpputresponsehoplimit +* AWS::AutoScaling::LaunchConfiguration.MetadataOptions HttpPutResponseHopLimit.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::AutoScaling::LaunchConfiguration.MetadataOptions HttpTokens.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfig-metadataoptions.html#cfn-autoscaling-launchconfig-metadataoptions-httptokens + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-metadataoptions.html#cfn-autoscaling-launchconfiguration-metadataoptions-httptokens +* AWS::AutoScaling::LaunchConfiguration.MetadataOptions HttpTokens.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::DynamoDB::GlobalTable.ReplicaSpecification TableClass (__added__) +* AWS::EKS::Nodegroup.RemoteAccess SourceSecurityGroups.DuplicatesAllowed (__added__) +* AWS::EKS::Nodegroup.ScalingConfig DesiredSize.PrimitiveType (__changed__) + * Old: Double + * New: Integer +* AWS::EKS::Nodegroup.ScalingConfig MaxSize.PrimitiveType (__changed__) + * Old: Double + * New: Integer +* AWS::EKS::Nodegroup.ScalingConfig MinSize.PrimitiveType (__changed__) + * Old: Double + * New: Integer +* AWS::SES::Template.Template SubjectPart.Required (__changed__) + * Old: false + * New: true + +## Unapplied changes + +* AWS::AppIntegrations is at 53.1.0 + # CloudFormation Resource Specification v55.0.0 ## New Resource Types diff --git a/packages/@aws-cdk/cfnspec/cfn.version b/packages/@aws-cdk/cfnspec/cfn.version index b406fbef67e73..8f7cbd8b05c11 100644 --- a/packages/@aws-cdk/cfnspec/cfn.version +++ b/packages/@aws-cdk/cfnspec/cfn.version @@ -1 +1 @@ -55.0.0 +62.0.0 diff --git a/packages/@aws-cdk/cfnspec/package.json b/packages/@aws-cdk/cfnspec/package.json index c9ed729376890..28df806d4572d 100644 --- a/packages/@aws-cdk/cfnspec/package.json +++ b/packages/@aws-cdk/cfnspec/package.json @@ -32,12 +32,12 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/fs-extra": "^8.1.2", - "@types/jest": "^27.4.0", - "@types/md5": "^2.3.1", + "@types/jest": "^27.4.1", + "@types/md5": "^2.3.2", "fast-json-patch": "^2.2.1", - "jest": "^27.4.7", - "json-diff": "^0.7.1", - "sort-json": "^2.0.0" + "jest": "^27.5.1", + "json-diff": "^0.7.3", + "sort-json": "^2.0.1" }, "dependencies": { "fs-extra": "^9.1.0", diff --git a/packages/@aws-cdk/cfnspec/spec-source/cfn-docs/cfn-docs.json b/packages/@aws-cdk/cfnspec/spec-source/cfn-docs/cfn-docs.json index ac0a400ae22e0..51903ee940094 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/cfn-docs/cfn-docs.json +++ b/packages/@aws-cdk/cfnspec/spec-source/cfn-docs/cfn-docs.json @@ -25,9 +25,26 @@ "Subject": "Contains information about the certificate subject. The Subject field in the certificate identifies the entity that owns or controls the public key in the certificate. The entity can be a user, computer, device, or service. The Subject must contain an X.500 distinguished name (DN). A DN is a sequence of relative distinguished names (RDNs). The RDNs are separated by commas in the certificate." } }, + "AWS::ACMPCA::Certificate.CustomAttribute": { + "attributes": {}, + "description": "Defines the X.500 relative distinguished name (RDN).", + "properties": { + "ObjectIdentifier": "Specifies the object identifier (OID) of the attribute type of the relative distinguished name (RDN).", + "Value": "Specifies the attribute value of relative distinguished name (RDN)." + } + }, + "AWS::ACMPCA::Certificate.CustomExtension": { + "attributes": {}, + "description": "Specifies the X.509 extension information for a certificate.\n\nExtensions present in `CustomExtensions` follow the `ApiPassthrough` [template rules](https://docs.aws.amazon.com/acm-pca/latest/userguide/UsingTemplates.html#template-order-of-operations) .", + "properties": { + "Critical": "Specifies the critical flag of the X.509 extension.", + "ObjectIdentifier": "Specifies the object identifier (OID) of the X.509 extension. For more information, see the [Global OID reference database.](https://docs.aws.amazon.com/https://oidref.com/2.5.29)", + "Value": "Specifies the base64-encoded value of the X.509 extension." + } + }, "AWS::ACMPCA::Certificate.EdiPartyName": { "attributes": {}, - "description": "Describes an Electronic Data Interchange (EDI) entity as described in as defined in [Subject Alternative Name](https://docs.aws.amazon.com/https://tools.ietf.org/html/rfc5280) in RFC 5280.", + "description": "Describes an Electronic Data Interchange (EDI) entity as described in as defined in [Subject Alternative Name](https://docs.aws.amazon.com/https://datatracker.ietf.org/doc/html/rfc5280) in RFC 5280.", "properties": { "NameAssigner": "Specifies the name assigner.", "PartyName": "Specifies the party name." @@ -38,7 +55,7 @@ "description": "Specifies additional purposes for which the certified public key may be used other than basic purposes indicated in the `KeyUsage` extension.", "properties": { "ExtendedKeyUsageObjectIdentifier": "Specifies a custom `ExtendedKeyUsage` with an object identifier (OID).", - "ExtendedKeyUsageType": "Specifies a standard `ExtendedKeyUsage` as defined as in [RFC 5280](https://docs.aws.amazon.com/https://tools.ietf.org/html/rfc5280#section-4.2.1.12) ." + "ExtendedKeyUsageType": "Specifies a standard `ExtendedKeyUsage` as defined as in [RFC 5280](https://docs.aws.amazon.com/https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.12) ." } }, "AWS::ACMPCA::Certificate.Extensions": { @@ -46,6 +63,7 @@ "description": "Contains X.509 extension information for a certificate.", "properties": { "CertificatePolicies": "Contains a sequence of one or more policy information terms, each of which consists of an object identifier (OID) and optional qualifiers. For more information, see NIST's definition of [Object Identifier (OID)](https://docs.aws.amazon.com/https://csrc.nist.gov/glossary/term/Object_Identifier) .\n\nIn an end-entity certificate, these terms indicate the policy under which the certificate was issued and the purposes for which it may be used. In a CA certificate, these terms limit the set of policies for certification paths that include this certificate.", + "CustomExtensions": "Contains a sequence of one or more X.509 extensions, each of which consists of an object identifier (OID), a base64-encoded value, and the critical flag. For more information, see the [Global OID reference database.](https://docs.aws.amazon.com/https://oidref.com/2.5.29)\n\n> The OID value of a [CustomExtension](https://docs.aws.amazon.com/acm-pca/latest/APIReference/API_CustomExtension.html) must not match the OID of a predefined extension.", "ExtendedKeyUsage": "Specifies additional purposes for which the certified public key may be used other than basic purposes indicated in the `KeyUsage` extension.", "KeyUsage": "Defines one or more purposes for which the key contained in the certificate can be used. Default value for each option is false.", "SubjectAlternativeNames": "The subject alternative name extension allows identities to be bound to the subject of the certificate. These identities may be included in addition to or in place of the identity in the subject field of the certificate." @@ -53,7 +71,7 @@ }, "AWS::ACMPCA::Certificate.GeneralName": { "attributes": {}, - "description": "Describes an ASN.1 X.400 `GeneralName` as defined in [RFC 5280](https://docs.aws.amazon.com/https://tools.ietf.org/html/rfc5280) . Only one of the following naming options should be provided. Providing more than one option results in an `InvalidArgsException` error.", + "description": "Describes an ASN.1 X.400 `GeneralName` as defined in [RFC 5280](https://docs.aws.amazon.com/https://datatracker.ietf.org/doc/html/rfc5280) . Only one of the following naming options should be provided. Providing more than one option results in an `InvalidArgsException` error.", "properties": { "DirectoryName": "Contains information about the certificate subject. The certificate can be one issued by your private certificate authority (CA) or it can be your private CA certificate. The Subject field in the certificate identifies the entity that owns or controls the public key in the certificate. The entity can be a user, computer, device, or service. The Subject must contain an X.500 distinguished name (DN). A DN is a sequence of relative distinguished names (RDNs). The RDNs are separated by commas in the certificate. The DN must be unique for each entity, but your private CA can issue more than one certificate with the same DN to the same entity.", "DnsName": "Represents `GeneralName` as a DNS name.", @@ -61,7 +79,7 @@ "IpAddress": "Represents `GeneralName` as an IPv4 or IPv6 address.", "OtherName": "Represents `GeneralName` using an `OtherName` object.", "RegisteredId": "Represents `GeneralName` as an object identifier (OID).", - "Rfc822Name": "Represents `GeneralName` as an [RFC 822](https://docs.aws.amazon.com/https://tools.ietf.org/html/rfc822) email address.", + "Rfc822Name": "Represents `GeneralName` as an [RFC 822](https://docs.aws.amazon.com/https://datatracker.ietf.org/doc/html/rfc822) email address.", "UniformResourceIdentifier": "Represents `GeneralName` as a URI." } }, @@ -106,7 +124,7 @@ }, "AWS::ACMPCA::Certificate.Qualifier": { "attributes": {}, - "description": "Defines a `PolicyInformation` qualifier. ACM Private CA supports the [certification practice statement (CPS) qualifier](https://docs.aws.amazon.com/https://tools.ietf.org/html/rfc5280#section-4.2.1.4) defined in RFC 5280.", + "description": "Defines a `PolicyInformation` qualifier. ACM Private CA supports the [certification practice statement (CPS) qualifier](https://docs.aws.amazon.com/https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4) defined in RFC 5280.", "properties": { "CpsUri": "Contains a pointer to a certification practice statement (CPS) published by the CA." } @@ -117,6 +135,7 @@ "properties": { "CommonName": "For CA and end-entity certificates in a private PKI, the common name (CN) can be any string within the length limit.\n\nNote: In publicly trusted certificates, the common name must be a fully qualified domain name (FQDN) associated with the certificate subject.", "Country": "Two-digit code that specifies the country in which the certificate subject located.", + "CustomAttributes": "Contains a sequence of one or more X.500 relative distinguished names (RDNs), each of which consists of an object identifier (OID) and a value. For more information, see NIST\u2019s definition of [Object Identifier (OID)](https://docs.aws.amazon.com/https://csrc.nist.gov/glossary/term/Object_Identifier) .\n\n> Custom attributes cannot be used in combination with standard attributes.", "DistinguishedNameQualifier": "Disambiguating information for the certificate subject.", "GenerationQualifier": "Typically a qualifier appended to the name of an individual. Examples include Jr. for junior, Sr. for senior, and III for third.", "GivenName": "First name.", @@ -159,7 +178,7 @@ }, "AWS::ACMPCA::CertificateAuthority.AccessDescription": { "attributes": {}, - "description": "Provides access information used by the `authorityInfoAccess` and `subjectInfoAccess` extensions described in [RFC 5280](https://docs.aws.amazon.com/https://tools.ietf.org/html/rfc5280) .", + "description": "Provides access information used by the `authorityInfoAccess` and `subjectInfoAccess` extensions described in [RFC 5280](https://docs.aws.amazon.com/https://datatracker.ietf.org/doc/html/rfc5280) .", "properties": { "AccessLocation": "The location of `AccessDescription` information.", "AccessMethod": "The type and format of `AccessDescription` information." @@ -175,7 +194,7 @@ }, "AWS::ACMPCA::CertificateAuthority.CrlConfiguration": { "attributes": {}, - "description": "Contains configuration information for a certificate revocation list (CRL). Your private certificate authority (CA) creates base CRLs. Delta CRLs are not supported. You can enable CRLs for your new or an existing private CA by setting the *Enabled* parameter to `true` . Your private CA writes CRLs to an S3 bucket that you specify in the *S3BucketName* parameter. You can hide the name of your bucket by specifying a value for the *CustomCname* parameter. Your private CA copies the CNAME or the S3 bucket name to the *CRL Distribution Points* extension of each certificate it issues. Your S3 bucket policy must give write permission to ACM Private CA.\n\nACM Private CA assets that are stored in Amazon S3 can be protected with encryption. For more information, see [Encrypting Your CRLs](https://docs.aws.amazon.com/acm-pca/latest/userguide/PcaCreateCa.html#crl-encryption) .\n\nYour private CA uses the value in the *ExpirationInDays* parameter to calculate the *nextUpdate* field in the CRL. The CRL is refreshed at 1/2 the age of next update or when a certificate is revoked. When a certificate is revoked, it is recorded in the next CRL that is generated and in the next audit report. Only time valid certificates are listed in the CRL. Expired certificates are not included.\n\nA CRL is typically updated approximately 30 minutes after a certificate is revoked. If for any reason a CRL update fails, ACM Private CA makes further attempts every 15 minutes.\n\nCRLs contain the following fields:\n\n- *Version* : The current version number defined in RFC 5280 is V2. The integer value is 0x1.\n- *Signature Algorithm* : The name of the algorithm used to sign the CRL.\n- *Issuer* : The X.500 distinguished name of your private CA that issued the CRL.\n- *Last Update* : The issue date and time of this CRL.\n- *Next Update* : The day and time by which the next CRL will be issued.\n- *Revoked Certificates* : List of revoked certificates. Each list item contains the following information.\n\n- *Serial Number* : The serial number, in hexadecimal format, of the revoked certificate.\n- *Revocation Date* : Date and time the certificate was revoked.\n- *CRL Entry Extensions* : Optional extensions for the CRL entry.\n\n- *X509v3 CRL Reason Code* : Reason the certificate was revoked.\n- *CRL Extensions* : Optional extensions for the CRL.\n\n- *X509v3 Authority Key Identifier* : Identifies the public key associated with the private key used to sign the certificate.\n- *X509v3 CRL Number:* : Decimal sequence number for the CRL.\n- *Signature Algorithm* : Algorithm used by your private CA to sign the CRL.\n- *Signature Value* : Signature computed over the CRL.\n\nCertificate revocation lists created by ACM Private CA are DER-encoded. You can use the following OpenSSL command to list a CRL.\n\n`openssl crl -inform DER -text -in *crl_path* -noout`\n\nFor more information, see [Planning a certificate revocation list (CRL)](https://docs.aws.amazon.com/acm-pca/latest/userguide/crl-planning.html) in the *AWS Certificate Manager Private Certificate Authority (PCA) User Guide*", + "description": "Contains configuration information for a certificate revocation list (CRL). Your private certificate authority (CA) creates base CRLs. Delta CRLs are not supported. You can enable CRLs for your new or an existing private CA by setting the *Enabled* parameter to `true` . Your private CA writes CRLs to an S3 bucket that you specify in the *S3BucketName* parameter. You can hide the name of your bucket by specifying a value for the *CustomCname* parameter. Your private CA copies the CNAME or the S3 bucket name to the *CRL Distribution Points* extension of each certificate it issues. Your S3 bucket policy must give write permission to ACM Private CA.\n\nACM Private CA assets that are stored in Amazon S3 can be protected with encryption. For more information, see [Encrypting Your CRLs](https://docs.aws.amazon.com/acm-pca/latest/userguide/PcaCreateCa.html#crl-encryption) .\n\nYour private CA uses the value in the *ExpirationInDays* parameter to calculate the *nextUpdate* field in the CRL. The CRL is refreshed prior to a certificate's expiration date or when a certificate is revoked. When a certificate is revoked, it appears in the CRL until the certificate expires, and then in one additional CRL after expiration, and it always appears in the audit report.\n\nA CRL is typically updated approximately 30 minutes after a certificate is revoked. If for any reason a CRL update fails, ACM Private CA makes further attempts every 15 minutes.\n\nCRLs contain the following fields:\n\n- *Version* : The current version number defined in RFC 5280 is V2. The integer value is 0x1.\n- *Signature Algorithm* : The name of the algorithm used to sign the CRL.\n- *Issuer* : The X.500 distinguished name of your private CA that issued the CRL.\n- *Last Update* : The issue date and time of this CRL.\n- *Next Update* : The day and time by which the next CRL will be issued.\n- *Revoked Certificates* : List of revoked certificates. Each list item contains the following information.\n\n- *Serial Number* : The serial number, in hexadecimal format, of the revoked certificate.\n- *Revocation Date* : Date and time the certificate was revoked.\n- *CRL Entry Extensions* : Optional extensions for the CRL entry.\n\n- *X509v3 CRL Reason Code* : Reason the certificate was revoked.\n- *CRL Extensions* : Optional extensions for the CRL.\n\n- *X509v3 Authority Key Identifier* : Identifies the public key associated with the private key used to sign the certificate.\n- *X509v3 CRL Number:* : Decimal sequence number for the CRL.\n- *Signature Algorithm* : Algorithm used by your private CA to sign the CRL.\n- *Signature Value* : Signature computed over the CRL.\n\nCertificate revocation lists created by ACM Private CA are DER-encoded. You can use the following OpenSSL command to list a CRL.\n\n`openssl crl -inform DER -text -in *crl_path* -noout`\n\nFor more information, see [Planning a certificate revocation list (CRL)](https://docs.aws.amazon.com/acm-pca/latest/userguide/crl-planning.html) in the *AWS Certificate Manager Private Certificate Authority (PCA) User Guide*", "properties": { "CustomCname": "Name inserted into the certificate *CRL Distribution Points* extension that enables the use of an alias for the CRL distribution point. Use this value if you don't want the name of your S3 bucket to be public.", "Enabled": "Boolean value that specifies whether certificate revocation lists (CRLs) are enabled. You can use this value to enable certificate revocation for a new CA when you call the `CreateCertificateAuthority` operation or for an existing CA when you call the `UpdateCertificateAuthority` operation.", @@ -189,12 +208,20 @@ "description": "Describes the certificate extensions to be added to the certificate signing request (CSR).", "properties": { "KeyUsage": "Indicates the purpose of the certificate and of the key contained in the certificate.", - "SubjectInformationAccess": "For CA certificates, provides a path to additional information pertaining to the CA, such as revocation and policy. For more information, see [Subject Information Access](https://docs.aws.amazon.com/https://tools.ietf.org/html/rfc5280#section-4.2.2.2) in RFC 5280." + "SubjectInformationAccess": "For CA certificates, provides a path to additional information pertaining to the CA, such as revocation and policy. For more information, see [Subject Information Access](https://docs.aws.amazon.com/https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.2.2) in RFC 5280." + } + }, + "AWS::ACMPCA::CertificateAuthority.CustomAttribute": { + "attributes": {}, + "description": "Defines the X.500 relative distinguished name (RDN).", + "properties": { + "ObjectIdentifier": "Specifies the object identifier (OID) of the attribute type of the relative distinguished name (RDN).", + "Value": "Specifies the attribute value of relative distinguished name (RDN)." } }, "AWS::ACMPCA::CertificateAuthority.EdiPartyName": { "attributes": {}, - "description": "Describes an Electronic Data Interchange (EDI) entity as described in as defined in [Subject Alternative Name](https://docs.aws.amazon.com/https://tools.ietf.org/html/rfc5280) in RFC 5280.", + "description": "Describes an Electronic Data Interchange (EDI) entity as described in as defined in [Subject Alternative Name](https://docs.aws.amazon.com/https://datatracker.ietf.org/doc/html/rfc5280) in RFC 5280.", "properties": { "NameAssigner": "Specifies the name assigner.", "PartyName": "Specifies the party name." @@ -202,7 +229,7 @@ }, "AWS::ACMPCA::CertificateAuthority.GeneralName": { "attributes": {}, - "description": "Describes an ASN.1 X.400 `GeneralName` as defined in [RFC 5280](https://docs.aws.amazon.com/https://tools.ietf.org/html/rfc5280) . Only one of the following naming options should be provided. Providing more than one option results in an `InvalidArgsException` error.", + "description": "Describes an ASN.1 X.400 `GeneralName` as defined in [RFC 5280](https://docs.aws.amazon.com/https://datatracker.ietf.org/doc/html/rfc5280) . Only one of the following naming options should be provided. Providing more than one option results in an `InvalidArgsException` error.", "properties": { "DirectoryName": "Contains information about the certificate subject. The certificate can be one issued by your private certificate authority (CA) or it can be your private CA certificate. The Subject field in the certificate identifies the entity that owns or controls the public key in the certificate. The entity can be a user, computer, device, or service. The Subject must contain an X.500 distinguished name (DN). A DN is a sequence of relative distinguished names (RDNs). The RDNs are separated by commas in the certificate. The DN must be unique for each entity, but your private CA can issue more than one certificate with the same DN to the same entity.", "DnsName": "Represents `GeneralName` as a DNS name.", @@ -210,7 +237,7 @@ "IpAddress": "Represents `GeneralName` as an IPv4 or IPv6 address.", "OtherName": "Represents `GeneralName` using an `OtherName` object.", "RegisteredId": "Represents `GeneralName` as an object identifier (OID).", - "Rfc822Name": "Represents `GeneralName` as an [RFC 822](https://docs.aws.amazon.com/https://tools.ietf.org/html/rfc822) email address.", + "Rfc822Name": "Represents `GeneralName` as an [RFC 822](https://docs.aws.amazon.com/https://datatracker.ietf.org/doc/html/rfc822) email address.", "UniformResourceIdentifier": "Represents `GeneralName` as a URI." } }, @@ -259,6 +286,7 @@ "properties": { "CommonName": "Fully qualified domain name (FQDN) associated with the certificate subject.", "Country": "Two-digit code that specifies the country in which the certificate subject located.", + "CustomAttributes": "Contains a sequence of one or more X.500 relative distinguished names (RDNs), each of which consists of an object identifier (OID) and a value. For more information, see NIST\u2019s definition of [Object Identifier (OID)](https://docs.aws.amazon.com/https://csrc.nist.gov/glossary/term/Object_Identifier) .\n\n> Custom attributes cannot be used in combination with standard attributes.", "DistinguishedNameQualifier": "Disambiguating information for the certificate subject.", "GenerationQualifier": "Typically a qualifier appended to the name of an individual. Examples include Jr. for junior, Sr. for senior, and III for third.", "GivenName": "First name.", @@ -639,10 +667,8 @@ "AWS::AmplifyUIBuilder::Component": { "attributes": { "AppId": "The unique ID for the Amplify app.", - "CreatedAt": "The time that the component was created.", "EnvironmentName": "The name of the backend environment that is a part of the Amplify app.", "Id": "The unique ID of the component.", - "ModifiedAt": "The time that the component was modified.", "Ref": "" }, "description": "The AWS::AmplifyUIBuilder::Component resource specifies a component within an Amplify app. A component is a user interface (UI) element that you can customize. Use `ComponentChild` to configure an instance of a `Component` . A `ComponentChild` instance inherits the configuration of the main `Component` .", @@ -651,14 +677,31 @@ "Children": "A list of the component's `ComponentChild` instances.", "CollectionProperties": "The data binding configuration for the component's properties. Use this for a collection component. You can't specify `tags` as a valid property for `collectionProperties` .", "ComponentType": "The type of the component. This can be an Amplify custom UI component or another custom component.", + "Events": "Describes the events that can be raised on the component. Use for the workflow feature in Amplify Studio that allows you to bind events and actions to components.", "Name": "The name of the component.", "Overrides": "Describes the component's properties that can be overriden in a customized instance of the component. You can't specify `tags` as a valid property for `overrides` .", "Properties": "Describes the component's properties. You can't specify `tags` as a valid property for `properties` .", + "SchemaVersion": "The schema version of the component when it was imported.", "SourceId": "The unique ID of the component in its original source system, such as Figma.", "Tags": "One or more key-value pairs to use when tagging the component.", "Variants": "A list of the component's variants. A variant is a unique style configuration of a main component." } }, + "AWS::AmplifyUIBuilder::Component.ActionParameters": { + "attributes": {}, + "description": "The `ActionParameters` property specifies the event action configuration for an element of a `Component` or `ComponentChild` . Use for the workflow feature in Amplify Studio that allows you to bind events and actions to components. `ActionParameters` defines the action that is performed when an event occurs on the component.", + "properties": { + "Anchor": "The HTML anchor link to the location to open. Specify this value for a navigation action.", + "Fields": "A dictionary of key-value pairs mapping Amplify Studio properties to fields in a data model. Use when the action performs an operation on an Amplify DataStore model.", + "Global": "Specifies whether the user should be signed out globally. Specify this value for an auth sign out action.", + "Id": "The unique ID of the component that the `ActionParameters` apply to.", + "Model": "The name of the data model. Use when the action performs an operation on an Amplify DataStore model.", + "State": "A key-value pair that specifies the state property name and its initial value.", + "Target": "The element within the same component to modify when the action occurs.", + "Type": "The type of navigation action. Valid values are `url` and `anchor` . This value is required for a navigation action.", + "Url": "The URL to the location to open. Specify this value for a navigation action." + } + }, "AWS::AmplifyUIBuilder::Component.ComponentBindingPropertiesValue": { "attributes": {}, "description": "The `ComponentBindingPropertiesValue` property specifies the data binding configuration for a component at runtime. You can use `ComponentBindingPropertiesValue` to add exposed properties to a component to allow different values to be entered when a component is reused in different places in an app.", @@ -687,6 +730,7 @@ "properties": { "Children": "The list of `ComponentChild` instances for this component.", "ComponentType": "The type of the child component.", + "Events": "Describes the events that can be raised on the child component. Use for the workflow feature in Amplify Studio that allows you to bind events and actions to components.", "Name": "The name of the child component.", "Properties": "Describes the properties of the child component. You can't specify `tags` as a valid property for `properties` ." } @@ -698,6 +742,7 @@ "Else": "The value to assign to the property if the condition is not met.", "Field": "The name of a field. Specify this when the property is a data model.", "Operand": "The value of the property to evaluate.", + "OperandType": "The type of the property to evaluate.", "Operator": "The operator to use to perform the evaluation, such as `eq` to represent equals.", "Property": "The name of the conditional property.", "Then": "The value to assign to the property if the condition is met." @@ -713,6 +758,19 @@ "Sort": "Describes how to sort the component's properties." } }, + "AWS::AmplifyUIBuilder::Component.ComponentEvent": { + "attributes": {}, + "description": "The `ComponentEvent` property specifies the configuration of an event. You can bind an event and a corresponding action to a `Component` or a `ComponentChild` . A button click is an example of an event.", + "properties": { + "Action": "The action to perform when a specific event is raised.", + "Parameters": "Describes information about the action." + } + }, + "AWS::AmplifyUIBuilder::Component.ComponentEvents": { + "attributes": {}, + "description": "The `ComponentEvents` property specifies the events that can be raised on the component. Use for the workflow feature in Amplify Studio that allows you to bind events and actions to components.", + "properties": {} + }, "AWS::AmplifyUIBuilder::Component.ComponentOverrides": { "attributes": {}, "description": "The `ComponentOverrides` property specifies the component's properties that can be overriden in a customized instance of the component.", @@ -735,6 +793,7 @@ "BindingProperties": "The information to bind the component property to data at runtime.", "Bindings": "The information to bind the component property to form data.", "CollectionBindingProperties": "The information to bind the component property to data at runtime. Use this for collection components.", + "ComponentName": "The name of the component that is affected by an event.", "Concat": "A list of component properties to concatenate to create the value to assign to this component property.", "Condition": "The conditional expression to use to assign a value to the component property.", "Configured": "Specifies whether the user configured the property in Amplify Studio after importing it.", @@ -742,6 +801,7 @@ "Event": "An event that occurs in your app. Use this for workflow data binding.", "ImportedValue": "The default value assigned to the property when the component is imported into an app.", "Model": "The data model to use to assign a value to the component property.", + "Property": "The name of the component's property that is affected by an event.", "Type": "The component type.", "UserAttribute": "An authenticated user attribute to use to assign a value to the component property.", "Value": "The value to assign to the component property." @@ -773,6 +833,15 @@ "description": "The `FormBindings` property specifies how to bind a component's properties to form data.", "properties": {} }, + "AWS::AmplifyUIBuilder::Component.MutationActionSetStateParameter": { + "attributes": {}, + "description": "The `MutationActionSetStateParameter` property specifies the state configuration when an action modifies a property of another element within the same component.", + "properties": { + "ComponentName": "The name of the component that is being modified.", + "Property": "The name of the component property to apply the state configuration to.", + "Set": "The state configuration to assign to the property." + } + }, "AWS::AmplifyUIBuilder::Component.Predicate": { "attributes": {}, "description": "The `Predicate` property specifies information for generating Amplify DataStore queries. Use `Predicate` to retrieve a subset of the data in a collection.", @@ -885,6 +954,7 @@ "properties": { "BasePath": "The base path name that callers of the API must provide in the URL after the domain name.", "DomainName": "The `DomainName` of an [AWS::ApiGateway::DomainName](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-domainname.html) resource.", + "Id": "", "RestApiId": "The ID of the API.", "Stage": "The name of the API's stage." } @@ -2214,8 +2284,10 @@ "properties": { "EventBridge": "The properties required to query Amazon EventBridge.", "LookoutMetrics": "The properties required to query Amazon Lookout for Metrics.", + "Marketo": "The properties required to query Marketo.", "Redshift": "The properties required to query Amazon Redshift.", "S3": "The properties required to query Amazon S3.", + "SAPOData": "The properties required to query SAPOData.", "Salesforce": "The properties required to query Salesforce.", "Snowflake": "The properties required to query Snowflake.", "Upsolver": "The properties required to query Upsolver.", @@ -2283,6 +2355,14 @@ "Object": "The object specified in the Amazon Lookout for Metrics flow destination." } }, + "AWS::AppFlow::Flow.MarketoDestinationProperties": { + "attributes": {}, + "description": "The properties that Amazon AppFlow applies when you use Marketo as a flow destination.", + "properties": { + "ErrorHandlingConfig": "", + "Object": "The object specified in the Marketo flow destination." + } + }, "AWS::AppFlow::Flow.MarketoSourceProperties": { "attributes": {}, "description": "The properties that are applied when Marketo is being used as a source.", @@ -2342,6 +2422,17 @@ "S3InputFormatConfig": "" } }, + "AWS::AppFlow::Flow.SAPODataDestinationProperties": { + "attributes": {}, + "description": "The properties that are applied when using SAPOData as a flow destination", + "properties": { + "ErrorHandlingConfig": "", + "IdFieldNames": "", + "ObjectPath": "The object path specified in the SAPOData flow destination.", + "SuccessResponseHandlingConfig": "Determines how Amazon AppFlow handles the success response that it gets from the connector after placing data.\n\nFor example, this setting would determine where to write the response from a destination connector upon a successful insert operation.", + "WriteOperationType": "" + } + }, "AWS::AppFlow::Flow.SAPODataSourceProperties": { "attributes": {}, "description": "", @@ -2442,6 +2533,14 @@ "SourceConnectorProperties": "Specifies the information that is required to query a particular source connector." } }, + "AWS::AppFlow::Flow.SuccessResponseHandlingConfig": { + "attributes": {}, + "description": "Determines how Amazon AppFlow handles the success response that it gets from the connector after placing data.\n\nFor example, this setting would determine where to write the response from the destination connector upon a successful insert operation.", + "properties": { + "BucketName": "The name of the Amazon S3 bucket.", + "BucketPrefix": "The Amazon S3 bucket prefix." + } + }, "AWS::AppFlow::Flow.Task": { "attributes": {}, "description": "The `Task` property type specifies the class for modeling different type of tasks. Task implementation varies based on the `TaskType` .", @@ -2826,6 +2925,11 @@ "Type": "The egress filter type. By default, the type is `DROP_ALL` , which allows egress only from virtual nodes to other defined resources in the service mesh (and any traffic to `*.amazonaws.com` for AWS API calls). You can set the egress filter type to `ALLOW_ALL` to allow egress to any endpoint inside or outside of the service mesh." } }, + "AWS::AppMesh::Mesh.MeshServiceDiscovery": { + "attributes": {}, + "description": "", + "properties": {} + }, "AWS::AppMesh::Mesh.MeshSpec": { "attributes": {}, "description": "An object that represents the specification of a service mesh.", @@ -3778,13 +3882,14 @@ }, "description": "Specify an AWS App Runner service by using the `AWS::AppRunner::Service` resource in an AWS CloudFormation template. \n\nThe `AWS::AppRunner::Service` resource is an AWS App Runner resource type that specifies an App Runner service.", "properties": { - "AutoScalingConfigurationArn": "The Amazon Resource Name (ARN) of an App Runner automatic scaling configuration resource that you want to associate with your service. If not provided, App Runner associates the latest revision of a default auto scaling configuration.", + "AutoScalingConfigurationArn": "The Amazon Resource Name (ARN) of an App Runner automatic scaling configuration resource that you want to associate with the App Runner service. If not provided, App Runner associates the latest revision of a default auto scaling configuration.", "EncryptionConfiguration": "An optional custom encryption key that App Runner uses to encrypt the copy of your source repository that it maintains and your service logs. By default, App Runner uses an AWS managed key .", - "HealthCheckConfiguration": "The settings for the health check that AWS App Runner performs to monitor the health of your service.", + "HealthCheckConfiguration": "The settings for the health check that AWS App Runner performs to monitor the health of the App Runner service.", "InstanceConfiguration": "The runtime configuration of instances (scaling units) of the App Runner service.", - "ServiceName": "A name for the new service. It must be unique across all the running App Runner services in your AWS account in the AWS Region .", + "NetworkConfiguration": "Configuration settings related to network traffic of the web application that the App Runner service runs.", + "ServiceName": "A name for the App Runner service. It must be unique across all the running App Runner services in your AWS account in the AWS Region .\n\nIf you don't specify a name, AWS CloudFormation generates a name for your Service.", "SourceConfiguration": "The source to deploy to the App Runner service. It can be a code or an image repository.", - "Tags": "An optional list of metadata items that you can associate with your service resource. A tag is a key-value pair." + "Tags": "An optional list of metadata items that you can associate with the App Runner service resource. A tag is a key-value pair." } }, "AWS::AppRunner::Service.AuthenticationConfiguration": { @@ -3823,6 +3928,14 @@ "SourceCodeVersion": "The version that should be used within the source code repository." } }, + "AWS::AppRunner::Service.EgressConfiguration": { + "attributes": {}, + "description": "Describes configuration settings related to outbound network traffic of an AWS App Runner service.", + "properties": { + "EgressType": "The type of egress configuration.\n\nSet to `DEFAULT` for access to resources hosted on public networks.\n\nSet to `VPC` to associate your service to a custom VPC specified by `VpcConnectorArn` .", + "VpcConnectorArn": "The Amazon Resource Name (ARN) of the App Runner VPC connector that you want to associate with your App Runner service. Only valid when `EgressType = VPC` ." + } + }, "AWS::AppRunner::Service.EncryptionConfiguration": { "attributes": {}, "description": "Describes a custom encryption key that AWS App Runner uses to encrypt copies of the source repository and service logs.", @@ -3877,6 +3990,13 @@ "Value": "The value string to which the key name is mapped." } }, + "AWS::AppRunner::Service.NetworkConfiguration": { + "attributes": {}, + "description": "Describes configuration settings related to network traffic of an AWS App Runner service. Consists of embedded objects for each configurable network feature.", + "properties": { + "EgressConfiguration": "Network configuration settings for outbound message traffic." + } + }, "AWS::AppRunner::Service.SourceCodeVersion": { "attributes": {}, "description": "Identifies a version of code that AWS App Runner refers to within a source code repository.", @@ -3895,6 +4015,20 @@ "ImageRepository": "The description of a source image repository.\n\nYou must provide either this member or `CodeRepository` (but not both)." } }, + "AWS::AppRunner::VpcConnector": { + "attributes": { + "Ref": "", + "VpcConnectorArn": "The Amazon Resource Name (ARN) of this VPC connector.", + "VpcConnectorRevision": "The revision of this VPC connector. It's unique among all the active connectors ( `\"Status\": \"ACTIVE\"` ) that share the same `Name` .\n\n> At this time, App Runner supports only one revision per name." + }, + "description": "Specify an AWS App Runner VPC connector by using the `AWS::AppRunner::VpcConnector` resource in an AWS CloudFormation template. \n\nThe `AWS::AppRunner::VpcConnector` resource is an AWS App Runner resource type that specifies an App Runner VPC connector.\n\nApp Runner requires this resource when you want to associate your App Runner service to a custom Amazon Virtual Private Cloud ( Amazon VPC ).", + "properties": { + "SecurityGroups": "A list of IDs of security groups that App Runner should use for access to AWS resources under the specified subnets. If not specified, App Runner uses the default security group of the Amazon VPC. The default security group allows all outbound traffic.", + "Subnets": "A list of IDs of subnets that App Runner should use when it associates your service with a custom Amazon VPC. Specify IDs of subnets of a single Amazon VPC. App Runner determines the Amazon VPC from the subnets you specify.", + "Tags": "A list of metadata items that you can associate with your VPC connector resource. A tag is a key-value pair.", + "VpcConnectorName": "A name for the VPC connector.\n\nIf you don't specify a name, AWS CloudFormation generates a name for your VPC connector." + } + }, "AWS::AppStream::AppBlock": { "attributes": { "Arn": "The ARN of the app block.", @@ -4332,6 +4466,7 @@ "AWS::AppSync::DomainName": { "attributes": { "AppSyncDomainName": "The domain name provided by AWS AppSync .", + "DomainName": "", "HostedZoneId": "The ID of your Amazon Route\u00a053 hosted zone.", "Ref": "When you pass the logical ID of an `AWS::AppSync::DomainName` resource to the intrinsic `Ref` function, the function returns the domain name.\n\nFor more information about using the `Ref` function, see [Ref](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref) ." }, @@ -4836,12 +4971,12 @@ "NamedQueryId": "The unique ID of the query.", "Ref": "`Ref` returns the resource name." }, - "description": "The `AWS::Athena::NamedQuery` resource specifies an Amazon Athena saved query, where `QueryString` is the list of SQL query statements that comprise the query.", + "description": "The `AWS::Athena::NamedQuery` resource specifies an Amazon Athena saved query, where `QueryString` contains the SQL query statements that make up the query.", "properties": { "Database": "The database to which the query belongs.", "Description": "The query description.", "Name": "The query name.", - "QueryString": "The SQL query statements that comprise the query.", + "QueryString": "The SQL statements that make up the query.", "WorkGroup": "The name of the workgroup that contains the named query." } }, @@ -4877,10 +5012,10 @@ }, "AWS::Athena::WorkGroup.EncryptionConfiguration": { "attributes": {}, - "description": "If query results are encrypted in Amazon S3, indicates the encryption option used (for example, `SSE-KMS` or `CSE-KMS` ) and key information.", + "description": "If query results are encrypted in Amazon S3, indicates the encryption option used (for example, `SSE_KMS` or `CSE_KMS` ) and key information.", "properties": { - "EncryptionOption": "Indicates whether Amazon S3 server-side encryption with Amazon S3-managed keys ( `SSE-S3` ), server-side encryption with KMS-managed keys ( `SSE-KMS` ), or client-side encryption with KMS-managed keys (CSE-KMS) is used.\n\nIf a query runs in a workgroup and the workgroup overrides client-side settings, then the workgroup's setting for encryption is used. It specifies whether query results must be encrypted, for all queries that run in this workgroup.", - "KmsKey": "For `SSE-KMS` and `CSE-KMS` , this is the KMS key ARN or ID." + "EncryptionOption": "Indicates whether Amazon S3 server-side encryption with Amazon S3-managed keys ( `SSE_S3` ), server-side encryption with KMS-managed keys ( `SSE_KMS` ), or client-side encryption with KMS-managed keys ( `CSE_KMS` ) is used.\n\nIf a query runs in a workgroup and the workgroup overrides client-side settings, then the workgroup's setting for encryption is used. It specifies whether query results must be encrypted, for all queries that run in this workgroup.", + "KmsKey": "For `SSE_KMS` and `CSE_KMS` , this is the KMS key ARN or ID." } }, "AWS::Athena::WorkGroup.EngineVersion": { @@ -4895,7 +5030,7 @@ "attributes": {}, "description": "The location in Amazon S3 where query results are stored and the encryption option, if any, used for query results. These are known as \"client-side settings\". If workgroup settings override client-side settings, then the query uses the workgroup settings.", "properties": { - "EncryptionConfiguration": "If query results are encrypted in Amazon S3, indicates the encryption option used (for example, `SSE-KMS` or `CSE-KMS` ) and key information. This is a client-side setting. If workgroup settings override client-side settings, then the query uses the encryption configuration that is specified for the workgroup, and also uses the location for storing query results specified in the workgroup. See `EnforceWorkGroupConfiguration` and [Workgroup Settings Override Client-Side Settings](https://docs.aws.amazon.com/athena/latest/ug/workgroups-settings-override.html) .", + "EncryptionConfiguration": "If query results are encrypted in Amazon S3, indicates the encryption option used (for example, `SSE_KMS` or `CSE_KMS` ) and key information. This is a client-side setting. If workgroup settings override client-side settings, then the query uses the encryption configuration that is specified for the workgroup, and also uses the location for storing query results specified in the workgroup. See `EnforceWorkGroupConfiguration` and [Workgroup Settings Override Client-Side Settings](https://docs.aws.amazon.com/athena/latest/ug/workgroups-settings-override.html) .", "OutputLocation": "The location in Amazon S3 where your query results are stored, such as `s3://path/to/query/bucket/` . To run a query, you must specify the query results location using either a client-side setting for individual queries or a location specified by the workgroup. If workgroup settings override client-side settings, then the query uses the location specified for the workgroup. If no query location is set, Athena issues an error. For more information, see [Working with Query Results, Output Files, and Query History](https://docs.aws.amazon.com/athena/latest/ug/querying.html) and `EnforceWorkGroupConfiguration` ." } }, @@ -5039,7 +5174,7 @@ "MixedInstancesPolicy": "An embedded object that specifies a mixed instances policy.\n\nThe policy includes properties that not only define the distribution of On-Demand Instances and Spot Instances, the maximum price to pay for Spot Instances (optional), and how the Auto Scaling group allocates instance types to fulfill On-Demand and Spot capacities, but also the properties that specify the instance configuration information\u2014the launch template and instance types. The policy can also include a weight for each instance type and different launch templates for individual instance types.\n\nFor more information, see [Auto Scaling groups with multiple instance types and purchase options](https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-mixed-instances-groups.html) in the *Amazon EC2 Auto Scaling User Guide* .\n\nIf you specify `LaunchTemplate` , `InstanceId` , or `LaunchConfigurationName` , don't specify `MixedInstancesPolicy` .", "NewInstancesProtectedFromScaleIn": "Indicates whether newly launched instances are protected from termination by Amazon EC2 Auto Scaling when scaling in. For more information about preventing instances from terminating on scale in, see [Instance Protection](https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-instance-termination.html#instance-protection) in the *Amazon EC2 Auto Scaling User Guide* .", "NotificationConfigurations": "Configures an Auto Scaling group to send notifications when specified events take place.", - "PlacementGroup": "The name of the placement group into which you want to launch your instances. A placement group is a logical grouping of instances within a single Availability Zone. For more information, see [Placement Groups](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/placement-groups.html) in the *Amazon EC2 User Guide for Linux Instances* .", + "PlacementGroup": "The name of the placement group into which you want to launch your instances. For more information, see [Placement groups](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/placement-groups.html) in the *Amazon EC2 User Guide for Linux Instances* .\n\n> A *cluster* placement group is a logical grouping of instances within a single Availability Zone. You cannot specify multiple Availability Zones and a cluster placement group.", "ServiceLinkedRoleARN": "The Amazon Resource Name (ARN) of the service-linked role that the Auto Scaling group uses to call other AWS services on your behalf. By default, Amazon EC2 Auto Scaling uses a service-linked role named `AWSServiceRoleForAutoScaling` , which it creates if it does not exist. For more information, see [Service-linked roles for Amazon EC2 Auto Scaling](https://docs.aws.amazon.com/autoscaling/ec2/userguide/autoscaling-service-linked-role.html) in the *Amazon EC2 Auto Scaling User Guide* .", "Tags": "One or more tags. You can tag your Auto Scaling group and propagate the tags to the Amazon EC2 instances it launches. For more information, see [Tagging Auto Scaling groups and instances](https://docs.aws.amazon.com/autoscaling/ec2/userguide/autoscaling-tagging.html) in the *Amazon EC2 Auto Scaling User Guide* .", "TargetGroupARNs": "One or more Amazon Resource Names (ARN) of load balancer target groups to associate with the Auto Scaling group. Instances are registered as targets in a target group, and traffic is routed to the target group. For more information, see [Elastic Load Balancing and Amazon EC2 Auto Scaling](https://docs.aws.amazon.com/autoscaling/ec2/userguide/autoscaling-load-balancer.html) in the *Amazon EC2 Auto Scaling User Guide* .", @@ -5091,9 +5226,9 @@ "MemoryGiBPerVCpu": "The minimum and maximum amount of memory per vCPU for an instance type, in GiB.\n\nDefault: No minimum or maximum", "MemoryMiB": "The minimum and maximum instance memory size for an instance type, in MiB.", "NetworkInterfaceCount": "The minimum and maximum number of network interfaces for an instance type.\n\nDefault: No minimum or maximum", - "OnDemandMaxPricePercentageOverLowestPrice": "The price protection threshold for On-Demand Instances. This is the maximum you\u2019ll pay for an On-Demand Instance, expressed as a percentage higher than the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 Auto Scaling selects instance types with your attributes, we will exclude instance types whose price is higher than your threshold. The parameter accepts an integer, which Amazon EC2 Auto Scaling interprets as a percentage. To turn off price protection, specify a high value, such as `999999` .\n\nDefault: `20`", + "OnDemandMaxPricePercentageOverLowestPrice": "The price protection threshold for On-Demand Instances. This is the maximum you\u2019ll pay for an On-Demand Instance, expressed as a percentage higher than the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 Auto Scaling selects instance types with your attributes, we will exclude instance types whose price is higher than your threshold. The parameter accepts an integer, which Amazon EC2 Auto Scaling interprets as a percentage. To turn off price protection, specify a high value, such as `999999` .\n\nIf you set `DesiredCapacityType` to `vcpu` or `memory-mib` , the price protection threshold is applied based on the per vCPU or per memory price instead of the per instance price.\n\nDefault: `20`", "RequireHibernateSupport": "Indicates whether instance types must provide On-Demand Instance hibernation support.\n\nDefault: `false`", - "SpotMaxPricePercentageOverLowestPrice": "The price protection threshold for Spot Instances. This is the maximum you\u2019ll pay for a Spot Instance, expressed as a percentage higher than the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 Auto Scaling selects instance types with your attributes, we will exclude instance types whose price is higher than your threshold. The parameter accepts an integer, which Amazon EC2 Auto Scaling interprets as a percentage. To turn off price protection, specify a high value, such as `999999` .\n\nDefault: `100`", + "SpotMaxPricePercentageOverLowestPrice": "The price protection threshold for Spot Instances. This is the maximum you\u2019ll pay for a Spot Instance, expressed as a percentage higher than the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 Auto Scaling selects instance types with your attributes, we will exclude instance types whose price is higher than your threshold. The parameter accepts an integer, which Amazon EC2 Auto Scaling interprets as a percentage. To turn off price protection, specify a high value, such as `999999` .\n\nIf you set `DesiredCapacityType` to `vcpu` or `memory-mib` , the price protection threshold is applied based on the per vCPU or per memory price instead of the per instance price.\n\nDefault: `100`", "TotalLocalStorageGB": "The minimum and maximum total local storage size for an instance type, in GB.\n\nDefault: No minimum or maximum", "VCpuCount": "The minimum and maximum number of vCPUs for an instance type." } @@ -5124,7 +5259,7 @@ "properties": { "InstanceRequirements": "The instance requirements. When you specify instance requirements, Amazon EC2 Auto Scaling finds instance types that satisfy your requirements, and then uses your On-Demand and Spot allocation strategies to launch instances from these instance types, in the same way as when you specify a list of specific instance types.\n\n> `InstanceRequirements` are incompatible with the `InstanceType` property. If you specify both of these properties, Amazon EC2 Auto Scaling will return a `ValidationException` exception.", "InstanceType": "The instance type, such as `m3.xlarge` . You must use an instance type that is supported in your requested Region and Availability Zones. For more information, see [Available instance types](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html#AvailableInstanceTypes) in the *Amazon EC2 User Guide for Linux Instances.*", - "LaunchTemplateSpecification": "Provides the launch template to be used when launching the instance type specified in `InstanceType` . For example, some instance types might require a launch template with a different AMI. If not provided, Amazon EC2 Auto Scaling uses the launch template that's defined for your mixed instances policy. For more information, see [Specifying a different launch template for an instance type](https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-mixed-instances-groups-launch-template-overrides.html) in the *Amazon EC2 Auto Scaling User Guide* .", + "LaunchTemplateSpecification": "Provides a launch template for the specified instance type or instance requirements. For example, some instance types might require a launch template with a different AMI. If not provided, Amazon EC2 Auto Scaling uses the launch template that's defined for your mixed instances policy. For more information, see [Specifying a different launch template for an instance type](https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-mixed-instances-groups-launch-template-overrides.html) in the *Amazon EC2 Auto Scaling User Guide* .", "WeightedCapacity": "The number of capacity units provided by the instance type specified in `InstanceType` in terms of virtual CPUs, memory, storage, throughput, or other relative performance characteristic. When a Spot or On-Demand Instance is provisioned, the capacity units count toward the desired capacity. Amazon EC2 Auto Scaling provisions instances until the desired capacity is totally fulfilled, even if this results in an overage. For example, if there are 2 units remaining to fulfill capacity, and Amazon EC2 Auto Scaling can only provision an instance with a `WeightedCapacity` of 5 units, the instance is provisioned, and the desired capacity is exceeded by 3 units. For more information, see [Instance weighting for Amazon EC2 Auto Scaling](https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-mixed-instances-groups-instance-weighting.html) in the *Amazon EC2 Auto Scaling User Guide* . Value must be in the range of 1-999.\n\n> Every Auto Scaling group has three size parameters ( `DesiredCapacity` , `MaxSize` , and `MinSize` ). Usually, you set these sizes based on a specific number of instances. However, if you configure a mixed instances policy that defines weights for the instance types, you must specify these sizes with the same units that you use for weighting instances." } }, @@ -5231,8 +5366,8 @@ "properties": { "AssociatePublicIpAddress": "For Auto Scaling groups that are running in a virtual private cloud (VPC), specifies whether to assign a public IP address to the group's instances. If you specify `true` , each instance in the Auto Scaling group receives a unique public IP address. For more information, see [Launching Auto Scaling instances in a VPC](https://docs.aws.amazon.com/autoscaling/ec2/userguide/asg-in-vpc.html) in the *Amazon EC2 Auto Scaling User Guide* .\n\nIf an instance receives a public IP address and is also in a VPC that is defined in the same stack template, you must use the [DependsOn attribute](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-dependson.html) to declare a dependency on the [VPC-gateway attachment](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpc-gateway-attachment.html) .\n\n> If the instance is launched into a default subnet, the default is to assign a public IP address, unless you disabled the option to assign a public IP address on the subnet. If the instance is launched into a nondefault subnet, the default is not to assign a public IP address, unless you enabled the option to assign a public IP address on the subnet.", "BlockDeviceMappings": "Specifies how block devices are exposed to the instance. You can specify virtual devices and EBS volumes.", - "ClassicLinkVPCId": "The ID of a ClassicLink-enabled VPC to link your EC2-Classic instances to.\n\nFor more information, see [ClassicLink](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/vpc-classiclink.html) in the *Amazon EC2 User Guide for Linux Instances* and [Linking EC2-Classic instances to a VPC](https://docs.aws.amazon.com/autoscaling/ec2/userguide/asg-in-vpc.html#as-ClassicLink) in the *Amazon EC2 Auto Scaling User Guide* .\n\nThis property can only be used if you are launching EC2-Classic instances.", - "ClassicLinkVPCSecurityGroups": "The IDs of one or more security groups for the VPC that you specified in the `ClassicLinkVPCId` property.\n\nIf you specify the `ClassicLinkVPCId` property, you must specify this property.", + "ClassicLinkVPCId": "*EC2-Classic retires on August 15, 2022. This parameter is not supported after that date.*\n\nThe ID of a ClassicLink-enabled VPC to link your EC2-Classic instances to.", + "ClassicLinkVPCSecurityGroups": "*EC2-Classic retires on August 15, 2022. This parameter is not supported after that date.*\n\nThe IDs of one or more security groups for the VPC that you specified in the `ClassicLinkVPCId` property.\n\nIf you specify the `ClassicLinkVPCId` property, you must specify this property.", "EbsOptimized": "Specifies whether the launch configuration is optimized for EBS I/O ( `true` ) or not ( `false` ). This optimization provides dedicated throughput to Amazon EBS and an optimized configuration stack to provide optimal EBS I/O performance. Additional fees are incurred when you enable EBS optimization for an instance type that is not EBS-optimized by default. For more information, see [Amazon EBS\u2013optimized instances](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSOptimized.html) in the *Amazon EC2 User Guide for Linux Instances* .\n\nThe default value is `false` .", "IamInstanceProfile": "Provides the name or the Amazon Resource Name (ARN) of the instance profile associated with the IAM role for the instance. The instance profile contains the IAM role.\n\nFor more information, see [IAM role for applications that run on Amazon EC2 instances](https://docs.aws.amazon.com/autoscaling/ec2/userguide/us-iam-role.html) in the *Amazon EC2 Auto Scaling User Guide* .", "ImageId": "Provides the unique ID of the Amazon Machine Image (AMI) that was assigned during registration. For more information, see [Finding a Linux AMI](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html) in the *Amazon EC2 User Guide for Linux Instances* .", @@ -5311,7 +5446,7 @@ "MetricAggregationType": "The aggregation type for the CloudWatch metrics. The valid values are `Minimum` , `Maximum` , and `Average` . If the aggregation type is null, the value is treated as `Average` .\n\nValid only if the policy type is `StepScaling` .", "MinAdjustmentMagnitude": "The minimum value to scale by when the adjustment type is `PercentChangeInCapacity` . For example, suppose that you create a step scaling policy to scale out an Auto Scaling group by 25 percent and you specify a `MinAdjustmentMagnitude` of 2. If the group has 4 instances and the scaling policy is performed, 25 percent of 4 is 1. However, because you specified a `MinAdjustmentMagnitude` of 2, Amazon EC2 Auto Scaling scales out the group by 2 instances.\n\nValid only if the policy type is `StepScaling` or `SimpleScaling` . For more information, see [Scaling adjustment types](https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-scaling-simple-step.html#as-scaling-adjustment) in the *Amazon EC2 Auto Scaling User Guide* .\n\n> Some Auto Scaling groups use instance weights. In this case, set the `MinAdjustmentMagnitude` to a value that is at least as large as your largest instance weight.", "PolicyType": "One of the following policy types:\n\n- `TargetTrackingScaling`\n- `StepScaling`\n- `SimpleScaling` (default)\n- `PredictiveScaling`\n\nFor more information, see [Target tracking scaling policies](https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-scaling-target-tracking.html) and [Step and simple scaling policies](https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-scaling-simple-step.html) in the *Amazon EC2 Auto Scaling User Guide* .", - "PredictiveScalingConfiguration": "A predictive scaling policy. Includes support for predefined metrics only.", + "PredictiveScalingConfiguration": "A predictive scaling policy. Provides support for predefined and custom metrics.\n\nPredefined metrics include CPU utilization, network in/out, and the Application Load Balancer request count.", "ScalingAdjustment": "The amount by which to scale, based on the specified adjustment type. A positive value adds to the current capacity while a negative number removes from the current capacity. For exact capacity, you must specify a positive value.\n\nRequired if the policy type is `SimpleScaling` . (Not used with any other policy type.)", "StepAdjustments": "A set of adjustments that enable you to scale based on the size of the alarm breach.\n\nRequired if the policy type is `StepScaling` . (Not used with any other policy type.)", "TargetTrackingConfiguration": "A target tracking scaling policy. Includes support for predefined or customized metrics.\n\nThe following predefined metrics are available:\n\n- `ASGAverageCPUUtilization`\n- `ASGAverageNetworkIn`\n- `ASGAverageNetworkOut`\n- `ALBRequestCountPerTarget`\n\nIf you specify `ALBRequestCountPerTarget` for the metric, you must specify the `ResourceLabel` property with the `PredefinedMetricSpecification` ." @@ -5328,6 +5463,26 @@ "Unit": "The unit of the metric. For a complete list of the units that CloudWatch supports, see the [MetricDatum](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_MetricDatum.html) data type in the *Amazon CloudWatch API Reference* ." } }, + "AWS::AutoScaling::ScalingPolicy.Metric": { + "attributes": {}, + "description": "Represents a specific metric.\n\n`Metric` is a property of the [AWS::AutoScaling::ScalingPolicy MetricStat](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricstat.html) property type.", + "properties": { + "Dimensions": "The dimensions for the metric. For the list of available dimensions, see the AWS documentation available from the table in [AWS services that publish CloudWatch metrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/aws-services-cloudwatch-metrics.html) in the *Amazon CloudWatch User Guide* .\n\nConditional: If you published your metric with dimensions, you must specify the same dimensions in your scaling policy.", + "MetricName": "The name of the metric.", + "Namespace": "The namespace of the metric. For more information, see the table in [AWS services that publish CloudWatch metrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/aws-services-cloudwatch-metrics.html) in the *Amazon CloudWatch User Guide* ." + } + }, + "AWS::AutoScaling::ScalingPolicy.MetricDataQuery": { + "attributes": {}, + "description": "The metric data to return. Also defines whether this call is returning data for one metric only, or whether it is performing a math expression on the values of returned metric statistics to create a new time series. A time series is a series of data points, each of which is associated with a timestamp.\n\n`MetricDataQuery` is a property of the following property types:\n\n- [AWS::AutoScaling::ScalingPolicy PredictiveScalingCustomizedScalingMetric](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingcustomizedscalingmetric.html)\n- [AWS::AutoScaling::ScalingPolicy PredictiveScalingCustomizedLoadMetric](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingcustomizedloadmetric.html)\n- [AWS::AutoScaling::ScalingPolicy PredictiveScalingCustomizedCapacityMetric](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingcustomizedcapacitymetric.html)\n\nPredictive scaling uses the time series data received from CloudWatch to understand how to schedule capacity based on your historical workload patterns.\n\nYou can call for a single metric or perform math expressions on multiple metrics. Any expressions used in a metric specification must eventually return a single time series.\n\nFor more information and examples, see [Advanced predictive scaling policy configurations using custom metrics](https://docs.aws.amazon.com/autoscaling/ec2/userguide/predictive-scaling-customized-metric-specification.html) in the *Amazon EC2 Auto Scaling User Guide* .", + "properties": { + "Expression": "The math expression to perform on the returned data, if this object is performing a math expression. This expression can use the `Id` of the other metrics to refer to those metrics, and can also use the `Id` of other expressions to use the result of those expressions.\n\nConditional: Within each `MetricDataQuery` object, you must specify either `Expression` or `MetricStat` , but not both.", + "Id": "A short name that identifies the object's results in the response. This name must be unique among all `MetricDataQuery` objects specified for a single scaling policy. If you are performing math expressions on this set of data, this name represents that data and can serve as a variable in the mathematical expression. The valid characters are letters, numbers, and underscores. The first character must be a lowercase letter.", + "Label": "A human-readable label for this metric or expression. This is especially useful if this is a math expression, so that you know what the value represents.", + "MetricStat": "Information about the metric data to return.\n\nConditional: Within each `MetricDataQuery` object, you must specify either `Expression` or `MetricStat` , but not both.", + "ReturnData": "Indicates whether to return the timestamps and raw data values of this metric.\n\nIf you use any math expressions, specify `true` for this value for only the final math expression that the metric specification is based on. You must specify `false` for `ReturnData` for all the other metrics and expressions used in the metric specification.\n\nIf you are only retrieving metrics and not performing any math expressions, do not specify anything for `ReturnData` . This sets it to its default ( `true` )." + } + }, "AWS::AutoScaling::ScalingPolicy.MetricDimension": { "attributes": {}, "description": "`MetricDimension` specifies a name/value pair that is part of the identity of a CloudWatch metric for the `Dimensions` property of the [AWS::AutoScaling::ScalingPolicy CustomizedMetricSpecification](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-customizedmetricspecification.html) property type. Duplicate dimensions are not allowed.", @@ -5336,6 +5491,15 @@ "Value": "The value of the dimension." } }, + "AWS::AutoScaling::ScalingPolicy.MetricStat": { + "attributes": {}, + "description": "`MetricStat` is a property of the [AWS::AutoScaling::ScalingPolicy MetricDataQuery](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricdataquery.html) property type.\n\nThis structure defines the CloudWatch metric to return, along with the statistic, period, and unit.\n\nFor more information about the CloudWatch terminology below, see [Amazon CloudWatch concepts](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_concepts.html) in the *Amazon CloudWatch User Guide* .", + "properties": { + "Metric": "The CloudWatch metric to return, including the metric name, namespace, and dimensions. To get the exact metric name, namespace, and dimensions, inspect the [Metric](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_Metric.html) object that is returned by a call to [ListMetrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_ListMetrics.html) .", + "Stat": "The statistic to return. It can include any CloudWatch statistic or extended statistic. For a list of valid values, see the table in [Statistics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_concepts.html#Statistic) in the *Amazon CloudWatch User Guide* .\n\nThe most commonly used metrics for predictive scaling are `Average` and `Sum` .", + "Unit": "The unit to use for the returned data points. For a complete list of the units that CloudWatch supports, see the [MetricDatum](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_MetricDatum.html) data type in the *Amazon CloudWatch API Reference* ." + } + }, "AWS::AutoScaling::ScalingPolicy.PredefinedMetricSpecification": { "attributes": {}, "description": "Contains predefined metric specification information for a target tracking scaling policy for Amazon EC2 Auto Scaling.\n\n`PredefinedMetricSpecification` is a property of the [AWS::AutoScaling::ScalingPolicy TargetTrackingConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-targettrackingconfiguration.html) property type.", @@ -5355,10 +5519,34 @@ "SchedulingBufferTime": "The amount of time, in seconds, by which the instance launch time can be advanced. For example, the forecast says to add capacity at 10:00 AM, and you choose to pre-launch instances by 5 minutes. In that case, the instances will be launched at 9:55 AM. The intention is to give resources time to be provisioned. It can take a few minutes to launch an EC2 instance. The actual amount of time required depends on several factors, such as the size of the instance and whether there are startup scripts to complete.\n\nThe value must be less than the forecast interval duration of 3600 seconds (60 minutes). Defaults to 300 seconds if not specified." } }, + "AWS::AutoScaling::ScalingPolicy.PredictiveScalingCustomizedCapacityMetric": { + "attributes": {}, + "description": "Contains capacity metric information for the `CustomizedCapacityMetricSpecification` property of the [AWS::AutoScaling::ScalingPolicy PredictiveScalingMetricSpecification](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingmetricspecification.html) property type.", + "properties": { + "MetricDataQueries": "One or more metric data queries to provide the data points for a capacity metric. Use multiple metric data queries only if you are performing a math expression on returned data." + } + }, + "AWS::AutoScaling::ScalingPolicy.PredictiveScalingCustomizedLoadMetric": { + "attributes": {}, + "description": "Contains load metric information for the `CustomizedLoadMetricSpecification` property of the [AWS::AutoScaling::ScalingPolicy PredictiveScalingMetricSpecification](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingmetricspecification.html) property type.", + "properties": { + "MetricDataQueries": "One or more metric data queries to provide the data points for a load metric. Use multiple metric data queries only if you are performing a math expression on returned data." + } + }, + "AWS::AutoScaling::ScalingPolicy.PredictiveScalingCustomizedScalingMetric": { + "attributes": {}, + "description": "Contains scaling metric information for the `CustomizedScalingMetricSpecification` property of the [AWS::AutoScaling::ScalingPolicy PredictiveScalingMetricSpecification](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingmetricspecification.html) property type.", + "properties": { + "MetricDataQueries": "One or more metric data queries to provide the data points for a scaling metric. Use multiple metric data queries only if you are performing a math expression on returned data." + } + }, "AWS::AutoScaling::ScalingPolicy.PredictiveScalingMetricSpecification": { "attributes": {}, "description": "A structure that specifies a metric specification for the `MetricSpecifications` property of the [AWS::AutoScaling::ScalingPolicy PredictiveScalingConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingconfiguration.html) property type.\n\nFor more information, see [Predictive scaling](https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-predictive-scaling.html) in the *Amazon EC2 Auto Scaling User Guide* .", "properties": { + "CustomizedCapacityMetricSpecification": "The customized capacity metric specification.", + "CustomizedLoadMetricSpecification": "The customized load metric specification.", + "CustomizedScalingMetricSpecification": "The customized scaling metric specification.", "PredefinedLoadMetricSpecification": "The load metric specification.\n\nIf you specify `PredefinedMetricPairSpecification` , don't specify this property.", "PredefinedMetricPairSpecification": "The metric pair specification from which Amazon EC2 Auto Scaling determines the appropriate scaling metric and load metric to use.\n\n> With predictive scaling, you must specify either a metric pair, or a load metric and a scaling metric individually. Specifying a metric pair instead of individual metrics provides a simpler way to configure metrics for a scaling policy. You choose the metric pair, and the policy automatically knows the correct sum and average statistics to use for the load metric and the scaling metric.", "PredefinedScalingMetricSpecification": "The scaling metric specification.\n\nIf you specify `PredefinedMetricPairSpecification` , don't specify this property.", @@ -5429,7 +5617,7 @@ "description": "The `AWS::AutoScaling::WarmPool` resource creates a pool of pre-initialized EC2 instances that sits alongside the Auto Scaling group. Whenever your application needs to scale out, the Auto Scaling group can draw on the warm pool to meet its new desired capacity.\n\nWhen you create a warm pool, you can define a minimum size. When your Auto Scaling group scales out and the size of the warm pool shrinks, Amazon EC2 Auto Scaling launches new instances into the warm pool to maintain its minimum size.\n\nFor more information, see [Warm pools for Amazon EC2 Auto Scaling](https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-warm-pools.html) in the *Amazon EC2 Auto Scaling User Guide* .\n\n> CloudFormation supports the `UpdatePolicy` attribute for Auto Scaling groups. During an update, if `UpdatePolicy` is set to `AutoScalingRollingUpdate` , CloudFormation replaces `InService` instances only. Instances in the warm pool are not replaced. The difference in which instances are replaced can potentially result in different instance configurations after the stack update completes. If `UpdatePolicy` is set to `AutoScalingReplacingUpdate` , you do not encounter this issue because CloudFormation replaces both the Auto Scaling group and the warm pool.", "properties": { "AutoScalingGroupName": "The name of the Auto Scaling group.", - "InstanceReusePolicy": "", + "InstanceReusePolicy": "Indicates whether instances in the Auto Scaling group can be returned to the warm pool on scale in. The default is to terminate instances in the Auto Scaling group when the group scales in.", "MaxGroupPreparedCapacity": "Specifies the maximum number of instances that are allowed to be in the warm pool or in any state except `Terminated` for the Auto Scaling group. This is an optional property. Specify it only if you do not want the warm pool size to be determined by the difference between the group's maximum capacity and its desired capacity.\n\n> If a value for `MaxGroupPreparedCapacity` is not specified, Amazon EC2 Auto Scaling launches and maintains the difference between the group's maximum capacity and its desired capacity. If you specify a value for `MaxGroupPreparedCapacity` , Amazon EC2 Auto Scaling uses the difference between the `MaxGroupPreparedCapacity` and the desired capacity instead.\n> \n> The size of the warm pool is dynamic. Only when `MaxGroupPreparedCapacity` and `MinSize` are set to the same value does the warm pool have an absolute size. \n\nIf the desired capacity of the Auto Scaling group is higher than the `MaxGroupPreparedCapacity` , the capacity of the warm pool is 0, unless you specify a value for `MinSize` . To remove a value that you previously set, include the property but specify -1 for the value.", "MinSize": "Specifies the minimum number of instances to maintain in the warm pool. This helps you to ensure that there is always a certain number of warmed instances available to handle traffic spikes. Defaults to 0 if not specified.", "PoolState": "Sets the instance state to transition to after the lifecycle actions are complete. Default is `Stopped` ." @@ -5437,9 +5625,9 @@ }, "AWS::AutoScaling::WarmPool.InstanceReusePolicy": { "attributes": {}, - "description": "", + "description": "A structure that specifies an instance reuse policy for the `InstanceReusePolicy` property of the [AWS::AutoScaling::WarmPool](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-warmpool.html) resource type.\n\nFor more information, see [Warm pools for Amazon EC2 Auto Scaling](https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-warm-pools.html) in the *Amazon EC2 Auto Scaling User Guide* .", "properties": { - "ReuseOnScaleIn": "" + "ReuseOnScaleIn": "Specifies whether instances in the Auto Scaling group can be returned to the warm pool on scale in." } }, "AWS::AutoScalingPlans::ScalingPlan": { @@ -5653,7 +5841,7 @@ "AccessPolicy": "A resource-based policy that is used to manage access permissions on the target backup vault.", "BackupVaultName": "The name of a logical container where backups are stored. Backup vaults are identified by names that are unique to the account used to create them and the AWS Region where they are created. They consist of lowercase letters, numbers, and hyphens.", "BackupVaultTags": "Metadata that you can assign to help organize the resources that you create. Each tag is a key-value pair.", - "EncryptionKeyArn": "The server-side encryption key that is used to protect your backups; for example, `arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab` .", + "EncryptionKeyArn": "A server-side encryption key you can specify to encrypt your backups from services that support full AWS Backup management; for example, `arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab` . If you specify a key, you must specify its ARN, not its alias. If you do not specify a key, AWS Backup creates a KMS key for you by default.\n\nTo learn which AWS Backup services support full AWS Backup management and how AWS Backup handles encryption for backups from services that do not yet support full AWS Backup , see [Encryption for backups in AWS Backup](https://docs.aws.amazon.com/aws-backup/latest/devguide/encryption.html)", "LockConfiguration": "Configuration for [AWS Backup Vault Lock](https://docs.aws.amazon.com/aws-backup/latest/devguide/vault-lock.html) .", "Notifications": "The SNS event notifications for the specified backup vault." } @@ -5734,21 +5922,21 @@ }, "AWS::Budgets::Budget.BudgetData": { "attributes": {}, - "description": "Represents the output of the `CreateBudget` operation. The content consists of the detailed metadata and data file information, and the current status of the `budget` object.\n\nThis is the ARN pattern for a budget:\n\n`arn:aws:budgets::AccountId:budget/budgetName`", + "description": "Represents the output of the `CreateBudget` operation. The content consists of the detailed metadata and data file information, and the current status of the `budget` object.\n\nThis is the Amazon Resource Name (ARN) pattern for a budget:\n\n`arn:aws:budgets::AccountId:budget/budgetName`", "properties": { - "BudgetLimit": "The total amount of cost, usage, RI utilization, RI coverage, Savings Plans utilization, or Savings Plans coverage that you want to track with your budget.\n\n`BudgetLimit` is required for cost or usage budgets, but optional for RI or Savings Plans utilization or coverage budgets. RI and Savings Plans utilization or coverage budgets default to `100` , which is the only valid value for RI or Savings Plans utilization or coverage budgets. You can't use `BudgetLimit` with `PlannedBudgetLimits` for `CreateBudget` and `UpdateBudget` actions.", + "BudgetLimit": "The total amount of cost, usage, RI utilization, RI coverage, Savings Plans utilization, or Savings Plans coverage that you want to track with your budget.\n\n`BudgetLimit` is required for cost or usage budgets, but optional for RI or Savings Plans utilization or coverage budgets. RI and Savings Plans utilization or coverage budgets default to `100` . This is the only valid value for RI or Savings Plans utilization or coverage budgets. You can't use `BudgetLimit` with `PlannedBudgetLimits` for `CreateBudget` and `UpdateBudget` actions.", "BudgetName": "The name of a budget. The value must be unique within an account. `BudgetName` can't include `:` and `\\` characters. If you don't include value for `BudgetName` in the template, Billing and Cost Management assigns your budget a randomly generated name.", - "BudgetType": "Whether this budget tracks costs, usage, RI utilization, RI coverage, Savings Plans utilization, or Savings Plans coverage.", + "BudgetType": "Specifies whether this budget tracks costs, usage, RI utilization, RI coverage, Savings Plans utilization, or Savings Plans coverage.", "CostFilters": "The cost filters, such as `Region` , `Service` , `member account` , `Tag` , or `Cost Category` , that are applied to a budget.\n\nAWS Budgets supports the following services as a `Service` filter for RI budgets:\n\n- Amazon EC2\n- Amazon Redshift\n- Amazon Relational Database Service\n- Amazon ElastiCache\n- Amazon OpenSearch Service", "CostTypes": "The types of costs that are included in this `COST` budget.\n\n`USAGE` , `RI_UTILIZATION` , `RI_COVERAGE` , `SAVINGS_PLANS_UTILIZATION` , and `SAVINGS_PLANS_COVERAGE` budgets do not have `CostTypes` .", - "PlannedBudgetLimits": "A map containing multiple `BudgetLimit` , including current or future limits.\n\n`PlannedBudgetLimits` is available for cost or usage budget and supports monthly and quarterly `TimeUnit` .\n\nFor monthly budgets, provide 12 months of `PlannedBudgetLimits` values. This must start from the current month and include the next 11 months. The `key` is the start of the month, `UTC` in epoch seconds.\n\nFor quarterly budgets, provide 4 quarters of `PlannedBudgetLimits` value entries in standard calendar quarter increments. This must start from the current quarter and include the next 3 quarters. The `key` is the start of the quarter, `UTC` in epoch seconds.\n\nIf the planned budget expires before 12 months for monthly or 4 quarters for quarterly, provide the `PlannedBudgetLimits` values only for the remaining periods.\n\nIf the budget begins at a date in the future, provide `PlannedBudgetLimits` values from the start date of the budget.\n\nAfter all of the `BudgetLimit` values in `PlannedBudgetLimits` are used, the budget continues to use the last limit as the `BudgetLimit` . At that point, the planned budget provides the same experience as a fixed budget.\n\n`DescribeBudget` and `DescribeBudgets` response along with `PlannedBudgetLimits` will also contain `BudgetLimit` representing the current month or quarter limit present in `PlannedBudgetLimits` . This only applies to budgets created with `PlannedBudgetLimits` . Budgets created without `PlannedBudgetLimits` will only contain `BudgetLimit` , and no `PlannedBudgetLimits` .", + "PlannedBudgetLimits": "A map containing multiple `BudgetLimit` , including current or future limits.\n\n`PlannedBudgetLimits` is available for cost or usage budget and supports both monthly and quarterly `TimeUnit` .\n\nFor monthly budgets, provide 12 months of `PlannedBudgetLimits` values. This must start from the current month and include the next 11 months. The `key` is the start of the month, `UTC` in epoch seconds.\n\nFor quarterly budgets, provide four quarters of `PlannedBudgetLimits` value entries in standard calendar quarter increments. This must start from the current quarter and include the next three quarters. The `key` is the start of the quarter, `UTC` in epoch seconds.\n\nIf the planned budget expires before 12 months for monthly or four quarters for quarterly, provide the `PlannedBudgetLimits` values only for the remaining periods.\n\nIf the budget begins at a date in the future, provide `PlannedBudgetLimits` values from the start date of the budget.\n\nAfter all of the `BudgetLimit` values in `PlannedBudgetLimits` are used, the budget continues to use the last limit as the `BudgetLimit` . At that point, the planned budget provides the same experience as a fixed budget.\n\n`DescribeBudget` and `DescribeBudgets` response along with `PlannedBudgetLimits` also contain `BudgetLimit` representing the current month or quarter limit present in `PlannedBudgetLimits` . This only applies to budgets that are created with `PlannedBudgetLimits` . Budgets that are created without `PlannedBudgetLimits` only contain `BudgetLimit` . They don't contain `PlannedBudgetLimits` .", "TimePeriod": "The period of time that is covered by a budget. The period has a start date and an end date. The start date must come before the end date. There are no restrictions on the end date.\n\nThe start date for a budget. If you created your budget and didn't specify a start date, the start date defaults to the start of the chosen time period (MONTHLY, QUARTERLY, or ANNUALLY). For example, if you create your budget on January 24, 2019, choose `MONTHLY` , and don't set a start date, the start date defaults to `01/01/19 00:00 UTC` . The defaults are the same for the AWS Billing and Cost Management console and the API.\n\nYou can change your start date with the `UpdateBudget` operation.\n\nAfter the end date, AWS deletes the budget and all associated notifications and subscribers.", "TimeUnit": "The length of time until a budget resets the actual and forecasted spend. `DAILY` is available only for `RI_UTILIZATION` and `RI_COVERAGE` budgets." } }, "AWS::Budgets::Budget.CostTypes": { "attributes": {}, - "description": "The types of cost that are included in a `COST` budget, such as tax and subscriptions.\n\n`USAGE` , `RI_UTILIZATION` , `RI_COVERAGE` , `SAVINGS_PLANS_UTILIZATION` , and `SAVINGS_PLANS_COVERAGE` budgets do not have `CostTypes` .", + "description": "The types of cost that are included in a `COST` budget, such as tax and subscriptions.\n\n`USAGE` , `RI_UTILIZATION` , `RI_COVERAGE` , `SAVINGS_PLANS_UTILIZATION` , and `SAVINGS_PLANS_COVERAGE` budgets don't have `CostTypes` .", "properties": { "IncludeCredit": "Specifies whether a budget includes credits.\n\nThe default value is `true` .", "IncludeDiscount": "Specifies whether a budget includes discounts.\n\nThe default value is `true` .", @@ -5765,11 +5953,11 @@ }, "AWS::Budgets::Budget.Notification": { "attributes": {}, - "description": "A notification that is associated with a budget. A budget can have up to ten notifications.\n\nEach notification must have at least one subscriber. A notification can have one SNS subscriber and up to 10 email subscribers, for a total of 11 subscribers.\n\nFor example, if you have a budget for 200 dollars and you want to be notified when you go over 160 dollars, create a notification with the following parameters:\n\n- A notificationType of `ACTUAL`\n- A `thresholdType` of `PERCENTAGE`\n- A `comparisonOperator` of `GREATER_THAN`\n- A notification `threshold` of `80`", + "description": "A notification that's associated with a budget. A budget can have up to ten notifications.\n\nEach notification must have at least one subscriber. A notification can have one SNS subscriber and up to 10 email subscribers, for a total of 11 subscribers.\n\nFor example, if you have a budget for 200 dollars and you want to be notified when you go over 160 dollars, create a notification with the following parameters:\n\n- A notificationType of `ACTUAL`\n- A `thresholdType` of `PERCENTAGE`\n- A `comparisonOperator` of `GREATER_THAN`\n- A notification `threshold` of `80`", "properties": { - "ComparisonOperator": "The comparison that is used for this notification.", - "NotificationType": "Whether the notification is for how much you have spent ( `ACTUAL` ) or for how much you're forecasted to spend ( `FORECASTED` ).", - "Threshold": "The threshold that is associated with a notification. Thresholds are always a percentage, and many customers find value being alerted between 50% - 200% of the budgeted amount. The maximum limit for your threshold is 1,000,000% above the budgeted amount.", + "ComparisonOperator": "The comparison that's used for this notification.", + "NotificationType": "Specifies whether the notification is for how much you have spent ( `ACTUAL` ) or for how much that you're forecasted to spend ( `FORECASTED` ).", + "Threshold": "The threshold that's associated with a notification. Thresholds are always a percentage, and many customers find value being alerted between 50% - 200% of the budgeted amount. The maximum limit for your threshold is 1,000,000% above the budgeted amount.", "ThresholdType": "The type of threshold for a notification. For `ABSOLUTE_VALUE` thresholds, AWS notifies you when you go over or are forecasted to go over your total cost threshold. For `PERCENTAGE` thresholds, AWS notifies you when you go over or are forecasted to go over a certain percentage of your forecasted spend. For example, if you have a budget for 200 dollars and you have a `PERCENTAGE` threshold of 80%, AWS notifies you when you go over 160 dollars." } }, @@ -5777,16 +5965,16 @@ "attributes": {}, "description": "A notification with subscribers. A notification can have one SNS subscriber and up to 10 email subscribers, for a total of 11 subscribers.", "properties": { - "Notification": "The notification that is associated with a budget.", + "Notification": "The notification that's associated with a budget.", "Subscribers": "A list of subscribers who are subscribed to this notification." } }, "AWS::Budgets::Budget.Spend": { "attributes": {}, - "description": "The amount of cost or usage that is measured for a budget.\n\nFor example, a `Spend` for `3 GB` of S3 usage would have the following parameters:\n\n- An `Amount` of `3`\n- A `unit` of `GB`", + "description": "The amount of cost or usage that's measured for a budget.\n\nFor example, a `Spend` for `3 GB` of S3 usage has the following parameters:\n\n- An `Amount` of `3`\n- A `unit` of `GB`", "properties": { - "Amount": "The cost or usage amount that is associated with a budget forecast, actual spend, or budget threshold.", - "Unit": "The unit of measurement that is used for the budget forecast, actual spend, or budget threshold, such as USD or GB." + "Amount": "The cost or usage amount that's associated with a budget forecast, actual spend, or budget threshold.", + "Unit": "The unit of measurement that's used for the budget forecast, actual spend, or budget threshold, such as USD or GBP." } }, "AWS::Budgets::Budget.Subscriber": { @@ -5801,7 +5989,7 @@ "attributes": {}, "description": "The period of time that is covered by a budget. The period has a start date and an end date. The start date must come before the end date. There are no restrictions on the end date.", "properties": { - "End": "The end date for a budget. If you didn't specify an end date, AWS set your end date to `06/15/87 00:00 UTC` . The defaults are the same for the AWS Billing and Cost Management console and the API.\n\nAfter the end date, AWS deletes the budget and all associated notifications and subscribers. You can change your end date with the `UpdateBudget` operation.", + "End": "The end date for a budget. If you didn't specify an end date, AWS set your end date to `06/15/87 00:00 UTC` . The defaults are the same for the AWS Billing and Cost Management console and the API.\n\nAfter the end date, AWS deletes the budget and all the associated notifications and subscribers. You can change your end date with the `UpdateBudget` operation.", "Start": "The start date for a budget. If you created your budget and didn't specify a start date, the start date defaults to the start of the chosen time period (MONTHLY, QUARTERLY, or ANNUALLY). For example, if you create your budget on January 24, 2019, choose `MONTHLY` , and don't set a start date, the start date defaults to `01/01/19 00:00 UTC` . The defaults are the same for the AWS Billing and Cost Management console and the API.\n\nYou can change your start date with the `UpdateBudget` operation.\n\nValid values depend on the value of `BudgetType` :\n\n- If `BudgetType` is `COST` or `USAGE` : Valid values are `MONTHLY` , `QUARTERLY` , and `ANNUALLY` .\n- If `BudgetType` is `RI_UTILIZATION` or `RI_COVERAGE` : Valid values are `DAILY` , `MONTHLY` , `QUARTERLY` , and `ANNUALLY` ." } }, @@ -5867,7 +6055,7 @@ }, "AWS::Budgets::BudgetsAction.Subscriber": { "attributes": {}, - "description": "The subscriber to a budget notification. The subscriber consists of a subscription type and either an Amazon SNS topic or an email address.\n\nFor example, an email subscriber would have the following parameters:\n\n- A `subscriptionType` of `EMAIL`\n- An `address` of `example@example.com`", + "description": "The subscriber to a budget notification. The subscriber consists of a subscription type and either an Amazon SNS topic or an email address.\n\nFor example, an email subscriber has the following parameters:\n\n- A `subscriptionType` of `EMAIL`\n- An `address` of `example@example.com`", "properties": { "Address": "The address that AWS sends budget notifications to, either an SNS topic or an email.\n\nWhen you create a subscriber, the value of `Address` can't contain line breaks.", "Type": "The type of notification that AWS sends to a subscriber." @@ -5940,7 +6128,7 @@ "BillingViewArn": "The Amazon Resource Name (ARN) of the billing view. You can get this value by using the billing view service public APIs.", "Compression": "The compression format that Amazon Web Services uses for the report.", "Format": "The format that Amazon Web Services saves the report in.", - "RefreshClosedReports": "Whether you want Amazon Web Services to update your reports after they have been finalized if Amazon Web Services detects charges related to previous months. These charges can include refunds, credits, or support fees.", + "RefreshClosedReports": "Whether you want Amazon Web Services to update your reports after they have been finalized if AWS detects charges related to previous months. These charges can include refunds, credits, or support fees.", "ReportName": "The name of the report that you want to create. The name must be unique, is case sensitive, and can't include spaces.", "ReportVersioning": "Whether you want Amazon Web Services to overwrite the previous version of each report or to deliver the report in addition to the previous versions.", "S3Bucket": "The S3 bucket where Amazon Web Services delivers the report.", @@ -6107,7 +6295,57 @@ "attributes": {}, "description": "In a CloudFormation template, you use the `AWS::CloudFormation::CustomResource` or `Custom:: *String*` resource type to specify custom resources.\n\nCustom resources provide a way for you to write custom provisioning logic in CloudFormation template and have CloudFormation run it during a stack operation, such as when you create, update or delete a stack. For more information, see [Custom resources](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html) .\n\n> If you use the [VPC endpoints](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-endpoints.html) feature, custom resources in the VPC must have access to CloudFormation -specific Amazon Simple Storage Service ( Amazon S3 ) buckets. Custom resources must send responses to a presigned Amazon S3 URL. If they can't send responses to Amazon S3 , CloudFormation won't receive a response and the stack operation fails. For more information, see [Setting up VPC endpoints for AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-vpce-bucketnames.html) .", "properties": { - "ServiceToken": "> Only one property is defined by AWS for a custom resource: `ServiceToken` . All other properties are defined by the service provider. \n\nThe service token that was given to the template developer by the service provider to access the service, such as an Amazon SNS topic ARN or Lambda function ARN. The service token must be from the same Region in which you are creating the stack.\n\nUpdates are not supported." + "ServiceToken": "> Only one property is defined by AWS for a custom resource: `ServiceToken` . All other properties are defined by the service provider. \n\nThe service token that was given to the template developer by the service provider to access the service, such as an Amazon SNS topic ARN or Lambda function ARN. The service token must be from the same Region in which you are creating the stack.\n\nUpdates aren't supported." + } + }, + "AWS::CloudFormation::HookDefaultVersion": { + "attributes": { + "Arn": "The Amazon Resource Number (ARN) of the activated extension, in this account and Region.", + "Ref": "`Ref` returns the Amazon Resource Name (ARN) of the resource version. For example:\n\n`arn:aws:cloudformation:us-west-2:012345678901:type/hook/Sample-CloudFormation-Hook/00000001`" + }, + "description": "The `HookDefaultVersion` resource specifies the default version of the hook. The default version of the hook is used in CloudFormation operations for this AWS account and AWS Region .", + "properties": { + "TypeName": "The name of the hook.\n\nYou must specify either `TypeVersionArn` , or `TypeName` and `VersionId` .", + "TypeVersionArn": "The version ID of the type configuration.\n\nYou must specify either `TypeVersionArn` , or `TypeName` and `VersionId` .", + "VersionId": "The version ID of the type specified.\n\nYou must specify either `TypeVersionArn` , or `TypeName` and `VersionId` ." + } + }, + "AWS::CloudFormation::HookTypeConfig": { + "attributes": { + "ConfigurationArn": "The Amazon Resource Number (ARN) of the activated hook type configuration, in this account and Region.", + "Ref": "`Ref` returns the ARN of the resource version. For example:\n\n`arn:aws:cloudformation:us-west-2:123456789012:type-configuration/hook/My-Sample-Hook/default`" + }, + "description": "The `HookTypeConfig` resource specifies the configuration of a hook.", + "properties": { + "Configuration": "Specifies the activated hook type configuration, in this AWS account and AWS Region .\n\nYou must specify either `TypeName` and `Configuration` or `TypeARN` and `Configuration` .", + "ConfigurationAlias": "Specifies the activated hook type configuration, in this AWS account and AWS Region .\n\nDefaults to `default` alias. Hook types currently support default configuration alias.", + "TypeArn": "The Amazon Resource Number (ARN) for the hook to set `Configuration` for.\n\nYou must specify either `TypeName` and `Configuration` or `TypeARN` and `Configuration` .", + "TypeName": "The unique name for your hook. Specifies a three-part namespace for your hook, with a recommended pattern of `Organization::Service::Hook` .\n\nYou must specify either `TypeName` and `Configuration` or `TypeARN` and `Configuration` ." + } + }, + "AWS::CloudFormation::HookVersion": { + "attributes": { + "Arn": "The Amazon Resource Name (ARN) of the hook.", + "IsDefaultVersion": "Whether the specified hook version is set as the default version.", + "Ref": "`Ref` returns the ARN of the resource version. For example:\n\n`arn:aws:cloudformation:us-west-2:012345678901:type/hook/Sample-CloudFormation-Hook/00000001`", + "TypeArn": "The Amazon Resource Number (ARN) assigned to this version of the hook.", + "VersionId": "The ID of this version of the hook.", + "Visibility": "The scope at which the resource is visible and usable in CloudFormation operations.\n\nValid values include:\n\n- `PRIVATE` : The resource is only visible and usable within the account in which it's registered. CloudFormation marks any resources you register as `PRIVATE` .\n- `PUBLIC` : The resource is publicly visible and usable within any Amazon account." + }, + "description": "The `HookVersion` resource publishes new or first hook version to the AWS CloudFormation registry.", + "properties": { + "ExecutionRoleArn": "The Amazon Resource Name (ARN) of the task execution role that grants the hook permission.", + "LoggingConfig": "Contains logging configuration information for an extension.", + "SchemaHandlerPackage": "A URL to the Amazon S3 bucket containing the hook project package that contains the necessary files for the hook you want to register.\n\nFor information on generating a schema handler package for the resource you want to register, see [submit](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/resource-type-cli-submit.html) in the *CloudFormation CLI User Guide for Extension Development* .\n\n> The user registering the resource must be able to access the package in the S3 bucket. That's, the user must have [GetObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html) permissions for the schema handler package. For more information, see [Actions, Resources, and Condition Keys for Amazon S3](https://docs.aws.amazon.com/IAM/latest/UserGuide/list_amazons3.html) in the *AWS Identity and Access Management User Guide* .", + "TypeName": "The unique name for your hook. Specifies a three-part namespace for your hook, with a recommended pattern of `Organization::Service::Hook` .\n\n> The following organization namespaces are reserved and can't be used in your hook type names:\n> \n> - `Alexa`\n> - `AMZN`\n> - `Amazon`\n> - `ASK`\n> - `AWS`\n> - `Custom`\n> - `Dev`" + } + }, + "AWS::CloudFormation::HookVersion.LoggingConfig": { + "attributes": {}, + "description": "The `LoggingConfig` property type specifies logging configuration information for an extension.", + "properties": { + "LogGroupName": "The Amazon CloudWatch Logs group to which CloudFormation sends error logging information when invoking the extension's handlers.", + "LogRoleArn": "The Amazon Resource Name (ARN) of the role that CloudFormation should assume when sending log entries to CloudWatch Logs." } }, "AWS::CloudFormation::Macro": { @@ -6118,8 +6356,8 @@ "properties": { "Description": "A description of the macro.", "FunctionName": "The Amazon Resource Name (ARN) of the underlying AWS Lambda function that you want AWS CloudFormation to invoke when the macro is run.", - "LogGroupName": "The Amazon CloudWatch log group to which AWS CloudFormation sends error logging information when invoking the macro's underlying AWS Lambda function.", - "LogRoleARN": "The ARN of the role AWS CloudFormation should assume when sending log entries to CloudWatch logs.", + "LogGroupName": "The CloudWatch Logs group to which AWS CloudFormation sends error logging information when invoking the macro's underlying AWS Lambda function.", + "LogRoleARN": "The ARN of the role AWS CloudFormation should assume when sending log entries to CloudWatch Logs .", "Name": "The name of the macro. The name of the macro must be unique across all macros in the account." } }, @@ -6127,7 +6365,7 @@ "attributes": { "Ref": "`Ref` returns the Amazon Resource Name (ARN) of the module version." }, - "description": "Specifies the default version of a module. The default version of the module will be used in CloudFormation operations for this account and region.\n\nTo register a module version, use the `[AWS::CloudFormation::ModuleVersion](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-moduleversion.html)` resource.\n\nFor more information using modules, see [Using modules to encapsulate and reuse resource configurations](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/modules.html) and [Registering extensions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/registry.html#registry-register) in the *CloudFormation User Guide* . For information on developing modules, see [Developing modules](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/modules.html) in the *CloudFormation CLI User Guide* .", + "description": "Specifies the default version of a module. The default version of the module will be used in CloudFormation operations for this account and Region.\n\nTo register a module version, use the `[AWS::CloudFormation::ModuleVersion](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-moduleversion.html)` resource.\n\nFor more information using modules, see [Using modules to encapsulate and reuse resource configurations](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/modules.html) and [Registering extensions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/registry.html#registry-register) in the *CloudFormation User Guide* . For information on developing modules, see [Developing modules](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/modules.html) in the *CloudFormation CLI User Guide* .", "properties": { "Arn": "The Amazon Resource Name (ARN) of the module version to set as the default version.\n\nConditional: You must specify either `Arn` , or `ModuleName` and `VersionId` .", "ModuleName": "The name of the module.\n\nConditional: You must specify either `Arn` , or `ModuleName` and `VersionId` .", @@ -6144,12 +6382,12 @@ "Schema": "The schema that defines the module.", "TimeCreated": "When the specified module version was registered.", "VersionId": "The ID of this version of the module.", - "Visibility": "The scope at which the module is visible and usable in CloudFormation operations.\n\nValid values include:\n\n- `PRIVATE` : The module is only visible and usable within the account in which it is registered.\n- `PUBLIC` : The module is publicly visible and usable within any Amazon account." + "Visibility": "The scope at which the module is visible and usable in CloudFormation operations.\n\nValid values include:\n\n- `PRIVATE` : The module is only visible and usable within the account in which it's registered.\n- `PUBLIC` : The module is publicly visible and usable within any Amazon account." }, - "description": "Registers the specified version of the module with the CloudFormation service. Registering a module makes it available for use in CloudFormation templates in your AWS account and region.\n\nTo specify a module version as the default version, use the `[AWS::CloudFormation::ModuleDefaultVersion](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-moduledefaultversion.html)` resource.\n\nFor more information using modules, see [Using modules to encapsulate and reuse resource configurations](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/modules.html) and [Registering extensions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/registry.html#registry-register) in the *CloudFormation User Guide* . For information on developing modules, see [Developing modules](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/modules.html) in the *CloudFormation CLI User Guide* .", + "description": "Registers the specified version of the module with the CloudFormation service. Registering a module makes it available for use in CloudFormation templates in your AWS account and Region.\n\nTo specify a module version as the default version, use the `[AWS::CloudFormation::ModuleDefaultVersion](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-moduledefaultversion.html)` resource.\n\nFor more information using modules, see [Using modules to encapsulate and reuse resource configurations](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/modules.html) and [Registering extensions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/registry.html#registry-register) in the *CloudFormation User Guide* . For information on developing modules, see [Developing modules](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/modules.html) in the *CloudFormation CLI User Guide* .", "properties": { "ModuleName": "The name of the module being registered.", - "ModulePackage": "A URL to the S3 bucket containing the package that contains the template fragment and schema files for the module version to register.\n\n> The user registering the module version must be able to access the module package in the S3 bucket. That is, the user needs to have [GetObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html) permissions for the package. For more information, see [Actions, Resources, and Condition Keys for Amazon S3](https://docs.aws.amazon.com/IAM/latest/UserGuide/list_amazons3.html) in the *AWS Identity and Access Management User Guide* ." + "ModulePackage": "A URL to the S3 bucket containing the package that contains the template fragment and schema files for the module version to register.\n\n> The user registering the module version must be able to access the module package in the S3 bucket. That's, the user needs to have [GetObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html) permissions for the package. For more information, see [Actions, Resources, and Condition Keys for Amazon S3](https://docs.aws.amazon.com/IAM/latest/UserGuide/list_amazons3.html) in the *AWS Identity and Access Management User Guide* ." } }, "AWS::CloudFormation::PublicTypeVersion": { @@ -6159,11 +6397,11 @@ "Ref": "`Ref` returns the Amazon Resource Number (ARN) assigned to the public extension upon publication. For example:\n\n`{ \"Ref\": \"arn:aws:cloudformation:us-east-1::type/resource/2a33349e7e606a8ad2e30e3c84521f93123456/My-Extension/2.1.3\" }`", "TypeVersionArn": "The Amazon Resource Number (ARN) assigned to this version of the extension." }, - "description": "Tests and publishes a registered extension as a public, third-party extension.\n\nCloudFormation first tests the extension to make sure it meets all necessary requirements for being published in the CloudFormation registry. If it does, CloudFormation then publishes it to the registry as a public third-party extension in this region. Public extensions are available for use by all CloudFormation users.\n\n- For resource types, testing includes passing all contracts tests defined for the type.\n- For modules, testing includes determining if the module's model meets all necessary requirements.\n\nFor more information, see [Testing your public extension prior to publishing](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/publish-extension.html#publish-extension-testing) in the *CloudFormation CLI User Guide* .\n\nIf you don't specify a version, CloudFormation uses the default version of the extension in your account and region for testing.\n\nTo perform testing, CloudFormation assumes the execution role specified when the type was registered.\n\nAn extension must have a test status of `PASSED` before it can be published. For more information, see [Publishing extensions to make them available for public use](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/resource-type-publish.html) in the *CloudFormation CLI User Guide* .", + "description": "Tests and publishes a registered extension as a public, third-party extension.\n\nCloudFormation first tests the extension to make sure it meets all necessary requirements for being published in the CloudFormation registry. If it does, CloudFormation then publishes it to the registry as a public third-party extension in this Region. Public extensions are available for use by all CloudFormation users.\n\n- For resource types, testing includes passing all contracts tests defined for the type.\n- For modules, testing includes determining if the module's model meets all necessary requirements.\n\nFor more information, see [Testing your public extension prior to publishing](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/publish-extension.html#publish-extension-testing) in the *CloudFormation CLI User Guide* .\n\nIf you don't specify a version, CloudFormation uses the default version of the extension in your account and Region for testing.\n\nTo perform testing, CloudFormation assumes the execution role specified when the type was registered.\n\nAn extension must have a test status of `PASSED` before it can be published. For more information, see [Publishing extensions to make them available for public use](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/resource-type-publish.html) in the *CloudFormation CLI User Guide* .", "properties": { "Arn": "The Amazon Resource Number (ARN) of the extension.\n\nConditional: You must specify `Arn` , or `TypeName` and `Type` .", "LogDeliveryBucket": "The S3 bucket to which CloudFormation delivers the contract test execution logs.\n\nCloudFormation delivers the logs by the time contract testing has completed and the extension has been assigned a test type status of `PASSED` or `FAILED` .\n\nThe user initiating the stack operation must be able to access items in the specified S3 bucket. Specifically, the user needs the following permissions:\n\n- GetObject\n- PutObject\n\nFor more information, see [Actions, Resources, and Condition Keys for Amazon S3](https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazons3.html) in the *AWS Identity and Access Management User Guide* .", - "PublicVersionNumber": "The version number to assign to this version of the extension.\n\nUse the following format, and adhere to semantic versioning when assigning a version number to your extension:\n\n`MAJOR.MINOR.PATCH`\n\nFor more information, see [Semantic Versioning 2.0.0](https://docs.aws.amazon.com/https://semver.org/) .\n\nIf you do not specify a version number, CloudFormation increments the version number by one minor version release.\n\nYou cannot specify a version number the first time you publish a type. AWS CloudFormation automatically sets the first version number to be `1.0.0` .", + "PublicVersionNumber": "The version number to assign to this version of the extension.\n\nUse the following format, and adhere to semantic versioning when assigning a version number to your extension:\n\n`MAJOR.MINOR.PATCH`\n\nFor more information, see [Semantic Versioning 2.0.0](https://docs.aws.amazon.com/https://semver.org/) .\n\nIf you don't specify a version number, CloudFormation increments the version number by one minor version release.\n\nYou cannot specify a version number the first time you publish a type. AWS CloudFormation automatically sets the first version number to be `1.0.0` .", "Type": "The type of the extension to test.\n\nConditional: You must specify `Arn` , or `TypeName` and `Type` .", "TypeName": "The name of the extension to test.\n\nConditional: You must specify `Arn` , or `TypeName` and `Type` ." } @@ -6198,13 +6436,13 @@ "attributes": { "Arn": "The Amazon Resource Name (ARN) of the resource version.", "IsDefaultVersion": "Whether the resource version is set as the default version.", - "ProvisioningType": "The provisioning behavior of the resource type. CloudFormation determines the provisioning type during registration, based on the types of handlers in the schema handler package submitted.\n\nValid values include:\n\n- `FULLY_MUTABLE` : The resource type includes an update handler to process updates to the type during stack update operations.\n- `IMMUTABLE` : The resource type does not include an update handler, so the type cannot be updated and must instead be replaced during stack update operations.\n- `NON_PROVISIONABLE` : The resource type does not include all of the following handlers, and therefore cannot actually be provisioned.\n\n- create\n- read\n- delete", + "ProvisioningType": "The provisioning behavior of the resource type. CloudFormation determines the provisioning type during registration, based on the types of handlers in the schema handler package submitted.\n\nValid values include:\n\n- `FULLY_MUTABLE` : The resource type includes an update handler to process updates to the type during stack update operations.\n- `IMMUTABLE` : The resource type doesn't include an update handler, so the type can't be updated and must instead be replaced during stack update operations.\n- `NON_PROVISIONABLE` : The resource type doesn't include all the following handlers, and therefore can't actually be provisioned.\n\n- create\n- read\n- delete", "Ref": "`Ref` returns the ARN of the resource version. For example:\n\n`arn:aws:cloudformation:us-west-2:012345678901:type/resource/Sample-CloudFormation-Resource/00000001`", "TypeArn": "The Amazon Resource Name (ARN) of the resource.", "VersionId": "The ID of a specific version of the resource. The version ID is the value at the end of the Amazon Resource Name (ARN) assigned to the resource version when it is registered.", "Visibility": "The scope at which the resource is visible and usable in CloudFormation operations.\n\nValid values include:\n\n- `PRIVATE` : The resource is only visible and usable within the account in which it's registered. CloudFormation marks any resources you register as `PRIVATE` .\n- `PUBLIC` : The resource is publicly visible and usable within any Amazon account." }, - "description": "Registers a resource version with the CloudFormation service. Registering a resource version makes it available for use in CloudFormation templates in your AWS account , and includes:\n\n- Validating the resource schema.\n- Determining which handlers, if any, have been specified for the resource.\n- Making the resource available for use in your account.\n\nFor more information on how to develop resources and ready them for registration, see [Creating Resource Providers](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/resource-types.html) in the *CloudFormation CLI User Guide* .\n\nYou can have a maximum of 50 resource versions registered at a time. This maximum is per account and per region.", + "description": "Registers a resource version with the CloudFormation service. Registering a resource version makes it available for use in CloudFormation templates in your AWS account , and includes:\n\n- Validating the resource schema.\n- Determining which handlers, if any, have been specified for the resource.\n- Making the resource available for use in your account.\n\nFor more information on how to develop resources and ready them for registration, see [Creating Resource Providers](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/resource-types.html) in the *CloudFormation CLI User Guide* .\n\nYou can have a maximum of 50 resource versions registered at a time. This maximum is per account and per Region.", "properties": { "ExecutionRoleArn": "The Amazon Resource Name (ARN) of the IAM role for CloudFormation to assume when invoking the resource. If your resource calls AWS APIs in any of its handlers, you must create an *[IAM execution role](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html)* that includes the necessary permissions to call those AWS APIs, and provision that execution role in your account. When CloudFormation needs to invoke the resource type handler, CloudFormation assumes this execution role to create a temporary session token, which it then passes to the resource type handler, thereby supplying your resource type with the appropriate credentials.", "LoggingConfig": "Logging configuration information for a resource.", @@ -6224,13 +6462,13 @@ "attributes": { "Ref": "`Ref` returns the stack ID. For example:\n\n`arn:aws:cloudformation:us-east-2:123456789012:stack/mystack-mynestedstack-sggfrhxhum7w/f449b250-b969-11e0-a185-5081d0136786`" }, - "description": "The `AWS::CloudFormation::Stack` type nests a stack as a resource in a top-level template.\n\nYou can add output values from a nested stack within the containing template. You use the [GetAtt](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html) function with the nested stack's logical name and the name of the output value in the nested stack in the format `Outputs. *NestedStackOutputName*` .\n\n> We strongly recommend that updates to nested stacks are run from the parent stack. \n\nWhen you apply template changes to update a top-level stack, CloudFormation updates the top-level stack and initiates an update to its nested stacks. CloudFormation updates the resources of modified nested stacks, but doesn't update the resources of unmodified nested stacks. For more information, see [CloudFormation stack updates](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks.html) .\n\n> You must acknowledge IAM capabilities for nested stacks that contain IAM resources. Also, verify that you have cancel update stack permissions, which is required if an update rolls back. For more information about IAM and CloudFormation , see [Controlling access with AWS Identity and Access Management](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-iam-template.html) .", + "description": "The `AWS::CloudFormation::Stack` resource nests a stack as a resource in a top-level template.\n\nYou can add output values from a nested stack within the containing template. You use the [GetAtt](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html) function with the nested stack's logical name and the name of the output value in the nested stack in the format `Outputs. *NestedStackOutputName*` .\n\n> We strongly recommend that updates to nested stacks are run from the parent stack. \n\nWhen you apply template changes to update a top-level stack, CloudFormation updates the top-level stack and initiates an update to its nested stacks. CloudFormation updates the resources of modified nested stacks, but doesn't update the resources of unmodified nested stacks. For more information, see [CloudFormation stack updates](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks.html) .\n\n> You must acknowledge IAM capabilities for nested stacks that contain IAM resources. Also, verify that you have cancel update stack permissions, which is required if an update rolls back. For more information about IAM and CloudFormation , see [Controlling access with AWS Identity and Access Management](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-iam-template.html) .", "properties": { - "NotificationARNs": "The Simple Notification Service (SNS) topic ARNs to publish stack related events. You can find your SNS topic ARNs using the SNS console or your Command Line Interface (CLI).", + "NotificationARNs": "The Amazon Simple Notification Service (Amazon SNS) topic ARNs to publish stack related events. You can find your Amazon SNS topic ARNs using the Amazon SNS console or your Command Line Interface (CLI).", "Parameters": "The set value pairs that represent the parameters passed to CloudFormation when this nested stack is created. Each parameter has a name corresponding to a parameter defined in the embedded template and a value representing the value that you want to set for the parameter.\n\n> If you use the `Ref` function to pass a parameter value to a nested stack, comma-delimited list parameters must be of type `String` . In other words, you can't pass values that are of type `CommaDelimitedList` to nested stacks. \n\nConditional. Required if the nested stack requires input parameters.\n\nWhether an update causes interruptions depends on the resources that are being updated. An update never causes a nested stack to be replaced.", "Tags": "Key-value pairs to associate with this stack. AWS CloudFormation also propagates these tags to the resources created in the stack. A maximum number of 50 tags can be specified.", "TemplateURL": "Location of file containing the template body. The URL must point to a template (max size: 460,800 bytes) that's located in an Amazon S3 bucket. For more information, see [Template anatomy](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html) .\n\nWhether an update causes interruptions depends on the resources that are being updated. An update never causes a nested stack to be replaced.", - "TimeoutInMinutes": "The length of time, in minutes, that CloudFormation waits for the nested stack to reach the `CREATE_COMPLETE` state. The default is no timeout. When CloudFormation detects that the nested stack has reached the `CREATE_COMPLETE` state, it marks the nested stack resource as `CREATE_COMPLETE` in the parent stack and resumes creating the parent stack. If the timeout period expires before the nested stack reaches `CREATE_COMPLETE` , CloudFormation marks the nested stack as failed and rolls back both the nested stack and parent stack.\n\nUpdates are not supported." + "TimeoutInMinutes": "The length of time, in minutes, that CloudFormation waits for the nested stack to reach the `CREATE_COMPLETE` state. The default is no timeout. When CloudFormation detects that the nested stack has reached the `CREATE_COMPLETE` state, it marks the nested stack resource as `CREATE_COMPLETE` in the parent stack and resumes creating the parent stack. If the timeout period expires before the nested stack reaches `CREATE_COMPLETE` , CloudFormation marks the nested stack as failed and rolls back both the nested stack and parent stack.\n\nUpdates aren't supported." } }, "AWS::CloudFormation::StackSet": { @@ -6238,7 +6476,7 @@ "Ref": "When you pass the logical ID of this resource to the intrinsic `Ref` function, `Ref` returns the StackSetId.", "StackSetId": "The ID of the stack that you're creating." }, - "description": "The `AWS::CloudFormation::StackSet` enables you to provision stacks into AWS accounts and across Regions by using a single CloudFormation template. In the stack set, you specify the template to use, as well as any parameters and capabilities that the template requires.", + "description": "The `AWS::CloudFormation::StackSet` enables you to provision stacks into AWS accounts and across Regions by using a single CloudFormation template. In the stack set, you specify the template to use, in addition to any parameters and capabilities that the template requires.", "properties": { "AdministrationRoleARN": "The Amazon Resource Number (ARN) of the IAM role to use to create this stack set. Specify an IAM role only if you are using customized administrator roles to control which users or groups can manage specific stack sets within the same administrator account.\n\nUse customized administrator roles to control which users or groups can manage specific stack sets within the same administrator account. For more information, see [Prerequisites: Granting Permissions for Stack Set Operations](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-prereqs.html) in the *AWS CloudFormation User Guide* .\n\n*Minimum* : `20`\n\n*Maximum* : `2048`", "AutoDeployment": "[ `Service-managed` permissions] Describes whether StackSets automatically deploys to AWS Organizations accounts that are added to a target organization or organizational unit (OU).", @@ -6281,7 +6519,7 @@ "FailureTolerancePercentage": "The percentage of accounts, per Region, for which this stack operation can fail before AWS CloudFormation stops the operation in that Region. If the operation is stopped in a Region, AWS CloudFormation doesn't attempt the operation in any subsequent Regions.\n\nWhen calculating the number of accounts based on the specified percentage, AWS CloudFormation rounds *down* to the next whole number.\n\nConditional: You must specify either `FailureToleranceCount` or `FailureTolerancePercentage` , but not both.", "MaxConcurrentCount": "The maximum number of accounts in which to perform this operation at one time. This is dependent on the value of `FailureToleranceCount` . `MaxConcurrentCount` is at most one more than the `FailureToleranceCount` .\n\nNote that this setting lets you specify the *maximum* for operations. For large deployments, under certain circumstances the actual number of accounts acted upon concurrently may be lower due to service throttling.\n\nConditional: You must specify either `MaxConcurrentCount` or `MaxConcurrentPercentage` , but not both.", "MaxConcurrentPercentage": "The maximum percentage of accounts in which to perform this operation at one time.\n\nWhen calculating the number of accounts based on the specified percentage, AWS CloudFormation rounds down to the next whole number. This is true except in cases where rounding down would result is zero. In this case, CloudFormation sets the number as one instead.\n\nNote that this setting lets you specify the *maximum* for operations. For large deployments, under certain circumstances the actual number of accounts acted upon concurrently may be lower due to service throttling.\n\nConditional: You must specify either `MaxConcurrentCount` or `MaxConcurrentPercentage` , but not both.", - "RegionConcurrencyType": "The concurrency type of deploying StackSets operations in regions, could be in parallel or one region at a time.\n\n*Allowed values* : `SEQUENTIAL` | `PARALLEL`", + "RegionConcurrencyType": "The concurrency type of deploying StackSets operations in Regions, could be in parallel or one Region at a time.\n\n*Allowed values* : `SEQUENTIAL` | `PARALLEL`", "RegionOrder": "The order of the Regions where you want to perform the stack operation." } }, @@ -6289,7 +6527,7 @@ "attributes": {}, "description": "The Parameter data type.", "properties": { - "ParameterKey": "The key associated with the parameter. If you don't specify a key and value for a particular parameter, AWS CloudFormation uses the default value that is specified in your template.", + "ParameterKey": "The key associated with the parameter. If you don't specify a key and value for a particular parameter, AWS CloudFormation uses the default value that's specified in your template.", "ParameterValue": "The input value associated with the parameter." } }, @@ -6307,7 +6545,7 @@ "Arn": "The Amazon Resource Number (ARN) of the activated extension, in this account and Region.", "Ref": "`Ref` returns the Amazon Resource Number (ARN) of the activated extension, in this account and Region.\n\n`{ \"Ref\": \"arn:aws:cloudformation:us-east-1:123456789013:type/resource/My-Example\" }`" }, - "description": "Activates a public third-party extension, making it available for use in stack templates. For more information, see [Using public extensions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/registry-public.html) in the *CloudFormation User Guide* .\n\nOnce you have activated a public third-party extension in your account and region, use [SetTypeConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_SetTypeConfiguration.html) to specify configuration properties for the extension. For more information, see [Configuring extensions at the account level](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/registry-register.html#registry-set-configuration) in the *CloudFormation User Guide* .", + "description": "Activates a public third-party extension, making it available for use in stack templates. For more information, see [Using public extensions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/registry-public.html) in the *AWS CloudFormation User Guide* .\n\nOnce you have activated a public third-party extension in your account and region, use [SetTypeConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_SetTypeConfiguration.html) to specify configuration properties for the extension. For more information, see [Configuring extensions at the account level](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/registry-register.html#registry-set-configuration) in the *CloudFormation User Guide* .", "properties": { "AutoUpdate": "Whether to automatically update the extension in this account and region when a new *minor* version is published by the extension publisher. Major versions released by the publisher must be manually updated.\n\nThe default is `true` .", "ExecutionRoleArn": "The name of the IAM execution role to use to activate the extension.", @@ -6325,8 +6563,8 @@ "attributes": {}, "description": "Contains logging configuration information for an extension.", "properties": { - "LogGroupName": "The Amazon CloudWatch log group to which CloudFormation sends error logging information when invoking the extension's handlers.", - "LogRoleArn": "The ARN of the role that CloudFormation should assume when sending log entries to CloudWatch logs." + "LogGroupName": "The Amazon CloudWatch Logs group to which CloudFormation sends error logging information when invoking the extension's handlers.", + "LogRoleArn": "The Amazon Resource Name (ARN) of the role that CloudFormation should assume when sending log entries to CloudWatch Logs." } }, "AWS::CloudFormation::WaitCondition": { @@ -6334,10 +6572,10 @@ "Data": "A JSON object that contains the `UniqueId` and `Data` values from the wait condition signal(s) for the specified wait condition. For more information about wait condition signals, see [Wait condition signal JSON format](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-waitcondition.html#using-cfn-waitcondition-signaljson) .\n\nExample return value for a wait condition with 2 signals:\n\n`{ \"Signal1\" : \"Step 1 complete.\" , \"Signal2\" : \"Step 2 complete.\" }`", "Ref": "`Ref` returns the resource name." }, - "description": "> For Amazon EC2 and Auto Scaling resources, we recommend that you use a `CreationPolicy` attribute instead of wait conditions. Add a CreationPolicy attribute to those resources, and use the cfn-signal helper script to signal when an instance creation process has completed successfully. \n\nYou can use a wait condition for situations like the following:\n\n- To coordinate stack resource creation with configuration actions that are external to the stack creation.\n- To track the status of a configuration process.\n\nFor these situations, we recommend that you associate a [CreationPolicy](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-creationpolicy.html) attribute with the wait condition so that you don't have to use a wait condition handle. For more information and an example, see [Creating wait conditions in a template](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-waitcondition.html) . If you use a CreationPolicy with a wait condition, do not specify any of the wait condition's properties.\n\n> If you use the [VPC endpoints](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-endpoints.html) feature, resources in the VPC that respond to wait conditions must have access to CloudFormation , specific Amazon Simple Storage Service ( Amazon S3 ) buckets. Resources must send wait condition responses to a presigned Amazon S3 URL. If they can't send responses to Amazon S3 , CloudFormation won't receive a response and the stack operation fails. For more information, see [Setting up VPC endpoints for AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-vpce-bucketnames.html) .", + "description": "> For Amazon EC2 and Auto Scaling resources, we recommend that you use a `CreationPolicy` attribute instead of wait conditions. Add a CreationPolicy attribute to those resources, and use the cfn-signal helper script to signal when an instance creation process has completed successfully. \n\nYou can use a wait condition for situations like the following:\n\n- To coordinate stack resource creation with configuration actions that are external to the stack creation.\n- To track the status of a configuration process.\n\nFor these situations, we recommend that you associate a [CreationPolicy](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-creationpolicy.html) attribute with the wait condition so that you don't have to use a wait condition handle. For more information and an example, see [Creating wait conditions in a template](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-waitcondition.html) . If you use a CreationPolicy with a wait condition, don't specify any of the wait condition's properties.\n\n> If you use the [VPC endpoints](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-endpoints.html) feature, resources in the VPC that respond to wait conditions must have access to CloudFormation , specific Amazon Simple Storage Service ( Amazon S3 ) buckets. Resources must send wait condition responses to a presigned Amazon S3 URL. If they can't send responses to Amazon S3 , CloudFormation won't receive a response and the stack operation fails. For more information, see [Setting up VPC endpoints for AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-vpce-bucketnames.html) .", "properties": { - "Count": "The number of success signals that CloudFormation must receive before it continues the stack creation process. When the wait condition receives the requisite number of success signals, CloudFormation resumes the creation of the stack. If the wait condition does not receive the specified number of success signals before the Timeout period expires, CloudFormation assumes that the wait condition has failed and rolls the stack back.\n\nUpdates are not supported.", - "Handle": "A reference to the wait condition handle used to signal this wait condition. Use the `Ref` intrinsic function to specify an [AWS::CloudFormation::WaitConditionHandle](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-waitconditionhandle.html) resource.\n\nAnytime you add a WaitCondition resource during a stack update, you must associate the wait condition with a new WaitConditionHandle resource. Don't reuse an old wait condition handle that has already been defined in the template. If you reuse a wait condition handle, the wait condition might evaluate old signals from a previous create or update stack command.\n\nUpdates are not supported.", + "Count": "The number of success signals that CloudFormation must receive before it continues the stack creation process. When the wait condition receives the requisite number of success signals, CloudFormation resumes the creation of the stack. If the wait condition doesn't receive the specified number of success signals before the Timeout period expires, CloudFormation assumes that the wait condition has failed and rolls the stack back.\n\nUpdates aren't supported.", + "Handle": "A reference to the wait condition handle used to signal this wait condition. Use the `Ref` intrinsic function to specify an [AWS::CloudFormation::WaitConditionHandle](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-waitconditionhandle.html) resource.\n\nAnytime you add a WaitCondition resource during a stack update, you must associate the wait condition with a new WaitConditionHandle resource. Don't reuse an old wait condition handle that has already been defined in the template. If you reuse a wait condition handle, the wait condition might evaluate old signals from a previous create or update stack command.\n\nUpdates aren't supported.", "Timeout": "The length of time (in seconds) to wait for the number of signals that the `Count` property specifies. `Timeout` is a minimum-bound property, meaning the timeout occurs no sooner than the time you specify, but can occur shortly thereafter. The maximum time that can be specified for this property is 12 hours (43200 seconds).\n\nUpdates aren't supported." } }, @@ -7184,7 +7422,7 @@ }, "AWS::CloudWatch::AnomalyDetector.Dimension": { "attributes": {}, - "description": "A dimension is a name/value pair that is part of the identity of a metric. You can assign up to 10 dimensions to a metric. Because dimensions are part of the unique identifier for a metric, whenever you add a unique name/value pair to one of your metrics, you are creating a new variation of that metric.", + "description": "A dimension is a name/value pair that is part of the identity of a metric. Because dimensions are part of the unique identifier for a metric, whenever you add a unique name/value pair to one of your metrics, you are creating a new variation of that metric. For example, many Amazon EC2 metrics publish `InstanceId` as a dimension name, and the actual instance ID as the value for that dimension.\n\nYou can assign up to 10 dimensions to a metric.", "properties": { "Name": "The name of the dimension.", "Value": "The value of the dimension. Dimension values must contain only ASCII characters and must include at least one non-whitespace character." @@ -7748,7 +7986,9 @@ "LoadBalancerInfo": "Information about the load balancer to use in a deployment. For more information, see [Integrating CodeDeploy with Elastic Load Balancing](https://docs.aws.amazon.com/codedeploy/latest/userguide/integrations-aws-elastic-load-balancing.html) in the *AWS CodeDeploy User Guide* .", "OnPremisesInstanceTagFilters": "The on-premises instance tags already applied to on-premises instances that you want to include in the deployment group. CodeDeploy includes all on-premises instances identified by any of the tags you specify in this deployment group. To register on-premises instances with CodeDeploy , see [Working with On-Premises Instances for CodeDeploy](https://docs.aws.amazon.com/codedeploy/latest/userguide/instances-on-premises.html) in the *AWS CodeDeploy User Guide* . Duplicates are not allowed.\n\nYou can specify `OnPremisesInstanceTagFilters` or `OnPremisesInstanceTagSet` , but not both.", "OnPremisesTagSet": "Information about groups of tags applied to on-premises instances. The deployment group includes only on-premises instances identified by all the tag groups.\n\nYou can specify `OnPremisesInstanceTagFilters` or `OnPremisesInstanceTagSet` , but not both.", + "OutdatedInstancesStrategy": "Indicates what happens when new Amazon EC2 instances are launched mid-deployment and do not receive the deployed application revision.\n\nIf this option is set to `UPDATE` or is unspecified, CodeDeploy initiates one or more 'auto-update outdated instances' deployments to apply the deployed application revision to the new Amazon EC2 instances.\n\nIf this option is set to `IGNORE` , CodeDeploy does not initiate a deployment to update the new Amazon EC2 instances. This may result in instances having different revisions.", "ServiceRoleArn": "A service role Amazon Resource Name (ARN) that grants CodeDeploy permission to make calls to AWS services on your behalf. For more information, see [Create a Service Role for AWS CodeDeploy](https://docs.aws.amazon.com/codedeploy/latest/userguide/getting-started-create-service-role.html) in the *AWS CodeDeploy User Guide* .\n\n> In some cases, you might need to add a dependency on the service role's policy. For more information, see IAM role policy in [DependsOn Attribute](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-dependson.html) .", + "Tags": "The metadata that you apply to CodeDeploy deployment groups to help you organize and categorize them. Each tag consists of a key and an optional value, both of which you define.", "TriggerConfigurations": "Information about triggers associated with the deployment group. Duplicates are not allowed" } }, @@ -7876,7 +8116,8 @@ "description": "The `LoadBalancerInfo` property type specifies information about the load balancer or target group used for an AWS CodeDeploy deployment group. For more information, see [Integrating CodeDeploy with Elastic Load Balancing](https://docs.aws.amazon.com/codedeploy/latest/userguide/integrations-aws-elastic-load-balancing.html) in the *AWS CodeDeploy User Guide* .\n\nFor AWS CloudFormation to use the properties specified in `LoadBalancerInfo` , the `DeploymentStyle.DeploymentOption` property must be set to `WITH_TRAFFIC_CONTROL` . If `DeploymentStyle.DeploymentOption` is not set to `WITH_TRAFFIC_CONTROL` , AWS CloudFormation ignores any settings specified in `LoadBalancerInfo` .\n\n> AWS CloudFormation supports blue/green deployments on the AWS Lambda compute platform only. \n\n`LoadBalancerInfo` is a property of the [DeploymentGroup](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codedeploy-deploymentgroup.html) resource.", "properties": { "ElbInfoList": "An array that contains information about the load balancer to use for load balancing in a deployment. In Elastic Load Balancing, load balancers are used with Classic Load Balancers.\n\n> Adding more than one load balancer to the array is not supported.", - "TargetGroupInfoList": "An array that contains information about the target group to use for load balancing in a deployment. In Elastic Load Balancing , target groups are used with Application Load Balancers .\n\n> Adding more than one target group to the array is not supported." + "TargetGroupInfoList": "An array that contains information about the target group to use for load balancing in a deployment. In Elastic Load Balancing , target groups are used with Application Load Balancers .\n\n> Adding more than one target group to the array is not supported.", + "TargetGroupPairInfoList": "The target group pair information. This is an array of `TargeGroupPairInfo` objects with a maximum size of one." } }, "AWS::CodeDeploy::DeploymentGroup.OnPremisesTagSet": { @@ -7929,6 +8170,22 @@ "Name": "For blue/green deployments, the name of the target group that instances in the original environment are deregistered from, and instances in the replacement environment registered with. For in-place deployments, the name of the target group that instances are deregistered from, so they are not serving traffic during a deployment, and then re-registered with after the deployment completes. No duplicates allowed.\n\n> AWS CloudFormation supports blue/green deployments on AWS Lambda compute platforms only. \n\nThis value cannot exceed 32 characters, so you should use the `Name` property of the target group, or the `TargetGroupName` attribute with the `Fn::GetAtt` intrinsic function, as shown in the following example. Don't use the group's Amazon Resource Name (ARN) or `TargetGroupFullName` attribute." } }, + "AWS::CodeDeploy::DeploymentGroup.TargetGroupPairInfo": { + "attributes": {}, + "description": "Information about two target groups and how traffic is routed during an Amazon ECS deployment. An optional test traffic route can be specified.", + "properties": { + "ProdTrafficRoute": "The path used by a load balancer to route production traffic when an Amazon ECS deployment is complete.", + "TargetGroups": "One pair of target groups. One is associated with the original task set. The second is associated with the task set that serves traffic after the deployment is complete.", + "TestTrafficRoute": "An optional path used by a load balancer to route test traffic after an Amazon ECS deployment. Validation can occur while test traffic is served during a deployment." + } + }, + "AWS::CodeDeploy::DeploymentGroup.TrafficRoute": { + "attributes": {}, + "description": "Information about a listener. The listener contains the path used to route traffic that is received from the load balancer to a target group.", + "properties": { + "ListenerArns": "The Amazon Resource Name (ARN) of one listener. The listener identifies the route between a target group and a load balancer. This is an array of strings with a maximum size of one." + } + }, "AWS::CodeDeploy::DeploymentGroup.TriggerConfig": { "attributes": {}, "description": "Information about notification triggers for the deployment group.", @@ -8060,7 +8317,7 @@ "properties": { "Category": "A category defines what kind of action can be taken in the stage, and constrains the provider type for the action. Valid categories are limited to one of the values below.\n\n- `Source`\n- `Build`\n- `Test`\n- `Deploy`\n- `Invoke`\n- `Approval`", "Owner": "The creator of the action being called. There are three valid values for the `Owner` field in the action category section within your pipeline structure: `AWS` , `ThirdParty` , and `Custom` . For more information, see [Valid Action Types and Providers in CodePipeline](https://docs.aws.amazon.com/codepipeline/latest/userguide/reference-pipeline-structure.html#actions-valid-providers) .", - "Provider": "The provider of the service being called by the action. Valid providers are determined by the action category. For example, an action in the Deploy category type might have a provider of CodeDeploy, which would be specified as CodeDeploy. For more information, see [Valid Action Types and Providers in CodePipeline](https://docs.aws.amazon.com/codepipeline/latest/userguide/reference-pipeline-structure.html#actions-valid-providers) .", + "Provider": "The provider of the service being called by the action. Valid providers are determined by the action category. For example, an action in the Deploy category type might have a provider of CodeDeploy, which would be specified as `CodeDeploy` . For more information, see [Valid Action Types and Providers in CodePipeline](https://docs.aws.amazon.com/codepipeline/latest/userguide/reference-pipeline-structure.html#actions-valid-providers) .", "Version": "A string that describes the action version." } }, @@ -8333,7 +8590,7 @@ "AliasAttributes": "Attributes supported as an alias for this user pool. Possible values: *phone_number* , *email* , or *preferred_username* .\n\n> This user pool property cannot be updated.", "AutoVerifiedAttributes": "The attributes to be auto-verified. Possible values: *email* , *phone_number* .", "DeviceConfiguration": "The device configuration.", - "EmailConfiguration": "The email configuration.", + "EmailConfiguration": "The email configuration of your user pool. The email configuration type sets your preferred sending method, AWS Region, and sender for messages from your user pool.", "EmailVerificationMessage": "A string representing the email verification message. EmailVerificationMessage is allowed only if [EmailSendingAccount](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_EmailConfigurationType.html#CognitoUserPools-Type-EmailConfigurationType-EmailSendingAccount) is DEVELOPER.", "EmailVerificationSubject": "A string representing the email verification subject. EmailVerificationSubject is allowed only if [EmailSendingAccount](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_EmailConfigurationType.html#CognitoUserPools-Type-EmailConfigurationType-EmailSendingAccount) is DEVELOPER.", "EnabledMfas": "Enables MFA on a specified user pool. To disable all MFAs after it has been enabled, set MfaConfiguration to \u201cOFF\u201d and remove EnabledMfas. MFAs can only be all disabled if MfaConfiguration is OFF. Once SMS_MFA is enabled, SMS_MFA can only be disabled by setting MfaConfiguration to \u201cOFF\u201d. Can be one of the following values:\n\n- `SMS_MFA` - Enables SMS MFA for the user pool. SMS_MFA can only be enabled if SMS configuration is provided.\n- `SOFTWARE_TOKEN_MFA` - Enables software token MFA for the user pool.\n\nAllowed values: `SMS_MFA` | `SOFTWARE_TOKEN_MFA`", @@ -8342,7 +8599,7 @@ "Policies": "The policy associated with a user pool.", "Schema": "The schema attributes for the new user pool. These attributes can be standard or custom attributes.\n\n> During a user pool update, you can add new schema attributes but you cannot modify or delete an existing schema attribute.", "SmsAuthenticationMessage": "A string representing the SMS authentication message.", - "SmsConfiguration": "The SMS configuration.", + "SmsConfiguration": "The SMS configuration with the settings that your Amazon Cognito user pool must use to send an SMS message from your AWS account through Amazon Simple Notification Service. To send SMS messages with Amazon SNS in the AWS Region that you want, the Amazon Cognito user pool uses an AWS Identity and Access Management (IAM) role in your AWS account .", "SmsVerificationMessage": "A string representing the SMS verification message.", "UserPoolAddOns": "Enables advanced security risk detection. Set the key `AdvancedSecurityMode` to the value \"AUDIT\".", "UserPoolName": "A string used to name the user pool.", @@ -8394,13 +8651,13 @@ }, "AWS::Cognito::UserPool.EmailConfiguration": { "attributes": {}, - "description": "The email configuration.", + "description": "The email configuration of your user pool. The email configuration type sets your preferred sending method, AWS Region, and sender for messages from your user pool.", "properties": { "ConfigurationSet": "The set of configuration rules that can be applied to emails sent using Amazon SES. A configuration set is applied to an email by including a reference to the configuration set in the headers of the email. Once applied, all of the rules in that configuration set are applied to the email. Configuration sets can be used to apply the following types of rules to emails:\n\n- Event publishing \u2013 Amazon SES can track the number of send, delivery, open, click, bounce, and complaint events for each email sent. Use event publishing to send information about these events to other AWS services such as SNS and CloudWatch.\n- IP pool management \u2013 When leasing dedicated IP addresses with Amazon SES, you can create groups of IP addresses, called dedicated IP pools. You can then associate the dedicated IP pools with configuration sets.", - "EmailSendingAccount": "Specifies whether Amazon Cognito emails your users by using its built-in email functionality or your Amazon Simple Email Service email configuration. Specify one of the following values:\n\n- **COGNITO_DEFAULT** - When Amazon Cognito emails your users, it uses its built-in email functionality. When you use the default option, Amazon Cognito allows only a limited number of emails each day for your user pool. For typical production environments, the default email limit is less than the required delivery volume. To achieve a higher delivery volume, specify DEVELOPER to use your Amazon SES email configuration.\n\nTo look up the email delivery limit for the default option, see [Limits in](https://docs.aws.amazon.com/cognito/latest/developerguide/limits.html) in the *Developer Guide* .\n\nThe default FROM address is `no-reply@verificationemail.com` . To customize the FROM address, provide the Amazon Resource Name (ARN) of an Amazon SES verified email address for the `SourceArn` parameter.\n\nIf EmailSendingAccount is COGNITO_DEFAULT, you can't use the following parameters:\n\n- EmailVerificationMessage\n- EmailVerificationSubject\n- InviteMessageTemplate.EmailMessage\n- InviteMessageTemplate.EmailSubject\n- VerificationMessageTemplate.EmailMessage\n- VerificationMessageTemplate.EmailMessageByLink\n- VerificationMessageTemplate.EmailSubject,\n- VerificationMessageTemplate.EmailSubjectByLink\n\n> DEVELOPER EmailSendingAccount is required.\n- **DEVELOPER** - When Amazon Cognito emails your users, it uses your Amazon SES configuration. Amazon Cognito calls Amazon SES on your behalf to send email from your verified email address. When you use this option, the email delivery limits are the same limits that apply to your Amazon SES verified email address in your AWS account .\n\nIf you use this option, you must provide the ARN of an Amazon SES verified email address for the `SourceArn` parameter.\n\nBefore Amazon Cognito can email your users, it requires additional permissions to call Amazon SES on your behalf. When you update your user pool with this option, Amazon Cognito creates a *service-linked role* , which is a type of role, in your AWS account . This role contains the permissions that allow to access Amazon SES and send email messages with your address. For more information about the service-linked role that Amazon Cognito creates, see [Using Service-Linked Roles for Amazon Cognito](https://docs.aws.amazon.com/cognito/latest/developerguide/using-service-linked-roles.html) in the *Amazon Cognito Developer Guide* .", + "EmailSendingAccount": "Specifies whether Amazon Cognito uses its built-in functionality to send your users email messages, or uses your Amazon Simple Email Service email configuration. Specify one of the following values:\n\n- **COGNITO_DEFAULT** - When Amazon Cognito emails your users, it uses its built-in email functionality. When you use the default option, Amazon Cognito allows only a limited number of emails each day for your user pool. For typical production environments, the default email limit is less than the required delivery volume. To achieve a higher delivery volume, specify DEVELOPER to use your Amazon SES email configuration.\n\nTo look up the email delivery limit for the default option, see [Limits in](https://docs.aws.amazon.com/cognito/latest/developerguide/limits.html) in the *Developer Guide* .\n\nThe default FROM address is `no-reply@verificationemail.com` . To customize the FROM address, provide the Amazon Resource Name (ARN) of an Amazon SES verified email address for the `SourceArn` parameter.\n\nIf EmailSendingAccount is COGNITO_DEFAULT, you can't use the following parameters:\n\n- EmailVerificationMessage\n- EmailVerificationSubject\n- InviteMessageTemplate.EmailMessage\n- InviteMessageTemplate.EmailSubject\n- VerificationMessageTemplate.EmailMessage\n- VerificationMessageTemplate.EmailMessageByLink\n- VerificationMessageTemplate.EmailSubject,\n- VerificationMessageTemplate.EmailSubjectByLink\n\n> DEVELOPER EmailSendingAccount is required.\n- **DEVELOPER** - When Amazon Cognito emails your users, it uses your Amazon SES configuration. Amazon Cognito calls Amazon SES on your behalf to send email from your verified email address. When you use this option, the email delivery limits are the same limits that apply to your Amazon SES verified email address in your AWS account .\n\nIf you use this option, you must provide the ARN of an Amazon SES verified email address for the `SourceArn` parameter.\n\nBefore Amazon Cognito can email your users, it requires additional permissions to call Amazon SES on your behalf. When you update your user pool with this option, Amazon Cognito creates a *service-linked role* , which is a type of role, in your AWS account . This role contains the permissions that allow to access Amazon SES and send email messages with your address. For more information about the service-linked role that Amazon Cognito creates, see [Using Service-Linked Roles for Amazon Cognito](https://docs.aws.amazon.com/cognito/latest/developerguide/using-service-linked-roles.html) in the *Amazon Cognito Developer Guide* .", "From": "Identifies either the sender's email address or the sender's name with their email address. For example, `testuser@example.com` or `Test User ` . This address appears before the body of the email.", "ReplyToEmailAddress": "The destination to which the receiver of the email should reply.", - "SourceArn": "The ARN of a verified email address in Amazon SES. Amazon Cognito uses this email address in one of the following ways, depending on the value that you specify for the `EmailSendingAccount` parameter:\n\n- If you specify `COGNITO_DEFAULT` , Amazon Cognito uses this address as the custom FROM address when it emails your users using its built-in email account.\n- If you specify `DEVELOPER` , Amazon Cognito emails your users with this address by calling Amazon SES on your behalf." + "SourceArn": "The ARN of a verified email address in Amazon SES. Amazon Cognito uses this email address in one of the following ways, depending on the value that you specify for the `EmailSendingAccount` parameter:\n\n- If you specify `COGNITO_DEFAULT` , Amazon Cognito uses this address as the custom FROM address when it emails your users using its built-in email account.\n- If you specify `DEVELOPER` , Amazon Cognito emails your users with this address by calling Amazon SES on your behalf.\n\nThe Region value of the `SourceArn` parameter must indicate a supported AWS Region of your user pool. Typically, the Region in the `SourceArn` and the user pool Region are the same. For more information, see [Amazon SES email configuration regions](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-email.html#user-pool-email-developer-region-mapping) in the [Amazon Cognito Developer Guide](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools.html) ." } }, "AWS::Cognito::UserPool.InviteMessageTemplate": { @@ -8484,7 +8741,8 @@ "description": "The SMS configuration type that includes the settings the Cognito User Pool needs to call for the Amazon SNS service to send an SMS message from your AWS account . The Cognito User Pool makes the request to the Amazon SNS Service by using an IAM role that you provide for your AWS account .", "properties": { "ExternalId": "The external ID is a value. We recommend you use `ExternalId` to add security to your IAM role, which is used to call Amazon SNS to send SMS messages for your user pool. If you provide an `ExternalId` , the Cognito User Pool uses it when attempting to assume your IAM role. You can also set your roles trust policy to require the `ExternalID` . If you use the Cognito Management Console to create a role for SMS MFA, Cognito creates a role with the required permissions and a trust policy that uses `ExternalId` .", - "SnsCallerArn": "The Amazon Resource Name (ARN) of the Amazon SNS caller. This is the ARN of the IAM role in your AWS account that Amazon Cognito will use to send SMS messages. SMS messages are subject to a [spending limit](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-email-phone-verification.html) ." + "SnsCallerArn": "The Amazon Resource Name (ARN) of the Amazon SNS caller. This is the ARN of the IAM role in your AWS account that Amazon Cognito will use to send SMS messages. SMS messages are subject to a [spending limit](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-email-phone-verification.html) .", + "SnsRegion": "The AWS Region to use with Amazon SNS integration. You can choose the same Region as your user pool, or a supported *Legacy Amazon SNS alternate Region* .\n\nAmazon Cognito resources in the Asia Pacific (Seoul) AWS Region must use your Amazon SNS configuration in the Asia Pacific (Tokyo) Region. For more information, see [SMS message settings for Amazon Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-sms-settings.html) ." } }, "AWS::Cognito::UserPool.StringAttributeConstraints": { @@ -8506,7 +8764,7 @@ "attributes": {}, "description": "The `UsernameConfiguration` property type specifies case sensitivity on the username input for the selected sign-in option.", "properties": { - "CaseSensitive": "Specifies whether username case sensitivity will be applied for all users in the user pool through Amazon Cognito APIs.\n\nValid values include:\n\n- *`True`* : Enables case sensitivity for all username input. When this option is set to `True` , users must sign in using the exact capitalization of their given username, such as \u201cUserName\u201d. This is the default value.\n- *`False`* : Enables case insensitivity for all username input. For example, when this option is set to `False` , users can sign in using either \"username\" or \"Username\". This option also enables both `preferred_username` and `email` alias to be case insensitive, in addition to the `username` attribute." + "CaseSensitive": "Specifies whether username case sensitivity will be applied for all users in the user pool through Amazon Cognito APIs.\n\nValid values include:\n\n- **True** - Enables case sensitivity for all username input. When this option is set to `True` , users must sign in using the exact capitalization of their given username, such as \u201cUserName\u201d. This is the default value.\n- **False** - Enables case insensitivity for all username input. For example, when this option is set to `False` , users can sign in using either \"username\" or \"Username\". This option also enables both `preferred_username` and `email` alias to be case insensitive, in addition to the `username` attribute." } }, "AWS::Cognito::UserPool.VerificationMessageTemplate": { @@ -8531,12 +8789,12 @@ "AllowedOAuthFlows": "The allowed OAuth flows.\n\nSet to `code` to initiate a code grant flow, which provides an authorization code as the response. This code can be exchanged for access tokens with the token endpoint.\n\nSet to `implicit` to specify that the client should get the access token (and, optionally, ID token, based on scopes) directly.\n\nSet to `client_credentials` to specify that the client should get the access token (and, optionally, ID token, based on scopes) from the token endpoint using a combination of client and client_secret.", "AllowedOAuthFlowsUserPoolClient": "Set to true if the client is allowed to follow the OAuth protocol when interacting with Amazon Cognito user pools.", "AllowedOAuthScopes": "The allowed OAuth scopes. Possible values provided by OAuth are: `phone` , `email` , `openid` , and `profile` . Possible values provided by AWS are: `aws.cognito.signin.user.admin` . Custom scopes created in Resource Servers are also supported.", - "AnalyticsConfiguration": "The Amazon Pinpoint analytics configuration for collecting metrics for this user pool.\n\n> In AWS Regions where isn't available, User Pools only supports sending events to Amazon Pinpoint projects in AWS Region us-east-1. In Regions where is available, User Pools will support sending events to Amazon Pinpoint projects within that same Region.", + "AnalyticsConfiguration": "The user pool analytics configuration for collecting metrics and sending them to your Amazon Pinpoint campaign.\n\n> In AWS Regions where Amazon Pinpoint isn't available, user pools only support sending events to Amazon Pinpoint projects in AWS Region us-east-1. In Regions where Amazon Pinpoint is available, user pools support sending events to Amazon Pinpoint projects within that same Region.", "CallbackURLs": "A list of allowed redirect (callback) URLs for the identity providers.\n\nA redirect URI must:\n\n- Be an absolute URI.\n- Be registered with the authorization server.\n- Not include a fragment component.\n\nSee [OAuth 2.0 - Redirection Endpoint](https://docs.aws.amazon.com/https://tools.ietf.org/html/rfc6749#section-3.1.2) .\n\nAmazon Cognito requires HTTPS over HTTP except for http://localhost for testing purposes only.\n\nApp callback URLs such as myapp://example are also supported.", "ClientName": "The client name for the user pool client you would like to create.", "DefaultRedirectURI": "The default redirect URI. Must be in the `CallbackURLs` list.\n\nA redirect URI must:\n\n- Be an absolute URI.\n- Be registered with the authorization server.\n- Not include a fragment component.\n\nSee [OAuth 2.0 - Redirection Endpoint](https://docs.aws.amazon.com/https://tools.ietf.org/html/rfc6749#section-3.1.2) .\n\nAmazon Cognito requires HTTPS over HTTP except for http://localhost for testing purposes only.\n\nApp callback URLs such as myapp://example are also supported.", "EnableTokenRevocation": "Activates or deactivates token revocation. For more information about revoking tokens, see [RevokeToken](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RevokeToken.html) .\n\nIf you don't include this parameter, token revocation is automatically activated for the new user pool client.", - "ExplicitAuthFlows": "The authentication flows that are supported by the user pool clients. Flow names without the `ALLOW_` prefix are no longer supported, in favor of new names with the `ALLOW_` prefix. Note that values with `ALLOW_` prefix must be used only along with the `ALLOW_` prefix.\n\nValid values include:\n\n- `ALLOW_ADMIN_USER_PASSWORD_AUTH` : Enable admin based user password authentication flow `ADMIN_USER_PASSWORD_AUTH` . This setting replaces the `ADMIN_NO_SRP_AUTH` setting. With this authentication flow, Amazon Cognito receives the password in the request instead of using the Secure Remote Password (SRP) protocol to verify passwords.\n- `ALLOW_CUSTOM_AUTH` : Enable AWS Lambda trigger based authentication.\n- `ALLOW_USER_PASSWORD_AUTH` : Enable user password-based authentication. In this flow, Amazon Cognito receives the password in the request instead of using the SRP protocol to verify passwords.\n- `ALLOW_USER_SRP_AUTH` : Enable SRP-based authentication.\n- `ALLOW_REFRESH_TOKEN_AUTH` : Enable authflow to refresh tokens.", + "ExplicitAuthFlows": "The authentication flows that are supported by the user pool clients. Flow names without the `ALLOW_` prefix are no longer supported, in favor of new names with the `ALLOW_` prefix.\n\n> Values with `ALLOW_` prefix must be used only along with the `ALLOW_` prefix. \n\nValid values include:\n\n- `ALLOW_ADMIN_USER_PASSWORD_AUTH` : Enable admin based user password authentication flow `ADMIN_USER_PASSWORD_AUTH` . This setting replaces the `ADMIN_NO_SRP_AUTH` setting. With this authentication flow, Amazon Cognito receives the password in the request instead of using the Secure Remote Password (SRP) protocol to verify passwords.\n- `ALLOW_CUSTOM_AUTH` : Enable AWS Lambda trigger based authentication.\n- `ALLOW_USER_PASSWORD_AUTH` : Enable user password-based authentication. In this flow, Amazon Cognito receives the password in the request instead of using the SRP protocol to verify passwords.\n- `ALLOW_USER_SRP_AUTH` : Enable SRP-based authentication.\n- `ALLOW_REFRESH_TOKEN_AUTH` : Enable authflow to refresh tokens.", "GenerateSecret": "Boolean to specify whether you want to generate a secret for the user pool client being created.", "IdTokenValidity": "The time limit, after which the ID token is no longer valid and cannot be used.", "LogoutURLs": "A list of allowed logout URLs for the identity providers.", @@ -8546,12 +8804,12 @@ "SupportedIdentityProviders": "A list of provider names for the identity providers that are supported on this client. The following are supported: `COGNITO` , `Facebook` , `SignInWithApple` , `Google` and `LoginWithAmazon` .", "TokenValidityUnits": "The units in which the validity times are represented in. Default for RefreshToken is days, and default for ID and access tokens are hours.", "UserPoolId": "The user pool ID for the user pool where you want to create a user pool client.", - "WriteAttributes": "The user pool attributes that the app client can write to.\n\nIf your app client allows users to sign in through an identity provider, this array must include all attributes that are mapped to identity provider attributes. Amazon Cognito updates mapped attributes when users sign in to your application through an identity provider. If your app client lacks write access to a mapped attribute, Amazon Cognito throws an error when it tries to update the attribute. For more information, see [Specifying Identity Provider Attribute Mappings for Your User Pool](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-specifying-attribute-mapping.html) ." + "WriteAttributes": "The user pool attributes that the app client can write to.\n\nIf your app client allows users to sign in through an identity provider, this array must include all attributes that you have mapped to identity provider attributes. Amazon Cognito updates mapped attributes when users sign in to your application through an identity provider. If your app client does not have write access to a mapped attribute, Amazon Cognito throws an error when it tries to update the attribute. For more information, see [Specifying Identity Provider Attribute Mappings for Your user pool](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-specifying-attribute-mapping.html) ." } }, "AWS::Cognito::UserPoolClient.AnalyticsConfiguration": { "attributes": {}, - "description": "The Amazon Pinpoint analytics configuration for collecting metrics for a user pool.\n\n> In Regions where Pinpoint isn't available, User Pools only supports sending events to Amazon Pinpoint projects in us-east-1. In Regions where Pinpoint is available, User Pools will support sending events to Amazon Pinpoint projects within that same Region.", + "description": "The Amazon Pinpoint analytics configuration for collecting metrics for a user pool.\n\n> In Regions where Amazon Pinpointisn't available, user pools only support sending events to Amazon Pinpoint projects in us-east-1. In Regions where Amazon Pinpoint is available, user pools support sending events to Amazon Pinpoint projects within that same Region.", "properties": { "ApplicationArn": "The Amazon Resource Name (ARN) of an Amazon Pinpoint project. You can use the Amazon Pinpoint project for integration with the chosen user pool client. Amazon Cognito publishes events to the Amazon Pinpoint project that the app ARN declares.", "ApplicationId": "The application ID for an Amazon Pinpoint application.", @@ -8651,7 +8909,7 @@ "attributes": {}, "description": "Account takeover action type.", "properties": { - "EventAction": "The event action.\n\n- `BLOCK` Choosing this action will block the request.\n- `MFA_IF_CONFIGURED` Present an MFA challenge if user has configured it, else allow the request.\n- `MFA_REQUIRED` Present an MFA challenge if user has configured it, else block the request.\n- `NO_ACTION` Allow the user to sign in.", + "EventAction": "The action to take in response to the account takeover action. Valid values are:\n\n- `BLOCK` Choosing this action will block the request.\n- `MFA_IF_CONFIGURED` Present an MFA challenge if user has configured it, else allow the request.\n- `MFA_REQUIRED` Present an MFA challenge if user has configured it, else block the request.\n- `NO_ACTION` Allow the user to sign in.", "Notify": "Flag specifying whether to send a notification." } }, @@ -9249,146 +9507,155 @@ "description": "The AWS::CustomerProfiles::Integration resource specifies an Amazon Connect Customer Profiles Integration.", "properties": { "DomainName": "The unique name of the domain.", - "FlowDefinition": "", + "FlowDefinition": "The configuration that controls how Customer Profiles retrieves data from the source.", "ObjectTypeName": "The name of the profile object type mapping to use.", + "ObjectTypeNames": "", "Tags": "The tags used to organize, track, or control access for this resource.", "Uri": "The URI of the S3 bucket or any other type of data source." } }, "AWS::CustomerProfiles::Integration.ConnectorOperator": { "attributes": {}, - "description": "", + "description": "The operation to be performed on the provided source fields.", "properties": { - "Marketo": "", - "S3": "", - "Salesforce": "", - "ServiceNow": "", - "Zendesk": "" + "Marketo": "The operation to be performed on the provided Marketo source fields.", + "S3": "The operation to be performed on the provided Amazon S3 source fields.", + "Salesforce": "The operation to be performed on the provided Salesforce source fields.", + "ServiceNow": "The operation to be performed on the provided ServiceNow source fields.", + "Zendesk": "The operation to be performed on the provided Zendesk source fields." } }, "AWS::CustomerProfiles::Integration.FlowDefinition": { "attributes": {}, - "description": "", + "description": "The configurations that control how Customer Profiles retrieves data from the source, Amazon AppFlow. Customer Profiles uses this information to create an AppFlow flow on behalf of customers.", "properties": { - "Description": "", - "FlowName": "", - "KmsArn": "", - "SourceFlowConfig": "", - "Tasks": "", - "TriggerConfig": "" + "Description": "A description of the flow you want to create.", + "FlowName": "The specified name of the flow. Use underscores (_) or hyphens (-) only. Spaces are not allowed.", + "KmsArn": "The Amazon Resource Name (ARN) of the AWS Key Management Service (KMS) key you provide for encryption.", + "SourceFlowConfig": "The configuration that controls how Customer Profiles retrieves data from the source.", + "Tasks": "A list of tasks that Customer Profiles performs while transferring the data in the flow run.", + "TriggerConfig": "The trigger settings that determine how and when the flow runs." } }, "AWS::CustomerProfiles::Integration.IncrementalPullConfig": { "attributes": {}, - "description": "", + "description": "Specifies the configuration used when importing incremental records from the source.", "properties": { - "DatetimeTypeFieldName": "" + "DatetimeTypeFieldName": "A field that specifies the date time or timestamp field as the criteria to use when importing incremental records from the source." } }, "AWS::CustomerProfiles::Integration.MarketoSourceProperties": { + "attributes": {}, + "description": "The properties that are applied when Marketo is being used as a source.", + "properties": { + "Object": "The object specified in the Marketo flow source." + } + }, + "AWS::CustomerProfiles::Integration.ObjectTypeMapping": { "attributes": {}, "description": "", "properties": { - "Object": "" + "Key": "", + "Value": "" } }, "AWS::CustomerProfiles::Integration.S3SourceProperties": { "attributes": {}, - "description": "", + "description": "The properties that are applied when Amazon S3 is being used as the flow source.", "properties": { - "BucketName": "", - "BucketPrefix": "" + "BucketName": "The Amazon S3 bucket name where the source files are stored.", + "BucketPrefix": "The object key for the Amazon S3 bucket in which the source files are stored." } }, "AWS::CustomerProfiles::Integration.SalesforceSourceProperties": { "attributes": {}, - "description": "", + "description": "The properties that are applied when Salesforce is being used as a source.", "properties": { - "EnableDynamicFieldUpdate": "", - "IncludeDeletedRecords": "", - "Object": "" + "EnableDynamicFieldUpdate": "The flag that enables dynamic fetching of new (recently added) fields in the Salesforce objects while running a flow.", + "IncludeDeletedRecords": "Indicates whether Amazon AppFlow includes deleted files in the flow run.", + "Object": "The object specified in the Salesforce flow source." } }, "AWS::CustomerProfiles::Integration.ScheduledTriggerProperties": { "attributes": {}, - "description": "", + "description": "Specifies the configuration details of a scheduled-trigger flow that you define. Currently, these settings only apply to the scheduled-trigger type.", "properties": { - "DataPullMode": "", - "FirstExecutionFrom": "", - "ScheduleEndTime": "", - "ScheduleExpression": "", - "ScheduleOffset": "", - "ScheduleStartTime": "", - "Timezone": "" + "DataPullMode": "Specifies whether a scheduled flow has an incremental data transfer or a complete data transfer for each flow run.", + "FirstExecutionFrom": "Specifies the date range for the records to import from the connector in the first flow run.", + "ScheduleEndTime": "Specifies the scheduled end time for a scheduled-trigger flow.", + "ScheduleExpression": "The scheduling expression that determines the rate at which the schedule will run, for example rate (5 minutes).", + "ScheduleOffset": "Specifies the optional offset that is added to the time interval for a schedule-triggered flow.", + "ScheduleStartTime": "Specifies the scheduled start time for a scheduled-trigger flow.", + "Timezone": "Specifies the time zone used when referring to the date and time of a scheduled-triggered flow, such as America/New_York." } }, "AWS::CustomerProfiles::Integration.ServiceNowSourceProperties": { "attributes": {}, - "description": "", + "description": "The properties that are applied when ServiceNow is being used as a source.", "properties": { - "Object": "" + "Object": "The object specified in the ServiceNow flow source." } }, "AWS::CustomerProfiles::Integration.SourceConnectorProperties": { "attributes": {}, - "description": "", + "description": "Specifies the information that is required to query a particular Amazon AppFlow connector. Customer Profiles supports Salesforce, Zendesk, Marketo, ServiceNow and Amazon S3.", "properties": { - "Marketo": "", - "S3": "", - "Salesforce": "", - "ServiceNow": "", - "Zendesk": "" + "Marketo": "The properties that are applied when Marketo is being used as a source.", + "S3": "The properties that are applied when Amazon S3 is being used as the flow source.", + "Salesforce": "The properties that are applied when Salesforce is being used as a source.", + "ServiceNow": "The properties that are applied when ServiceNow is being used as a source.", + "Zendesk": "The properties that are applied when using Zendesk as a flow source." } }, "AWS::CustomerProfiles::Integration.SourceFlowConfig": { "attributes": {}, - "description": "", + "description": "The configuration that controls how Customer Profiles retrieves data from the source.", "properties": { - "ConnectorProfileName": "", - "ConnectorType": "", - "IncrementalPullConfig": "", - "SourceConnectorProperties": "" + "ConnectorProfileName": "The name of the Amazon AppFlow connector profile. This name must be unique for each connector profile in the AWS account.", + "ConnectorType": "The type of connector, such as Salesforce, Marketo, and so on.", + "IncrementalPullConfig": "Defines the configuration for a scheduled incremental data pull. If a valid configuration is provided, the fields specified in the configuration are used when querying for the incremental data pull.", + "SourceConnectorProperties": "Specifies the information that is required to query a particular source connector." } }, "AWS::CustomerProfiles::Integration.Task": { "attributes": {}, - "description": "", + "description": "The `Task` property type specifies the class for modeling different type of tasks. Task implementation varies based on the TaskType.", "properties": { - "ConnectorOperator": "", - "DestinationField": "", - "SourceFields": "", - "TaskProperties": "", - "TaskType": "" + "ConnectorOperator": "The operation to be performed on the provided source fields.", + "DestinationField": "A field in a destination connector, or a field value against which Amazon AppFlow validates a source field.", + "SourceFields": "The source fields to which a particular task is applied.", + "TaskProperties": "A map used to store task-related information. The service looks for particular information based on the TaskType.", + "TaskType": "Specifies the particular task implementation that Amazon AppFlow performs." } }, "AWS::CustomerProfiles::Integration.TaskPropertiesMap": { "attributes": {}, - "description": "", + "description": "A map used to store task-related information. The execution service looks for particular information based on the `TaskType` .", "properties": { - "OperatorPropertyKey": "", - "Property": "" + "OperatorPropertyKey": "The task property key.", + "Property": "The task property value." } }, "AWS::CustomerProfiles::Integration.TriggerConfig": { "attributes": {}, - "description": "", + "description": "The trigger settings that determine how and when Amazon AppFlow runs the specified flow.", "properties": { - "TriggerProperties": "", - "TriggerType": "" + "TriggerProperties": "Specifies the configuration details of a schedule-triggered flow that you define. Currently, these settings only apply to the Scheduled trigger type.", + "TriggerType": "Specifies the type of flow trigger. It can be OnDemand, Scheduled, or Event." } }, "AWS::CustomerProfiles::Integration.TriggerProperties": { "attributes": {}, - "description": "", + "description": "Specifies the configuration details that control the trigger for a flow. Currently, these settings only apply to the Scheduled trigger type.", "properties": { - "Scheduled": "" + "Scheduled": "Specifies the configuration details of a schedule-triggered flow that you define." } }, "AWS::CustomerProfiles::Integration.ZendeskSourceProperties": { "attributes": {}, - "description": "", + "description": "The properties that are applied when using Zendesk as a flow source.", "properties": { - "Object": "" + "Object": "The object specified in the Zendesk flow source." } }, "AWS::CustomerProfiles::ObjectType": { @@ -9673,11 +9940,11 @@ "attributes": { "Ref": "`Ref` returns the Amazon Resource Name (ARN) of the certificate." }, - "description": "The `AWS::DMS::Certificate` resource creates an SSL certificate that encrypts connections between AWS DMS endpoints and the replication instance.", + "description": "The `AWS::DMS::Certificate` resource creates an Secure Sockets Layer (SSL) certificate that encrypts connections between AWS DMS endpoints and the replication instance.", "properties": { "CertificateIdentifier": "A customer-assigned name for the certificate. Identifiers must begin with a letter and must contain only ASCII letters, digits, and hyphens. They can't end with a hyphen or contain two consecutive hyphens.", "CertificatePem": "The contents of a `.pem` file, which contains an X.509 certificate.", - "CertificateWallet": "The location of an imported Oracle Wallet certificate for use with SSL. Example: `filebase64(\"${path.root}/rds-ca-2019-root.sso\")`" + "CertificateWallet": "The location of an imported Oracle Wallet certificate for use with SSL. An example is: `filebase64(\"${path.root}/rds-ca-2019-root.sso\")`" } }, "AWS::DMS::Endpoint": { @@ -9685,69 +9952,69 @@ "ExternalId": "A value that can be used for cross-account validation.", "Ref": "`Ref` returns the ARN of the endpoint." }, - "description": "The `AWS::DMS::Endpoint` resource creates an AWS DMS endpoint.\n\nCurrently, the only endpoint setting types that AWS CloudFormation supports are *DynamoDBSettings* , *ElasticSearchSettings* , and *NeptuneSettings* .", + "description": "The `AWS::DMS::Endpoint` resource specifies an AWS DMS endpoint.\n\nCurrently, AWS CloudFormation supports all AWS DMS endpoint types.", "properties": { "CertificateArn": "The Amazon Resource Name (ARN) for the certificate.", - "DatabaseName": "The name of the endpoint database. For a MySQL source or target endpoint, do not specify DatabaseName. To migrate to a specific database, use this setting and `targetDbType` .", - "DocDbSettings": "Settings in JSON format for the source DocumentDB endpoint. For more information about the available settings, see the configuration properties section in [Using DocumentDB as a Target for AWS Database Migration Service](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.DocumentDB.html) in the *AWS Database Migration Service User Guide.*", - "DynamoDbSettings": "Settings in JSON format for the target Amazon DynamoDB endpoint. For information about other available settings, see [Using Object Mapping to Migrate Data to DynamoDB](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.DynamoDB.html#CHAP_Target.DynamoDB.ObjectMapping) in the *AWS Database Migration Service User Guide.*", - "ElasticsearchSettings": "Settings in JSON format for the target OpenSearch endpoint. For more information about the available settings, see [Extra Connection Attributes When Using OpenSearch as a Target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Elasticsearch.html#CHAP_Target.Elasticsearch.Configuration) in the *AWS Database Migration Service User Guide* .", + "DatabaseName": "The name of the endpoint database. For a MySQL source or target endpoint, don't specify `DatabaseName` . To migrate to a specific database, use this setting and `targetDbType` .", + "DocDbSettings": "Settings in JSON format for the source and target DocumentDB endpoint. For more information about other available settings, see [Using extra connections attributes with Amazon DocumentDB as a source](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.DocumentDB.html#CHAP_Source.DocumentDB.ECAs) and [Using Amazon DocumentDB as a target for AWS Database Migration Service](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.DocumentDB.html) in the *AWS Database Migration Service User Guide* .", + "DynamoDbSettings": "Settings in JSON format for the target Amazon DynamoDB endpoint. For information about other available settings, see [Using object mapping to migrate data to DynamoDB](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.DynamoDB.html#CHAP_Target.DynamoDB.ObjectMapping) in the *AWS Database Migration Service User Guide* .", + "ElasticsearchSettings": "Settings in JSON format for the target OpenSearch endpoint. For more information about the available settings, see [Extra connection attributes when using OpenSearch as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Elasticsearch.html#CHAP_Target.Elasticsearch.Configuration) in the *AWS Database Migration Service User Guide* .", "EndpointIdentifier": "The database endpoint identifier. Identifiers must begin with a letter and must contain only ASCII letters, digits, and hyphens. They can't end with a hyphen, or contain two consecutive hyphens.", "EndpointType": "The type of endpoint. Valid values are `source` and `target` .", - "EngineName": "The type of engine for the endpoint. Valid values, depending on the `EndpointType` value, include `\"mysql\"` , `\"oracle\"` , `\"postgres\"` , `\"mariadb\"` , `\"aurora\"` , `\"aurora-postgresql\"` , `\"opensearch\"` , `\"redshift\"` , `\"s3\"` , `\"db2\"` , `\"azuredb\"` , `\"sybase\"` , `\"dynamodb\"` , `\"mongodb\"` , `\"kinesis\"` , `\"kafka\"` , `\"elasticsearch\"` , `\"docdb\"` , `\"sqlserver\"` , and `\"neptune\"` .", - "ExtraConnectionAttributes": "Additional attributes associated with the connection. Each attribute is specified as a name-value pair associated by an equal sign (=). Multiple attributes are separated by a semicolon (;) with no additional white space. For information on the attributes available for connecting your source or target endpoint, see [Working with AWS DMS Endpoints](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Endpoints.html) in the *AWS Database Migration Service User Guide.*", - "GcpMySQLSettings": "Settings in JSON format for the source GCP MySQL endpoint.", - "IbmDb2Settings": "Not currently supported by AWS CloudFormation .", - "KafkaSettings": "Settings in JSON format for the target Apache Kafka endpoint. For more information about the available settings, see [Using object mapping to migrate data to a Kafka topic](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Kafka.html#CHAP_Target.Kafka.ObjectMapping) in the *AWS Database Migration Service User Guide.*", - "KinesisSettings": "Settings in JSON format for the target endpoint for Amazon Kinesis Data Streams. For more information about the available settings, see [Using Amazon Kinesis Data Streams as a Target for AWS Database Migration Service](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Kinesis.html) in the *AWS Database Migration Service User Guide.*", - "KmsKeyId": "An AWS KMS key identifier that is used to encrypt the connection parameters for the endpoint.\n\nIf you don't specify a value for the `KmsKeyId` parameter, then AWS DMS uses your default encryption key.\n\nAWS KMS creates the default encryption key for your AWS account . Your AWS account has a different default encryption key for each AWS Region .", - "MicrosoftSqlServerSettings": "Not currently supported by AWS CloudFormation .", - "MongoDbSettings": "Not currently supported by AWS CloudFormation .", - "MySqlSettings": "Settings in JSON format for the source and target MySQL endpoint. For information about other available settings, see [Extra connection attributes when using MySQL as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.MySQL.html#CHAP_Source.MySQL.ConnectionAttrib) and [Extra connection attributes when using a MySQL-compatible database as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.MySQL.html#CHAP_Target.MySQL.ConnectionAttrib) in the *AWS Database Migration Service User Guide.*", - "NeptuneSettings": "", - "OracleSettings": "Settings in JSON format for the source and target Oracle endpoint. For information about other available settings, see [Extra connection attributes when using Oracle as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.Oracle.html#CHAP_Source.Oracle.ConnectionAttrib) and [Extra connection attributes when using Oracle as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Oracle.html#CHAP_Target.Oracle.ConnectionAttrib) in the *AWS Database Migration Service User Guide.*", + "EngineName": "The type of engine for the endpoint, depending on the `EndpointType` value.\n\n*Valid values* : `mysql` | `oracle` | `postgres` | `mariadb` | `aurora` | `aurora-postgresql` | `opensearch` | `redshift` | `s3` | `db2` | `azuredb` | `sybase` | `dynamodb` | `mongodb` | `kinesis` | `kafka` | `elasticsearch` | `docdb` | `sqlserver` | `neptune`", + "ExtraConnectionAttributes": "Additional attributes associated with the connection. Each attribute is specified as a name-value pair associated by an equal sign (=). Multiple attributes are separated by a semicolon (;) with no additional white space. For information on the attributes available for connecting your source or target endpoint, see [Working with AWS DMS Endpoints](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Endpoints.html) in the *AWS Database Migration Service User Guide* .", + "GcpMySQLSettings": "Settings in JSON format for the source GCP MySQL endpoint. These settings are much the same as the settings for any MySQL-compatible endpoint. For more information, see [Extra connection attributes when using MySQL as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.MySQL.html#CHAP_Source.MySQL.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .", + "IbmDb2Settings": "Settings in JSON format for the source IBM Db2 LUW endpoint. For information about other available settings, see [Extra connection attributes when using Db2 LUW as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.DB2.html#CHAP_Source.DB2.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .", + "KafkaSettings": "Settings in JSON format for the target Apache Kafka endpoint. For more information about other available settings, see [Using object mapping to migrate data to a Kafka topic](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Kafka.html#CHAP_Target.Kafka.ObjectMapping) in the *AWS Database Migration Service User Guide* .", + "KinesisSettings": "Settings in JSON format for the target endpoint for Amazon Kinesis Data Streams. For more information about other available settings, see [Using object mapping to migrate data to a Kinesis data stream](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Kinesis.html#CHAP_Target.Kinesis.ObjectMapping) in the *AWS Database Migration Service User Guide* .", + "KmsKeyId": "An AWS KMS key identifier that is used to encrypt the connection parameters for the endpoint.\n\nIf you don't specify a value for the `KmsKeyId` parameter, AWS DMS uses your default encryption key.\n\nAWS KMS creates the default encryption key for your AWS account . Your AWS account has a different default encryption key for each AWS Region .", + "MicrosoftSqlServerSettings": "Settings in JSON format for the source and target Microsoft SQL Server endpoint. For information about other available settings, see [Extra connection attributes when using SQL Server as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.SQLServer.html#CHAP_Source.SQLServer.ConnectionAttrib) and [Extra connection attributes when using SQL Server as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.SQLServer.html#CHAP_Target.SQLServer.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .", + "MongoDbSettings": "Settings in JSON format for the source MongoDB endpoint. For more information about the available settings, see [Using MongoDB as a target for AWS Database Migration Service](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.MongoDB.html#CHAP_Source.MongoDB.Configuration) in the *AWS Database Migration Service User Guide* .", + "MySqlSettings": "Settings in JSON format for the source and target MySQL endpoint. For information about other available settings, see [Extra connection attributes when using MySQL as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.MySQL.html#CHAP_Source.MySQL.ConnectionAttrib) and [Extra connection attributes when using a MySQL-compatible database as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.MySQL.html#CHAP_Target.MySQL.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .", + "NeptuneSettings": "Settings in JSON format for the target Amazon Neptune endpoint. For more information about the available settings, see [Specifying endpoint settings for Amazon Neptune as a target](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Neptune.html#CHAP_Target.Neptune.EndpointSettings) in the *AWS Database Migration Service User Guide* .", + "OracleSettings": "Settings in JSON format for the source and target Oracle endpoint. For information about other available settings, see [Extra connection attributes when using Oracle as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.Oracle.html#CHAP_Source.Oracle.ConnectionAttrib) and [Extra connection attributes when using Oracle as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Oracle.html#CHAP_Target.Oracle.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .", "Password": "The password to be used to log in to the endpoint database.", "Port": "The port used by the endpoint database.", - "PostgreSqlSettings": "Not currently supported by AWS CloudFormation .", - "RedisSettings": "Settings in JSON format for the target Redis endpoint.", - "RedshiftSettings": "Not currently supported by AWS CloudFormation .", - "ResourceIdentifier": "A friendly name for the resource identifier at the end of the `EndpointArn` response parameter that is returned in the created `Endpoint` object. The value for this parameter can have up to 31 characters. It can contain only ASCII letters, digits, and hyphen ('-'). Also, it can't end with a hyphen or contain two consecutive hyphens, and can only begin with a letter, such as `Example-App-ARN1` . For example, this value might result in the `EndpointArn` value `arn:aws:dms:eu-west-1:012345678901:rep:Example-App-ARN1` . If you don't specify a `ResourceIdentifier` value, AWS DMS generates a default identifier value for the end of `EndpointArn` .", - "S3Settings": "Settings in JSON format for the target Amazon S3 endpoint. For more information about the available settings, see [Extra Connection Attributes When Using Amazon S3 as a Target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.S3.html#CHAP_Target.S3.Configuring) in the *AWS Database Migration Service User Guide.*", + "PostgreSqlSettings": "Settings in JSON format for the source and target PostgreSQL endpoint.\n\nFor information about other available settings, see [Extra connection attributes when using PostgreSQL as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.PostgreSQL.html#CHAP_Source.PostgreSQL.ConnectionAttrib) and [Extra connection attributes when using PostgreSQL as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.PostgreSQL.html#CHAP_Target.PostgreSQL.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .", + "RedisSettings": "Settings in JSON format for the target Redis endpoint. For information about other available settings, see [Specifying endpoint settings for Redis as a target](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Redis.html#CHAP_Target.Redis.EndpointSettings) in the *AWS Database Migration Service User Guide* .", + "RedshiftSettings": "Settings in JSON format for the Amazon Redshift endpoint.\n\nFor more information about other available settings, see [Extra connection attributes when using Amazon Redshift as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Redshift.html#CHAP_Target.Redshift.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .", + "ResourceIdentifier": "A display name for the resource identifier at the end of the `EndpointArn` response parameter that is returned in the created `Endpoint` object. The value for this parameter can have up to 31 characters. It can contain only ASCII letters, digits, and hyphen ('-'). Also, it can't end with a hyphen or contain two consecutive hyphens, and can only begin with a letter, such as `Example-App-ARN1` .\n\nFor example, this value might result in the `EndpointArn` value `arn:aws:dms:eu-west-1:012345678901:rep:Example-App-ARN1` . If you don't specify a `ResourceIdentifier` value, AWS DMS generates a default identifier value for the end of `EndpointArn` .", + "S3Settings": "Settings in JSON format for the source and target Amazon S3 endpoint. For more information about other available settings, see [Extra connection attributes when using Amazon S3 as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.S3.html#CHAP_Source.S3.Configuring) and [Extra connection attributes when using Amazon S3 as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.S3.html#CHAP_Target.S3.Configuring) in the *AWS Database Migration Service User Guide* .", "ServerName": "The name of the server where the endpoint database resides.", - "SslMode": "The Secure Sockets Layer (SSL) mode to use for the SSL connection. The default is `none` .\n\n> When `engine_name` is set to S3, then the only allowed value is `none` .", - "SybaseSettings": "Settings in JSON format for the source and target SAP ASE endpoint. For information about other available settings, see [Extra connection attributes when using SAP ASE as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.SAP.html#CHAP_Source.SAP.ConnectionAttrib) and [Extra connection attributes when using SAP ASE as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.SAP.html#CHAP_Target.SAP.ConnectionAttrib) in the *AWS Database Migration Service User Guide.*", + "SslMode": "The Secure Sockets Layer (SSL) mode to use for the SSL connection. The default is `none` .\n\n> When `engine_name` is set to S3, the only allowed value is `none` .", + "SybaseSettings": "Settings in JSON format for the source and target SAP ASE endpoint. For information about other available settings, see [Extra connection attributes when using SAP ASE as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.SAP.html#CHAP_Source.SAP.ConnectionAttrib) and [Extra connection attributes when using SAP ASE as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.SAP.html#CHAP_Target.SAP.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .", "Tags": "One or more tags to be assigned to the endpoint.", "Username": "The user name to be used to log in to the endpoint database." } }, "AWS::DMS::Endpoint.DocDbSettings": { "attributes": {}, - "description": "Not currently supported by AWS CloudFormation .", + "description": "Provides information that defines a DocumentDB endpoint. This information includes the output format of records applied to the endpoint and details of transaction and control table data information. For more information about other available settings, see [Using extra connections attributes with Amazon DocumentDB as a source](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.DocumentDB.html#CHAP_Source.DocumentDB.ECAs) and [Using Amazon DocumentDB as a target for AWS Database Migration Service](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.DocumentDB.html) in the *AWS Database Migration Service User Guide* .", "properties": { - "SecretsManagerAccessRoleArn": "Not currently supported by AWS CloudFormation .", - "SecretsManagerSecretId": "Not currently supported by AWS CloudFormation ." + "SecretsManagerAccessRoleArn": "The full Amazon Resource Name (ARN) of the IAM role that specifies AWS DMS as the trusted entity and grants the required permissions to access the value in `SecretsManagerSecret` . The role must allow the `iam:PassRole` action. `SecretsManagerSecret` has the value of the AWS Secrets Manager secret that allows access to the DocumentDB endpoint.\n\n> You can specify one of two sets of values for these permissions. You can specify the values for this setting and `SecretsManagerSecretId` . Or you can specify clear-text values for `UserName` , `Password` , `ServerName` , and `Port` . You can't specify both.\n> \n> For more information on creating this `SecretsManagerSecret` , the corresponding `SecretsManagerAccessRoleArn` , and the `SecretsManagerSecretId` that is required to access it, see [Using secrets to access AWS Database Migration Service resources](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Security.html#security-iam-secretsmanager) in the *AWS Database Migration Service User Guide* .", + "SecretsManagerSecretId": "The full ARN, partial ARN, or display name of the `SecretsManagerSecret` that contains the DocumentDB endpoint connection details." } }, "AWS::DMS::Endpoint.DynamoDbSettings": { "attributes": {}, - "description": "Provides the Amazon Resource Name (ARN) of the AWS Identity and Access Management (IAM) role used to define an Amazon DynamoDB target endpoint.", + "description": "Provides information, including the Amazon Resource Name (ARN) of the IAM role used to define an Amazon DynamoDB target endpoint. This information also includes the output format of records applied to the endpoint and details of transaction and control table data information. For information about other available settings, see [Using object mapping to migrate data to DynamoDB](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.DynamoDB.html#CHAP_Target.DynamoDB.ObjectMapping) in the *AWS Database Migration Service User Guide* .", "properties": { "ServiceAccessRoleArn": "The Amazon Resource Name (ARN) used by the service to access the IAM role. The role must allow the `iam:PassRole` action." } }, "AWS::DMS::Endpoint.ElasticsearchSettings": { "attributes": {}, - "description": "Provides information that defines an OpenSearch endpoint.", + "description": "Provides information that defines an OpenSearch endpoint. This information includes the output format of records applied to the endpoint and details of transaction and control table data information. For more information about the available settings, see [Extra connection attributes when using OpenSearch as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Elasticsearch.html#CHAP_Target.Elasticsearch.Configuration) in the *AWS Database Migration Service User Guide* .", "properties": { - "EndpointUri": "The endpoint for the OpenSearch cluster. AWS DMS uses HTTPS if a transport protocol (http/https) is not specified.", + "EndpointUri": "The endpoint for the OpenSearch cluster. AWS DMS uses HTTPS if a transport protocol (either HTTP or HTTPS) isn't specified.", "ErrorRetryDuration": "The maximum number of seconds for which DMS retries failed API requests to the OpenSearch cluster.", - "FullLoadErrorPercentage": "The maximum percentage of records that can fail to be written before a full load operation stops.\n\nTo avoid early failure, this counter is only effective after 1000 records are transferred. OpenSearch also has the concept of error monitoring during the last 10 minutes of an Observation Window. If transfer of all records fail in the last 10 minutes, the full load operation stops.", + "FullLoadErrorPercentage": "The maximum percentage of records that can fail to be written before a full load operation stops.\n\nTo avoid early failure, this counter is only effective after 1,000 records are transferred. OpenSearch also has the concept of error monitoring during the last 10 minutes of an Observation Window. If transfer of all records fail in the last 10 minutes, the full load operation stops.", "ServiceAccessRoleArn": "The Amazon Resource Name (ARN) used by the service to access the IAM role. The role must allow the `iam:PassRole` action." } }, "AWS::DMS::Endpoint.GcpMySQLSettings": { "attributes": {}, - "description": "Settings in JSON format for the source GCP MySQL endpoint.", + "description": "Provides information that defines a GCP MySQL endpoint. This information includes the output format of records applied to the endpoint and details of transaction and control table data information. These settings are much the same as the settings for any MySQL-compatible endpoint. For more information, see [Extra connection attributes when using MySQL as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.MySQL.html#CHAP_Source.MySQL.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .", "properties": { "AfterConnectScript": "Specifies a script to run immediately after AWS DMS connects to the endpoint. The migration task continues running regardless if the SQL statement succeeds or fails.\n\nFor this parameter, provide the code of the script itself, not the name of a file containing the script.", "CleanSourceMetadataOnMismatch": "Adjusts the behavior of AWS DMS when migrating from an SQL Server source database that is hosted as part of an Always On availability group cluster. If you need AWS DMS to poll all the nodes in the Always On cluster for transaction backups, set this attribute to `false` .", @@ -9756,127 +10023,127 @@ "MaxFileSize": "Specifies the maximum size (in KB) of any .csv file used to transfer data to a MySQL-compatible database.\n\nExample: `maxFileSize=512`", "ParallelLoadThreads": "Improves performance when loading data into the MySQL-compatible target database. Specifies how many threads to use to load the data into the MySQL-compatible target database. Setting a large number of threads can have an adverse effect on database performance, because a separate connection is required for each thread. The default is one.\n\nExample: `parallelLoadThreads=1`", "Password": "Endpoint connection password.", - "Port": "", - "SecretsManagerAccessRoleArn": "The full Amazon Resource Name (ARN) of the IAM role that specifies AWS DMS as the trusted entity and grants the required permissions to access the value in `SecretsManagerSecret.` The role must allow the `iam:PassRole` action. `SecretsManagerSecret` has the value of the AWS Secrets Manager secret that allows access to the MySQL endpoint.\n\n> You can specify one of two sets of values for these permissions. You can specify the values for this setting and `SecretsManagerSecretId` . Or you can specify clear-text values for `UserName` , `Password` , `ServerName` , and `Port` . You can't specify both. For more information on creating this `SecretsManagerSecret` and the `SecretsManagerAccessRoleArn` and `SecretsManagerSecretId` required to access it, see [Using secrets to access AWS Database Migration Service resources](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Security.html#security-iam-secretsmanager) in the AWS Database Migration Service User Guide.", - "SecretsManagerSecretId": "The full ARN, partial ARN, or friendly name of the `SecretsManagerSecret` that contains the MySQL endpoint connection details.", + "Port": "The port used by the endpoint database.", + "SecretsManagerAccessRoleArn": "The full Amazon Resource Name (ARN) of the IAM role that specifies AWS DMS as the trusted entity and grants the required permissions to access the value in `SecretsManagerSecret.` The role must allow the `iam:PassRole` action. `SecretsManagerSecret` has the value of the AWS Secrets Manager secret that allows access to the MySQL endpoint.\n\n> You can specify one of two sets of values for these permissions. You can specify the values for this setting and `SecretsManagerSecretId` . Or you can specify clear-text values for `UserName` , `Password` , `ServerName` , and `Port` . You can't specify both.\n> \n> For more information on creating this `SecretsManagerSecret` , the corresponding `SecretsManagerAccessRoleArn` , and the `SecretsManagerSecretId` required to access it, see [Using secrets to access AWS Database Migration Service resources](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Security.html#security-iam-secretsmanager) in the *AWS Database Migration Service User Guide* .", + "SecretsManagerSecretId": "The full ARN, partial ARN, or display name of the `SecretsManagerSecret` that contains the MySQL endpoint connection details.", "ServerName": "Endpoint TCP port.", - "ServerTimezone": "Specifies the time zone for the source MySQL database.\n\nExample: `serverTimezone=US/Pacific;`\n\nNote: Do not enclose time zones in single quotes.", + "ServerTimezone": "Specifies the time zone for the source MySQL database. Don't enclose time zones in single quotation marks.\n\nExample: `serverTimezone=US/Pacific;`", "Username": "Endpoint connection user name." } }, "AWS::DMS::Endpoint.IbmDb2Settings": { "attributes": {}, - "description": "Not currently supported by AWS CloudFormation .", + "description": "Provides information that defines an IBMDB2 endpoint. This information includes the output format of records applied to the endpoint and details of transaction and control table data information. For more information about other available settings, see [Extra connection attributes when using Db2 LUW as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.DB2.html#CHAP_Source.DB2.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .", "properties": { - "SecretsManagerAccessRoleArn": "Not currently supported by AWS CloudFormation .", - "SecretsManagerSecretId": "Not currently supported by AWS CloudFormation ." + "SecretsManagerAccessRoleArn": "The full Amazon Resource Name (ARN) of the IAM role that specifies AWS DMS as the trusted entity and grants the required permissions to access the value in `SecretsManagerSecret` . The role must allow the `iam:PassRole` action. `SecretsManagerSecret` has the value ofthe AWS Secrets Manager secret that allows access to the Db2 LUW endpoint.\n\n> You can specify one of two sets of values for these permissions. You can specify the values for this setting and `SecretsManagerSecretId` . Or you can specify clear-text values for `UserName` , `Password` , `ServerName` , and `Port` . You can't specify both.\n> \n> For more information on creating this `SecretsManagerSecret` , the corresponding `SecretsManagerAccessRoleArn` , and the `SecretsManagerSecretId` that is required to access it, see [Using secrets to access AWS Database Migration Service resources](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Security.html#security-iam-secretsmanager) in the *AWS Database Migration Service User Guide* .", + "SecretsManagerSecretId": "The full ARN, partial ARN, or display name of the `SecretsManagerSecret` that contains the IBMDB2 endpoint connection details." } }, "AWS::DMS::Endpoint.KafkaSettings": { "attributes": {}, - "description": "Not currently supported by AWS CloudFormation .", + "description": "Provides information that describes an Apache Kafka endpoint. This information includes the output format of records applied to the endpoint and details of transaction and control table data information. For more information about other available settings, see [Using object mapping to migrate data to a Kafka topic](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Kafka.html#CHAP_Target.Kafka.ObjectMapping) in the *AWS Database Migration Service User Guide* .", "properties": { - "Broker": "Not currently supported by AWS CloudFormation .", + "Broker": "A comma-separated list of one or more broker locations in your Kafka cluster that host your Kafka instance. Specify each broker location in the form `*broker-hostname-or-ip* : *port*` . For example, `\"ec2-12-345-678-901.compute-1.amazonaws.com:2345\"` . For more information and examples of specifying a list of broker locations, see [Using Apache Kafka as a target for AWS Database Migration Service](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Kafka.html) in the *AWS Database Migration Service User Guide* .", "IncludeControlDetails": "Shows detailed control information for table definition, column definition, and table and column changes in the Kafka message output. The default is `false` .", "IncludeNullAndEmpty": "Include NULL and empty columns for records migrated to the endpoint. The default is `false` .", "IncludeTableAlterOperations": "Includes any data definition language (DDL) operations that change the table in the control data, such as `rename-table` , `drop-table` , `add-column` , `drop-column` , and `rename-column` . The default is `false` .", "IncludeTransactionDetails": "Provides detailed transaction information from the source database. This information includes a commit timestamp, a log position, and values for `transaction_id` , previous `transaction_id` , and `transaction_record_id` (the record offset within a transaction). The default is `false` .", "NoHexPrefix": "Set this optional parameter to `true` to avoid adding a '0x' prefix to raw data in hexadecimal format. For example, by default, AWS DMS adds a '0x' prefix to the LOB column type in hexadecimal format moving from an Oracle source to a Kafka target. Use the `NoHexPrefix` endpoint setting to enable migration of RAW data type columns without adding the '0x' prefix.", "PartitionIncludeSchemaTable": "Prefixes schema and table names to partition values, when the partition type is `primary-key-type` . Doing this increases data distribution among Kafka partitions. For example, suppose that a SysBench schema has thousands of tables and each table has only limited range for a primary key. In this case, the same primary key is sent from thousands of tables to the same partition, which causes throttling. The default is `false` .", - "SaslPassword": "The secure password you created when you first set up your MSK cluster to validate a client identity and make an encrypted connection between server and client using SASL-SSL authentication.", - "SaslUserName": "The secure user name you created when you first set up your MSK cluster to validate a client identity and make an encrypted connection between server and client using SASL-SSL authentication.", + "SaslPassword": "The secure password that you created when you first set up your Amazon MSK cluster to validate a client identity and make an encrypted connection between server and client using SASL-SSL authentication.", + "SaslUserName": "The secure user name you created when you first set up your Amazon MSK cluster to validate a client identity and make an encrypted connection between server and client using SASL-SSL authentication.", "SecurityProtocol": "Set secure connection to a Kafka target endpoint using Transport Layer Security (TLS). Options include `ssl-encryption` , `ssl-authentication` , and `sasl-ssl` . `sasl-ssl` requires `SaslUsername` and `SaslPassword` .", "SslCaCertificateArn": "The Amazon Resource Name (ARN) for the private certificate authority (CA) cert that AWS DMS uses to securely connect to your Kafka target endpoint.", "SslClientCertificateArn": "The Amazon Resource Name (ARN) of the client certificate used to securely connect to a Kafka target endpoint.", "SslClientKeyArn": "The Amazon Resource Name (ARN) for the client private key used to securely connect to a Kafka target endpoint.", "SslClientKeyPassword": "The password for the client private key used to securely connect to a Kafka target endpoint.", - "Topic": "Not currently supported by AWS CloudFormation ." + "Topic": "The topic to which you migrate the data. If you don't specify a topic, AWS DMS specifies `\"kafka-default-topic\"` as the migration topic." } }, "AWS::DMS::Endpoint.KinesisSettings": { "attributes": {}, - "description": "Not currently supported by AWS CloudFormation ..", + "description": "Provides information that describes an Amazon Kinesis Data Stream endpoint. This information includes the output format of records applied to the endpoint and details of transaction and control table data information. For more information about other available settings, see [Using object mapping to migrate data to a Kinesis data stream](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Kinesis.html#CHAP_Target.Kinesis.ObjectMapping) in the *AWS Database Migration Service User Guide* .", "properties": { "IncludeControlDetails": "Shows detailed control information for table definition, column definition, and table and column changes in the Kinesis message output. The default is `false` .", "IncludeNullAndEmpty": "Include NULL and empty columns for records migrated to the endpoint. The default is `false` .", "IncludeTableAlterOperations": "Includes any data definition language (DDL) operations that change the table in the control data, such as `rename-table` , `drop-table` , `add-column` , `drop-column` , and `rename-column` . The default is `false` .", "IncludeTransactionDetails": "Provides detailed transaction information from the source database. This information includes a commit timestamp, a log position, and values for `transaction_id` , previous `transaction_id` , and `transaction_record_id` (the record offset within a transaction). The default is `false` .", - "MessageFormat": "Not currently supported by AWS CloudFormation .", + "MessageFormat": "The output format for the records created on the endpoint. The message format is `JSON` (default) or `JSON_UNFORMATTED` (a single line with no tab).", "NoHexPrefix": "Set this optional parameter to `true` to avoid adding a '0x' prefix to raw data in hexadecimal format. For example, by default, AWS DMS adds a '0x' prefix to the LOB column type in hexadecimal format moving from an Oracle source to an Amazon Kinesis target. Use the `NoHexPrefix` endpoint setting to enable migration of RAW data type columns without adding the '0x' prefix.", "PartitionIncludeSchemaTable": "Prefixes schema and table names to partition values, when the partition type is `primary-key-type` . Doing this increases data distribution among Kinesis shards. For example, suppose that a SysBench schema has thousands of tables and each table has only limited range for a primary key. In this case, the same primary key is sent from thousands of tables to the same shard, which causes throttling. The default is `false` .", - "ServiceAccessRoleArn": "Not currently supported by AWS CloudFormation .", - "StreamArn": "Not currently supported by AWS CloudFormation ." + "ServiceAccessRoleArn": "The Amazon Resource Name (ARN) for the IAM role that AWS DMS uses to write to the Kinesis data stream. The role must allow the `iam:PassRole` action.", + "StreamArn": "The Amazon Resource Name (ARN) for the Amazon Kinesis Data Streams endpoint." } }, "AWS::DMS::Endpoint.MicrosoftSqlServerSettings": { "attributes": {}, - "description": "Not currently supported by AWS CloudFormation .", + "description": "Provides information that defines a Microsoft SQL Server endpoint. This information includes the output format of records applied to the endpoint and details of transaction and control table data information. For information about other available settings, see [Extra connection attributes when using SQL Server as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.SQLServer.html#CHAP_Source.SQLServer.ConnectionAttrib) and [Extra connection attributes when using SQL Server as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.SQLServer.html#CHAP_Target.SQLServer.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .", "properties": { - "SecretsManagerAccessRoleArn": "Not currently supported by AWS CloudFormation .", - "SecretsManagerSecretId": "Not currently supported by AWS CloudFormation ." + "SecretsManagerAccessRoleArn": "The full Amazon Resource Name (ARN) of the IAM role that specifies AWS DMS as the trusted entity and grants the required permissions to access the value in `SecretsManagerSecret` . The role must allow the `iam:PassRole` action. `SecretsManagerSecret` has the value of the AWS Secrets Manager secret that allows access to the SQL Server endpoint.\n\n> You can specify one of two sets of values for these permissions. You can specify the values for this setting and `SecretsManagerSecretId` . Or you can specify clear-text values for `UserName` , `Password` , `ServerName` , and `Port` . You can't specify both.\n> \n> For more information on creating this `SecretsManagerSecret` , the corresponding `SecretsManagerAccessRoleArn` , and the `SecretsManagerSecretId` that is required to access it, see [Using secrets to access AWS Database Migration Service resources](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Security.html#security-iam-secretsmanager) in the *AWS Database Migration Service User Guide* .", + "SecretsManagerSecretId": "The full ARN, partial ARN, or display name of the `SecretsManagerSecret` that contains the MicrosoftSQLServer endpoint connection details." } }, "AWS::DMS::Endpoint.MongoDbSettings": { "attributes": {}, - "description": "Not currently supported by AWS CloudFormation .", + "description": "Provides information that defines a MongoDB endpoint. This information includes the output format of records applied to the endpoint and details of transaction and control table data information. For more information about other available settings, see [Endpoint configuration settings when using MongoDB as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.MongoDB.html#CHAP_Source.MongoDB.Configuration) in the *AWS Database Migration Service User Guide* .", "properties": { - "AuthMechanism": "Not currently supported by AWS CloudFormation .", - "AuthSource": "Not currently supported by AWS CloudFormation .", - "AuthType": "Not currently supported by AWS CloudFormation .", - "DatabaseName": "Not currently supported by AWS CloudFormation .", - "DocsToInvestigate": "Not currently supported by AWS CloudFormation .", - "ExtractDocId": "Not currently supported by AWS CloudFormation .", - "NestingLevel": "Not currently supported by AWS CloudFormation .", - "Password": "Not currently supported by AWS CloudFormation .", - "Port": "Not currently supported by AWS CloudFormation .", - "SecretsManagerAccessRoleArn": "Not currently supported by AWS CloudFormation .", - "SecretsManagerSecretId": "Not currently supported by AWS CloudFormation .", - "ServerName": "Not currently supported by AWS CloudFormation .", - "Username": "Not currently supported by AWS CloudFormation ." + "AuthMechanism": "The authentication mechanism you use to access the MongoDB source endpoint.\n\nFor the default value, in MongoDB version 2.x, `\"default\"` is `\"mongodb_cr\"` . For MongoDB version 3.x or later, `\"default\"` is `\"scram_sha_1\"` . This setting isn't used when `AuthType` is set to `\"no\"` .", + "AuthSource": "The MongoDB database name. This setting isn't used when `AuthType` is set to `\"no\"` .\n\nThe default is `\"admin\"` .", + "AuthType": "The authentication type you use to access the MongoDB source endpoint.\n\nWhen set to `\"no\"` , user name and password parameters are not used and can be empty.", + "DatabaseName": "The database name on the MongoDB source endpoint.", + "DocsToInvestigate": "Indicates the number of documents to preview to determine the document organization. Use this setting when `NestingLevel` is set to `\"one\"` .\n\nMust be a positive value greater than `0` . Default value is `1000` .", + "ExtractDocId": "Specifies the document ID. Use this setting when `NestingLevel` is set to `\"none\"` .\n\nDefault value is `\"false\"` .", + "NestingLevel": "Specifies either document or table mode.\n\nDefault value is `\"none\"` . Specify `\"none\"` to use document mode. Specify `\"one\"` to use table mode.", + "Password": "The password for the user account you use to access the MongoDB source endpoint.", + "Port": "The port value for the MongoDB source endpoint.", + "SecretsManagerAccessRoleArn": "The full Amazon Resource Name (ARN) of the IAM role that specifies AWS DMS as the trusted entity and grants the required permissions to access the value in `SecretsManagerSecret` . The role must allow the `iam:PassRole` action. `SecretsManagerSecret` has the value of the AWS Secrets Manager secret that allows access to the MongoDB endpoint.\n\n> You can specify one of two sets of values for these permissions. You can specify the values for this setting and `SecretsManagerSecretId` . Or you can specify clear-text values for `UserName` , `Password` , `ServerName` , and `Port` . You can't specify both.\n> \n> For more information on creating this `SecretsManagerSecret` , the corresponding `SecretsManagerAccessRoleArn` , and the `SecretsManagerSecretId` that is required to access it, see [Using secrets to access AWS Database Migration Service resources](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Security.html#security-iam-secretsmanager) in the *AWS Database Migration Service User Guide* .", + "SecretsManagerSecretId": "The full ARN, partial ARN, or display name of the `SecretsManagerSecret` that contains the MongoDB endpoint connection details.", + "ServerName": "The name of the server on the MongoDB source endpoint.", + "Username": "The user name you use to access the MongoDB source endpoint." } }, "AWS::DMS::Endpoint.MySqlSettings": { "attributes": {}, - "description": "Not currently supported by AWS CloudFormation .", + "description": "Provides information that defines a MySQL endpoint. This information includes the output format of records applied to the endpoint and details of transaction and control table data information. For information about other available settings, see [Extra connection attributes when using MySQL as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.MySQL.html#CHAP_Source.MySQL.ConnectionAttrib) and [Extra connection attributes when using a MySQL-compatible database as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.MySQL.html#CHAP_Target.MySQL.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .", "properties": { - "SecretsManagerAccessRoleArn": "Not currently supported by AWS CloudFormation .", - "SecretsManagerSecretId": "Not currently supported by AWS CloudFormation ." + "SecretsManagerAccessRoleArn": "The full Amazon Resource Name (ARN) of the IAM role that specifies AWS DMS as the trusted entity and grants the required permissions to access the value in `SecretsManagerSecret` . The role must allow the `iam:PassRole` action. `SecretsManagerSecret` has the value of the AWS Secrets Manager secret that allows access to the MySQL endpoint.\n\n> You can specify one of two sets of values for these permissions. You can specify the values for this setting and `SecretsManagerSecretId` . Or you can specify clear-text values for `UserName` , `Password` , `ServerName` , and `Port` . You can't specify both.\n> \n> For more information on creating this `SecretsManagerSecret` , the corresponding `SecretsManagerAccessRoleArn` , and the `SecretsManagerSecretId` that is required to access it, see [Using secrets to access AWS Database Migration Service resources](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Security.html#security-iam-secretsmanager) in the *AWS Database Migration Service User Guide* .", + "SecretsManagerSecretId": "The full ARN, partial ARN, or display name of the `SecretsManagerSecret` that contains the MySQL endpoint connection details." } }, "AWS::DMS::Endpoint.NeptuneSettings": { "attributes": {}, - "description": "Provides information that defines an Amazon Neptune endpoint.", + "description": "Provides information that defines an Amazon Neptune endpoint. This information includes the output format of records applied to the endpoint and details of transaction and control table data information. For more information about the available settings, see [Specifying endpoint settings for Amazon Neptune as a target](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Neptune.html#CHAP_Target.Neptune.EndpointSettings) in the *AWS Database Migration Service User Guide* .", "properties": { "ErrorRetryDuration": "The number of milliseconds for AWS DMS to wait to retry a bulk-load of migrated graph data to the Neptune target database before raising an error. The default is 250.", - "IamAuthEnabled": "If you want AWS Identity and Access Management (IAM) authorization enabled for this endpoint, set this parameter to `true` . Then attach the appropriate IAM policy document to your service role specified by `ServiceAccessRoleArn` . The default is `false` .", + "IamAuthEnabled": "If you want IAM authorization enabled for this endpoint, set this parameter to `true` . Then attach the appropriate IAM policy document to your service role specified by `ServiceAccessRoleArn` . The default is `false` .", "MaxFileSize": "The maximum size in kilobytes of migrated graph data stored in a .csv file before AWS DMS bulk-loads the data to the Neptune target database. The default is 1,048,576 KB. If the bulk load is successful, AWS DMS clears the bucket, ready to store the next batch of migrated graph data.", "MaxRetryCount": "The number of times for AWS DMS to retry a bulk load of migrated graph data to the Neptune target database before raising an error. The default is 5.", "S3BucketFolder": "A folder path where you want AWS DMS to store migrated graph data in the S3 bucket specified by `S3BucketName`", "S3BucketName": "The name of the Amazon S3 bucket where AWS DMS can temporarily store migrated graph data in .csv files before bulk-loading it to the Neptune target database. AWS DMS maps the SQL source data to graph data before storing it in these .csv files.", - "ServiceAccessRoleArn": "The Amazon Resource Name (ARN) of the service role that you created for the Neptune target endpoint. The role must allow the `iam:PassRole` action. For more information, see [Creating an IAM Service Role for Accessing Amazon Neptune as a Target](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Neptune.html#CHAP_Target.Neptune.ServiceRole) in the *AWS Database Migration Service User Guide.*" + "ServiceAccessRoleArn": "The Amazon Resource Name (ARN) of the service role that you created for the Neptune target endpoint. The role must allow the `iam:PassRole` action.\n\nFor more information, see [Creating an IAM Service Role for Accessing Amazon Neptune as a Target](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Neptune.html#CHAP_Target.Neptune.ServiceRole) in the *AWS Database Migration Service User Guide* ." } }, "AWS::DMS::Endpoint.OracleSettings": { "attributes": {}, - "description": "Not currently supported by AWS CloudFormation .", + "description": "Provides information that defines an Oracle endpoint. This information includes the output format of records applied to the endpoint and details of transaction and control table data information. For information about other available settings, see [Extra connection attributes when using Oracle as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.Oracle.html#CHAP_Source.Oracle.ConnectionAttrib) and [Extra connection attributes when using Oracle as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Oracle.html#CHAP_Target.Oracle.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .", "properties": { - "SecretsManagerAccessRoleArn": "Not currently supported by AWS CloudFormation .", - "SecretsManagerOracleAsmAccessRoleArn": "Not currently supported by AWS CloudFormation .", - "SecretsManagerOracleAsmSecretId": "Not currently supported by AWS CloudFormation .", - "SecretsManagerSecretId": "Not currently supported by AWS CloudFormation ." + "SecretsManagerAccessRoleArn": "The full Amazon Resource Name (ARN) of the IAM role that specifies AWS DMS as the trusted entity and grants the required permissions to access the value in `SecretsManagerSecret` . The role must allow the `iam:PassRole` action. `SecretsManagerSecret` has the value of the AWS Secrets Manager secret that allows access to the Oracle endpoint.\n\n> You can specify one of two sets of values for these permissions. You can specify the values for this setting and `SecretsManagerSecretId` . Or you can specify clear-text values for `UserName` , `Password` , `ServerName` , and `Port` . You can't specify both.\n> \n> For more information on creating this `SecretsManagerSecret` , the corresponding `SecretsManagerAccessRoleArn` , and the `SecretsManagerSecretId` that is required to access it, see [Using secrets to access AWS Database Migration Service resources](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Security.html#security-iam-secretsmanager) in the *AWS Database Migration Service User Guide* .", + "SecretsManagerOracleAsmAccessRoleArn": "Required only if your Oracle endpoint uses Advanced Storage Manager (ASM). The full ARN of the IAM role that specifies AWS DMS as the trusted entity and grants the required permissions to access the `SecretsManagerOracleAsmSecret` . This `SecretsManagerOracleAsmSecret` has the secret value that allows access to the Oracle ASM of the endpoint.\n\n> You can specify one of two sets of values for these permissions. You can specify the values for this setting and `SecretsManagerOracleAsmSecretId` . Or you can specify clear-text values for `AsmUserName` , `AsmPassword` , and `AsmServerName` . You can't specify both.\n> \n> For more information on creating this `SecretsManagerOracleAsmSecret` , the corresponding `SecretsManagerOracleAsmAccessRoleArn` , and the `SecretsManagerOracleAsmSecretId` that is required to access it, see [Using secrets to access AWS Database Migration Service resources](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Security.html#security-iam-secretsmanager) in the *AWS Database Migration Service User Guide* .", + "SecretsManagerOracleAsmSecretId": "Required only if your Oracle endpoint uses Advanced Storage Manager (ASM). The full ARN, partial ARN, or display name of the `SecretsManagerOracleAsmSecret` that contains the Oracle ASM connection details for the Oracle endpoint.", + "SecretsManagerSecretId": "The full ARN, partial ARN, or display name of the `SecretsManagerSecret` that contains the Oracle endpoint connection details." } }, "AWS::DMS::Endpoint.PostgreSqlSettings": { "attributes": {}, - "description": "Not currently supported by AWS CloudFormation .", + "description": "Provides information that defines a PostgreSQL endpoint. This information includes the output format of records applied to the endpoint and details of transaction and control table data information. For information about other available settings, see [Extra connection attributes when using PostgreSQL as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.PostgreSQL.html#CHAP_Source.PostgreSQL.ConnectionAttrib) and [Extra connection attributes when using PostgreSQL as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.PostgreSQL.html#CHAP_Target.PostgreSQL.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .", "properties": { - "SecretsManagerAccessRoleArn": "Not currently supported by AWS CloudFormation .", - "SecretsManagerSecretId": "Not currently supported by AWS CloudFormation ." + "SecretsManagerAccessRoleArn": "The full Amazon Resource Name (ARN) of the IAM role that specifies AWS DMS as the trusted entity and grants the required permissions to access the value in `SecretsManagerSecret` . The role must allow the `iam:PassRole` action. `SecretsManagerSecret` has the value of the AWS Secrets Manager secret that allows access to the PostgreSQL endpoint.\n\n> You can specify one of two sets of values for these permissions. You can specify the values for this setting and `SecretsManagerSecretId` . Or you can specify clear-text values for `UserName` , `Password` , `ServerName` , and `Port` . You can't specify both.\n> \n> For more information on creating this `SecretsManagerSecret` , the corresponding `SecretsManagerAccessRoleArn` , and the `SecretsManagerSecretId` that is required to access it, see [Using secrets to access AWS Database Migration Service resources](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Security.html#security-iam-secretsmanager) in the *AWS Database Migration Service User Guide* .", + "SecretsManagerSecretId": "The full ARN, partial ARN, or display name of the `SecretsManagerSecret` that contains the PostgreSQL endpoint connection details." } }, "AWS::DMS::Endpoint.RedisSettings": { "attributes": {}, - "description": "Provides information that defines a Redis target endpoint.", + "description": "Provides information that defines a Redis target endpoint. This information includes the output format of records applied to the endpoint and details of transaction and control table data information. For information about other available settings, see [Specifying endpoint settings for Redis as a target](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Redis.html#CHAP_Target.Redis.EndpointSettings) in the *AWS Database Migration Service User Guide* .", "properties": { "AuthPassword": "The password provided with the `auth-role` and `auth-token` options of the `AuthType` setting for a Redis target endpoint.", "AuthType": "The type of authentication to perform when connecting to a Redis target. Options include `none` , `auth-token` , and `auth-role` . The `auth-token` option requires an `AuthPassword` value to be provided. The `auth-role` option requires `AuthUserName` and `AuthPassword` values to be provided.", @@ -9889,44 +10156,75 @@ }, "AWS::DMS::Endpoint.RedshiftSettings": { "attributes": {}, - "description": "Not currently supported by AWS CloudFormation .", + "description": "Provides information that defines an Amazon Redshift endpoint. This information includes the output format of records applied to the endpoint and details of transaction and control table data information. For more information about other available settings, see [Extra connection attributes when using Amazon Redshift as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Redshift.html#CHAP_Target.Redshift.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .", "properties": { - "SecretsManagerAccessRoleArn": "Not currently supported by AWS CloudFormation .", - "SecretsManagerSecretId": "Not currently supported by AWS CloudFormation ." + "SecretsManagerAccessRoleArn": "The full Amazon Resource Name (ARN) of the IAM role that specifies AWS DMS as the trusted entity and grants the required permissions to access the value in `SecretsManagerSecret` . The role must allow the `iam:PassRole` action. `SecretsManagerSecret` has the value of the AWS Secrets Manager secret that allows access to the Amazon Redshift endpoint.\n\n> You can specify one of two sets of values for these permissions. You can specify the values for this setting and `SecretsManagerSecretId` . Or you can specify clear-text values for `UserName` , `Password` , `ServerName` , and `Port` . You can't specify both.\n> \n> For more information on creating this `SecretsManagerSecret` , the corresponding `SecretsManagerAccessRoleArn` , and the `SecretsManagerSecretId` that is required to access it, see [Using secrets to access AWS Database Migration Service resources](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Security.html#security-iam-secretsmanager) in the *AWS Database Migration Service User Guide* .", + "SecretsManagerSecretId": "The full ARN, partial ARN, or display name of the `SecretsManagerSecret` that contains the Amazon Redshift endpoint connection details." } }, "AWS::DMS::Endpoint.S3Settings": { "attributes": {}, - "description": "Not currently supported by AWS CloudFormation .", - "properties": { - "BucketFolder": "Not currently supported by AWS CloudFormation .", - "BucketName": "Not currently supported by AWS CloudFormation .", - "CompressionType": "Not currently supported by AWS CloudFormation .", - "CsvDelimiter": "Not currently supported by AWS CloudFormation .", - "CsvRowDelimiter": "Not currently supported by AWS CloudFormation .", - "ExternalTableDefinition": "Not currently supported by AWS CloudFormation .", - "ServiceAccessRoleArn": "Not currently supported by AWS CloudFormation ." + "description": "Provides information that defines an Amazon S3 endpoint. This information includes the output format of records applied to the endpoint and details of transaction and control table data information. For more information about the available settings, see [Extra connection attributes when using Amazon S3 as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.S3.html#CHAP_Source.S3.Configuring) and [Extra connection attributes when using Amazon S3 as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.S3.html#CHAP_Target.S3.Configuring) in the *AWS Database Migration Service User Guide* .", + "properties": { + "AddColumnName": "An optional parameter that, when set to `true` or `y` , you can use to add column name information to the .csv output file.\n\nThe default value is `false` . Valid values are `true` , `false` , `y` , and `n` .", + "BucketFolder": "An optional parameter to set a folder name in the S3 bucket. If provided, tables are created in the path `*bucketFolder* / *schema_name* / *table_name* /` . If this parameter isn't specified, the path used is `*schema_name* / *table_name* /` .", + "BucketName": "The name of the S3 bucket.", + "CannedAclForObjects": "A value that enables AWS DMS to specify a predefined (canned) access control list (ACL) for objects created in an Amazon S3 bucket as .csv or .parquet files. For more information about Amazon S3 canned ACLs, see [Canned ACL](https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl) in the *Amazon S3 Developer Guide* .\n\nThe default value is NONE. Valid values include NONE, PRIVATE, PUBLIC_READ, PUBLIC_READ_WRITE, AUTHENTICATED_READ, AWS_EXEC_READ, BUCKET_OWNER_READ, and BUCKET_OWNER_FULL_CONTROL.", + "CdcInsertsAndUpdates": "A value that enables a change data capture (CDC) load to write INSERT and UPDATE operations to .csv or .parquet (columnar storage) output files. The default setting is `false` , but when `CdcInsertsAndUpdates` is set to `true` or `y` , only INSERTs and UPDATEs from the source database are migrated to the .csv or .parquet file.\n\nFor .csv file format only, how these INSERTs and UPDATEs are recorded depends on the value of the `IncludeOpForFullLoad` parameter. If `IncludeOpForFullLoad` is set to `true` , the first field of every CDC record is set to either `I` or `U` to indicate INSERT and UPDATE operations at the source. But if `IncludeOpForFullLoad` is set to `false` , CDC records are written without an indication of INSERT or UPDATE operations at the source. For more information about how these settings work together, see [Indicating Source DB Operations in Migrated S3 Data](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.S3.html#CHAP_Target.S3.Configuring.InsertOps) in the *AWS Database Migration Service User Guide* .\n\n> AWS DMS supports the use of the `CdcInsertsAndUpdates` parameter in versions 3.3.1 and later.\n> \n> `CdcInsertsOnly` and `CdcInsertsAndUpdates` can't both be set to `true` for the same endpoint. Set either `CdcInsertsOnly` or `CdcInsertsAndUpdates` to `true` for the same endpoint, but not both.", + "CdcInsertsOnly": "A value that enables a change data capture (CDC) load to write only INSERT operations to .csv or columnar storage (.parquet) output files. By default (the `false` setting), the first field in a .csv or .parquet record contains the letter I (INSERT), U (UPDATE), or D (DELETE). These values indicate whether the row was inserted, updated, or deleted at the source database for a CDC load to the target.\n\nIf `CdcInsertsOnly` is set to `true` or `y` , only INSERTs from the source database are migrated to the .csv or .parquet file. For .csv format only, how these INSERTs are recorded depends on the value of `IncludeOpForFullLoad` . If `IncludeOpForFullLoad` is set to `true` , the first field of every CDC record is set to I to indicate the INSERT operation at the source. If `IncludeOpForFullLoad` is set to `false` , every CDC record is written without a first field to indicate the INSERT operation at the source. For more information about how these settings work together, see [Indicating Source DB Operations in Migrated S3 Data](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.S3.html#CHAP_Target.S3.Configuring.InsertOps) in the *AWS Database Migration Service User Guide* .\n\n> AWS DMS supports the interaction described preceding between the `CdcInsertsOnly` and `IncludeOpForFullLoad` parameters in versions 3.1.4 and later.\n> \n> `CdcInsertsOnly` and `CdcInsertsAndUpdates` can't both be set to `true` for the same endpoint. Set either `CdcInsertsOnly` or `CdcInsertsAndUpdates` to `true` for the same endpoint, but not both.", + "CdcMaxBatchInterval": "Maximum length of the interval, defined in seconds, after which to output a file to Amazon S3.\n\nWhen `CdcMaxBatchInterval` and `CdcMinFileSize` are both specified, the file write is triggered by whichever parameter condition is met first within an AWS DMS CloudFormation template.\n\nThe default value is 60 seconds.", + "CdcMinFileSize": "Minimum file size, defined in megabytes, to reach for a file output to Amazon S3.\n\nWhen `CdcMinFileSize` and `CdcMaxBatchInterval` are both specified, the file write is triggered by whichever parameter condition is met first within an AWS DMS CloudFormation template.\n\nThe default value is 32 MB.", + "CdcPath": "Specifies the folder path of CDC files. For an S3 source, this setting is required if a task captures change data; otherwise, it's optional. If `CdcPath` is set, AWS DMS reads CDC files from this path and replicates the data changes to the target endpoint. For an S3 target if you set [`PreserveTransactions`](https://docs.aws.amazon.com/dms/latest/APIReference/API_S3Settings.html#DMS-Type-S3Settings-PreserveTransactions) to `true` , AWS DMS verifies that you have set this parameter to a folder path on your S3 target where AWS DMS can save the transaction order for the CDC load. AWS DMS creates this CDC folder path in either your S3 target working directory or the S3 target location specified by [`BucketFolder`](https://docs.aws.amazon.com/dms/latest/APIReference/API_S3Settings.html#DMS-Type-S3Settings-BucketFolder) and [`BucketName`](https://docs.aws.amazon.com/dms/latest/APIReference/API_S3Settings.html#DMS-Type-S3Settings-BucketName) .\n\nFor example, if you specify `CdcPath` as `MyChangedData` , and you specify `BucketName` as `MyTargetBucket` but do not specify `BucketFolder` , AWS DMS creates the CDC folder path following: `MyTargetBucket/MyChangedData` .\n\nIf you specify the same `CdcPath` , and you specify `BucketName` as `MyTargetBucket` and `BucketFolder` as `MyTargetData` , AWS DMS creates the CDC folder path following: `MyTargetBucket/MyTargetData/MyChangedData` .\n\nFor more information on CDC including transaction order on an S3 target, see [Capturing data changes (CDC) including transaction order on the S3 target](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.S3.html#CHAP_Target.S3.EndpointSettings.CdcPath) .\n\n> This setting is supported in AWS DMS versions 3.4.2 and later.", + "CompressionType": "An optional parameter. When set to GZIP it enables the service to compress the target files. To allow the service to write the target files uncompressed, either set this parameter to NONE (the default) or don't specify the parameter at all. This parameter applies to both .csv and .parquet file formats.", + "CsvDelimiter": "The delimiter used to separate columns in the .csv file for both source and target. The default is a comma.", + "CsvNoSupValue": "This setting only applies if your Amazon S3 output files during a change data capture (CDC) load are written in .csv format. If [`UseCsvNoSupValue`](https://docs.aws.amazon.com/dms/latest/APIReference/API_S3Settings.html#DMS-Type-S3Settings-UseCsvNoSupValue) is set to true, specify a string value that you want AWS DMS to use for all columns not included in the supplemental log. If you do not specify a string value, AWS DMS uses the null value for these columns regardless of the `UseCsvNoSupValue` setting.\n\n> This setting is supported in AWS DMS versions 3.4.1 and later.", + "CsvNullValue": "An optional parameter that specifies how AWS DMS treats null values. While handling the null value, you can use this parameter to pass a user-defined string as null when writing to the target. For example, when target columns are not nullable, you can use this option to differentiate between the empty string value and the null value. So, if you set this parameter value to the empty string (\"\" or ''), AWS DMS treats the empty string as the null value instead of `NULL` .\n\nThe default value is `NULL` . Valid values include any valid string.", + "CsvRowDelimiter": "The delimiter used to separate rows in the .csv file for both source and target.\n\nThe default is a carriage return ( `\\n` ).", + "DataFormat": "The format of the data that you want to use for output. You can choose one of the following:\n\n- `csv` : This is a row-based file format with comma-separated values (.csv).\n- `parquet` : Apache Parquet (.parquet) is a columnar storage file format that features efficient compression and provides faster query response.", + "DataPageSize": "The size of one data page in bytes. This parameter defaults to 1024 * 1024 bytes (1 MiB). This number is used for .parquet file format only.", + "DatePartitionDelimiter": "Specifies a date separating delimiter to use during folder partitioning. The default value is `SLASH` . Use this parameter when `DatePartitionedEnabled` is set to `true` .", + "DatePartitionEnabled": "When set to `true` , this parameter partitions S3 bucket folders based on transaction commit dates. The default value is `false` . For more information about date-based folder partitioning, see [Using date-based folder partitioning](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.S3.html#CHAP_Target.S3.DatePartitioning) .", + "DatePartitionSequence": "Identifies the sequence of the date format to use during folder partitioning. The default value is `YYYYMMDD` . Use this parameter when `DatePartitionedEnabled` is set to `true` .", + "DatePartitionTimezone": "When creating an S3 target endpoint, set `DatePartitionTimezone` to convert the current UTC time into a specified time zone. The conversion occurs when a date partition folder is created and a change data capture (CDC) file name is generated. The time zone format is Area/Location. Use this parameter when `DatePartitionedEnabled` is set to `true` , as shown in the following example.\n\n`s3-settings='{\"DatePartitionEnabled\": true, \"DatePartitionSequence\": \"YYYYMMDDHH\", \"DatePartitionDelimiter\": \"SLASH\", \"DatePartitionTimezone\":\" *Asia/Seoul* \", \"BucketName\": \"dms-nattarat-test\"}'`", + "DictPageSizeLimit": "The maximum size of an encoded dictionary page of a column. If the dictionary page exceeds this, this column is stored using an encoding type of `PLAIN` . This parameter defaults to 1024 * 1024 bytes (1 MiB), the maximum size of a dictionary page before it reverts to `PLAIN` encoding. This size is used for .parquet file format only.", + "EnableStatistics": "A value that enables statistics for Parquet pages and row groups. Choose `true` to enable statistics, `false` to disable. Statistics include `NULL` , `DISTINCT` , `MAX` , and `MIN` values. This parameter defaults to `true` . This value is used for .parquet file format only.", + "EncodingType": "The type of encoding that you're using:\n\n- `RLE_DICTIONARY` uses a combination of bit-packing and run-length encoding to store repeated values more efficiently. This is the default.\n- `PLAIN` doesn't use encoding at all. Values are stored as they are.\n- `PLAIN_DICTIONARY` builds a dictionary of the values encountered in a given column. The dictionary is stored in a dictionary page for each column chunk.", + "EncryptionMode": "The type of server-side encryption that you want to use for your data. This encryption type is part of the endpoint settings or the extra connections attributes for Amazon S3. You can choose either `SSE_S3` (the default) or `SSE_KMS` .\n\n> For the `ModifyEndpoint` operation, you can change the existing value of the `EncryptionMode` parameter from `SSE_KMS` to `SSE_S3` . But you can\u2019t change the existing value from `SSE_S3` to `SSE_KMS` . \n\nTo use `SSE_S3` , you need an IAM role with permission to allow `\"arn:aws:s3:::dms-*\"` to use the following actions:\n\n- `s3:CreateBucket`\n- `s3:ListBucket`\n- `s3:DeleteBucket`\n- `s3:GetBucketLocation`\n- `s3:GetObject`\n- `s3:PutObject`\n- `s3:DeleteObject`\n- `s3:GetObjectVersion`\n- `s3:GetBucketPolicy`\n- `s3:PutBucketPolicy`\n- `s3:DeleteBucketPolicy`", + "ExternalTableDefinition": "The external table definition.\n\nConditional: If `S3` is used as a source then `ExternalTableDefinition` is required.", + "IgnoreHeaderRows": "When this value is set to 1, AWS DMS ignores the first row header in a .csv file. A value of 1 turns on the feature; a value of 0 turns off the feature.\n\nThe default is 0.", + "IncludeOpForFullLoad": "A value that enables a full load to write INSERT operations to the comma-separated value (.csv) output files only to indicate how the rows were added to the source database.\n\n> AWS DMS supports the `IncludeOpForFullLoad` parameter in versions 3.1.4 and later. \n\nFor full load, records can only be inserted. By default (the `false` setting), no information is recorded in these output files for a full load to indicate that the rows were inserted at the source database. If `IncludeOpForFullLoad` is set to `true` or `y` , the INSERT is recorded as an I annotation in the first field of the .csv file. This allows the format of your target records from a full load to be consistent with the target records from a CDC load.\n\n> This setting works together with the `CdcInsertsOnly` and the `CdcInsertsAndUpdates` parameters for output to .csv files only. For more information about how these settings work together, see [Indicating Source DB Operations in Migrated S3 Data](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.S3.html#CHAP_Target.S3.Configuring.InsertOps) in the *AWS Database Migration Service User Guide* .", + "MaxFileSize": "A value that specifies the maximum size (in KB) of any .csv file to be created while migrating to an S3 target during full load.\n\nThe default value is 1,048,576 KB (1 GB). Valid values include 1 to 1,048,576.", + "ParquetTimestampInMillisecond": "A value that specifies the precision of any `TIMESTAMP` column values that are written to an Amazon S3 object file in .parquet format.\n\n> AWS DMS supports the `ParquetTimestampInMillisecond` parameter in versions 3.1.4 and later. \n\nWhen `ParquetTimestampInMillisecond` is set to `true` or `y` , AWS DMS writes all `TIMESTAMP` columns in a .parquet formatted file with millisecond precision. Otherwise, DMS writes them with microsecond precision.\n\nCurrently, Amazon Athena and AWS Glue can handle only millisecond precision for `TIMESTAMP` values. Set this parameter to `true` for S3 endpoint object files that are .parquet formatted only if you plan to query or process the data with Athena or AWS Glue .\n\n> AWS DMS writes any `TIMESTAMP` column values written to an S3 file in .csv format with microsecond precision.\n> \n> Setting `ParquetTimestampInMillisecond` has no effect on the string format of the timestamp column value that is inserted by setting the `TimestampColumnName` parameter.", + "ParquetVersion": "The version of the Apache Parquet format that you want to use: `parquet_1_0` (the default) or `parquet_2_0` .", + "PreserveTransactions": "If this setting is set to `true` , AWS DMS saves the transaction order for a change data capture (CDC) load on the Amazon S3 target specified by [`CdcPath`](https://docs.aws.amazon.com/dms/latest/APIReference/API_S3Settings.html#DMS-Type-S3Settings-CdcPath) . For more information, see [Capturing data changes (CDC) including transaction order on the S3 target](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.S3.html#CHAP_Target.S3.EndpointSettings.CdcPath) .\n\n> This setting is supported in AWS DMS versions 3.4.2 and later.", + "Rfc4180": "For an S3 source, when this value is set to `true` or `y` , each leading double quotation mark has to be followed by an ending double quotation mark. This formatting complies with RFC 4180. When this value is set to `false` or `n` , string literals are copied to the target as is. In this case, a delimiter (row or column) signals the end of the field. Thus, you can't use a delimiter as part of the string, because it signals the end of the value.\n\nFor an S3 target, an optional parameter used to set behavior to comply with RFC 4180 for data migrated to Amazon S3 using .csv file format only. When this value is set to `true` or `y` using Amazon S3 as a target, if the data has quotation marks or newline characters in it, AWS DMS encloses the entire column with an additional pair of double quotation marks (\"). Every quotation mark within the data is repeated twice.\n\nThe default value is `true` . Valid values include `true` , `false` , `y` , and `n` .", + "RowGroupLength": "The number of rows in a row group. A smaller row group size provides faster reads. But as the number of row groups grows, the slower writes become. This parameter defaults to 10,000 rows. This number is used for .parquet file format only.\n\nIf you choose a value larger than the maximum, `RowGroupLength` is set to the max row group length in bytes (64 * 1024 * 1024).", + "ServerSideEncryptionKmsKeyId": "If you are using `SSE_KMS` for the `EncryptionMode` , provide the AWS KMS key ID. The key that you use needs an attached policy that enables IAM user permissions and allows use of the key.\n\nHere is a CLI example: `aws dms create-endpoint --endpoint-identifier *value* --endpoint-type target --engine-name s3 --s3-settings ServiceAccessRoleArn= *value* ,BucketFolder= *value* ,BucketName= *value* ,EncryptionMode=SSE_KMS,ServerSideEncryptionKmsKeyId= *value*`", + "ServiceAccessRoleArn": "A required parameter that specifies the Amazon Resource Name (ARN) used by the service to access the IAM role. The role must allow the `iam:PassRole` action. It enables AWS DMS to read and write objects from an S3 bucket.", + "TimestampColumnName": "A value that when nonblank causes AWS DMS to add a column with timestamp information to the endpoint data for an Amazon S3 target.\n\n> AWS DMS supports the `TimestampColumnName` parameter in versions 3.1.4 and later. \n\nAWS DMS includes an additional `STRING` column in the .csv or .parquet object files of your migrated data when you set `TimestampColumnName` to a nonblank value.\n\nFor a full load, each row of this timestamp column contains a timestamp for when the data was transferred from the source to the target by DMS.\n\nFor a change data capture (CDC) load, each row of the timestamp column contains the timestamp for the commit of that row in the source database.\n\nThe string format for this timestamp column value is `yyyy-MM-dd HH:mm:ss.SSSSSS` . By default, the precision of this value is in microseconds. For a CDC load, the rounding of the precision depends on the commit timestamp supported by DMS for the source database.\n\nWhen the `AddColumnName` parameter is set to `true` , DMS also includes a name for the timestamp column that you set with `TimestampColumnName` .", + "UseCsvNoSupValue": "This setting applies if the S3 output files during a change data capture (CDC) load are written in .csv format. If this setting is set to `true` for columns not included in the supplemental log, AWS DMS uses the value specified by [`CsvNoSupValue`](https://docs.aws.amazon.com/dms/latest/APIReference/API_S3Settings.html#DMS-Type-S3Settings-CsvNoSupValue) . If this setting isn't set or is set to `false` , AWS DMS uses the null value for these columns.\n\n> This setting is supported in AWS DMS versions 3.4.1 and later.", + "UseTaskStartTimeForFullLoadTimestamp": "When set to true, this parameter uses the task start time as the timestamp column value instead of the time data is written to target. For full load, when `useTaskStartTimeForFullLoadTimestamp` is set to `true` , each row of the timestamp column contains the task start time. For CDC loads, each row of the timestamp column contains the transaction commit time.\n\nWhen `useTaskStartTimeForFullLoadTimestamp` is set to `false` , the full load timestamp in the timestamp column increments with the time data arrives at the target." } }, "AWS::DMS::Endpoint.SybaseSettings": { "attributes": {}, - "description": "Not currently supported by AWS CloudFormation .", + "description": "Provides information that defines a SAP ASE endpoint. This information includes the output format of records applied to the endpoint and details of transaction and control table data information. For information about other available settings, see [Extra connection attributes when using SAP ASE as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.SAP.html#CHAP_Source.SAP.ConnectionAttrib) and [Extra connection attributes when using SAP ASE as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.SAP.html#CHAP_Target.SAP.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .", "properties": { - "SecretsManagerAccessRoleArn": "Not currently supported by AWS CloudFormation .", - "SecretsManagerSecretId": "Not currently supported by AWS CloudFormation ." + "SecretsManagerAccessRoleArn": "The full Amazon Resource Name (ARN) of the IAM role that specifies AWS DMS as the trusted entity and grants the required permissions to access the value in `SecretsManagerSecret` . The role must allow the `iam:PassRole` action. `SecretsManagerSecret` has the value of the AWS Secrets Manager secret that allows access to the SAP ASE endpoint.\n\n> You can specify one of two sets of values for these permissions. You can specify the values for this setting and `SecretsManagerSecretId` . Or you can specify clear-text values for `UserName` , `Password` , `ServerName` , and `Port` . You can't specify both.\n> \n> For more information on creating this `SecretsManagerSecret` , the corresponding `SecretsManagerAccessRoleArn` , and the `SecretsManagerSecretId` that is required to access it, see [Using secrets to access AWS Database Migration Service resources](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Security.html#security-iam-secretsmanager) in the *AWS Database Migration Service User Guide* .", + "SecretsManagerSecretId": "The full ARN, partial ARN, or display name of the `SecretsManagerSecret` that contains the SAP SAE endpoint connection details." } }, "AWS::DMS::EventSubscription": { "attributes": { - "Ref": "`Ref` returns the resource name. For example:\n\n`{ \"Ref\": \"myEventSubscription\" }`" + "Ref": "`Ref` returns the resource name, for example:\n\n`{ \"Ref\": \"myEventSubscription\" }`" }, - "description": "Use the `AWS::DMS::EventSubscription` resource to get notifications for AWS Database Migration Service events through the Amazon Simple Notification Service. For more information, see [Using AWS DMS Event Notification](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Events.html) in the *AWS Database Migration Service User Guide.*", + "description": "Use the `AWS::DMS::EventSubscription` resource to get notifications for AWS Database Migration Service events through the Amazon Simple Notification Service . For more information, see [Working with events and notifications in AWS Database Migration Service](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Events.html) in the *AWS Database Migration Service User Guide* .", "properties": { "Enabled": "Indicates whether to activate the subscription. If you don't specify this property, AWS CloudFormation activates the subscription.", "EventCategories": "A list of event categories for a source type that you want to subscribe to. If you don't specify this property, you are notified about all event categories. For more information, see [Working with Events and Notifications](https://docs.aws.amazon.com//dms/latest/userguide/CHAP_Events.html) in the *AWS DMS User Guide* .", "SnsTopicArn": "The Amazon Resource Name (ARN) of the Amazon SNS topic created for event notification. The ARN is created by Amazon SNS when you create a topic and subscribe to it.", "SourceIds": "A list of identifiers for which AWS DMS provides notification events.\n\nIf you don't specify a value, notifications are provided for all sources.\n\nIf you specify multiple values, they must be of the same type. For example, if you specify a database instance ID, then all of the other values must be database instance IDs.", - "SourceType": "The type of AWS DMS resource that generates the events. For example, if you want to be notified of events generated by a replication instance, you set this parameter to `replication-instance` . If this value isn't specified, all events are returned.\n\nValid values: `replication-instance` | `replication-task`", + "SourceType": "The type of AWS DMS resource that generates the events. For example, if you want to be notified of events generated by a replication instance, you set this parameter to `replication-instance` . If this value isn't specified, all events are returned.\n\n*Valid values* : `replication-instance` | `replication-task`", "SubscriptionName": "The name of the AWS DMS event notification subscription. This name must be less than 255 characters.", "Tags": "One or more tags to be assigned to the event subscription." } @@ -9942,25 +10240,25 @@ "AllocatedStorage": "The amount of storage (in gigabytes) to be initially allocated for the replication instance.", "AllowMajorVersionUpgrade": "Indicates that major version upgrades are allowed. Changing this parameter does not result in an outage, and the change is asynchronously applied as soon as possible.\n\nThis parameter must be set to `true` when specifying a value for the `EngineVersion` parameter that is a different major version than the replication instance's current version.", "AutoMinorVersionUpgrade": "A value that indicates whether minor engine upgrades are applied automatically to the replication instance during the maintenance window. This parameter defaults to `true` .\n\nDefault: `true`", - "AvailabilityZone": "The Availability Zone that the replication instance will be created in.\n\nThe default value is a random, system-chosen Availability Zone in the endpoint's AWS Region , for example: `us-east-1d`", + "AvailabilityZone": "The Availability Zone that the replication instance will be created in.\n\nThe default value is a random, system-chosen Availability Zone in the endpoint's AWS Region , for example `us-east-1d` .", "EngineVersion": "The engine version number of the replication instance.\n\nIf an engine version number is not specified when a replication instance is created, the default is the latest engine version available.", - "KmsKeyId": "An AWS KMS key identifier that is used to encrypt the data on the replication instance.\n\nIf you don't specify a value for the `KmsKeyId` parameter, then AWS DMS uses your default encryption key.\n\nAWS KMS creates the default encryption key for your AWS account . Your AWS account has a different default encryption key for each AWS Region .", + "KmsKeyId": "An AWS KMS key identifier that is used to encrypt the data on the replication instance.\n\nIf you don't specify a value for the `KmsKeyId` parameter, AWS DMS uses your default encryption key.\n\nAWS KMS creates the default encryption key for your AWS account . Your AWS account has a different default encryption key for each AWS Region .", "MultiAZ": "Specifies whether the replication instance is a Multi-AZ deployment. You can't set the `AvailabilityZone` parameter if the Multi-AZ parameter is set to `true` .", - "PreferredMaintenanceWindow": "The weekly time range during which system maintenance can occur, in Universal Coordinated Time (UTC).\n\nFormat: `ddd:hh24:mi-ddd:hh24:mi`\n\nDefault: A 30-minute window selected at random from an 8-hour block of time per AWS Region , occurring on a random day of the week.\n\nValid Days: Mon, Tue, Wed, Thu, Fri, Sat, Sun\n\nConstraints: Minimum 30-minute window.", + "PreferredMaintenanceWindow": "The weekly time range during which system maintenance can occur, in UTC.\n\n*Format* : `ddd:hh24:mi-ddd:hh24:mi`\n\n*Default* : A 30-minute window selected at random from an 8-hour block of time per AWS Region , occurring on a random day of the week.\n\n*Valid days* ( `ddd` ): `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`\n\n*Constraints* : Minimum 30-minute window.", "PubliclyAccessible": "Specifies the accessibility options for the replication instance. A value of `true` represents an instance with a public IP address. A value of `false` represents an instance with a private IP address. The default value is `true` .", - "ReplicationInstanceClass": "The compute and memory capacity of the replication instance as defined for the specified replication instance class. For example to specify the instance class dms.c4.large, set this parameter to `\"dms.c4.large\"` .\n\nFor more information on the settings and capacities for the available replication instance classes, see [Selecting the right AWS DMS replication instance for your migration](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_ReplicationInstance.html#CHAP_ReplicationInstance.InDepth) .", + "ReplicationInstanceClass": "The compute and memory capacity of the replication instance as defined for the specified replication instance class. For example, to specify the instance class dms.c4.large, set this parameter to `\"dms.c4.large\"` . For more information on the settings and capacities for the available replication instance classes, see [Selecting the right AWS DMS replication instance for your migration](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_ReplicationInstance.html#CHAP_ReplicationInstance.InDepth) in the *AWS Database Migration Service User Guide* .", "ReplicationInstanceIdentifier": "The replication instance identifier. This parameter is stored as a lowercase string.\n\nConstraints:\n\n- Must contain 1-63 alphanumeric characters or hyphens.\n- First character must be a letter.\n- Can't end with a hyphen or contain two consecutive hyphens.\n\nExample: `myrepinstance`", "ReplicationSubnetGroupIdentifier": "A subnet group to associate with the replication instance.", - "ResourceIdentifier": "A friendly name for the resource identifier at the end of the `EndpointArn` response parameter that is returned in the created `Endpoint` object. The value for this parameter can have up to 31 characters. It can contain only ASCII letters, digits, and hyphen ('-'). Also, it can't end with a hyphen or contain two consecutive hyphens, and can only begin with a letter, such as `Example-App-ARN1` . For example, this value might result in the `EndpointArn` value `arn:aws:dms:eu-west-1:012345678901:rep:Example-App-ARN1` . If you don't specify a `ResourceIdentifier` value, AWS DMS generates a default identifier value for the end of `EndpointArn` .", + "ResourceIdentifier": "A display name for the resource identifier at the end of the `EndpointArn` response parameter that is returned in the created `Endpoint` object. The value for this parameter can have up to 31 characters. It can contain only ASCII letters, digits, and hyphen ('-'). Also, it can't end with a hyphen or contain two consecutive hyphens, and can only begin with a letter, such as `Example-App-ARN1` . For example, this value might result in the `EndpointArn` value `arn:aws:dms:eu-west-1:012345678901:rep:Example-App-ARN1` . If you don't specify a `ResourceIdentifier` value, AWS DMS generates a default identifier value for the end of `EndpointArn` .", "Tags": "One or more tags to be assigned to the replication instance.", - "VpcSecurityGroupIds": "Specifies the VPC security group to be used with the replication instance. The VPC security group must work with the VPC containing the replication instance." + "VpcSecurityGroupIds": "Specifies the virtual private cloud (VPC) security group to be used with the replication instance. The VPC security group must work with the VPC containing the replication instance." } }, "AWS::DMS::ReplicationSubnetGroup": { "attributes": { "Ref": "`Ref` returns the name of the replication subnet group, such as `mystack-myrepsubnetgroup-0a12bc456789de0fg` ." }, - "description": "The `AWS::DMS::ReplicationSubnetGroup` resource creates an AWS DMS replication subnet group. Subnet groups must contain at least two subnets in two different Availability Zones in the same region.\n\n> Resource creation will fail if the `dms-vpc-role` IAM role doesn't already exist. For more information, see [Creating the IAM Roles to Use With the AWS CLI and AWS DMS API](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Security.APIRole.html) in the *AWS Database Migration Service User Guide.*", + "description": "The `AWS::DMS::ReplicationSubnetGroup` resource creates an AWS DMS replication subnet group. Subnet groups must contain at least two subnets in two different Availability Zones in the same AWS Region .\n\n> Resource creation fails if the `dms-vpc-role` AWS Identity and Access Management ( IAM ) role doesn't already exist. For more information, see [Creating the IAM Roles to Use With the AWS CLI and AWS DMS API](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Security.APIRole.html) in the *AWS Database Migration Service User Guide* .", "properties": { "ReplicationSubnetGroupDescription": "The description for the subnet group.", "ReplicationSubnetGroupIdentifier": "The identifier for the replication subnet group. If you don't specify a name, AWS CloudFormation generates a unique ID and uses that ID for the identifier.", @@ -9974,16 +10272,16 @@ }, "description": "The `AWS::DMS::ReplicationTask` resource creates an AWS DMS replication task.", "properties": { - "CdcStartPosition": "Indicates when you want a change data capture (CDC) operation to start. Use either CdcStartPosition or CdcStartTime to specify when you want a CDC operation to start. Specifying both values results in an error.\n\nThe value can be in date, checkpoint, or LSN/SCN format.\n\nDate Example: --cdc-start-position \u201c2018-03-08T12:12:12\u201d\n\nCheckpoint Example: --cdc-start-position \"checkpoint:V1#27#mysql-bin-changelog.157832:1975:-1:2002:677883278264080:mysql-bin-changelog.157832:1876#0#0#*#0#93\"\n\nLSN Example: --cdc-start-position \u201cmysql-bin-changelog.000024:373\u201d\n\n> When you use this task setting with a source PostgreSQL database, a logical replication slot should already be created and associated with the source endpoint. You can verify this by setting the `slotName` extra connection attribute to the name of this logical replication slot. For more information, see [Extra Connection Attributes When Using PostgreSQL as a Source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.PostgreSQL.html#CHAP_Source.PostgreSQL.ConnectionAttrib) .", + "CdcStartPosition": "Indicates when you want a change data capture (CDC) operation to start. Use either `CdcStartPosition` or `CdcStartTime` to specify when you want a CDC operation to start. Specifying both values results in an error.\n\nThe value can be in date, checkpoint, log sequence number (LSN), or system change number (SCN) format.\n\nHere is a date example: `--cdc-start-position \"2018-03-08T12:12:12\"`\n\nHere is a checkpoint example: `--cdc-start-position \"checkpoint:V1#27#mysql-bin-changelog.157832:1975:-1:2002:677883278264080:mysql-bin-changelog.157832:1876#0#0#*#0#93\"`\n\nHere is an LSN example: `--cdc-start-position \u201cmysql-bin-changelog.000024:373\u201d`\n\n> When you use this task setting with a source PostgreSQL database, a logical replication slot should already be created and associated with the source endpoint. You can verify this by setting the `slotName` extra connection attribute to the name of this logical replication slot. For more information, see [Extra Connection Attributes When Using PostgreSQL as a Source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.PostgreSQL.html#CHAP_Source.PostgreSQL.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .", "CdcStartTime": "Indicates the start time for a change data capture (CDC) operation.", - "CdcStopPosition": "Indicates when you want a change data capture (CDC) operation to stop. The value can be either server time or commit time.\n\nServer time example: --cdc-stop-position \u201cserver_time:2018-02-09T12:12:12\u201d\n\nCommit time example: --cdc-stop-position \u201ccommit_time: 2018-02-09T12:12:12 \u201c", + "CdcStopPosition": "Indicates when you want a change data capture (CDC) operation to stop. The value can be either server time or commit time.\n\nHere is a server time example: `--cdc-stop-position \"server_time:2018-02-09T12:12:12\"`\n\nHere is a commit time example: `--cdc-stop-position \"commit_time: 2018-02-09T12:12:12\"`", "MigrationType": "The migration type. Valid values: `full-load` | `cdc` | `full-load-and-cdc`", "ReplicationInstanceArn": "The Amazon Resource Name (ARN) of a replication instance.", "ReplicationTaskIdentifier": "An identifier for the replication task.\n\nConstraints:\n\n- Must contain 1-255 alphanumeric characters or hyphens.\n- First character must be a letter.\n- Cannot end with a hyphen or contain two consecutive hyphens.", - "ReplicationTaskSettings": "Overall settings for the task, in JSON format. For more information, see [Specifying Task Settings for AWS Database Migration Service Tasks](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Tasks.CustomizingTasks.TaskSettings.html) in the *AWS Database Migration Service User Guide.*", - "ResourceIdentifier": "A friendly name for the resource identifier at the end of the `EndpointArn` response parameter that is returned in the created `Endpoint` object. The value for this parameter can have up to 31 characters. It can contain only ASCII letters, digits, and hyphen ('-'). Also, it can't end with a hyphen or contain two consecutive hyphens, and can only begin with a letter, such as `Example-App-ARN1` . For example, this value might result in the `EndpointArn` value `arn:aws:dms:eu-west-1:012345678901:rep:Example-App-ARN1` . If you don't specify a `ResourceIdentifier` value, AWS DMS generates a default identifier value for the end of `EndpointArn` .", + "ReplicationTaskSettings": "Overall settings for the task, in JSON format. For more information, see [Specifying Task Settings for AWS Database Migration Service Tasks](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Tasks.CustomizingTasks.TaskSettings.html) in the *AWS Database Migration Service User Guide* .", + "ResourceIdentifier": "A display name for the resource identifier at the end of the `EndpointArn` response parameter that is returned in the created `Endpoint` object. The value for this parameter can have up to 31 characters. It can contain only ASCII letters, digits, and hyphen ('-'). Also, it can't end with a hyphen or contain two consecutive hyphens, and can only begin with a letter, such as `Example-App-ARN1` .\n\nFor example, this value might result in the `EndpointArn` value `arn:aws:dms:eu-west-1:012345678901:rep:Example-App-ARN1` . If you don't specify a `ResourceIdentifier` value, AWS DMS generates a default identifier value for the end of `EndpointArn` .", "SourceEndpointArn": "An Amazon Resource Name (ARN) that uniquely identifies the source endpoint.", - "TableMappings": "The table mappings for the task, in JSON format. For more information, see [Using Table Mapping to Specify Task Settings](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Tasks.CustomizingTasks.TableMapping.html) in the *AWS Database Migration Service User Guide.*", + "TableMappings": "The table mappings for the task, in JSON format. For more information, see [Using Table Mapping to Specify Task Settings](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Tasks.CustomizingTasks.TableMapping.html) in the *AWS Database Migration Service User Guide* .", "Tags": "One or more tags to be assigned to the replication task.", "TargetEndpointArn": "An Amazon Resource Name (ARN) that uniquely identifies the target endpoint.", "TaskData": "" @@ -10092,10 +10390,24 @@ "SubnetArn": "The Amazon Resource Name (ARN) of the subnet that DataSync uses to access the target EFS file system." } }, + "AWS::DataSync::LocationFSxLustre": { + "attributes": { + "LocationArn": "The ARN of the specified FSx for Lustre file system location.", + "LocationUri": "The URI of the specified FSx for Lustre file system location.", + "Ref": "`Ref` returns the location resource ARN. For example:\n\n`arn:aws:datasync:us-east-2:111222333444:location/loc-07db7abfc326c50s3`" + }, + "description": "The `AWS::DataSync::LocationFSxLustre` resource specifies an endpoint for an Amazon FSx for Lustre file system.", + "properties": { + "FsxFilesystemArn": "The Amazon Resource Name (ARN) for the FSx for Lustre file system.", + "SecurityGroupArns": "The ARNs of the security groups that are used to configure the FSx for Lustre file system.\n\n*Pattern* : `^arn:(aws|aws-cn|aws-us-gov|aws-iso|aws-iso-b):ec2:[a-z\\-0-9]*:[0-9]{12}:security-group/.*$`\n\n*Length constraints* : Maximum length of 128.", + "Subdirectory": "A subdirectory in the location's path. This subdirectory in the FSx for Lustre file system is used to read data from the FSx for Lustre source location or write data to the FSx for Lustre destination.", + "Tags": "The key-value pair that represents a tag that you want to add to the resource. The value can be an empty string. This value helps you manage, filter, and search for your resources. We recommend that you create a name tag for your location." + } + }, "AWS::DataSync::LocationFSxWindows": { "attributes": { - "LocationArn": "The Amazon Resource Name (ARN) of the specified Amazon FSx for Windows Server file system location.", - "LocationUri": "The URI of the specified Amazon FSx for Windows Server file system.", + "LocationArn": "The ARN of the specified FSx for Windows Server file system location.", + "LocationUri": "The URI of the specified FSx for Windows Server file system location.", "Ref": "When you pass the logical ID of this resource to the intrinsic `Ref` function, `Ref` returns the location resource ARN. For example:\n\n`arn:aws:datasync:us-east-2:111222333444:location/loc-07db7abfc326c50s3`\n\nFor more information about using the `Ref` function, see [Ref](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) ." }, "description": "The `AWS::DataSync::LocationFSxWindows` resource specifies an endpoint for an Amazon FSx for Windows Server file system.", @@ -10103,7 +10415,7 @@ "Domain": "The name of the Windows domain that the FSx for Windows File Server belongs to.", "FsxFilesystemArn": "The Amazon Resource Name (ARN) for the FSx for Windows File Server file system.", "Password": "The password of the user who has the permissions to access files and folders in the FSx for Windows File Server file system.", - "SecurityGroupArns": "The Amazon Resource Names (ARNs) of the security groups that are used to configure the FSx for Windows File Server file system.\n\n*Pattern* : `^arn:(aws|aws-cn|aws-us-gov|aws-iso|aws-iso-b):ec2:[a-z\\-0-9]*:[0-9]{12}:security-group/.*$`\n\n*Length Constraints* : Maximum length of 128.", + "SecurityGroupArns": "The Amazon Resource Names (ARNs) of the security groups that are used to configure the FSx for Windows File Server file system.\n\n*Pattern* : `^arn:(aws|aws-cn|aws-us-gov|aws-iso|aws-iso-b):ec2:[a-z\\-0-9]*:[0-9]{12}:security-group/.*$`\n\n*Length constraints* : Maximum length of 128.", "Subdirectory": "A subdirectory in the location's path. This subdirectory in the Amazon FSx for Windows File Server file system is used to read data from the Amazon FSx for Windows File Server source location or write data to the FSx for Windows File Server destination.", "Tags": "The key-value pair that represents a tag that you want to add to the resource. The value can be an empty string. This value helps you manage, filter, and search for your resources. We recommend that you create a name tag for your location.", "User": "The user who has the permissions to access files and folders in the FSx for Windows File Server file system.\n\nFor information about choosing a user name that ensures sufficient permissions to files, folders, and metadata, see [user](https://docs.aws.amazon.com/datasync/latest/userguide/create-fsx-location.html#FSxWuser) ." @@ -10115,10 +10427,10 @@ "LocationUri": "The URI of the HDFS cluster location.", "Ref": "When you pass the logical ID of this resource to the intrinsic `Ref` function, `Ref` returns the location resource ARN. For example:\n\n`arn:aws:datasync:us-east-2:111222333444:location/loc-07db7abfc326c50s3`\n\nFor more information about using the `Ref` function, see [Ref](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) ." }, - "description": "Creates an endpoint for a Hadoop Distributed File System (HDFS).", + "description": "The `AWS::DataSync::LocationHDFS` resource specifies an endpoint for a Hadoop Distributed File System (HDFS).", "properties": { "AgentArns": "The Amazon Resource Names (ARNs) of the agents that are used to connect to the HDFS cluster.", - "AuthenticationType": "The type of authentication used to determine the identity of the user.", + "AuthenticationType": "", "BlockSize": "The size of data blocks to write into the HDFS cluster. The block size must be a multiple of 512 bytes. The default block size is 128 mebibytes (MiB).", "KerberosKeytab": "The Kerberos key table (keytab) that contains mappings between the defined Kerberos principal and the encrypted keys. Provide the base64-encoded file text. If `KERBEROS` is specified for `AuthType` , this value is required.", "KerberosKrb5Conf": "The `krb5.conf` file that contains the Kerberos configuration information. You can load the `krb5.conf` by providing a string of the file's contents or an Amazon S3 presigned URL of the file. If `KERBEROS` is specified for `AuthType` , this value is required.", @@ -10213,9 +10525,9 @@ }, "AWS::DataSync::LocationS3.S3Config": { "attributes": {}, - "description": "The Amazon Resource Name (ARN) of the AWS Identity and Access Management (IAM) role that is used to access an Amazon S3 bucket.\n\nFor detailed information about using such a role, see [Creating a Location for Amazon S3](https://docs.aws.amazon.com/datasync/latest/userguide/working-with-locations.html#create-s3-location) in the *AWS DataSync User Guide* .", + "description": "The Amazon Resource Name (ARN) of the AWS Identity and Access Management (IAM) role used to access an Amazon S3 bucket.\n\nFor detailed information about using such a role, see [Creating a Location for Amazon S3](https://docs.aws.amazon.com/datasync/latest/userguide/working-with-locations.html#create-s3-location) in the *AWS DataSync User Guide* .", "properties": { - "BucketAccessRoleArn": "The Amazon S3 bucket to access. This bucket is used as a parameter in the [CreateLocationS3](https://docs.aws.amazon.com/datasync/latest/userguide/API_CreateLocationS3.html) operation." + "BucketAccessRoleArn": "The ARN of the IAM role for accessing the S3 bucket." } }, "AWS::DataSync::LocationSMB": { @@ -10245,12 +10557,13 @@ }, "AWS::DataSync::Task": { "attributes": { - "DestinationNetworkInterfaceArns": "", - "ErrorCode": "Errors that AWS DataSync encountered during execution of the task. You can use this error code to help troubleshoot issues.", + "DestinationNetworkInterfaceArns": "The ARNs of the destination elastic network interfaces (ENIs) that were created for your subnet.", + "ErrorCode": "Errors encountered during task execution. Troubleshoot issues with this error code.", "ErrorDetail": "Detailed description of an error that was encountered during the task execution. You can use this information to help troubleshoot issues.", - "Ref": "When you pass the logical ID of this resource to the intrinsic `Ref` function, `Ref` returns the location resource ARN. For example:\n\n`arn:aws:datasync:us-east-2:111222333444:location/loc-07db7abfc326c50s3`\n\nFor more information about using the `Ref` function, see [Ref](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) .", + "Ref": "When you pass the logical ID of this resource to the intrinsic `Ref` function, `Ref` returns the location resource ARN. For example:\n\n`arn:aws:datasync:us-east-2:111222333444:task/task-07db7abfc326c50s3`\n\nFor more information about using the `Ref` function, see [Ref](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) .", + "SourceNetworkInterfaceArns": "The ARNs of the source ENIs that were created for your subnet.", "Status": "The status of the task that was described.", - "TaskArn": "The Amazon Resource Name (ARN) of the task." + "TaskArn": "The ARN of the task." }, "description": "The `AWS::DataSync::Task` resource specifies a task. A task is a set of two locations (source and destination) and a set of `Options` that you use to control the behavior of a task. If you don't specify `Options` when you create a task, AWS DataSync populates them with service defaults.", "properties": { @@ -10328,7 +10641,7 @@ "Id": "The ID of the notification channel.", "Ref": "When the logical ID of this resource is provided to the `Ref` intrinsic function, `Ref` returns Amazon Resource Name (ARN) of the `NotificationChannel` . For more information about using the `Ref` function, see [Ref](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) ." }, - "description": "Adds a notification channel to DevOps Guru. A notification channel is used to notify you about important DevOps Guru events, such as when an insight is generated.\n\nIf you use an Amazon SNS topic in another account, you must attach a policy to it that grants DevOps Guru permission to it notifications. DevOps Guru adds the required policy on your behalf to send notifications using Amazon SNS in your account. For more information, see [Permissions for cross account Amazon SNS topics](https://docs.aws.amazon.com/devops-guru/latest/userguide/sns-required-permissions.html) .\n\nIf you use an Amazon SNS topic that is encrypted by an AWS Key Management Service customer-managed key (CMK), then you must add permissions to the CMK. For more information, see [Permissions for AWS KMS\u2013encrypted Amazon SNS topics](https://docs.aws.amazon.com/devops-guru/latest/userguide/sns-kms-permissions.html) .", + "description": "Adds a notification channel to DevOps Guru. A notification channel is used to notify you about important DevOps Guru events, such as when an insight is generated.\n\nIf you use an Amazon SNS topic in another account, you must attach a policy to it that grants DevOps Guru permission to it notifications. DevOps Guru adds the required policy on your behalf to send notifications using Amazon SNS in your account. DevOps Guru only supports standard SNS topics. For more information, see [Permissions for cross account Amazon SNS topics](https://docs.aws.amazon.com/devops-guru/latest/userguide/sns-required-permissions.html) .\n\nIf you use an Amazon SNS topic in another account, you must attach a policy to it that grants DevOps Guru permission to it notifications. DevOps Guru adds the required policy on your behalf to send notifications using Amazon SNS in your account. For more information, see Permissions for cross account Amazon SNS topics.\n\nIf you use an Amazon SNS topic that is encrypted by an AWS Key Management Service customer-managed key (CMK), then you must add permissions to the CMK. For more information, see [Permissions for AWS KMS\u2013encrypted Amazon SNS topics](https://docs.aws.amazon.com/devops-guru/latest/userguide/sns-kms-permissions.html) .", "properties": { "Config": "A `NotificationChannelConfig` object that contains information about configured notification channels." } @@ -10337,12 +10650,12 @@ "attributes": {}, "description": "Information about notification channels you have configured with DevOps Guru. The one supported notification channel is Amazon Simple Notification Service (Amazon SNS).", "properties": { - "Sns": "Information about a notification channel configured in DevOps Guru to send notifications when insights are created.\n\nIf you use an Amazon SNS topic in another account, you must attach a policy to it that grants DevOps Guru permission to it notifications. DevOps Guru adds the required policy on your behalf to send notifications using Amazon SNS in your account. For more information, see [Permissions for cross account Amazon SNS topics](https://docs.aws.amazon.com/devops-guru/latest/userguide/sns-required-permissions.html) .\n\nIf you use an Amazon SNS topic that is encrypted by an AWS Key Management Service customer-managed key (CMK), then you must add permissions to the CMK. For more information, see [Permissions for AWS KMS\u2013encrypted Amazon SNS topics](https://docs.aws.amazon.com/devops-guru/latest/userguide/sns-kms-permissions.html) ." + "Sns": "Information about a notification channel configured in DevOps Guru to send notifications when insights are created.\n\nIf you use an Amazon SNS topic in another account, you must attach a policy to it that grants DevOps Guru permission to it notifications. DevOps Guru adds the required policy on your behalf to send notifications using Amazon SNS in your account. DevOps Guru only supports standard SNS topics. For more information, see [Permissions for cross account Amazon SNS topics](https://docs.aws.amazon.com/devops-guru/latest/userguide/sns-required-permissions.html) .\n\nIf you use an Amazon SNS topic in another account, you must attach a policy to it that grants DevOps Guru permission to it notifications. DevOps Guru adds the required policy on your behalf to send notifications using Amazon SNS in your account. For more information, see Permissions for cross account Amazon SNS topics.\n\nIf you use an Amazon SNS topic that is encrypted by an AWS Key Management Service customer-managed key (CMK), then you must add permissions to the CMK. For more information, see [Permissions for AWS KMS\u2013encrypted Amazon SNS topics](https://docs.aws.amazon.com/devops-guru/latest/userguide/sns-kms-permissions.html) ." } }, "AWS::DevOpsGuru::NotificationChannel.SnsChannelConfig": { "attributes": {}, - "description": "Contains the Amazon Resource Name (ARN) of an Amazon Simple Notification Service topic.\n\nIf you use an Amazon SNS topic in another account, you must attach a policy to it that grants DevOps Guru permission to it notifications. DevOps Guru adds the required policy on your behalf to send notifications using Amazon SNS in your account. For more information, see [Permissions for cross account Amazon SNS topics](https://docs.aws.amazon.com/devops-guru/latest/userguide/sns-required-permissions.html) .\n\nIf you use an Amazon SNS topic that is encrypted by an AWS Key Management Service customer-managed key (CMK), then you must add permissions to the CMK. For more information, see [Permissions for AWS KMS\u2013encrypted Amazon SNS topics](https://docs.aws.amazon.com/devops-guru/latest/userguide/sns-kms-permissions.html) .", + "description": "Contains the Amazon Resource Name (ARN) of an Amazon Simple Notification Service topic.\n\nIf you use an Amazon SNS topic in another account, you must attach a policy to it that grants DevOps Guru permission to it notifications. DevOps Guru adds the required policy on your behalf to send notifications using Amazon SNS in your account. DevOps Guru only supports standard SNS topics. For more information, see [Permissions for cross account Amazon SNS topics](https://docs.aws.amazon.com/devops-guru/latest/userguide/sns-required-permissions.html) .\n\nIf you use an Amazon SNS topic in another account, you must attach a policy to it that grants DevOps Guru permission to it notifications. DevOps Guru adds the required policy on your behalf to send notifications using Amazon SNS in your account. For more information, see Permissions for cross account Amazon SNS topics.\n\nIf you use an Amazon SNS topic that is encrypted by an AWS Key Management Service customer-managed key (CMK), then you must add permissions to the CMK. For more information, see [Permissions for AWS KMS\u2013encrypted Amazon SNS topics](https://docs.aws.amazon.com/devops-guru/latest/userguide/sns-kms-permissions.html) .", "properties": { "TopicArn": "The Amazon Resource Name (ARN) of an Amazon Simple Notification Service topic." } @@ -10542,6 +10855,7 @@ "properties": { "AvailabilityZones": "A list of Amazon EC2 Availability Zones that instances in the cluster can be created in.", "BackupRetentionPeriod": "The number of days for which automated backups are retained. You must specify a minimum value of 1.\n\nDefault: 1\n\nConstraints:\n\n- Must be a value from 1 to 35.", + "CopyTagsToSnapshot": "", "DBClusterIdentifier": "The cluster identifier. This parameter is stored as a lowercase string.\n\nConstraints:\n\n- Must contain from 1 to 63 letters, numbers, or hyphens.\n- The first character must be a letter.\n- Cannot end with a hyphen or contain two consecutive hyphens.\n\nExample: `my-cluster`", "DBClusterParameterGroupName": "The name of the cluster parameter group to associate with this cluster.", "DBSubnetGroupName": "A subnet group to associate with this cluster.\n\nConstraints: Must match the name of an existing `DBSubnetGroup` . Must not be default.\n\nExample: `mySubnetgroup`", @@ -10616,7 +10930,7 @@ "GlobalSecondaryIndexes": "Global secondary indexes to be created on the global table. You can create up to 20 global secondary indexes. Each replica in your global table will have the same global secondary index settings. You can only create or delete one global secondary index in a single stack operation.\n\nSince the backfilling of an index could take a long time, CloudFormation does not wait for the index to become active. If a stack operation rolls back, CloudFormation might not delete an index that has been added. In that case, you will need to delete the index manually.", "KeySchema": "Specifies the attributes that make up the primary key for the table. The attributes in the `KeySchema` property must also be defined in the `AttributeDefinitions` property.", "LocalSecondaryIndexes": "Local secondary indexes to be created on the table. You can create up to five local secondary indexes. Each index is scoped to a given hash key value. The size of each hash key can be up to 10 gigabytes. Each replica in your global table will have the same local secondary index settings.", - "Replicas": "Specifies the list of replicas for your global table. The list must contain at least one element, the region where the stack defining the global table is deployed. For example, if you define your table in a stack deployed to us-east-1, you must have an entry in `Replicas` with the region us-east-1. You cannot remove the replica in the stack region.\n\n> Adding a replica might take a few minutes for an empty table, or up to several hours for large tables. If you want to add or remove a replica, we recommend submitting an `UpdateStack` operation containing only that change.\n> \n> If you add or delete a replica during an update, we recommend that you don't update any other resources. If your stack fails to update and is rolled back while adding a new replica, you might need to manually delete the replica. \n\nYou can create a new global table with up to two replicas. You can add or remove replicas after table creation, but you can only add or remove a single replica in each update.", + "Replicas": "Specifies the list of replicas for your global table. The list must contain at least one element, the region where the stack defining the global table is deployed. For example, if you define your table in a stack deployed to us-east-1, you must have an entry in `Replicas` with the region us-east-1. You cannot remove the replica in the stack region.\n\n> Adding a replica might take a few minutes for an empty table, or up to several hours for large tables. If you want to add or remove a replica, we recommend submitting an `UpdateStack` operation containing only that change.\n> \n> If you add or delete a replica during an update, we recommend that you don't update any other resources. If your stack fails to update and is rolled back while adding a new replica, you might need to manually delete the replica. \n\nYou can create a new global table with as many replicas as needed. You can add or remove replicas after table creation, but you can only add or remove a single replica in each update.", "SSESpecification": "Specifies the settings to enable server-side encryption. These settings will be applied to all replicas. If you plan to use customer-managed KMS keys, you must provide a key for each replica using the `ReplicaSpecification.ReplicaSSESpecification` property.", "StreamSpecification": "Specifies the streams settings on your global table. You must provide a value for this property if your global table contains more than one replica. You can only change the streams settings if your global table has only one replica.", "TableName": "A name for the global table. If you don't specify a name, AWS CloudFormation generates a unique ID and uses that ID as the table name. For more information, see [Name type](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-name.html) .\n\n> If you specify a name, you cannot perform updates that require replacement of this resource. You can perform updates that require no or some interruption. If you must replace the resource, specify a new name.", @@ -10725,6 +11039,7 @@ "ReadProvisionedThroughputSettings": "Defines read capacity settings for the replica table.", "Region": "The region in which this replica exists.", "SSESpecification": "Allows you to specify a customer-managed key for the replica. When using customer-managed keys for server-side encryption, this property must have a value in all replicas.", + "TableClass": "The table class of the specified table. Valid values are `STANDARD` and `STANDARD_INFREQUENT_ACCESS` .", "Tags": "An array of key-value pairs to apply to this replica.\n\nFor more information, see [Tag](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resource-tags.html) ." } }, @@ -11116,7 +11431,7 @@ "description": "Specifies a set of DHCP options for your VPC.\n\nYou must specify at least one of the following properties: `DomainNameServers` , `NetbiosNameServers` , `NtpServers` . If you specify `NetbiosNameServers` , you must specify `NetbiosNodeType` .", "properties": { "DomainName": "This value is used to complete unqualified DNS hostnames. If you're using AmazonProvidedDNS in `us-east-1` , specify `ec2.internal` . If you're using AmazonProvidedDNS in another Region, specify *region* . `compute.internal` (for example, `ap-northeast-1.compute.internal` ). Otherwise, specify a domain name (for example, *MyCompany.com* ).", - "DomainNameServers": "The IPv4 addresses of up to four domain name servers, or AmazonProvidedDNS. The default DHCP option set specifies `AmazonProvidedDNS` . If specifying more than one domain name server, specify the IP addresses in a single parameter, separated by commas. To have your instance to receive a custom DNS hostname as specified in `DomainName` , you must set this to a custom DNS server.", + "DomainNameServers": "The IPv4 addresses of up to four domain name servers, or `AmazonProvidedDNS` . The default is `AmazonProvidedDNS` . To have your instance receive a custom DNS hostname as specified in `DomainName` , you must set this property to a custom DNS server.", "NetbiosNameServers": "The IPv4 addresses of up to four NetBIOS name servers.", "NetbiosNodeType": "The NetBIOS node type (1, 2, 4, or 8). We recommend that you specify 2 (broadcast and multicast are not currently supported).", "NtpServers": "The IPv4 addresses of up to four Network Time Protocol (NTP) servers.", @@ -11234,9 +11549,9 @@ "MemoryGiBPerVCpu": "The minimum and maximum amount of memory per vCPU, in GiB.\n\nDefault: No minimum or maximum limits", "MemoryMiB": "The minimum and maximum amount of memory, in MiB.", "NetworkInterfaceCount": "The minimum and maximum number of network interfaces.\n\nDefault: No minimum or maximum limits", - "OnDemandMaxPricePercentageOverLowestPrice": "The price protection threshold for On-Demand Instances. This is the maximum you\u2019ll pay for an On-Demand Instance, expressed as a percentage above the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 selects instance types with your attributes, it excludes instance types priced above your threshold.\n\nThe parameter accepts an integer, which Amazon EC2 interprets as a percentage.\n\nTo turn off price protection, specify a high value, such as `999999` .\n\nThis parameter is not supported for [GetSpotPlacementScores](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetSpotPlacementScores.html) and [GetInstanceTypesFromInstanceRequirements](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetInstanceTypesFromInstanceRequirements.html) .\n\nDefault: `20`", + "OnDemandMaxPricePercentageOverLowestPrice": "The price protection threshold for On-Demand Instances. This is the maximum you\u2019ll pay for an On-Demand Instance, expressed as a percentage above the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 selects instance types with your attributes, it excludes instance types priced above your threshold.\n\nThe parameter accepts an integer, which Amazon EC2 interprets as a percentage.\n\nTo turn off price protection, specify a high value, such as `999999` .\n\nThis parameter is not supported for [GetSpotPlacementScores](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetSpotPlacementScores.html) and [GetInstanceTypesFromInstanceRequirements](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetInstanceTypesFromInstanceRequirements.html) .\n\n> If you set `TargetCapacityUnitType` to `vcpu` or `memory-mib` , the price protection threshold is applied based on the per-vCPU or per-memory price instead of the per-instance price. \n\nDefault: `20`", "RequireHibernateSupport": "Indicates whether instance types must support hibernation for On-Demand Instances.\n\nThis parameter is not supported for [GetSpotPlacementScores](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetSpotPlacementScores.html) .\n\nDefault: `false`", - "SpotMaxPricePercentageOverLowestPrice": "The price protection threshold for Spot Instance. This is the maximum you\u2019ll pay for an Spot Instance, expressed as a percentage above the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 selects instance types with your attributes, it excludes instance types priced above your threshold.\n\nThe parameter accepts an integer, which Amazon EC2 interprets as a percentage.\n\nTo turn off price protection, specify a high value, such as `999999` .\n\nThis parameter is not supported for [GetSpotPlacementScores](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetSpotPlacementScores.html) and [GetInstanceTypesFromInstanceRequirements](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetInstanceTypesFromInstanceRequirements.html) .\n\nDefault: `100`", + "SpotMaxPricePercentageOverLowestPrice": "The price protection threshold for Spot Instance. This is the maximum you\u2019ll pay for an Spot Instance, expressed as a percentage above the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 selects instance types with your attributes, it excludes instance types priced above your threshold.\n\nThe parameter accepts an integer, which Amazon EC2 interprets as a percentage.\n\nTo turn off price protection, specify a high value, such as `999999` .\n\nThis parameter is not supported for [GetSpotPlacementScores](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetSpotPlacementScores.html) and [GetInstanceTypesFromInstanceRequirements](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetInstanceTypesFromInstanceRequirements.html) .\n\n> If you set `TargetCapacityUnitType` to `vcpu` or `memory-mib` , the price protection threshold is applied based on the per-vCPU or per-memory price instead of the per-instance price. \n\nDefault: `100`", "TotalLocalStorageGB": "The minimum and maximum amount of total local storage, in GB.\n\nDefault: No minimum or maximum limits", "VCpuCount": "The minimum and maximum number of vCPUs." } @@ -11404,7 +11719,7 @@ "description": "Specifies a VPC flow log that captures IP traffic for a specified network interface, subnet, or VPC. To view the log data, use Amazon CloudWatch Logs (CloudWatch Logs) to help troubleshoot connection issues. For example, you can use a flow log to investigate why certain traffic isn't reaching an instance, which can help you diagnose overly restrictive security group rules. For more information, see [VPC Flow Logs](https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html) in the *Amazon VPC User Guide* .", "properties": { "DeliverLogsPermissionArn": "The ARN for the IAM role that permits Amazon EC2 to publish flow logs to a CloudWatch Logs log group in your account.\n\nIf you specify `LogDestinationType` as `s3` , do not specify `DeliverLogsPermissionArn` or `LogGroupName` .", - "DestinationOptions": "The destination options.", + "DestinationOptions": "The destination options. The following options are supported:\n\n- `FileFormat` - The format for the flow log ( `plain-text` | `parquet` ). The default is `plain-text` .\n- `HiveCompatiblePartitions` - Indicates whether to use Hive-compatible prefixes for flow logs stored in Amazon S3 ( `true` | `false` ). The default is `false` .\n- `PerHourPartition` - Indicates whether to partition the flow log per hour ( `true` | `false` ). The default is `false` .", "LogDestination": "The destination to which the flow log data is to be published. Flow log data can be published to a CloudWatch Logs log group or an Amazon S3 bucket. The value specified for this parameter depends on the value specified for `LogDestinationType` .\n\nIf `LogDestinationType` is not specified or `cloud-watch-logs` , specify the Amazon Resource Name (ARN) of the CloudWatch Logs log group. For example, to publish to a log group called `my-logs` , specify `arn:aws:logs:us-east-1:123456789012:log-group:my-logs` . Alternatively, use `LogGroupName` instead.\n\nIf LogDestinationType is `s3` , specify the ARN of the Amazon S3 bucket. You can also specify a subfolder in the bucket. To specify a subfolder in the bucket, use the following ARN format: `bucket_ARN/subfolder_name/` . For example, to specify a subfolder named `my-logs` in a bucket named `my-bucket` , use the following ARN: `arn:aws:s3:::my-bucket/my-logs/` . You cannot use `AWSLogs` as a subfolder name. This is a reserved term.", "LogDestinationType": "The type of destination to which the flow log data is to be published. Flow log data can be published to CloudWatch Logs or Amazon S3. To publish flow log data to CloudWatch Logs, specify `cloud-watch-logs` . To publish flow log data to Amazon S3, specify `s3` .\n\nIf you specify `LogDestinationType` as `s3` , do not specify `DeliverLogsPermissionArn` or `LogGroupName` .\n\nDefault: `cloud-watch-logs`", "LogFormat": "The fields to include in the flow log record, in the order in which they should appear. For a list of available fields, see [Flow Log Records](https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html#flow-log-records) . If you omit this parameter, the flow log is created using the default format. If you specify this parameter, you must specify at least one field.\n\nSpecify the fields using the `${field-id}` format, separated by spaces.", @@ -11522,7 +11837,7 @@ "PoolCount": "The number of pools in a scope.", "Ref": "`Ref` returns the IPAM scope ID." }, - "description": "In IPAM, a scope is the highest-level container within IPAM. An IPAM contains two default scopes. Each scope represents the IP space for a single network. The private scope is intended for all private IP address space. The public scope is intended for all public IP address space. Scopes enable you to reuse IP addresses across multiple unconnected networks without causing IP address overlap or conflict.\n\nFor more information, see [How IPAM works](https://docs.aws.amazon.com//vpc/latest/ipam/how-it-works-ipam.html) in the *Amazon VPC IPAM User Guide*", + "description": "In IPAM, a scope is the highest-level container within IPAM. An IPAM contains two default scopes. Each scope represents the IP space for a single network. The private scope is intended for all private IP address space. The public scope is intended for all public IP address space. Scopes enable you to reuse IP addresses across multiple unconnected networks without causing IP address overlap or conflict.\n\nFor more information, see [How IPAM works](https://docs.aws.amazon.com//vpc/latest/ipam/how-it-works-ipam.html) in the *Amazon VPC IPAM User Guide* .", "properties": { "Description": "The description of the scope.", "IpamId": "The ID of the IPAM for which you're creating this scope.", @@ -11567,8 +11882,9 @@ "Monitoring": "Specifies whether detailed monitoring is enabled for the instance.", "NetworkInterfaces": "The network interfaces to associate with the instance.\n\n> If you use this property to point to a network interface, you must terminate the original interface before attaching a new one to allow the update of the instance to succeed.\n> \n> If this resource has a public IP address and is also in a VPC that is defined in the same template, you must use the [DependsOn Attribute](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-dependson.html) to declare a dependency on the VPC-gateway attachment.", "PlacementGroupName": "The name of an existing placement group that you want to launch the instance into (cluster | partition | spread).", + "PrivateDnsNameOptions": "The options for the instance hostname.", "PrivateIpAddress": "[EC2-VPC] The primary IPv4 address. You must specify a value from the IPv4 address range of the subnet.\n\nOnly one private IP address can be designated as primary. You can't specify this option if you've specified the option to designate a private IP address as the primary IP address in a network interface specification. You cannot specify this option if you're launching more than one instance in the request.\n\nYou cannot specify this option and the network interfaces option in the same request.\n\nIf you make an update to an instance that requires replacement, you must assign a new private IP address. During a replacement, AWS CloudFormation creates a new instance but doesn't delete the old instance until the stack has successfully updated. If the stack update fails, AWS CloudFormation uses the old instance to roll back the stack to the previous working state. The old and new instances cannot have the same private IP address.", - "PropagateTagsToVolumeOnCreation": "", + "PropagateTagsToVolumeOnCreation": "Indicates whether to assign the tags from the instance to all of the volumes attached to the instance at launch. If you specify `true` and you assign tags to the instance, those tags are automatically assigned to all of the volumes that you attach to the instance at launch. If you specify `false` , those tags are not assigned to the attached volumes.", "RamdiskId": "The ID of the RAM disk to select. Some kernels require additional drivers at launch. Check the kernel requirements for information about whether you need to specify a RAM disk. To find kernel requirements, go to the AWS Resource Center and search for the kernel ID.\n\n> We recommend that you use PV-GRUB instead of kernels and RAM disks. For more information, see [PV-GRUB](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/UserProvidedkernels.html) in the *Amazon EC2 User Guide* .", "SecurityGroupIds": "The IDs of the security groups. You can create a security group using [CreateSecurityGroup](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateSecurityGroup.html) .\n\nIf you specify a network interface, you must specify any security groups as part of the network interface.", "SecurityGroups": "[EC2-Classic, default VPC] The names of the security groups. For a nondefault VPC, you must use security group IDs instead.\n\nYou cannot specify this option and the network interfaces option in the same request. The list can contain both the name of existing Amazon EC2 security groups or references to AWS::EC2::SecurityGroup resources created in the template.\n\nDefault: Amazon EC2 uses the default security group.", @@ -11577,7 +11893,7 @@ "SubnetId": "[EC2-VPC] The ID of the subnet to launch the instance into.\n\nIf you specify a network interface, you must specify any subnets as part of the network interface.", "Tags": "The tags to add to the instance. These tags are not applied to the EBS volumes, such as the root volume.", "Tenancy": "The tenancy of the instance (if the instance is running in a VPC). An instance with a tenancy of `dedicated` runs on single-tenant hardware.", - "UserData": "The user data to make available to the instance. For more information, see [Run commands on your Linux instance at launch](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html) and [Run commands on your Windows instance at launch](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ec2-windows-user-data.html) . If you are using a command line tool, base64-encoding is performed for you, and you can load the text from a file. Otherwise, you must provide base64-encoded text. User data is limited to 16 KB.", + "UserData": "The user data script to make available to the instance. For more information, see [Run commands on your Linux instance at launch](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html) and [Run commands on your Windows instance at launch](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ec2-windows-user-data.html) . If you are using a command line tool, base64-encoding is performed for you, and you can load the text from a file. Otherwise, you must provide base64-encoded text. User data is limited to 16 KB.", "Volumes": "The volumes to attach to the instance." } }, @@ -11683,6 +11999,7 @@ "attributes": {}, "description": "Specifies a network interface that is to be attached to an instance.\n\nYou can create a network interface when launching an instance. For an example, see the [AWS::EC2::Instance examples](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#aws-properties-ec2-instance--examples--Automatically_assign_a_public_IP_address) .\n\nAlternatively, you can attach an existing network interface when launching an instance. For an example, see the [AWS::EC2:NetworkInterface examples](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#aws-resource-ec2-network-interface--examples--Basic_network_interface) .", "properties": { + "AssociateCarrierIpAddress": "", "AssociatePublicIpAddress": "Indicates whether to assign a public IPv4 address to an instance. Applies only if creating a network interface when launching an instance. The network interface must be the primary network interface. If launching into a default subnet, the default value is `true` .", "DeleteOnTermination": "Indicates whether the network interface is deleted when the instance is terminated. Applies only if creating a network interface when launching an instance.", "Description": "The description of the network interface. Applies only if creating a network interface when launching an instance.", @@ -11702,6 +12019,15 @@ "description": "Suppresses the specified device included in the block device mapping of the AMI. To suppress a device, specify an empty string.\n\n`NoDevice` is a property of the [Amazon EC2 BlockDeviceMapping](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-blockdev-mapping.html) property.", "properties": {} }, + "AWS::EC2::Instance.PrivateDnsNameOptions": { + "attributes": {}, + "description": "The type of hostnames to assign to instances in the subnet at launch. For IPv4 only subnets, an instance DNS name must be based on the instance IPv4 address. For IPv6 only subnets, an instance DNS name must be based on the instance ID. For dual-stack subnets, you can specify whether DNS names use the instance IPv4 address or the instance ID. For more information, see [Amazon EC2 instance hostname types](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-naming.html) in the *Amazon Elastic Compute Cloud User Guide* .", + "properties": { + "EnableResourceNameDnsAAAARecord": "Indicates whether to respond to DNS queries for instance hostnames with DNS AAAA records. For more information, see [Amazon EC2 instance hostname types](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-naming.html) in the *Amazon Elastic Compute Cloud User Guide* .", + "EnableResourceNameDnsARecord": "Indicates whether to respond to DNS queries for instance hostnames with DNS A records. For more information, see [Amazon EC2 instance hostname types](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-naming.html) in the *Amazon Elastic Compute Cloud User Guide* .", + "HostnameType": "The type of hostnames to assign to instances in the subnet at launch. For IPv4 only subnets, an instance DNS name must be based on the instance IPv4 address. For IPv6 only subnets, an instance DNS name must be based on the instance ID. For dual-stack subnets, you can specify whether DNS names use the instance IPv4 address or the instance ID. For more information, see [Amazon EC2 instance hostname types](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-naming.html) in the *Amazon Elastic Compute Cloud User Guide* ." + } + }, "AWS::EC2::Instance.PrivateIpAddressSpecification": { "attributes": {}, "description": "Specifies a secondary private IPv4 address for a network interface.\n\n`PrivateIpAddressSpecification` is a property of the [AWS::EC2::NetworkInterface](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html) resource.", @@ -11885,9 +12211,9 @@ "MemoryGiBPerVCpu": "The minimum and maximum amount of memory per vCPU, in GiB.\n\nDefault: No minimum or maximum limits", "MemoryMiB": "The minimum and maximum amount of memory, in MiB.", "NetworkInterfaceCount": "The minimum and maximum number of network interfaces.\n\nDefault: No minimum or maximum limits", - "OnDemandMaxPricePercentageOverLowestPrice": "The price protection threshold for On-Demand Instances. This is the maximum you\u2019ll pay for an On-Demand Instance, expressed as a percentage above the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 selects instance types with your attributes, it excludes instance types priced above your threshold.\n\nThe parameter accepts an integer, which Amazon EC2 interprets as a percentage.\n\nTo turn off price protection, specify a high value, such as `999999` .\n\nThis parameter is not supported for [GetSpotPlacementScores](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetSpotPlacementScores.html) and [GetInstanceTypesFromInstanceRequirements](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetInstanceTypesFromInstanceRequirements.html) .\n\nDefault: `20`", + "OnDemandMaxPricePercentageOverLowestPrice": "The price protection threshold for On-Demand Instances. This is the maximum you\u2019ll pay for an On-Demand Instance, expressed as a percentage above the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 selects instance types with your attributes, it excludes instance types priced above your threshold.\n\nThe parameter accepts an integer, which Amazon EC2 interprets as a percentage.\n\nTo turn off price protection, specify a high value, such as `999999` .\n\nThis parameter is not supported for [GetSpotPlacementScores](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetSpotPlacementScores.html) and [GetInstanceTypesFromInstanceRequirements](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetInstanceTypesFromInstanceRequirements.html) .\n\n> If you set `TargetCapacityUnitType` to `vcpu` or `memory-mib` , the price protection threshold is applied based on the per-vCPU or per-memory price instead of the per-instance price. \n\nDefault: `20`", "RequireHibernateSupport": "Indicates whether instance types must support hibernation for On-Demand Instances.\n\nThis parameter is not supported for [GetSpotPlacementScores](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetSpotPlacementScores.html) .\n\nDefault: `false`", - "SpotMaxPricePercentageOverLowestPrice": "The price protection threshold for Spot Instances. This is the maximum you\u2019ll pay for a Spot Instance, expressed as a percentage above the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 selects instance types with your attributes, it excludes instance types priced above your threshold.\n\nThe parameter accepts an integer, which Amazon EC2 interprets as a percentage.\n\nTo turn off price protection, specify a high value, such as `999999` .\n\nThis parameter is not supported for [GetSpotPlacementScores](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetSpotPlacementScores.html) and [GetInstanceTypesFromInstanceRequirements](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetInstanceTypesFromInstanceRequirements.html) .\n\nDefault: `100`", + "SpotMaxPricePercentageOverLowestPrice": "The price protection threshold for Spot Instances. This is the maximum you\u2019ll pay for a Spot Instance, expressed as a percentage above the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 selects instance types with your attributes, it excludes instance types priced above your threshold.\n\nThe parameter accepts an integer, which Amazon EC2 interprets as a percentage.\n\nTo turn off price protection, specify a high value, such as `999999` .\n\nThis parameter is not supported for [GetSpotPlacementScores](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetSpotPlacementScores.html) and [GetInstanceTypesFromInstanceRequirements](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetInstanceTypesFromInstanceRequirements.html) .\n\n> If you set `TargetCapacityUnitType` to `vcpu` or `memory-mib` , the price protection threshold is applied based on the per-vCPU or per-memory price instead of the per-instance price. \n\nDefault: `100`", "TotalLocalStorageGB": "The minimum and maximum amount of total local storage, in GB.\n\nDefault: No minimum or maximum limits", "VCpuCount": "The minimum and maximum number of vCPUs." } @@ -11926,6 +12252,7 @@ "Monitoring": "The monitoring for the instance.", "NetworkInterfaces": "One or more network interfaces. If you specify a network interface, you must specify any security groups and subnets as part of the network interface.", "Placement": "The placement for the instance.", + "PrivateDnsNameOptions": "The options for the instance hostname. The default values are inherited from the subnet.", "RamDiskId": "The ID of the RAM disk.\n\n> We recommend that you use PV-GRUB instead of kernels and RAM disks. For more information, see [User Provided Kernels](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/UserProvidedkernels.html) in the *Amazon Elastic Compute Cloud User Guide* .", "SecurityGroupIds": "One or more security group IDs. You can create a security group using [CreateSecurityGroup](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateSecurityGroup.html) . You cannot specify both a security group ID and security name in the same request.", "SecurityGroups": "[EC2-Classic, default VPC] One or more security group names. For a nondefault VPC, you must use security group IDs instead. You cannot specify both a security group ID and security name in the same request.", @@ -11979,7 +12306,8 @@ "HttpEndpoint": "Enables or disables the HTTP metadata endpoint on your instances. If the parameter is not specified, the default state is `enabled` .\n\n> If you specify a value of `disabled` , you will not be able to access your instance metadata.", "HttpProtocolIpv6": "Enables or disables the IPv6 endpoint for the instance metadata service.\n\nDefault: `disabled`", "HttpPutResponseHopLimit": "The desired HTTP PUT response hop limit for instance metadata requests. The larger the number, the further instance metadata requests can travel.\n\nDefault: 1\n\nPossible values: Integers from 1 to 64", - "HttpTokens": "The state of token usage for your instance metadata requests. If the parameter is not specified in the request, the default state is `optional` .\n\nIf the state is `optional` , you can choose to retrieve instance metadata with or without a signed token header on your request. If you retrieve the IAM role credentials without a token, the version 1.0 role credentials are returned. If you retrieve the IAM role credentials using a valid signed token, the version 2.0 role credentials are returned.\n\nIf the state is `required` , you must send a signed token header with any instance metadata retrieval requests. In this state, retrieving the IAM role credentials always returns the version 2.0 credentials; the version 1.0 credentials are not available." + "HttpTokens": "The state of token usage for your instance metadata requests. If the parameter is not specified in the request, the default state is `optional` .\n\nIf the state is `optional` , you can choose to retrieve instance metadata with or without a signed token header on your request. If you retrieve the IAM role credentials without a token, the version 1.0 role credentials are returned. If you retrieve the IAM role credentials using a valid signed token, the version 2.0 role credentials are returned.\n\nIf the state is `required` , you must send a signed token header with any instance metadata retrieval requests. In this state, retrieving the IAM role credentials always returns the version 2.0 credentials; the version 1.0 credentials are not available.", + "InstanceMetadataTags": "Set to `enabled` to allow access to instance tags from the instance metadata. Set to `disabled` to turn off access to instance tags from the instance metadata. For more information, see [Work with instance tags using the instance metadata](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html#work-with-tags-in-IMDS) .\n\nDefault: `disabled`" } }, "AWS::EC2::LaunchTemplate.Monitoring": { @@ -12032,6 +12360,15 @@ "Tenancy": "The tenancy of the instance (if the instance is running in a VPC). An instance with a tenancy of dedicated runs on single-tenant hardware." } }, + "AWS::EC2::LaunchTemplate.PrivateDnsNameOptions": { + "attributes": {}, + "description": "Describes the options for instance hostnames.", + "properties": { + "EnableResourceNameDnsAAAARecord": "Indicates whether to respond to DNS queries for instance hostnames with DNS AAAA records.", + "EnableResourceNameDnsARecord": "Indicates whether to respond to DNS queries for instance hostnames with DNS A records.", + "HostnameType": "The type of hostname for EC2 instances. For IPv4 only subnets, an instance DNS name must be based on the instance IPv4 address. For IPv6 only subnets, an instance DNS name must be based on the instance ID. For dual-stack subnets, you can specify whether DNS names use the instance IPv4 address or the instance ID. For more information, see [Amazon EC2 instance hostname types](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-naming.html) in the *Amazon Elastic Compute Cloud User Guide* ." + } + }, "AWS::EC2::LaunchTemplate.PrivateIpAdd": { "attributes": {}, "description": "Specifies a secondary private IPv4 address for a network interface.\n\n`PrivateIpAdd` is a property of [AWS::EC2::LaunchTemplate NetworkInterface](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-networkinterface.html) .", @@ -12167,7 +12504,7 @@ "Ref": "`Ref` returns the ID of the network insights scope.", "UpdatedDate": "The last updated date." }, - "description": "Describes a Network Access Scope.", + "description": "Describes a Network Access Scope. A Network Access Scope defines outbound (egress) and inbound (ingress) traffic patterns, including sources, destinations, paths, and traffic types.\n\nNetwork Access Analyzer identifies unintended network access to your resources on AWS . When you start an analysis on a Network Access Scope, Network Access Analyzer produces findings. For more information, see the [Network Access Analyzer User Guide](https://docs.aws.amazon.com/vpc/latest/network-access-analyzer/) .", "properties": { "ExcludePaths": "The paths to exclude.", "MatchPaths": "The paths to match.", @@ -12321,7 +12658,7 @@ "properties": { "NatGatewayId": "The ID of a NAT gateway.", "NetworkInterfaceId": "The ID of a network interface.", - "Origin": "Describes how the route was created. The following are possible values:\n\n- `CreateRouteTable` - The route was automatically created when the route table was created.\n- `CreateRoute` - The route was manually added to the route table.\n- `EnableVgwRoutePropagation` - The route was propagated by route propagation.", + "Origin": "Describes how the route was created. The following are the possible values:\n\n- CreateRouteTable - The route was automatically created when the route table was created.\n- CreateRoute - The route was manually added to the route table.\n- EnableVgwRoutePropagation - The route was propagated by route propagation.", "TransitGatewayId": "The ID of a transit gateway.", "VpcPeeringConnectionId": "The ID of a VPC peering connection.", "destinationCidr": "The destination IPv4 address, in CIDR notation.", @@ -12336,7 +12673,7 @@ "description": "Describes a security group rule.", "properties": { "Cidr": "The IPv4 address range, in CIDR notation.", - "Direction": "The direction. The following are possible values:\n\n- egress\n- ingress", + "Direction": "The direction. The following are the possible values:\n\n- egress\n- ingress", "PortRange": "The port range.", "PrefixListId": "The prefix list ID.", "Protocol": "The protocol name.", @@ -12359,7 +12696,7 @@ "CustomerGateway": "The customer gateway.", "Destination": "The destination.", "DestinationVpc": "The destination VPC.", - "Direction": "The direction. The following are possible values:\n\n- egress\n- ingress", + "Direction": "The direction. The following are the possible values:\n\n- egress\n- ingress", "ElasticLoadBalancerListener": "The load balancer listener.", "ExplanationCode": "The explanation code.", "IngressRouteTable": "The route table.", @@ -12448,7 +12785,7 @@ "properties": { "Description": "A description for the network interface.", "GroupSet": "The security group IDs associated with this network interface.", - "InterfaceType": "Indicates the type of network interface. To create an Elastic Fabric Adapter (EFA), specify `efa` . For more information, see [Elastic Fabric Adapter](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/efa.html) in the *Amazon Elastic Compute Cloud User Guide* . To create a trunk network interface, specify `trunk` .", + "InterfaceType": "The type of network interface. The default is `interface` . The supported values are `efa` and `trunk` .", "Ipv6AddressCount": "The number of IPv6 addresses to assign to a network interface. Amazon EC2 automatically selects the IPv6 addresses from the subnet range. To specify specific IPv6 addresses, use the `Ipv6Addresses` property and don't specify this property.", "Ipv6Addresses": "One or more specific IPv6 addresses from the IPv6 CIDR block range of your subnet to associate with the network interface. If you're specifying a number of IPv6 addresses, use the `Ipv6AddressCount` property and don't specify this property.", "PrivateIpAddress": "Assigns a single private IP address to the network interface, which is used as the primary private IP address. If you want to specify multiple private IP address, use the `PrivateIpAddresses` property.", @@ -12581,13 +12918,13 @@ }, "AWS::EC2::SecurityGroup.Egress": { "attributes": {}, - "description": "Specifies an outbound rule for a security group. An outbound rule permits instances to send traffic to the specified IPv4 or IPv6 address range, or to the instances associated with the specified destination security groups.\n\nYou must specify only one of the following properties: `CidrIp` , `CidrIpv6` , `DestinationPrefixListId` , or `DestinationSecurityGroupId` .\n\nThe EC2 Security Group Rule is an embedded property of the `AWS::EC2::SecurityGroup` type.", + "description": "[EC2-VPC only] Adds the specified egress rules to a security group for use with a VPC.\n\nAn outbound rule permits instances to send traffic to the specified destination IPv4 or IPv6 CIDR address ranges, or to the specified destination security groups for the same VPC.\n\nYou specify a protocol for each rule (for example, TCP). For the TCP and UDP protocols, you must also specify the destination port or port range. For the ICMP protocol, you must also specify the ICMP type and code. You can use -1 for the type or code to mean all types or all codes.\n\nYou must specify only one of the following properties: `CidrIp` , `CidrIpv6` , `DestinationPrefixListId` , or `DestinationSecurityGroupId` .\n\nYou must specify a destination security group ( `DestinationPrefixListId` or `DestinationSecurityGroupId` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ). If you do not specify one of these parameters, the stack will launch successfully but the rule will not be added to the security group.\n\nRule changes are propagated to affected instances as quickly as possible. However, a small delay might occur.\n\nFor more information about VPC security group limits, see [Amazon VPC Limits](https://docs.aws.amazon.com/vpc/latest/userguide/amazon-vpc-limits.html) .\n\nUse `SecurityGroup.Ingress` and `SecurityGroup.Egress` only when necessary, typically to allow security groups to reference each other in ingress and egress rules. Otherwise, use the embedded ingress and egress rules of the security group. For more information, see [Amazon EC2 Security Groups](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html) .\n\nThe EC2 Security Group Rule is an embedded property of the `AWS::EC2::SecurityGroup` type.", "properties": { - "CidrIp": "The IPv4 address range, in CIDR format.", - "CidrIpv6": "The IPv6 address range, in CIDR format.", + "CidrIp": "The IPv4 address range, in CIDR format.\n\nYou must specify a destination security group ( `DestinationPrefixListId` or `DestinationSecurityGroupId` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ).\n\nFor examples of rules that you can add to security groups for specific access scenarios, see [Security group rules for different use cases](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-rules-reference.html) in the *Amazon EC2 User Guide* .", + "CidrIpv6": "The IPv6 address range, in CIDR format.\n\nYou must specify a destination security group ( `DestinationPrefixListId` or `DestinationSecurityGroupId` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ).\n\nFor examples of rules that you can add to security groups for specific access scenarios, see [Security group rules for different use cases](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-rules-reference.html) in the *Amazon EC2 User Guide* .", "Description": "A description for the security group rule.\n\nConstraints: Up to 255 characters in length. Allowed characters are a-z, A-Z, 0-9, spaces, and ._-:/()#,@[]+=;{}!$*", - "DestinationPrefixListId": "[EC2-VPC only] The prefix list IDs for the destination AWS service. This is the AWS service that you want to access through a VPC endpoint from instances associated with the security group.", - "DestinationSecurityGroupId": "The ID of the destination VPC security group.", + "DestinationPrefixListId": "[EC2-VPC only] The prefix list IDs for the destination AWS service. This is the AWS service that you want to access through a VPC endpoint from instances associated with the security group.\n\nYou must specify a destination security group ( `DestinationPrefixListId` or `DestinationSecurityGroupId` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ).", + "DestinationSecurityGroupId": "The ID of the destination VPC security group.\n\nYou must specify a destination security group ( `DestinationPrefixListId` or `DestinationSecurityGroupId` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ).", "FromPort": "The start of port range for the TCP and UDP protocols, or an ICMP/ICMPv6 type number. A value of `-1` indicates all ICMP/ICMPv6 types. If you specify all ICMP/ICMPv6 types, you must specify all codes.", "IpProtocol": "The IP protocol name ( `tcp` , `udp` , `icmp` , `icmpv6` ) or number (see [Protocol Numbers](https://docs.aws.amazon.com/http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml) ).\n\n[VPC only] Use `-1` to specify all protocols. When authorizing security group rules, specifying `-1` or a protocol number other than `tcp` , `udp` , `icmp` , or `icmpv6` allows traffic on all ports, regardless of any port range you specify. For `tcp` , `udp` , and `icmp` , you must specify a port range. For `icmpv6` , the port range is optional; if you omit the port range, traffic for all types and codes is allowed.", "ToPort": "The end of port range for the TCP and UDP protocols, or an ICMP/ICMPv6 code. A value of `-1` indicates all ICMP/ICMPv6 codes. If you specify all ICMP/ICMPv6 types, you must specify all codes." @@ -12595,16 +12932,16 @@ }, "AWS::EC2::SecurityGroup.Ingress": { "attributes": {}, - "description": "Specifies an inbound rule for a security group. An inbound rule permits instances to receive traffic from the specified IPv4 or IPv6 CIDR address range, or from the instances associated with the specified security group.\n\nYou must specify only one of the following properties: `CidrIp` , `CidrIpv6` , `SourcePrefixListId` , `SourceSecurityGroupId` , or `SourceSecurityGroupName` .\n\nThe EC2 Security Group Rule is an embedded property of the `AWS::EC2::SecurityGroup` type.", + "description": "Adds an inbound rule to a security group.\n\nAn inbound rule permits instances to receive traffic from the specified IPv4 or IPv6 CIDR address range, or from the instances associated with the specified security group.\n\nYou must specify only one of the following properties: `CidrIp` , `CidrIpv6` , `SourcePrefixListId` , `SourceSecurityGroupId` , or `SourceSecurityGroupName` .\n\nYou specify a protocol for each rule (for example, TCP). For TCP and UDP, you must also specify a port or port range. For ICMP/ICMPv6, you must also specify the ICMP/ICMPv6 type and code. You can use -1 to mean all types or all codes.\n\nYou must specify a source security group ( `SourcePrefixListId` , `SourceSecurityGroupId` , or `SourceSecurityGroupName` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ). If you do not specify one of these parameters, the stack will launch successfully but the rule will not be added to the security group.\n\nRule changes are propagated to instances within the security group as quickly as possible. However, a small delay might occur.\n\nThe EC2 Security Group Rule is an embedded property of the `AWS::EC2::SecurityGroup` type.", "properties": { - "CidrIp": "The IPv4 address range, in CIDR format.", - "CidrIpv6": "The IPv6 address range, in CIDR format.", - "Description": "A description for the security group rule.\n\nConstraints: Up to 255 characters in length. Allowed characters are a-z, A-Z, 0-9, spaces, and ._-:/()#,@[]+=;{}!$*", + "CidrIp": "The IPv4 address range, in CIDR format.\n\nYou must specify a destination security group ( `DestinationPrefixListId` or `DestinationSecurityGroupId` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ).\n\nFor examples of rules that you can add to security groups for specific access scenarios, see [Security group rules for different use cases](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-rules-reference.html) in the *Amazon EC2 User Guide* .", + "CidrIpv6": "The IPv6 address range, in CIDR format.\n\nYou must specify a destination security group ( `DestinationPrefixListId` or `DestinationSecurityGroupId` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ).\n\nFor examples of rules that you can add to security groups for specific access scenarios, see [Security group rules for different use cases](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-rules-reference.html) in the *Amazon EC2 User Guide* .", + "Description": "Updates the description of an ingress (inbound) security group rule. You can replace an existing description, or add a description to a rule that did not have one previously.\n\nConstraints: Up to 255 characters in length. Allowed characters are a-z, A-Z, 0-9, spaces, and ._-:/()#,@[]+=;{}!$*", "FromPort": "The start of port range for the TCP and UDP protocols, or an ICMP/ICMPv6 type number. A value of `-1` indicates all ICMP/ICMPv6 types. If you specify all ICMP/ICMPv6 types, you must specify all codes.", "IpProtocol": "The IP protocol name ( `tcp` , `udp` , `icmp` , `icmpv6` ) or number (see [Protocol Numbers](https://docs.aws.amazon.com/http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml) ).\n\n[VPC only] Use `-1` to specify all protocols. When authorizing security group rules, specifying `-1` or a protocol number other than `tcp` , `udp` , `icmp` , or `icmpv6` allows traffic on all ports, regardless of any port range you specify. For `tcp` , `udp` , and `icmp` , you must specify a port range. For `icmpv6` , the port range is optional; if you omit the port range, traffic for all types and codes is allowed.", "SourcePrefixListId": "[EC2-VPC only] The ID of a prefix list.", "SourceSecurityGroupId": "The ID of the security group. You must specify either the security group ID or the security group name in the request. For security groups in a nondefault VPC, you must specify the security group ID.", - "SourceSecurityGroupName": "[EC2-Classic, default VPC] The name of the source security group. You can't specify this parameter in combination with an IP address range. Creates rules that grant full ICMP, UDP, and TCP access.", + "SourceSecurityGroupName": "[EC2-Classic, default VPC] The name of the source security group. You can't specify this parameter in combination with an IP address range. Creates rules that grant full ICMP, UDP, and TCP access.\n\nYou must specify the `GroupName` property or the `GroupId` property. For security groups that are in a VPC, you must use the `GroupId` property.", "SourceSecurityGroupOwnerId": "[nondefault VPC] The AWS account ID for the source security group, if the source security group is in a different account. You can't specify this property with an IP address range. Creates rules that grant full ICMP, UDP, and TCP access.\n\nIf you specify `SourceSecurityGroupName` or `SourceSecurityGroupId` and that security group is owned by a different account than the account creating the stack, you must specify the `SourceSecurityGroupOwnerId` ; otherwise, this property is optional.", "ToPort": "The end of port range for the TCP and UDP protocols, or an ICMP/ICMPv6 code. A value of `-1` indicates all ICMP/ICMPv6 codes. If you specify all ICMP/ICMPv6 types, you must specify all codes." } @@ -12613,11 +12950,11 @@ "attributes": { "Ref": "`Ref` returns the name of the security egress rule." }, - "description": "[EC2-VPC only] Adds the specified egress rules to a security group for use with a VPC.\n\nAn outbound rule permits instances to send traffic to the specified destination IPv4 or IPv6 CIDR address ranges, or to the specified destination security groups for the same VPC.\n\nYou specify a protocol for each rule (for example, TCP). For the TCP and UDP protocols, you must also specify the destination port or port range. For the ICMP protocol, you must also specify the ICMP type and code. You can use -1 for the type or code to mean all types or all codes.\n\nYou must specify a destination security group ( `DestinationPrefixListId` or `DestinationSecurityGroupId` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ). If you do not specify one of these parameters, the stack will launch successfully but the rule will not be added to the security group.\n\nRule changes are propagated to affected instances as quickly as possible. However, a small delay might occur.\n\nFor more information about VPC security group limits, see [Amazon VPC Limits](https://docs.aws.amazon.com/vpc/latest/userguide/amazon-vpc-limits.html) .\n\nUse `AWS::EC2::SecurityGroupIngress` and `AWS::EC2::SecurityGroupEgress` only when necessary, typically to allow security groups to reference each other in ingress and egress rules. Otherwise, use the embedded ingress and egress rules of the security group. For more information, see [Amazon EC2 Security Groups](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html) .", + "description": "[EC2-VPC only] Adds the specified egress rules to a security group for use with a VPC.\n\nAn outbound rule permits instances to send traffic to the specified destination IPv4 or IPv6 CIDR address ranges, or to the specified destination security groups for the same VPC.\n\nYou specify a protocol for each rule (for example, TCP). For the TCP and UDP protocols, you must also specify the destination port or port range. For the ICMP protocol, you must also specify the ICMP type and code. You can use -1 for the type or code to mean all types or all codes.\n\nYou must specify only one of the following properties: `CidrIp` , `CidrIpv6` , `DestinationPrefixListId` , or `DestinationSecurityGroupId` .\n\nYou must specify a destination security group ( `DestinationPrefixListId` or `DestinationSecurityGroupId` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ). If you do not specify one of these parameters, the stack will launch successfully but the rule will not be added to the security group.\n\nRule changes are propagated to affected instances as quickly as possible. However, a small delay might occur.\n\nFor more information about VPC security group limits, see [Amazon VPC Limits](https://docs.aws.amazon.com/vpc/latest/userguide/amazon-vpc-limits.html) .\n\nUse `AWS::EC2::SecurityGroupIngress` and `AWS::EC2::SecurityGroupEgress` only when necessary, typically to allow security groups to reference each other in ingress and egress rules. Otherwise, use the embedded ingress and egress rules of the security group. For more information, see [Amazon EC2 Security Groups](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html) .", "properties": { - "CidrIp": "The IPv4 address range, in CIDR format.\n\nYou must specify a destination security group ( `DestinationPrefixListId` or `DestinationSecurityGroupId` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ).", - "CidrIpv6": "The IPv6 address range, in CIDR format.\n\nYou must specify a destination security group ( `DestinationPrefixListId` or `DestinationSecurityGroupId` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ).", - "Description": "The description of an egress (outbound) security group rule.", + "CidrIp": "The IPv4 address range, in CIDR format.\n\nYou must specify a destination security group ( `DestinationPrefixListId` or `DestinationSecurityGroupId` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ).\n\nFor examples of rules that you can add to security groups for specific access scenarios, see [Security group rules for different use cases](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-rules-reference.html) in the *Amazon EC2 User Guide* .", + "CidrIpv6": "The IPv6 address range, in CIDR format.\n\nYou must specify a destination security group ( `DestinationPrefixListId` or `DestinationSecurityGroupId` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ).\n\nFor examples of rules that you can add to security groups for specific access scenarios, see [Security group rules for different use cases](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-rules-reference.html) in the *Amazon EC2 User Guide* .", + "Description": "The description of an egress (outbound) security group rule.\n\nConstraints: Up to 255 characters in length. Allowed characters are a-z, A-Z, 0-9, spaces, and ._-:/()#,@[]+=;{}!$*", "DestinationPrefixListId": "[EC2-VPC only] The prefix list IDs for an AWS service. This is the AWS service that you want to access through a VPC endpoint from instances associated with the security group.\n\nYou must specify a destination security group ( `DestinationPrefixListId` or `DestinationSecurityGroupId` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ).", "DestinationSecurityGroupId": "The ID of the security group.\n\nYou must specify a destination security group ( `DestinationPrefixListId` or `DestinationSecurityGroupId` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ).", "FromPort": "The start of port range for the TCP and UDP protocols, or an ICMP/ICMPv6 type number. A value of `-1` indicates all ICMP/ICMPv6 types. If you specify all ICMP/ICMPv6 types, you must specify all codes.", @@ -12628,19 +12965,19 @@ }, "AWS::EC2::SecurityGroupIngress": { "attributes": {}, - "description": "Adds an inbound rule to a security group.\n\nAn inbound rule permits instances to receive traffic from the specified IPv4 or IPv6 CIDR address range, or from the instances associated with the specified security group.\n\nYou specify a protocol for each rule (for example, TCP). For TCP and UDP, you must also specify a port or port range. For ICMP/ICMPv6, you must also specify the ICMP/ICMPv6 type and code. You can use -1 to mean all types or all codes.\n\nYou must specify a source security group ( `SourcePrefixListId` , `SourceSecurityGroupId` , or `SourceSecurityGroupName` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ). If you do not specify one of these parameters, the stack will launch successfully but the rule will not be added to the security group.\n\nRule changes are propagated to instances within the security group as quickly as possible. However, a small delay might occur.", + "description": "Adds an inbound rule to a security group.\n\nAn inbound rule permits instances to receive traffic from the specified IPv4 or IPv6 CIDR address range, or from the instances associated with the specified security group.\n\nYou must specify only one of the following properties: `CidrIp` , `CidrIpv6` , `SourcePrefixListId` , `SourceSecurityGroupId` , or `SourceSecurityGroupName` .\n\nYou specify a protocol for each rule (for example, TCP). For TCP and UDP, you must also specify a port or port range. For ICMP/ICMPv6, you must also specify the ICMP/ICMPv6 type and code. You can use -1 to mean all types or all codes.\n\nYou must specify a source security group ( `SourcePrefixListId` , `SourceSecurityGroupId` , or `SourceSecurityGroupName` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ). If you do not specify one of these parameters, the stack will launch successfully but the rule will not be added to the security group.\n\nRule changes are propagated to instances within the security group as quickly as possible. However, a small delay might occur.", "properties": { - "CidrIp": "The IPv4 address range, in CIDR format.", - "CidrIpv6": "The IPv6 address range, in CIDR format.", - "Description": "Updates the description of an ingress (inbound) security group rule. You can replace an existing description, or add a description to a rule that did not have one previously.", + "CidrIp": "The IPv4 address range, in CIDR format.\n\nYou must specify a destination security group ( `DestinationPrefixListId` or `DestinationSecurityGroupId` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ).\n\nFor examples of rules that you can add to security groups for specific access scenarios, see [Security group rules for different use cases](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-rules-reference.html) in the *Amazon EC2 User Guide* .", + "CidrIpv6": "The IPv6 address range, in CIDR format.\n\nYou must specify a destination security group ( `DestinationPrefixListId` or `DestinationSecurityGroupId` ) or a CIDR range ( `CidrIp` or `CidrIpv6` ).\n\nFor examples of rules that you can add to security groups for specific access scenarios, see [Security group rules for different use cases](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-rules-reference.html) in the *Amazon EC2 User Guide* .", + "Description": "Updates the description of an ingress (inbound) security group rule. You can replace an existing description, or add a description to a rule that did not have one previously.\n\nConstraints: Up to 255 characters in length. Allowed characters are a-z, A-Z, 0-9, spaces, and ._-:/()#,@[]+=;{}!$*", "FromPort": "The start of port range for the TCP and UDP protocols, or an ICMP/ICMPv6 type number. A value of `-1` indicates all ICMP/ICMPv6 types. If you specify all ICMP/ICMPv6 types, you must specify all codes.\n\nUse this for ICMP and any protocol that uses ports.", "GroupId": "The ID of the security group. You must specify either the security group ID or the security group name in the request. For security groups in a nondefault VPC, you must specify the security group ID.\n\nYou must specify the `GroupName` property or the `GroupId` property. For security groups that are in a VPC, you must use the `GroupId` property.", "GroupName": "The name of the security group.\n\nConstraints: Up to 255 characters in length. Cannot start with `sg-` .\n\nConstraints for EC2-Classic: ASCII characters\n\nConstraints for EC2-VPC: a-z, A-Z, 0-9, spaces, and ._-:/()#,@[]+=&;{}!$*", "IpProtocol": "The IP protocol name ( `tcp` , `udp` , `icmp` , `icmpv6` ) or number (see [Protocol Numbers](https://docs.aws.amazon.com/http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml) ).\n\n[VPC only] Use `-1` to specify all protocols. When authorizing security group rules, specifying `-1` or a protocol number other than `tcp` , `udp` , `icmp` , or `icmpv6` allows traffic on all ports, regardless of any port range you specify. For `tcp` , `udp` , and `icmp` , you must specify a port range. For `icmpv6` , the port range is optional; if you omit the port range, traffic for all types and codes is allowed.", "SourcePrefixListId": "[EC2-VPC only] The ID of a prefix list.", "SourceSecurityGroupId": "The ID of the security group. You must specify either the security group ID or the security group name. For security groups in a nondefault VPC, you must specify the security group ID.", - "SourceSecurityGroupName": "[EC2-Classic, default VPC] The name of the source security group.\n\nYou must specify the `GroupName` property or the `GroupId` property. For security groups that are in a VPC, you must use the `GroupId` property.", - "SourceSecurityGroupOwnerId": "[nondefault VPC] The AWS account ID that owns the source security group. You can't specify this property with an IP address range.\n\nIf you specify `SourceSecurityGroupName` or `SourceSecurityGroupId` and that security group is owned by a different account than the account creating the stack, you must specify the `SourceSecurityGroupOwnerId` ; otherwise, this property is optional.", + "SourceSecurityGroupName": "[EC2-Classic, default VPC] The name of the source security group. You can't specify this parameter in combination with an IP address range. Creates rules that grant full ICMP, UDP, and TCP access.\n\nYou must specify the `GroupName` property or the `GroupId` property. For security groups that are in a VPC, you must use the `GroupId` property.", + "SourceSecurityGroupOwnerId": "[nondefault VPC] The AWS account ID for the source security group, if the source security group is in a different account. You can't specify this property with an IP address range. Creates rules that grant full ICMP, UDP, and TCP access.\n\nIf you specify `SourceSecurityGroupName` or `SourceSecurityGroupId` and that security group is owned by a different account than the account creating the stack, you must specify the `SourceSecurityGroupOwnerId` ; otherwise, this property is optional.", "ToPort": "The end of port range for the TCP and UDP protocols, or an ICMP/ICMPv6 code. A value of `-1` indicates all ICMP/ICMPv6 codes for the specified ICMP type. If you specify all ICMP/ICMPv6 types, you must specify all codes.\n\nUse this for ICMP and any protocol that uses ports." } }, @@ -12720,7 +13057,7 @@ "properties": { "LaunchTemplateId": "The ID of the launch template. If you specify the template ID, you can't specify the template name.", "LaunchTemplateName": "The name of the launch template. You must specify either a template name or a template ID.\n\nMinimum length of 3. Maximum length of 128. Names must match the following pattern: `[a-zA-Z0-9\\(\\)\\.-/_]+`", - "Version": "The version number of the launch template. You must specify a version number. AWS CloudFormation does not support specifying `$Latest` or `$Default` for the template version number.\n\nMinimum length of 1. Maximum length of 255. Versions must fit the following pattern: `[\\u0020-\\uD7FF\\uE000-\\uFFFD\\uD800\\uDC00-\\uDBFF\\uDFFF\\r\\n\\t]*`" + "Version": "The version number of the launch template. You must specify a version number.\n\nMinimum length of 1. Maximum length of 255. Versions must fit the following pattern: `[\\u0020-\\uD7FF\\uE000-\\uFFFD\\uD800\\uDC00-\\uDBFF\\uDFFF\\r\\n\\t]*`" } }, "AWS::EC2::SpotFleet.GroupIdentifier": { @@ -12781,9 +13118,9 @@ "MemoryGiBPerVCpu": "The minimum and maximum amount of memory per vCPU, in GiB.\n\nDefault: No minimum or maximum limits", "MemoryMiB": "The minimum and maximum amount of memory, in MiB.", "NetworkInterfaceCount": "The minimum and maximum number of network interfaces.\n\nDefault: No minimum or maximum limits", - "OnDemandMaxPricePercentageOverLowestPrice": "The price protection threshold for On-Demand Instances. This is the maximum you\u2019ll pay for an On-Demand Instance, expressed as a percentage above the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 selects instance types with your attributes, it excludes instance types priced above your threshold.\n\nThe parameter accepts an integer, which Amazon EC2 interprets as a percentage.\n\nTo turn off price protection, specify a high value, such as `999999` .\n\nThis parameter is not supported for [GetSpotPlacementScores](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetSpotPlacementScores.html) and [GetInstanceTypesFromInstanceRequirements](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetInstanceTypesFromInstanceRequirements.html) .\n\nDefault: `20`", + "OnDemandMaxPricePercentageOverLowestPrice": "The price protection threshold for On-Demand Instances. This is the maximum you\u2019ll pay for an On-Demand Instance, expressed as a percentage above the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 selects instance types with your attributes, it excludes instance types priced above your threshold.\n\nThe parameter accepts an integer, which Amazon EC2 interprets as a percentage.\n\nTo turn off price protection, specify a high value, such as `999999` .\n\nThis parameter is not supported for [GetSpotPlacementScores](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetSpotPlacementScores.html) and [GetInstanceTypesFromInstanceRequirements](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetInstanceTypesFromInstanceRequirements.html) .\n\n> If you set `TargetCapacityUnitType` to `vcpu` or `memory-mib` , the price protection threshold is applied based on the per-vCPU or per-memory price instead of the per-instance price. \n\nDefault: `20`", "RequireHibernateSupport": "Indicates whether instance types must support hibernation for On-Demand Instances.\n\nThis parameter is not supported for [GetSpotPlacementScores](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetSpotPlacementScores.html) .\n\nDefault: `false`", - "SpotMaxPricePercentageOverLowestPrice": "The price protection threshold for Spot Instance. This is the maximum you\u2019ll pay for an Spot Instance, expressed as a percentage above the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 selects instance types with your attributes, it excludes instance types priced above your threshold.\n\nThe parameter accepts an integer, which Amazon EC2 interprets as a percentage.\n\nTo turn off price protection, specify a high value, such as `999999` .\n\nThis parameter is not supported for [GetSpotPlacementScores](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetSpotPlacementScores.html) and [GetInstanceTypesFromInstanceRequirements](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetInstanceTypesFromInstanceRequirements.html) .\n\nDefault: `100`", + "SpotMaxPricePercentageOverLowestPrice": "The price protection threshold for Spot Instance. This is the maximum you\u2019ll pay for an Spot Instance, expressed as a percentage above the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 selects instance types with your attributes, it excludes instance types priced above your threshold.\n\nThe parameter accepts an integer, which Amazon EC2 interprets as a percentage.\n\nTo turn off price protection, specify a high value, such as `999999` .\n\nThis parameter is not supported for [GetSpotPlacementScores](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetSpotPlacementScores.html) and [GetInstanceTypesFromInstanceRequirements](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_GetInstanceTypesFromInstanceRequirements.html) .\n\n> If you set `TargetCapacityUnitType` to `vcpu` or `memory-mib` , the price protection threshold is applied based on the per-vCPU or per-memory price instead of the per-instance price. \n\nDefault: `100`", "TotalLocalStorageGB": "The minimum and maximum amount of total local storage, in GB.\n\nDefault: No minimum or maximum limits", "VCpuCount": "The minimum and maximum number of vCPUs." } @@ -12803,6 +13140,7 @@ "AvailabilityZone": "The Availability Zone in which to launch the instances.", "InstanceRequirements": "The instance requirements. When you specify instance requirements, Amazon EC2 will identify instance types with the provided requirements, and then use your On-Demand and Spot allocation strategies to launch instances from these instance types, in the same way as when you specify a list of instance types.\n\n> If you specify `InstanceRequirements` , you can't specify `InstanceTypes` .", "InstanceType": "The instance type.", + "Priority": "The priority for the launch template override. The highest priority is launched first.\n\nIf `OnDemandAllocationStrategy` is set to `prioritized` , Spot Fleet uses priority to determine which launch template override to use first in fulfilling On-Demand capacity.\n\nIf the Spot `AllocationStrategy` is set to `capacityOptimizedPrioritized` , Spot Fleet uses priority on a best-effort basis to determine which launch template override to use in fulfilling Spot capacity, but optimizes for capacity first.\n\nValid values are whole numbers starting at `0` . The lower the number, the higher the priority. If no number is set, the launch template override has the lowest priority. You can set the same priority for different launch template overrides.", "SpotPrice": "The maximum price per unit hour that you are willing to pay for a Spot Instance.", "SubnetId": "The ID of the subnet in which to launch the instances.", "WeightedCapacity": "The number of units provided by the specified instance type." @@ -12976,16 +13314,21 @@ "NetworkAclAssociationId": "The ID of the network ACL that is associated with the subnet's VPC, such as `acl-5fb85d36` .", "OutpostArn": "The Amazon Resource Name (ARN) of the Outpost.", "Ref": "`Ref` returns the ID of the subnet.", + "SubnetId": "The ID of the subnet.", "VpcId": "The ID of the subnet's VPC, such as `vpc-11ad4878` ." }, "description": "Specifies a subnet for a VPC.\n\nWhen you create each subnet, you provide the VPC ID and IPv4 CIDR block for the subnet. After you create a subnet, you can't change its CIDR block. The size of the subnet's IPv4 CIDR block can be the same as a VPC's IPv4 CIDR block, or a subset of a VPC's IPv4 CIDR block. If you create more than one subnet in a VPC, the subnets' CIDR blocks must not overlap. The smallest IPv4 subnet (and VPC) you can create uses a /28 netmask (16 IPv4 addresses), and the largest uses a /16 netmask (65,536 IPv4 addresses).\n\nIf you've associated an IPv6 CIDR block with your VPC, you can create a subnet with an IPv6 CIDR block that uses a /64 prefix length.", "properties": { "AssignIpv6AddressOnCreation": "Indicates whether a network interface created in this subnet receives an IPv6 address. The default value is `false` .\n\nIf you specify `AssignIpv6AddressOnCreation` , you must also specify `Ipv6CidrBlock` .\n\nIf you specify `AssignIpv6AddressOnCreation` , you cannot specify `MapPublicIpOnLaunch` .", "AvailabilityZone": "The Availability Zone of the subnet.\n\nIf you update this property, you must also update the `CidrBlock` property.", + "AvailabilityZoneId": "The AZ ID of the subnet.", "CidrBlock": "The IPv4 CIDR block assigned to the subnet.\n\nIf you update this property, we create a new subnet, and then delete the existing one.", + "EnableDns64": "Indicates whether DNS queries made to the Amazon-provided DNS Resolver in this subnet should return synthetic IPv6 addresses for IPv4-only destinations. For more information, see [DNS64 and NAT64](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html#nat-gateway-nat64-dns64) in the *Amazon Virtual Private Cloud User Guide* .", "Ipv6CidrBlock": "The IPv6 CIDR block.\n\nIf you specify `AssignIpv6AddressOnCreation` , you must also specify `Ipv6CidrBlock` .", + "Ipv6Native": "Indicates whether this is an IPv6 only subnet. For more information, see [Subnet basics](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Subnets.html#subnet-basics) in the *Amazon Virtual Private Cloud User Guide* .", "MapPublicIpOnLaunch": "Indicates whether instances launched in this subnet receive a public IPv4 address. The default value is `false` .\n\nIf you specify `MapPublicIpOnLaunch` , you cannot specify `AssignIpv6AddressOnCreation` .", "OutpostArn": "The Amazon Resource Name (ARN) of the Outpost.", + "PrivateDnsNameOptionsOnLaunch": "The hostname type for EC2 instances launched into this subnet and how DNS A and AAAA record queries to the instances should be handled. For more information, see [Amazon EC2 instance hostname types](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-naming.html) in the *Amazon Elastic Compute Cloud User Guide* .", "Tags": "Any tags assigned to the subnet.", "VpcId": "The ID of the VPC the subnet is in.\n\nIf you update this property, you must also update the `CidrBlock` property." } @@ -13218,7 +13561,6 @@ }, "description": "Requests a transit gateway peering attachment between the specified transit gateway (requester) and a peer transit gateway (accepter). The transit gateways must be in different Regions. The peer transit gateway can be in your account or a different AWS account .\n\nAfter you create the peering attachment, the owner of the accepter transit gateway must accept the attachment request.", "properties": { - "Options": "", "PeerAccountId": "The ID of the AWS account that owns the transit gateway.", "PeerRegion": "The Region of the transit gateway.", "PeerTransitGatewayId": "The ID of the transit gateway.", @@ -13226,13 +13568,6 @@ "TransitGatewayId": "The ID of the transit gateway peering attachment." } }, - "AWS::EC2::TransitGatewayPeeringAttachment.TransitGatewayPeeringAttachmentOptions": { - "attributes": {}, - "description": "", - "properties": { - "DynamicRouting": "" - } - }, "AWS::EC2::TransitGatewayRoute": { "attributes": { "Ref": "`Ref` returns the ID of the transit gateway route." @@ -13306,6 +13641,8 @@ "EnableDnsHostnames": "Indicates whether the instances launched in the VPC get DNS hostnames. If enabled, instances in the VPC get DNS hostnames; otherwise, they do not. Disabled by default for nondefault VPCs. For more information, see [DNS attributes in your VPC](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html#vpc-dns-support) .\n\nYou can only enable DNS hostnames if you've enabled DNS support.", "EnableDnsSupport": "Indicates whether the DNS resolution is supported for the VPC. If enabled, queries to the Amazon provided DNS server at the 169.254.169.253 IP address, or the reserved IP address at the base of the VPC network range \"plus two\" succeed. If disabled, the Amazon provided DNS service in the VPC that resolves public DNS hostnames to IP addresses is not enabled. Enabled by default. For more information, see [DNS attributes in your VPC](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html#vpc-dns-support) .", "InstanceTenancy": "The allowed tenancy of instances launched into the VPC.\n\n- `\"default\"` : An instance launched into the VPC runs on shared hardware by default, unless you explicitly specify a different tenancy during instance launch.\n- `\"dedicated\"` : An instance launched into the VPC is a Dedicated Instance by default, unless you explicitly specify a tenancy of host during instance launch. You cannot specify a tenancy of default during instance launch.\n\nUpdating `InstanceTenancy` requires no replacement only if you are updating its value from `\"dedicated\"` to `\"default\"` . Updating `InstanceTenancy` from `\"default\"` to `\"dedicated\"` requires replacement.", + "Ipv4IpamPoolId": "The ID of an IPv4 IPAM pool you want to use for allocating this VPC's CIDR. For more information, see [What is IPAM?](https://docs.aws.amazon.com//vpc/latest/ipam/what-is-it-ipam.html) in the *Amazon VPC IPAM User Guide* .", + "Ipv4NetmaskLength": "The netmask length of the IPv4 CIDR you want to allocate to this VPC from an Amazon VPC IP Address Manager (IPAM) pool. For more information about IPAM, see [What is IPAM?](https://docs.aws.amazon.com//vpc/latest/ipam/what-is-it-ipam.html) in the *Amazon VPC IPAM User Guide* .", "Tags": "The tags for the VPC." } }, @@ -13317,7 +13654,11 @@ "properties": { "AmazonProvidedIpv6CidrBlock": "Requests an Amazon-provided IPv6 CIDR block with a /56 prefix length for the VPC. You cannot specify the range of IPv6 addresses, or the size of the CIDR block.", "CidrBlock": "An IPv4 CIDR block to associate with the VPC.", + "Ipv4IpamPoolId": "Associate a CIDR allocated from an IPv4 IPAM pool to a VPC. For more information about Amazon VPC IP Address Manager (IPAM), see [What is IPAM?](https://docs.aws.amazon.com//vpc/latest/ipam/what-is-it-ipam.html) in the *Amazon VPC IPAM User Guide* .", + "Ipv4NetmaskLength": "The netmask length of the IPv4 CIDR you would like to associate from an Amazon VPC IP Address Manager (IPAM) pool. For more information about IPAM, see [What is IPAM?](https://docs.aws.amazon.com//vpc/latest/ipam/what-is-it-ipam.html) in the *Amazon VPC IPAM User Guide* .", "Ipv6CidrBlock": "An IPv6 CIDR block from the IPv6 address pool. You must also specify `Ipv6Pool` in the request.\n\nTo let Amazon choose the IPv6 CIDR block for you, omit this parameter.", + "Ipv6IpamPoolId": "Associates a CIDR allocated from an IPv6 IPAM pool to a VPC. For more information about Amazon VPC IP Address Manager (IPAM), see [What is IPAM?](https://docs.aws.amazon.com//vpc/latest/ipam/what-is-it-ipam.html) in the *Amazon VPC IPAM User Guide* .", + "Ipv6NetmaskLength": "The netmask length of the IPv6 CIDR you would like to associate from an Amazon VPC IP Address Manager (IPAM) pool. For more information about IPAM, see [What is IPAM?](https://docs.aws.amazon.com//vpc/latest/ipam/what-is-it-ipam.html) in the *Amazon VPC IPAM User Guide* .", "Ipv6Pool": "The ID of an IPv6 address pool from which to allocate the IPv6 CIDR block.", "VpcId": "The ID of the VPC." } @@ -13336,18 +13677,18 @@ "AWS::EC2::VPCEndpoint": { "attributes": { "CreationTimestamp": "The date and time the VPC endpoint was created. For example: `Fri Sep 28 23:34:36 UTC 2018.`", - "DnsEntries": "(Interface endpoint) The DNS entries for the endpoint. Each entry is a combination of the hosted zone ID and the DNS name. The entries are ordered as follows: regional public DNS, zonal public DNS, private DNS, and wildcard DNS. This order is not enforced for AWS Marketplace services.\n\nThe following is an example. In the first entry, the hosted zone ID is Z1HUB23UULQXV and the DNS name is vpce-01abc23456de78f9g-12abccd3.ec2.us-east-1.vpce.amazonaws.com.\n\n[\"Z1HUB23UULQXV:vpce-01abc23456de78f9g-12abccd3.ec2.us-east-1.vpce.amazonaws.com\", \"Z1HUB23UULQXV:vpce-01abc23456de78f9g-12abccd3-us-east-1a.ec2.us-east-1.vpce.amazonaws.com\", \"Z1C12344VYDITB0:ec2.us-east-1.amazonaws.com\"]\n\nIf you update the `PrivateDnsEnabled` or `SubnetIds` properties, the DNS entries in the list will change.", - "NetworkInterfaceIds": "(Interface endpoint) One or more network interface IDs. If you update the `PrivateDnsEnabled` or `SubnetIds` properties, the items in this list might change.", + "DnsEntries": "(Interface endpoints) The DNS entries for the endpoint. Each entry is a combination of the hosted zone ID and the DNS name. The entries are ordered as follows: regional public DNS, zonal public DNS, private DNS, and wildcard DNS. This order is not enforced for AWS Marketplace services.\n\nThe following is an example. In the first entry, the hosted zone ID is Z1HUB23UULQXV and the DNS name is vpce-01abc23456de78f9g-12abccd3.ec2.us-east-1.vpce.amazonaws.com.\n\n[\"Z1HUB23UULQXV:vpce-01abc23456de78f9g-12abccd3.ec2.us-east-1.vpce.amazonaws.com\", \"Z1HUB23UULQXV:vpce-01abc23456de78f9g-12abccd3-us-east-1a.ec2.us-east-1.vpce.amazonaws.com\", \"Z1C12344VYDITB0:ec2.us-east-1.amazonaws.com\"]\n\nIf you update the `PrivateDnsEnabled` or `SubnetIds` properties, the DNS entries in the list will change.", + "NetworkInterfaceIds": "(Interface endpoints) One or more network interface IDs. If you update the `PrivateDnsEnabled` or `SubnetIds` properties, the items in this list might change.", "Ref": "`Ref` returns the ID of the VPC endpoint." }, - "description": "Specifies a VPC endpoint for a service. An endpoint enables you to create a private connection between your VPC and the service. The service may be provided by AWS , an AWS Marketplace Partner, or another AWS account. For more information, see [VPC Endpoints](https://docs.aws.amazon.com/vpc/latest/privatelink/vpc-endpoints.html) in the *AWS PrivateLink User Guide* .\n\nA `gateway` endpoint serves as a target for a route in your route table for traffic destined for the AWS service. You can specify an endpoint policy to attach to the endpoint, which controls access to the service from your VPC. You can also specify the VPC route tables that use the endpoint.\n\nFor information about connectivity when you use a gateway endpoint to connect to an Amazon S3 bucket from an EC2 instance, see [Why can\u2019t I connect to an S3 bucket using a gateway VPC endpoint](https://docs.aws.amazon.com/premiumsupport/knowledge-center/connect-s3-vpc-endpoint) .\n\nAn `interface` endpoint is a network interface in your subnet that serves as an endpoint for communicating with the specified service. You can specify the subnets in which to create an endpoint, and the security groups to associate with the endpoint network interface.\n\nA `GatewayLoadBalancer` endpoint is a network interface in your subnet that serves an endpoint for communicating with a Gateway Load Balancer that you've configured as a VPC endpoint service.", + "description": "Specifies a VPC endpoint for a service. An endpoint enables you to create a private connection between your VPC and the service. The service may be provided by AWS , an AWS Marketplace Partner, or another AWS account. For more information, see the [AWS PrivateLink User Guide](https://docs.aws.amazon.com/vpc/latest/privatelink/) .\n\nAn interface endpoint establishes connections between the subnets in your VPC and an AWS service, your own service, or a service hosted by another AWS account . You can specify the subnets in which to create the endpoint and the security groups to associate with the endpoint network interface.\n\nA gateway endpoint serves as a target for a route in your route table for traffic destined for Amazon S3 or Amazon DynamoDB. You can specify an endpoint policy for the endpoint, which controls access to the service from your VPC. You can also specify the VPC route tables that use the endpoint. For information about connectivity to Amazon S3, see [Why can\u2019t I connect to an S3 bucket using a gateway VPC endpoint?](https://docs.aws.amazon.com/premiumsupport/knowledge-center/connect-s3-vpc-endpoint)\n\nA Gateway Load Balancer endpoint provides private connectivity between your VPC and virtual appliances from a service provider.", "properties": { - "PolicyDocument": "(Interface and gateway endpoints) A policy to attach to the endpoint that controls access to the service. If this parameter is not specified, we attach a default policy that allows full access to the service.\n\nFor CloudFormation templates in YAML, you can provide the policy in JSON or YAML format. AWS CloudFormation converts YAML policies to JSON format before calling the API to create or modify the VPC endpoint.", - "PrivateDnsEnabled": "(Interface endpoint) Indicate whether to associate a private hosted zone with the specified VPC. The private hosted zone contains a record set for the default public DNS name for the service for the Region (for example, `kinesis.us-east-1.amazonaws.com` ) which resolves to the private IP addresses of the endpoint network interfaces in the VPC. This enables you to make requests to the default public DNS name for the service instead of the public DNS names that are automatically generated by the VPC endpoint service.\n\nTo use a private hosted zone, you must set the following VPC attributes to `true` : `enableDnsHostnames` and `enableDnsSupport` .\n\nDefault: `false`", - "RouteTableIds": "(Gateway endpoint) One or more route table IDs.", - "SecurityGroupIds": "(Interface endpoint) The ID of one or more security groups to associate with the endpoint network interface.", - "ServiceName": "The service name. To get a list of available services, use the [DescribeVpcEndpointServices](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcEndpointServices.html) request, or get the name from the service provider.", - "SubnetIds": "(Interface and Gateway Load Balancer endpoints) The ID of one or more subnets in which to create an endpoint network interface. For a Gateway Load Balancer endpoint, you can specify one subnet only.", + "PolicyDocument": "A policy that controls access to the service from the VPC. If this parameter is not specified, the default policy allows full access to the service. Endpoint policies are supported only for gateway and interface endpoints.\n\nFor CloudFormation templates in YAML, you can provide the policy in JSON or YAML format. AWS CloudFormation converts YAML policies to JSON format before calling the API to create or modify the VPC endpoint.", + "PrivateDnsEnabled": "Indicate whether to associate a private hosted zone with the specified VPC. The private hosted zone contains a record set for the default public DNS name for the service for the Region (for example, `kinesis.us-east-1.amazonaws.com` ), which resolves to the private IP addresses of the endpoint network interfaces in the VPC. This enables you to make requests to the default public DNS name for the service instead of the public DNS names that are automatically generated by the VPC endpoint service.\n\nTo use a private hosted zone, you must set the following VPC attributes to `true` : `enableDnsHostnames` and `enableDnsSupport` .\n\nThis property is supported only for interface endpoints.\n\nDefault: `false`", + "RouteTableIds": "The route table IDs. Routing is supported only for gateway endpoints.", + "SecurityGroupIds": "The IDs of the security groups to associate with the endpoint network interface. Security groups are supported only for interface endpoints.", + "ServiceName": "The service name. To list the available services, use [DescribeVpcEndpointServices](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcEndpointServices.html) . Otherwise, get the name from the service provider.", + "SubnetIds": "The ID of the subnets in which to create an endpoint network interface. You must specify this property for an interface endpoints or a Gateway Load Balancer endpoint. You can't specify this property for a gateway endpoint. For a Gateway Load Balancer endpoint, you can specify only one subnet.", "VpcEndpointType": "The type of endpoint.\n\nDefault: Gateway", "VpcId": "The ID of the VPC in which the endpoint will be used." } @@ -13368,7 +13709,7 @@ "attributes": { "Ref": "`Ref` returns the ID of the VPC endpoint service configuration." }, - "description": "Creates a VPC endpoint service configuration to which service consumers ( AWS accounts, IAM users, and IAM roles) can connect.\n\nTo create an endpoint service configuration, you must first create one of the following for your service:\n\n- A [Network Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/introduction.html) . Service consumers connect to your service using an interface endpoint.\n- A [Gateway Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/gateway/introduction.html) . Service consumers connect to your service using a Gateway Load Balancer endpoint.\n\nFor more information, see [VPC Endpoint Services](https://docs.aws.amazon.com/vpc/latest/userguide/endpoint-service.html) in the *Amazon Virtual Private Cloud User Guide* .", + "description": "Creates a VPC endpoint service configuration to which service consumers ( AWS accounts, IAM users, and IAM roles) can connect.\n\nTo create an endpoint service configuration, you must first create one of the following for your service:\n\n- A [Network Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/introduction.html) . Service consumers connect to your service using an interface endpoint.\n- A [Gateway Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/gateway/introduction.html) . Service consumers connect to your service using a Gateway Load Balancer endpoint.\n\nFor more information, see the [AWS PrivateLink User Guide](https://docs.aws.amazon.com/vpc/latest/privatelink/) .", "properties": { "AcceptanceRequired": "Indicates whether requests from service consumers to create an endpoint to your service must be accepted.", "GatewayLoadBalancerArns": "The Amazon Resource Names (ARNs) of one or more Gateway Load Balancers.", @@ -13508,6 +13849,16 @@ "Tags": "An array of key-value pairs to apply to this resource." } }, + "AWS::ECR::PullThroughCacheRule": { + "attributes": { + "RegistryId": "The account ID of the private registry." + }, + "description": "Creates a pull through cache rule. A pull through cache rule provides a way to cache images from an external public registry in your Amazon ECR private registry.", + "properties": { + "EcrRepositoryPrefix": "The Amazon ECR repository prefix associated with the pull through cache rule.", + "UpstreamRegistryUrl": "The upstream registry URL associated with the pull through cache rule." + } + }, "AWS::ECR::RegistryPolicy": { "attributes": { "RegistryId": "The account ID of the private registry the policy is associated with." @@ -13624,7 +13975,7 @@ "InstanceWarmupPeriod": "The period of time, in seconds, after a newly launched Amazon EC2 instance can contribute to CloudWatch metrics for Auto Scaling group. If this parameter is omitted, the default value of `300` seconds is used.", "MaximumScalingStepSize": "The maximum number of container instances that Amazon ECS scales in or scales out at one time. If this parameter is omitted, the default value of `10000` is used.", "MinimumScalingStepSize": "The minimum number of container instances that Amazon ECS scales in or scales out at one time. If this parameter is omitted, the default value of `1` is used.", - "Status": "Determines whether to enable managed scaling for the capacity provider.", + "Status": "Determines whether to use managed scaling for the capacity provider.", "TargetCapacity": "The target capacity value for the capacity provider. The specified value must be greater than `0` and less than or equal to `100` . A value of `100` results in the Amazon EC2 instances in your Auto Scaling group being completely used." } }, @@ -13661,7 +14012,7 @@ }, "AWS::ECS::Cluster.ClusterSettings": { "attributes": {}, - "description": "The settings to use when creating a cluster. This parameter is used to enable CloudWatch Container Insights for a cluster.", + "description": "The settings to use when creating a cluster. This parameter is used to turn on CloudWatch Container Insights for a cluster.", "properties": { "Name": "The name of the cluster setting. The only supported value is `containerInsights` .", "Value": "The value to set for the cluster setting. The supported values are `enabled` and `disabled` . If `enabled` is specified, CloudWatch Container Insights will be enabled for the cluster, otherwise it will be disabled unless the `containerInsights` account setting is enabled. If a cluster value is specified, it will override the `containerInsights` value set with [PutAccountSetting](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_PutAccountSetting.html) or [PutAccountSettingDefault](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_PutAccountSettingDefault.html) ." @@ -13680,7 +14031,7 @@ "attributes": {}, "description": "The log configuration for the results of the execute command actions. The logs can be sent to CloudWatch Logs or an Amazon S3 bucket.", "properties": { - "CloudWatchEncryptionEnabled": "Determines whether to enable encryption on the CloudWatch logs. If not specified, encryption will be disabled.", + "CloudWatchEncryptionEnabled": "Determines whether to use encryption on the CloudWatch logs. If not specified, encryption will be disabled.", "CloudWatchLogGroupName": "The name of the CloudWatch log group to send logs to.\n\n> The CloudWatch log group must already be created.", "S3BucketName": "The name of the S3 bucket to send logs to.\n\n> The S3 bucket must already be created.", "S3EncryptionEnabled": "Determines whether to use encryption on the S3 logs. If not specified, encryption is not used.", @@ -13731,9 +14082,9 @@ "DeploymentConfiguration": "Optional deployment parameters that control how many tasks run during the deployment and the ordering of stopping and starting tasks.", "DeploymentController": "The deployment controller to use for the service. If no deployment controller is specified, the default value of `ECS` is used.", "DesiredCount": "The number of instantiations of the specified task definition to place and keep running on your cluster.\n\nFor new services, if a desired count is not specified, a default value of `1` is used. When using the `DAEMON` scheduling strategy, the desired count is not required.\n\nFor existing services, if a desired count is not specified, it is omitted from the operation.", - "EnableECSManagedTags": "Specifies whether to enable Amazon ECS managed tags for the tasks within the service. For more information, see [Tagging Your Amazon ECS Resources](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-using-tags.html) in the *Amazon Elastic Container Service Developer Guide* .", + "EnableECSManagedTags": "Specifies whether to turn on Amazon ECS managed tags for the tasks within the service. For more information, see [Tagging Your Amazon ECS Resources](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-using-tags.html) in the *Amazon Elastic Container Service Developer Guide* .", "EnableExecuteCommand": "Determines whether the execute command functionality is enabled for the service. If `true` , the execute command functionality is enabled for all containers in tasks as part of the service.", - "HealthCheckGracePeriodSeconds": "The period of time, in seconds, that the Amazon ECS service scheduler ignores unhealthy Elastic Load Balancing target health checks after a task has first started. This is only used when your service is configured to use a load balancer. If your service has a load balancer defined and you don't specify a health check grace period value, the default value of `0` is used.\n\nIf your service's tasks take a while to start and respond to Elastic Load Balancing health checks, you can specify a health check grace period of up to 2,147,483,647 seconds (about 69 years). During that time, the Amazon ECS service scheduler ignores health check status. This grace period can prevent the service scheduler from marking tasks as unhealthy and stopping them before they have time to come up.", + "HealthCheckGracePeriodSeconds": "The period of time, in seconds, that the Amazon ECS service scheduler ignores unhealthy Elastic Load Balancing target health checks after a task has first started. This is only used when your service is configured to use a load balancer. If your service has a load balancer defined and you don't specify a health check grace period value, the default value of `0` is used.\n\nIf you do not use an Elastic Load Balancing, we recomend that you use the `startPeriod` in the task definition healtch check parameters. For more information, see [Health check](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_HealthCheck.html) .\n\nIf your service's tasks take a while to start and respond to Elastic Load Balancing health checks, you can specify a health check grace period of up to 2,147,483,647 seconds (about 69 years). During that time, the Amazon ECS service scheduler ignores health check status. This grace period can prevent the service scheduler from marking tasks as unhealthy and stopping them before they have time to come up.", "LaunchType": "The launch type on which to run your service. For more information, see [Amazon ECS Launch Types](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/launch_types.html) in the *Amazon Elastic Container Service Developer Guide* .", "LoadBalancers": "A list of load balancer objects to associate with the service. If you specify the `Role` property, `LoadBalancers` must be specified as well. For information about the number of load balancers that you can specify per service, see [Service Load Balancing](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-load-balancing.html) in the *Amazon Elastic Container Service Developer Guide* .", "NetworkConfiguration": "The network configuration for the service. This parameter is required for task definitions that use the `awsvpc` network mode to receive their own elastic network interface, and it is not supported for other network modes. For more information, see [Task Networking](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-networking.html) in the *Amazon Elastic Container Service Developer Guide* .", @@ -13771,8 +14122,8 @@ "attributes": {}, "description": "> The deployment circuit breaker can only be used for services using the rolling update ( `ECS` ) deployment type. \n\nThe `DeploymentCircuitBreaker` property determines whether a service deployment will fail if the service can't reach a steady state. If deployment circuit breaker is enabled, a service deployment will transition to a failed state and stop launching new tasks. If rollback is enabled, when a service deployment fails, the service is rolled back to the last deployment that completed successfully.", "properties": { - "Enable": "Determines whether to enable the deployment circuit breaker logic for the service.", - "Rollback": "Determines whether to enable Amazon ECS to roll back the service if a service deployment fails. If rollback is enabled, when a service deployment fails, the service is rolled back to the last deployment that completed successfully." + "Enable": "Determines whether to use the deployment circuit breaker logic for the service.", + "Rollback": "Determines whether to configure Amazon ECS to roll back the service if a service deployment fails. If rollback is enabled, when a service deployment fails, the service is rolled back to the last deployment that completed successfully." } }, "AWS::ECS::Service.DeploymentConfiguration": { @@ -13853,7 +14204,7 @@ "PlacementConstraints": "An array of placement constraint objects to use for tasks.\n\n> This parameter isn't supported for tasks run on AWS Fargate .", "ProxyConfiguration": "The `ProxyConfiguration` property specifies the configuration details for the App Mesh proxy.\n\nYour Amazon ECS container instances require at least version 1.26.0 of the container agent and at least version 1.26.0-1 of the `ecs-init` package to enable a proxy configuration. If your container instances are launched from the Amazon ECS-optimized AMI version `20190301` or later, then they contain the required versions of the container agent and `ecs-init` . For more information, see [Amazon ECS-optimized Linux AMI](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI.html) in the *Amazon Elastic Container Service Developer Guide* .", "RequiresCompatibilities": "The task launch types the task definition was validated against. To determine which task launch types the task definition is validated for, see the `TaskDefinition$compatibilities` parameter.", - "RuntimePlatform": "", + "RuntimePlatform": "The operating system that your tasks definitions run on. A platform family is specified only for tasks using the Fargate launch type.\n\nWhen you specify a task definition in a service, this value must match the `runtimePlatform` value of the service.", "Tags": "The metadata that you apply to the task definition to help you categorize and organize them. Each tag consists of a key and an optional value. You define both of them.\n\nThe following basic restrictions apply to tags:\n\n- Maximum number of tags per resource - 50\n- For each resource, each tag key must be unique, and each tag key can have only one value.\n- Maximum key length - 128 Unicode characters in UTF-8\n- Maximum value length - 256 Unicode characters in UTF-8\n- If your tagging schema is used across multiple services and resources, remember that other services may have restrictions on allowed characters. Generally allowed characters are: letters, numbers, and spaces representable in UTF-8, and the following characters: + - = . _ : / @.\n- Tag keys and values are case-sensitive.\n- Do not use `aws:` , `AWS:` , or any upper or lowercase combination of such as a prefix for either keys or values as it is reserved for AWS use. You cannot edit or delete tag keys or values with this prefix. Tags with this prefix do not count against your tags per resource limit.", "TaskRoleArn": "The short name or full Amazon Resource Name (ARN) of the AWS Identity and Access Management role that grants containers in the task permission to call AWS APIs on your behalf. For more information, see [Amazon ECS Task Role](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html) in the *Amazon Elastic Container Service Developer Guide* .\n\nIAM roles for tasks on Windows require that the `-EnableTaskIAMRole` option is set when you launch the Amazon ECS-optimized Windows AMI. Your containers must also run some configuration code to use the feature. For more information, see [Windows IAM roles for tasks](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/windows_task_IAM_roles.html) in the *Amazon Elastic Container Service Developer Guide* .", "Volumes": "The list of data volume definitions for the task. For more information, see [Using data volumes in tasks](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using_data_volumes.html) in the *Amazon Elastic Container Service Developer Guide* .\n\n> The `host` and `sourcePath` parameters aren't supported for tasks run on AWS Fargate ." @@ -13873,7 +14224,7 @@ "properties": { "Command": "The command that's passed to the container. This parameter maps to `Cmd` in the [Create a container](https://docs.aws.amazon.com/https://docs.docker.com/engine/api/v1.35/#operation/ContainerCreate) section of the [Docker Remote API](https://docs.aws.amazon.com/https://docs.docker.com/engine/api/v1.35/) and the `COMMAND` parameter to [docker run](https://docs.aws.amazon.com/https://docs.docker.com/engine/reference/run/#security-configuration) . For more information, see [https://docs.docker.com/engine/reference/builder/#cmd](https://docs.aws.amazon.com/https://docs.docker.com/engine/reference/builder/#cmd) . If there are multiple arguments, each argument is a separated string in the array.", "Cpu": "The number of `cpu` units reserved for the container. This parameter maps to `CpuShares` in the [Create a container](https://docs.aws.amazon.com/https://docs.docker.com/engine/api/v1.35/#operation/ContainerCreate) section of the [Docker Remote API](https://docs.aws.amazon.com/https://docs.docker.com/engine/api/v1.35/) and the `--cpu-shares` option to [docker run](https://docs.aws.amazon.com/https://docs.docker.com/engine/reference/run/#security-configuration) .\n\nThis field is optional for tasks using the Fargate launch type, and the only requirement is that the total amount of CPU reserved for all containers within a task be lower than the task-level `cpu` value.\n\n> You can determine the number of CPU units that are available per EC2 instance type by multiplying the vCPUs listed for that instance type on the [Amazon EC2 Instances](https://docs.aws.amazon.com/ec2/instance-types/) detail page by 1,024. \n\nLinux containers share unallocated CPU units with other containers on the container instance with the same ratio as their allocated amount. For example, if you run a single-container task on a single-core instance type with 512 CPU units specified for that container, and that's the only task running on the container instance, that container could use the full 1,024 CPU unit share at any given time. However, if you launched another copy of the same task on that container instance, each task is guaranteed a minimum of 512 CPU units when needed. Moreover, each container could float to higher CPU usage if the other container was not using it. If both tasks were 100% active all of the time, they would be limited to 512 CPU units.\n\nOn Linux container instances, the Docker daemon on the container instance uses the CPU value to calculate the relative CPU share ratios for running containers. For more information, see [CPU share constraint](https://docs.aws.amazon.com/https://docs.docker.com/engine/reference/run/#cpu-share-constraint) in the Docker documentation. The minimum valid CPU share value that the Linux kernel allows is 2. However, the CPU parameter isn't required, and you can use CPU values below 2 in your container definitions. For CPU values below 2 (including null), the behavior varies based on your Amazon ECS container agent version:\n\n- *Agent versions less than or equal to 1.1.0:* Null and zero CPU values are passed to Docker as 0, which Docker then converts to 1,024 CPU shares. CPU values of 1 are passed to Docker as 1, which the Linux kernel converts to two CPU shares.\n- *Agent versions greater than or equal to 1.2.0:* Null, zero, and CPU values of 1 are passed to Docker as 2.\n\nOn Windows container instances, the CPU limit is enforced as an absolute limit, or a quota. Windows containers only have access to the specified amount of CPU that's described in the task definition. A null or zero CPU value is passed to Docker as `0` , which Windows interprets as 1% of one CPU.", - "DependsOn": "The dependencies defined for container startup and shutdown. A container can contain multiple dependencies. When a dependency is defined for container startup, for container shutdown it is reversed.\n\nFor tasks using the EC2 launch type, the container instances require at least version 1.26.0 of the container agent to enable container dependencies. However, we recommend using the latest container agent version. For information about checking your agent version and updating to the latest version, see [Updating the Amazon ECS Container Agent](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-agent-update.html) in the *Amazon Elastic Container Service Developer Guide* . If you're using an Amazon ECS-optimized Linux AMI, your instance needs at least version 1.26.0-1 of the `ecs-init` package. If your container instances are launched from version `20190301` or later, then they contain the required versions of the container agent and `ecs-init` . For more information, see [Amazon ECS-optimized Linux AMI](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI.html) in the *Amazon Elastic Container Service Developer Guide* .\n\nFor tasks using the Fargate launch type, the task or service requires the following platforms:\n\n- Linux platform version `1.3.0` or later.\n- Windows platform version `1.0.0` or later.", + "DependsOn": "The dependencies defined for container startup and shutdown. A container can contain multiple dependencies. When a dependency is defined for container startup, for container shutdown it is reversed.\n\nFor tasks using the EC2 launch type, the container instances require at least version 1.26.0 of the container agent to turn on container dependencies. However, we recommend using the latest container agent version. For information about checking your agent version and updating to the latest version, see [Updating the Amazon ECS Container Agent](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-agent-update.html) in the *Amazon Elastic Container Service Developer Guide* . If you're using an Amazon ECS-optimized Linux AMI, your instance needs at least version 1.26.0-1 of the `ecs-init` package. If your container instances are launched from version `20190301` or later, then they contain the required versions of the container agent and `ecs-init` . For more information, see [Amazon ECS-optimized Linux AMI](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI.html) in the *Amazon Elastic Container Service Developer Guide* .\n\nFor tasks using the Fargate launch type, the task or service requires the following platforms:\n\n- Linux platform version `1.3.0` or later.\n- Windows platform version `1.0.0` or later.", "DisableNetworking": "When this parameter is true, networking is disabled within the container. This parameter maps to `NetworkDisabled` in the [Create a container](https://docs.aws.amazon.com/https://docs.docker.com/engine/api/v1.35/#operation/ContainerCreate) section of the [Docker Remote API](https://docs.aws.amazon.com/https://docs.docker.com/engine/api/v1.35/) .\n\n> This parameter is not supported for Windows containers.", "DnsSearchDomains": "A list of DNS search domains that are presented to the container. This parameter maps to `DnsSearch` in the [Create a container](https://docs.aws.amazon.com/https://docs.docker.com/engine/api/v1.35/#operation/ContainerCreate) section of the [Docker Remote API](https://docs.aws.amazon.com/https://docs.docker.com/engine/api/v1.35/) and the `--dns-search` option to [docker run](https://docs.aws.amazon.com/https://docs.docker.com/engine/reference/run/#security-configuration) .\n\n> This parameter is not supported for Windows containers.", "DnsServers": "A list of DNS servers that are presented to the container. This parameter maps to `Dns` in the [Create a container](https://docs.aws.amazon.com/https://docs.docker.com/engine/api/v1.35/#operation/ContainerCreate) section of the [Docker Remote API](https://docs.aws.amazon.com/https://docs.docker.com/engine/api/v1.35/) and the `--dns` option to [docker run](https://docs.aws.amazon.com/https://docs.docker.com/engine/reference/run/#security-configuration) .\n\n> This parameter is not supported for Windows containers.", @@ -13903,8 +14254,8 @@ "RepositoryCredentials": "The private repository authentication credentials to use.", "ResourceRequirements": "The type and amount of a resource to assign to a container. The only supported resource is a GPU.", "Secrets": "The secrets to pass to the container. For more information, see [Specifying Sensitive Data](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/specifying-sensitive-data.html) in the *Amazon Elastic Container Service Developer Guide* .", - "StartTimeout": "Time duration (in seconds) to wait before giving up on resolving dependencies for a container. For example, you specify two containers in a task definition with containerA having a dependency on containerB reaching a `COMPLETE` , `SUCCESS` , or `HEALTHY` status. If a `startTimeout` value is specified for containerB and it doesn't reach the desired status within that time then containerA gives up and not start. This results in the task transitioning to a `STOPPED` state.\n\n> When the `ECS_CONTAINER_START_TIMEOUT` container agent configuration variable is used, it's enforced independently from this start timeout value. \n\nFor tasks using the Fargate launch type, the task or service requires the following platforms:\n\n- Linux platform version `1.3.0` or later.\n- Windows platform version `1.0.0` or later.\n\nFor tasks using the EC2 launch type, your container instances require at least version `1.26.0` of the container agent to enable a container start timeout value. However, we recommend using the latest container agent version. For information about checking your agent version and updating to the latest version, see [Updating the Amazon ECS Container Agent](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-agent-update.html) in the *Amazon Elastic Container Service Developer Guide* . If you're using an Amazon ECS-optimized Linux AMI, your instance needs at least version `1.26.0-1` of the `ecs-init` package. If your container instances are launched from version `20190301` or later, then they contain the required versions of the container agent and `ecs-init` . For more information, see [Amazon ECS-optimized Linux AMI](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI.html) in the *Amazon Elastic Container Service Developer Guide* .", - "StopTimeout": "Time duration (in seconds) to wait before the container is forcefully killed if it doesn't exit normally on its own.\n\nFor tasks using the Fargate launch type, the task or service requires the following platforms:\n\n- Linux platform version `1.3.0` or later.\n- Windows platform version `1.0.0` or later.\n\nThe max stop timeout value is 120 seconds and if the parameter is not specified, the default value of 30 seconds is used.\n\nFor tasks that use the EC2 launch type, if the `stopTimeout` parameter isn't specified, the value set for the Amazon ECS container agent configuration variable `ECS_CONTAINER_STOP_TIMEOUT` is used. If neither the `stopTimeout` parameter or the `ECS_CONTAINER_STOP_TIMEOUT` agent configuration variable are set, then the default values of 30 seconds for Linux containers and 30 seconds on Windows containers are used. Your container instances require at least version 1.26.0 of the container agent to enable a container stop timeout value. However, we recommend using the latest container agent version. For information about checking your agent version and updating to the latest version, see [Updating the Amazon ECS Container Agent](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-agent-update.html) in the *Amazon Elastic Container Service Developer Guide* . If you're using an Amazon ECS-optimized Linux AMI, your instance needs at least version 1.26.0-1 of the `ecs-init` package. If your container instances are launched from version `20190301` or later, then they contain the required versions of the container agent and `ecs-init` . For more information, see [Amazon ECS-optimized Linux AMI](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI.html) in the *Amazon Elastic Container Service Developer Guide* .", + "StartTimeout": "Time duration (in seconds) to wait before giving up on resolving dependencies for a container. For example, you specify two containers in a task definition with containerA having a dependency on containerB reaching a `COMPLETE` , `SUCCESS` , or `HEALTHY` status. If a `startTimeout` value is specified for containerB and it doesn't reach the desired status within that time then containerA gives up and not start. This results in the task transitioning to a `STOPPED` state.\n\n> When the `ECS_CONTAINER_START_TIMEOUT` container agent configuration variable is used, it's enforced independently from this start timeout value. \n\nFor tasks using the Fargate launch type, the task or service requires the following platforms:\n\n- Linux platform version `1.3.0` or later.\n- Windows platform version `1.0.0` or later.\n\nFor tasks using the EC2 launch type, your container instances require at least version `1.26.0` of the container agent to use a container start timeout value. However, we recommend using the latest container agent version. For information about checking your agent version and updating to the latest version, see [Updating the Amazon ECS Container Agent](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-agent-update.html) in the *Amazon Elastic Container Service Developer Guide* . If you're using an Amazon ECS-optimized Linux AMI, your instance needs at least version `1.26.0-1` of the `ecs-init` package. If your container instances are launched from version `20190301` or later, then they contain the required versions of the container agent and `ecs-init` . For more information, see [Amazon ECS-optimized Linux AMI](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI.html) in the *Amazon Elastic Container Service Developer Guide* .", + "StopTimeout": "Time duration (in seconds) to wait before the container is forcefully killed if it doesn't exit normally on its own.\n\nFor tasks using the Fargate launch type, the task or service requires the following platforms:\n\n- Linux platform version `1.3.0` or later.\n- Windows platform version `1.0.0` or later.\n\nThe max stop timeout value is 120 seconds and if the parameter is not specified, the default value of 30 seconds is used.\n\nFor tasks that use the EC2 launch type, if the `stopTimeout` parameter isn't specified, the value set for the Amazon ECS container agent configuration variable `ECS_CONTAINER_STOP_TIMEOUT` is used. If neither the `stopTimeout` parameter or the `ECS_CONTAINER_STOP_TIMEOUT` agent configuration variable are set, then the default values of 30 seconds for Linux containers and 30 seconds on Windows containers are used. Your container instances require at least version 1.26.0 of the container agent to use a container stop timeout value. However, we recommend using the latest container agent version. For information about checking your agent version and updating to the latest version, see [Updating the Amazon ECS Container Agent](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-agent-update.html) in the *Amazon Elastic Container Service Developer Guide* . If you're using an Amazon ECS-optimized Linux AMI, your instance needs at least version 1.26.0-1 of the `ecs-init` package. If your container instances are launched from version `20190301` or later, then they contain the required versions of the container agent and `ecs-init` . For more information, see [Amazon ECS-optimized Linux AMI](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI.html) in the *Amazon Elastic Container Service Developer Guide* .", "SystemControls": "A list of namespaced kernel parameters to set in the container. This parameter maps to `Sysctls` in the [Create a container](https://docs.aws.amazon.com/https://docs.docker.com/engine/api/v1.35/#operation/ContainerCreate) section of the [Docker Remote API](https://docs.aws.amazon.com/https://docs.docker.com/engine/api/v1.35/) and the `--sysctl` option to [docker run](https://docs.aws.amazon.com/https://docs.docker.com/engine/reference/run/#security-configuration) .\n\n> We don't recommended that you specify network-related `systemControls` parameters for multiple containers in a single task that also uses either the `awsvpc` or `host` network modes. For tasks that use the `awsvpc` network mode, the container that's started last determines which `systemControls` parameters take effect. For tasks that use the `host` network mode, it changes the container instance's namespaced kernel parameters as well as the containers.", "Ulimits": "A list of `ulimits` to set in the container. This parameter maps to `Ulimits` in the [Create a container](https://docs.aws.amazon.com/https://docs.docker.com/engine/api/v1.35/#operation/ContainerCreate) section of the [Docker Remote API](https://docs.aws.amazon.com/https://docs.docker.com/engine/api/v1.35/) and the `--ulimit` option to [docker run](https://docs.aws.amazon.com/https://docs.docker.com/engine/reference/run/) . Valid naming values are displayed in the [Ulimit](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_Ulimit.html) data type. This parameter requires version 1.18 of the Docker Remote API or greater on your container instance. To check the Docker Remote API version on your container instance, log in to your container instance and run the following command: `sudo docker version --format '{{.Server.APIVersion}}'`\n\n> This parameter is not supported for Windows containers.", "User": "The user to use inside the container. This parameter maps to `User` in the [Create a container](https://docs.aws.amazon.com/https://docs.docker.com/engine/api/v1.35/#operation/ContainerCreate) section of the [Docker Remote API](https://docs.aws.amazon.com/https://docs.docker.com/engine/api/v1.35/) and the `--user` option to [docker run](https://docs.aws.amazon.com/https://docs.docker.com/engine/reference/run/#security-configuration) .\n\n> When running tasks using the `host` network mode, don't run containers using the root user (UID 0). We recommend using a non-root user for better security. \n\nYou can specify the `user` using the following formats. If specifying a UID or GID, you must specify it as a positive integer.\n\n- `user`\n- `user:group`\n- `uid`\n- `uid:gid`\n- `user:gid`\n- `uid:group`\n\n> This parameter is not supported for Windows containers.", @@ -13947,7 +14298,7 @@ "AuthorizationConfig": "The authorization configuration details for the Amazon EFS file system.", "FilesystemId": "The Amazon EFS file system ID to use.", "RootDirectory": "The directory within the Amazon EFS file system to mount as the root directory inside the host. If this parameter is omitted, the root of the Amazon EFS volume will be used. Specifying `/` will have the same effect as omitting this parameter.\n\n> If an EFS access point is specified in the `authorizationConfig` , the root directory parameter must either be omitted or set to `/` which will enforce the path set on the EFS access point.", - "TransitEncryption": "Determines whether to enable encryption for Amazon EFS data in transit between the Amazon ECS host and the Amazon EFS server. Transit encryption must be enabled if Amazon EFS IAM authorization is used. If this parameter is omitted, the default value of `DISABLED` is used. For more information, see [Encrypting Data in Transit](https://docs.aws.amazon.com/efs/latest/ug/encryption-in-transit.html) in the *Amazon Elastic File System User Guide* .", + "TransitEncryption": "Determines whether to use encryption for Amazon EFS data in transit between the Amazon ECS host and the Amazon EFS server. Transit encryption must be enabled if Amazon EFS IAM authorization is used. If this parameter is omitted, the default value of `DISABLED` is used. For more information, see [Encrypting Data in Transit](https://docs.aws.amazon.com/efs/latest/ug/encryption-in-transit.html) in the *Amazon Elastic File System User Guide* .", "TransitEncryptionPort": "The port to use when sending encrypted data between the Amazon ECS host and the Amazon EFS server. If you do not specify a transit encryption port, it will use the port selection strategy that the Amazon EFS mount helper uses. For more information, see [EFS Mount Helper](https://docs.aws.amazon.com/efs/latest/ug/efs-mount-helper.html) in the *Amazon Elastic File System User Guide* ." } }, @@ -14090,10 +14441,10 @@ }, "AWS::ECS::TaskDefinition.RuntimePlatform": { "attributes": {}, - "description": "", + "description": "Information about the platform for the Amazon ECS service or task.\n\nFor more informataion about `RuntimePlatform` , see [RuntimePlatform](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html#runtime-platform) in the *Amazon Elastic Container Service Developer Guide* .", "properties": { - "CpuArchitecture": "", - "OperatingSystemFamily": "" + "CpuArchitecture": "The CPU architecture.\n\nYou can run your Linux tasks on an ARM-based platform by setting the value to `ARM64` . This option is avaiable for tasks that run on Linuc Amazon EC2 instance or Linux containers on Fargate.", + "OperatingSystemFamily": "The operating system." } }, "AWS::ECS::TaskDefinition.Secret": { @@ -14101,7 +14452,7 @@ "description": "The `Secret` property specifies an object representing the secret to expose to your container. For more information, see [Specifying Sensitive Data](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/specifying-sensitive-data.html) in the *Amazon Elastic Container Service Developer Guide* .", "properties": { "Name": "The name of the secret.", - "ValueFrom": "The secret to expose to the container. The supported values are either the full ARN of the AWS Secrets Manager secret or the full ARN of the parameter in the SSM Parameter Store.\n\n> If the SSM Parameter Store parameter exists in the same Region as the task you're launching, then you can use either the full ARN or name of the parameter. If the parameter exists in a different Region, then the full ARN must be specified." + "ValueFrom": "The secret to expose to the container. The supported values are either the full ARN of the AWS Secrets Manager secret or the full ARN of the parameter in the SSM Parameter Store.\n\nFor information about the require AWS Identity and Access Management permissions, see [Required IAM permissions for Amazon ECS secrets](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/specifying-sensitive-data-secrets.html#secrets-iam) (for Secrets Manager) or [Required IAM permissions for Amazon ECS secrets](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/specifying-sensitive-data-parameters.html) (for Systems Manager Parameter store) in the *Amazon Elastic Container Service Developer Guide* .\n\n> If the SSM Parameter Store parameter exists in the same Region as the task you're launching, then you can use either the full ARN or name of the parameter. If the parameter exists in a different Region, then the full ARN must be specified." } }, "AWS::ECS::TaskDefinition.SystemControl": { @@ -14211,7 +14562,7 @@ }, "AWS::ECS::TaskSet.ServiceRegistry": { "attributes": {}, - "description": "The details for the service registry.", + "description": "The details for the service registry.\n\nEach service may be associated with one service registry. Multiple service registries for each service are not supported.\n\nWhen you add, update, or remove the service registries configuration, Amazon ECS starts a new deployment. New tasks are registered and deregistered to the updated service registry configuration.", "properties": { "ContainerName": "The container name value to be used for your service discovery service. It's already specified in the task definition. If the task definition that your service task specifies uses the `bridge` or `host` network mode, you must specify a `containerName` and `containerPort` combination from the task definition. If the task definition that your service task specifies uses the `awsvpc` network mode and a type SRV DNS record is used, you must specify either a `containerName` and `containerPort` combination or a `port` value. However, you can't specify both.", "ContainerPort": "The port value to be used for your service discovery service. It's already specified in the task definition. If the task definition your service task specifies uses the `bridge` or `host` network mode, you must specify a `containerName` and `containerPort` combination from the task definition. If the task definition your service task specifies uses the `awsvpc` network mode and a type SRV DNS record is used, you must specify either a `containerName` and `containerPort` combination or a `port` value. However, you can't specify both.", @@ -14329,7 +14680,7 @@ "AWS::EKS::Addon": { "attributes": { "Arn": "The ARN of the add-on, such as `arn:aws:eks:us-west-2:111122223333:addon/1-19/vpc-cni/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` .", - "Ref": "`Ref` returns the resource name. For example:\n\n`{ \"Ref\": \"vpc-cni\" }`\n\nFor the add-on `vpc-cni` , `Ref` returns the name of the add-on. For example, `|` ." + "Ref": "`Ref` returns the resource name. For example:\n\n`{ \"Ref\": \"vpc-cni\" }`\n\nFor the add-on `vpc-cni` , `Ref` returns the name of the add-on. For example, `cluster-name|vpc-cni` ." }, "description": "Creates an Amazon EKS add-on.\n\nAmazon EKS add-ons help to automate the provisioning and lifecycle management of common operational software for Amazon EKS clusters. Amazon EKS add-ons require clusters running version 1.18 or later because Amazon EKS add-ons rely on the Server-side Apply Kubernetes feature, which is only available in Kubernetes 1.18 and later. For more information, see [Amazon EKS add-ons](https://docs.aws.amazon.com/eks/latest/userguide/eks-add-ons.html) in the *Amazon EKS User Guide* .", "properties": { @@ -14349,7 +14700,7 @@ "EncryptionConfigKeyArn": "Amazon Resource Name (ARN) or alias of the customer master key (CMK).", "Endpoint": "The endpoint for your Kubernetes API server, such as `https://5E1D0CEXAMPLEA591B746AFC5AB30262.yl4.us-west-2.eks.amazonaws.com` .", "KubernetesNetworkConfig.ServiceIpv6Cidr": "The CIDR block that Kubernetes Service IP addresses are assigned from if you created a 1.21 or later cluster with version 1.10.1 or later of the Amazon VPC CNI add-on and specified `ipv6` for *ipFamily* when you created the cluster. Kubernetes assigns Service addresses from the unique local address range ( `fc00::/7` ) because you can't specify a custom IPv6 CIDR block when you create the cluster.", - "OpenIdConnectIssuerUrl": "The issuer URL for the OIDC identity provider of the cluster, such as `https://oidc.eks.us-west-2.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E` . If you need to remove `https://` from this output value, you can include the following code in your template.\n\n`!Select [1, !Split [\"//\", !GetAtt EKSCluster.OpenIdConnectIssuerUrl]]`", + "OpenIdConnectIssuerUrl": "", "Ref": "`Ref` returns the resource name. For example:\n\n`{ \"Ref\": \"myCluster\" }`\n\nFor the Amazon EKS cluster `myCluster` , `Ref` returns the name of the cluster." }, "description": "Creates an Amazon EKS control plane.\n\nThe Amazon EKS control plane consists of control plane instances that run the Kubernetes software, such as `etcd` and the API server. The control plane runs in an account managed by AWS , and the Kubernetes API is exposed by the Amazon EKS API server endpoint. Each Amazon EKS cluster control plane is single tenant and unique. It runs on its own set of Amazon EC2 instances.\n\nThe cluster control plane is provisioned across multiple Availability Zones and fronted by an Elastic Load Balancing Network Load Balancer. Amazon EKS also provisions elastic network interfaces in your VPC subnets to provide connectivity from the control plane instances to the nodes (for example, to support `kubectl exec` , `logs` , and `proxy` data flows).\n\nAmazon EKS nodes run in your AWS account and connect to your cluster's control plane over the Kubernetes API server endpoint and a certificate file that is created for your cluster.\n\nIn most cases, it takes several minutes to create a cluster. After you create an Amazon EKS cluster, you must configure your Kubernetes tooling to communicate with the API server and launch nodes into your cluster. For more information, see [Managing Cluster Authentication](https://docs.aws.amazon.com/eks/latest/userguide/managing-auth.html) and [Launching Amazon EKS nodes](https://docs.aws.amazon.com/eks/latest/userguide/launch-workers.html) in the *Amazon EKS User Guide* .", @@ -14416,7 +14767,7 @@ "AWS::EKS::FargateProfile": { "attributes": { "Arn": "The ARN of the cluster, such as `arn:aws:eks:us-west-2:666666666666:fargateprofile/myCluster/myFargateProfile/1cb1a11a-1dc1-1d11-cf11-1111f11fa111` .", - "Ref": "`Ref` returns the resource name. For example:\n\n`{ \"Ref\": \"myFargateProfile\" }`\n\nFor the Fargate profile `myFargateProfile` , Ref returns the physical resource ID of the Fargate profile. For example, `/` ." + "Ref": "`Ref` returns the resource name. For example:\n\n`{ \"Ref\": \"myFargateProfile\" }`\n\nFor the Fargate profile `myFargateProfile` , Ref returns the physical resource ID of the Fargate profile. For example, `/` ." }, "description": "Creates an AWS Fargate profile for your Amazon EKS cluster. You must have at least one Fargate profile in a cluster to be able to run pods on Fargate.\n\nThe Fargate profile allows an administrator to declare which pods run on Fargate and specify which pods run on which Fargate profile. This declaration is done through the profile\u2019s selectors. Each profile can have up to five selectors that contain a namespace and labels. A namespace is required for every selector. The label field consists of multiple optional key-value pairs. Pods that match the selectors are scheduled on Fargate. If a to-be-scheduled pod matches any of the selectors in the Fargate profile, then that pod is run on Fargate.\n\nWhen you create a Fargate profile, you must specify a pod execution role to use with the pods that are scheduled with the profile. This role is added to the cluster's Kubernetes [Role Based Access Control](https://docs.aws.amazon.com/https://kubernetes.io/docs/admin/authorization/rbac/) (RBAC) for authorization so that the `kubelet` that is running on the Fargate infrastructure can register with your Amazon EKS cluster so that it can appear in your cluster as a node. The pod execution role also provides IAM permissions to the Fargate infrastructure to allow read access to Amazon ECR image repositories. For more information, see [Pod Execution Role](https://docs.aws.amazon.com/eks/latest/userguide/pod-execution-role.html) in the *Amazon EKS User Guide* .\n\nFargate profiles are immutable. However, you can create a new updated profile to replace an existing profile and then delete the original after the updated profile has finished creating.\n\nIf any Fargate profiles in a cluster are in the `DELETING` status, you must wait for that Fargate profile to finish deleting before you can create any other profiles in that cluster.\n\nFor more information, see [AWS Fargate Profile](https://docs.aws.amazon.com/eks/latest/userguide/fargate-profile.html) in the *Amazon EKS User Guide* .", "properties": { @@ -14444,12 +14795,48 @@ "Namespace": "The Kubernetes namespace that the selector should match." } }, + "AWS::EKS::IdentityProviderConfig": { + "attributes": { + "IdentityProviderConfigArn": "The Amazon Resource Name (ARN) associated with the identity provider config.", + "Ref": "`Ref` returns the resource name. For example:\n\n`{ \"Ref\": \"myIdentityProviderConfig\" }`\n\nFor the IdentityProviderConfig, Ref returns the physical resource ID of the config. For example, `cluster-name/oidc/identity-provider-config-name` ." + }, + "description": "Associate an identity provider configuration to a cluster.\n\nIf you want to authenticate identities using an identity provider, you can create an identity provider configuration and associate it to your cluster. After configuring authentication to your cluster you can create Kubernetes `roles` and `clusterroles` to assign permissions to the roles, and then bind the roles to the identities using Kubernetes `rolebindings` and `clusterrolebindings` . For more information see [Using RBAC Authorization](https://docs.aws.amazon.com/https://kubernetes.io/docs/reference/access-authn-authz/rbac/) in the Kubernetes documentation.", + "properties": { + "ClusterName": "The cluster that the configuration is associated to.", + "IdentityProviderConfigName": "The name of the configuration.", + "Oidc": "An object that represents an OpenID Connect (OIDC) identity provider configuration.", + "Tags": "The metadata to apply to the provider configuration to assist with categorization and organization. Each tag consists of a key and an optional value. You define both.", + "Type": "The type of the identity provider configuration. The only type available is `oidc` ." + } + }, + "AWS::EKS::IdentityProviderConfig.OidcIdentityProviderConfig": { + "attributes": {}, + "description": "An object that represents the configuration for an OpenID Connect (OIDC) identity provider.", + "properties": { + "ClientId": "This is also known as *audience* . The ID of the client application that makes authentication requests to the OIDC identity provider.", + "GroupsClaim": "The JSON web token (JWT) claim that the provider uses to return your groups.", + "GroupsPrefix": "The prefix that is prepended to group claims to prevent clashes with existing names (such as `system:` groups). For example, the value `oidc:` creates group names like `oidc:engineering` and `oidc:infra` . The prefix can't contain `system:`", + "IssuerUrl": "The URL of the OIDC identity provider that allows the API server to discover public signing keys for verifying tokens.", + "RequiredClaims": "The key-value pairs that describe required claims in the identity token. If set, each claim is verified to be present in the token with a matching value.", + "UsernameClaim": "The JSON Web token (JWT) claim that is used as the username.", + "UsernamePrefix": "The prefix that is prepended to username claims to prevent clashes with existing names. The prefix can't contain `system:`" + } + }, + "AWS::EKS::IdentityProviderConfig.RequiredClaim": { + "attributes": {}, + "description": "A key-value pair that describes a required claim in the identity token. If set, each claim is verified to be present in the token with a matching value.", + "properties": { + "Key": "The key to match from the token.", + "Value": "The value for the key from the token." + } + }, "AWS::EKS::Nodegroup": { "attributes": { "Arn": "The Amazon Resource Name (ARN) associated with the managed node group.", "ClusterName": "The name of the cluster that the managed node group resides in.", + "Id": "", "NodegroupName": "The name associated with an Amazon EKS managed node group.", - "Ref": "`Ref` returns the resource name. For example:\n\n`{ \"Ref\": \"myNodegroup\" }`\n\nFor the Amazon EKS node group `myNodegroup` , Ref returns the physical resource ID of the node group. For example, `/` ." + "Ref": "`Ref` returns the resource name. For example:\n\n`{ \"Ref\": \"myNodegroup\" }`\n\nFor the Amazon EKS node group `myNodegroup` , Ref returns the physical resource ID of the node group. For example, `cluster-name/nodegroup_name` ." }, "description": "Creates a managed node group for an Amazon EKS cluster. You can only create a node group for your cluster that is equal to the current Kubernetes version for the cluster. All node groups are created with the latest AMI release version for the respective minor Kubernetes version of the cluster, unless you deploy a custom AMI using a launch template. For more information about using launch templates, see [Launch template support](https://docs.aws.amazon.com/eks/latest/userguide/launch-templates.html) .\n\nAn Amazon EKS managed node group is an Amazon EC2 Auto Scaling group and associated Amazon EC2 instances that are managed by AWS for an Amazon EKS cluster. Each node group uses a version of the Amazon EKS optimized Amazon Linux 2 AMI. For more information, see [Managed Node Groups](https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html) in the *Amazon EKS User Guide* .", "properties": { @@ -14461,14 +14848,14 @@ "InstanceTypes": "Specify the instance types for a node group. If you specify a GPU instance type, be sure to specify `AL2_x86_64_GPU` with the `amiType` parameter. If you specify `launchTemplate` , then you can specify zero or one instance type in your launch template *or* you can specify 0-20 instance types for `instanceTypes` . If however, you specify an instance type in your launch template *and* specify any `instanceTypes` , the node group deployment will fail. If you don't specify an instance type in a launch template or for `instanceTypes` , then `t3.medium` is used, by default. If you specify `Spot` for `capacityType` , then we recommend specifying multiple values for `instanceTypes` . For more information, see [Managed node group capacity types](https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html#managed-node-group-capacity-types) and [Launch template support](https://docs.aws.amazon.com/eks/latest/userguide/launch-templates.html) in the *Amazon EKS User Guide* .", "Labels": "The Kubernetes labels to be applied to the nodes in the node group when they are created.", "LaunchTemplate": "An object representing a node group's launch template specification. If specified, then do not specify `instanceTypes` , `diskSize` , or `remoteAccess` and make sure that the launch template meets the requirements in `launchTemplateSpecification` .", - "NodeRole": "The Amazon Resource Name (ARN) of the IAM role to associate with your node group. The Amazon EKS worker node `kubelet` daemon makes calls to AWS APIs on your behalf. Nodes receive permissions for these API calls through an IAM instance profile and associated policies. Before you can launch nodes and register them into a cluster, you must create an IAM role for those nodes to use when they are launched. For more information, see [Amazon EKS node IAM role](https://docs.aws.amazon.com/eks/latest/userguide/worker_node_IAM_role.html) in the **Amazon EKS User Guide** . If you specify `launchTemplate` , then don't specify [`IamInstanceProfile`](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_IamInstanceProfile.html) in your launch template, or the node group deployment will fail. For more information about using launch templates with Amazon EKS, see [Launch template support](https://docs.aws.amazon.com/eks/latest/userguide/launch-templates.html) in the *Amazon EKS User Guide* .", + "NodeRole": "The Amazon Resource Name (ARN) of the IAM role to associate with your node group. The Amazon EKS worker node `kubelet` daemon makes calls to AWS APIs on your behalf. Nodes receive permissions for these API calls through an IAM instance profile and associated policies. Before you can launch nodes and register them into a cluster, you must create an IAM role for those nodes to use when they are launched. For more information, see [Amazon EKS node IAM role](https://docs.aws.amazon.com/eks/latest/userguide/create-node-role.html) in the **Amazon EKS User Guide** . If you specify `launchTemplate` , then don't specify [`IamInstanceProfile`](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_IamInstanceProfile.html) in your launch template, or the node group deployment will fail. For more information about using launch templates with Amazon EKS, see [Launch template support](https://docs.aws.amazon.com/eks/latest/userguide/launch-templates.html) in the *Amazon EKS User Guide* .", "NodegroupName": "The unique name to give your node group.", "ReleaseVersion": "The AMI version of the Amazon EKS optimized AMI to use with your node group (for example, `1.14.7- *YYYYMMDD*` ). By default, the latest available AMI version for the node group's current Kubernetes version is used. For more information, see [Amazon EKS optimized Linux AMI Versions](https://docs.aws.amazon.com/eks/latest/userguide/eks-linux-ami-versions.html) in the *Amazon EKS User Guide* .\n\n> Changing this value triggers an update of the node group if one is available. However, only the latest available AMI release version is valid as an input. You cannot roll back to a previous AMI release version.", "RemoteAccess": "The remote access (SSH) configuration to use with your node group. If you specify `launchTemplate` , then don't specify `remoteAccess` , or the node group deployment will fail. For more information about using launch templates with Amazon EKS, see [Launch template support](https://docs.aws.amazon.com/eks/latest/userguide/launch-templates.html) in the *Amazon EKS User Guide* .", "ScalingConfig": "The scaling configuration details for the Auto Scaling group that is created for your node group.", "Subnets": "The subnets to use for the Auto Scaling group that is created for your node group. If you specify `launchTemplate` , then don't specify [`SubnetId`](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateNetworkInterface.html) in your launch template, or the node group deployment will fail. For more information about using launch templates with Amazon EKS, see [Launch template support](https://docs.aws.amazon.com/eks/latest/userguide/launch-templates.html) in the *Amazon EKS User Guide* .", "Tags": "The metadata to apply to the node group to assist with categorization and organization. Each tag consists of a key and an optional value. You define both. Node group tags do not propagate to any other resources associated with the node group, such as the Amazon EC2 instances or subnets.", - "Taints": "The Kubernetes taints to be applied to the nodes in the node group when they are created. Effect is one of `No_Schedule` , `Prefer_No_Schedule` , or `No_Execute` . Kubernetes taints can be used together with tolerations to control how workloads are scheduled to your nodes.", + "Taints": "The Kubernetes taints to be applied to the nodes in the node group when they are created. Effect is one of `No_Schedule` , `Prefer_No_Schedule` , or `No_Execute` . Kubernetes taints can be used together with tolerations to control how workloads are scheduled to your nodes. For more information, see [Node taints on managed node groups](https://docs.aws.amazon.com/eks/latest/userguide/node-taints-managed-node-groups.html) .", "UpdateConfig": "The node group update configuration.", "Version": "The Kubernetes version to use for your managed nodes. By default, the Kubernetes version of the cluster is used, and this is the only accepted specified value. If you specify `launchTemplate` , and your launch template uses a custom AMI, then don't specify `version` , or the node group deployment will fail. For more information about using launch templates with Amazon EKS, see [Launch template support](https://docs.aws.amazon.com/eks/latest/userguide/launch-templates.html) in the *Amazon EKS User Guide* ." } @@ -14501,7 +14888,7 @@ }, "AWS::EKS::Nodegroup.Taint": { "attributes": {}, - "description": "A property that allows a node to repel a set of pods.", + "description": "A property that allows a node to repel a set of pods. For more information, see [Node taints on managed node groups](https://docs.aws.amazon.com/eks/latest/userguide/node-taints-managed-node-groups.html) .", "properties": { "Effect": "The effect of the taint.", "Key": "The key of the taint.", @@ -14700,8 +15087,6 @@ "MasterInstanceGroup": "Describes the EC2 instances and instance configurations for the master instance group when using clusters with the uniform instance group configuration.", "Placement": "The Availability Zone in which the cluster runs.", "ServiceAccessSecurityGroup": "The identifier of the Amazon EC2 security group for the Amazon EMR service to access clusters in VPC private subnets.", - "TaskInstanceFleets": "Describes the EC2 instances and instance configurations for the task instance fleets when using clusters with the instance fleet configuration. These task instance fleets are added to the cluster as part of the cluster launch. Each task instance fleet must have a unique name specified so that CloudFormation can differentiate between the task instance fleets.\n\n> You can currently specify only one task instance fleet for a cluster. After creating the cluster, you can only modify the mutable properties of `InstanceFleetConfig` , which are `TargetOnDemandCapacity` and `TargetSpotCapacity` . Modifying any other property results in cluster replacement.", - "TaskInstanceGroups": "Describes the EC2 instances and instance configurations for task instance groups when using clusters with the uniform instance group configuration. These task instance groups are added to the cluster as part of the cluster launch. Each task instance group must have a unique name specified so that CloudFormation can differentiate between the task instance groups.\n\n> After creating the cluster, you can only modify the mutable properties of `InstanceGroupConfig` , which are `AutoScalingPolicy` and `InstanceCount` . Modifying any other property results in cluster replacement.", "TerminationProtected": "Specifies whether to lock the cluster to prevent the Amazon EC2 instances from being terminated by API call, user intervention, or in the event of a job-flow error." } }, @@ -15166,7 +15551,7 @@ "properties": { "AZMode": "Specifies whether the nodes in this Memcached cluster are created in a single Availability Zone or created across multiple Availability Zones in the cluster's region.\n\nThis parameter is only supported for Memcached clusters.\n\nIf the `AZMode` and `PreferredAvailabilityZones` are not specified, ElastiCache assumes `single-az` mode.", "AutoMinorVersionUpgrade": "If you are running Redis engine version 6.0 or later, set this parameter to yes if you want to opt-in to the next minor version upgrade campaign. This parameter is disabled for previous versions.", - "CacheNodeType": "The compute and memory capacity of the nodes in the node group (shard).\n\nThe following node types are supported by ElastiCache. Generally speaking, the current generation types provide more memory and computational power at lower cost when compared to their equivalent previous generation counterparts. Changing the CacheNodeType of a Memcached instance is currently not supported. If you need to scale using Memcached, we recommend forcing a replacement update by changing the `LogicalResourceId` of the resource.\n\n- General purpose:\n\n- Current generation:\n\n*M6g node types:* `cache.m6g.large` , `cache.m6g.xlarge` , `cache.m6g.2xlarge` , `cache.m6g.4xlarge` , `cache.m6g.12xlarge` , `cache.m6g.24xlarge`\n\n*M5 node types:* `cache.m5.large` , `cache.m5.xlarge` , `cache.m5.2xlarge` , `cache.m5.4xlarge` , `cache.m5.12xlarge` , `cache.m5.24xlarge`\n\n*M4 node types:* `cache.m4.large` , `cache.m4.xlarge` , `cache.m4.2xlarge` , `cache.m4.4xlarge` , `cache.m4.10xlarge`\n\n*T4g node types:* `cache.t4g.micro` , `cache.t4g.small` , `cache.t4g.medium`\n\n*T3 node types:* `cache.t3.micro` , `cache.t3.small` , `cache.t3.medium`\n\n*T2 node types:* `cache.t2.micro` , `cache.t2.small` , `cache.t2.medium`\n- Previous generation: (not recommended)\n\n*T1 node types:* `cache.t1.micro`\n\n*M1 node types:* `cache.m1.small` , `cache.m1.medium` , `cache.m1.large` , `cache.m1.xlarge`\n\n*M3 node types:* `cache.m3.medium` , `cache.m3.large` , `cache.m3.xlarge` , `cache.m3.2xlarge`\n- Compute optimized:\n\n- Previous generation: (not recommended)\n\n*C1 node types:* `cache.c1.xlarge`\n- Memory optimized:\n\n- Current generation:\n\n*R6gd node types:* `cache.r6gd.xlarge` , `cache.r6gd.2xlarge` , `cache.r6gd.4xlarge` , `cache.r6gd.8xlarge` , `cache.r6gd.12xlarge` , `cache.r6gd.16xlarge`\n\n> The `r6gd` family is available in the following regions: `us-east-2` , `us-east-1` , `us-west-2` , `us-west-1` , `eu-west-1` , `eu-central-1` , `ap-northeast-1` , `ap-southeast-1` , `ap-southeast-2` . \n\n*R6g node types:* `cache.r6g.large` , `cache.r6g.xlarge` , `cache.r6g.2xlarge` , `cache.r6g.4xlarge` , `cache.r6g.12xlarge` , `cache.r6g.24xlarge`\n\n*R5 node types:* `cache.r5.large` , `cache.r5.xlarge` , `cache.r5.2xlarge` , `cache.r5.4xlarge` , `cache.r5.12xlarge` , `cache.r5.24xlarge`\n\n*R4 node types:* `cache.r4.large` , `cache.r4.xlarge` , `cache.r4.2xlarge` , `cache.r4.4xlarge` , `cache.r4.8xlarge` , `cache.r4.16xlarge`\n- Previous generation: (not recommended)\n\n*M2 node types:* `cache.m2.xlarge` , `cache.m2.2xlarge` , `cache.m2.4xlarge`\n\n*R3 node types:* `cache.r3.large` , `cache.r3.xlarge` , `cache.r3.2xlarge` , `cache.r3.4xlarge` , `cache.r3.8xlarge`\n\nFor region availability, see [Supported Node Types by Amazon Region](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/CacheNodes.SupportedTypes.html#CacheNodes.SupportedTypesByRegion)\n\n*Additional node type info*\n\n- All current generation instance types are created in Amazon VPC by default.\n- Redis append-only files (AOF) are not supported for T1 or T2 instances.\n- Redis Multi-AZ with automatic failover is not supported on T1 instances.\n- Redis configuration variables `appendonly` and `appendfsync` are not supported on Redis version 2.8.22 and later.", + "CacheNodeType": "The compute and memory capacity of the nodes in the node group (shard).\n\nThe following node types are supported by ElastiCache. Generally speaking, the current generation types provide more memory and computational power at lower cost when compared to their equivalent previous generation counterparts. Changing the CacheNodeType of a Memcached instance is currently not supported. If you need to scale using Memcached, we recommend forcing a replacement update by changing the `LogicalResourceId` of the resource.\n\n- General purpose:\n\n- Current generation:\n\n*M6g node types:* `cache.m6g.large` , `cache.m6g.xlarge` , `cache.m6g.2xlarge` , `cache.m6g.4xlarge` , `cache.m6g.8xlarge` , `cache.m6g.12xlarge` , `cache.m6g.16xlarge` , `cache.m6g.24xlarge`\n\n*M5 node types:* `cache.m5.large` , `cache.m5.xlarge` , `cache.m5.2xlarge` , `cache.m5.4xlarge` , `cache.m5.12xlarge` , `cache.m5.24xlarge`\n\n*M4 node types:* `cache.m4.large` , `cache.m4.xlarge` , `cache.m4.2xlarge` , `cache.m4.4xlarge` , `cache.m4.10xlarge`\n\n*T4g node types:* `cache.t4g.micro` , `cache.t4g.small` , `cache.t4g.medium`\n\n*T3 node types:* `cache.t3.micro` , `cache.t3.small` , `cache.t3.medium`\n\n*T2 node types:* `cache.t2.micro` , `cache.t2.small` , `cache.t2.medium`\n- Previous generation: (not recommended)\n\n*T1 node types:* `cache.t1.micro`\n\n*M1 node types:* `cache.m1.small` , `cache.m1.medium` , `cache.m1.large` , `cache.m1.xlarge`\n\n*M3 node types:* `cache.m3.medium` , `cache.m3.large` , `cache.m3.xlarge` , `cache.m3.2xlarge`\n- Compute optimized:\n\n- Previous generation: (not recommended)\n\n*C1 node types:* `cache.c1.xlarge`\n- Memory optimized:\n\n- Current generation:\n\n*R6gd node types:* `cache.r6gd.xlarge` , `cache.r6gd.2xlarge` , `cache.r6gd.4xlarge` , `cache.r6gd.8xlarge` , `cache.r6gd.12xlarge` , `cache.r6gd.16xlarge`\n\n> The `r6gd` family is available in the following regions: `us-east-2` , `us-east-1` , `us-west-2` , `us-west-1` , `eu-west-1` , `eu-central-1` , `ap-northeast-1` , `ap-southeast-1` , `ap-southeast-2` . \n\n*R6g node types:* `cache.r6g.large` , `cache.r6g.xlarge` , `cache.r6g.2xlarge` , `cache.r6g.4xlarge` , `cache.r6g.8xlarge` , `cache.r6g.12xlarge` , `cache.r6g.16xlarge` , `cache.r6g.24xlarge`\n\n*R5 node types:* `cache.r5.large` , `cache.r5.xlarge` , `cache.r5.2xlarge` , `cache.r5.4xlarge` , `cache.r5.12xlarge` , `cache.r5.24xlarge`\n\n*R4 node types:* `cache.r4.large` , `cache.r4.xlarge` , `cache.r4.2xlarge` , `cache.r4.4xlarge` , `cache.r4.8xlarge` , `cache.r4.16xlarge`\n- Previous generation: (not recommended)\n\n*M2 node types:* `cache.m2.xlarge` , `cache.m2.2xlarge` , `cache.m2.4xlarge`\n\n*R3 node types:* `cache.r3.large` , `cache.r3.xlarge` , `cache.r3.2xlarge` , `cache.r3.4xlarge` , `cache.r3.8xlarge`\n\nFor region availability, see [Supported Node Types by Amazon Region](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/CacheNodes.SupportedTypes.html#CacheNodes.SupportedTypesByRegion)\n\n*Additional node type info*\n\n- All current generation instance types are created in Amazon VPC by default.\n- Redis append-only files (AOF) are not supported for T1 or T2 instances.\n- Redis Multi-AZ with automatic failover is not supported on T1 instances.\n- Redis configuration variables `appendonly` and `appendfsync` are not supported on Redis version 2.8.22 and later.", "CacheParameterGroupName": "The name of the parameter group to associate with this cluster. If this argument is omitted, the default parameter group for the specified engine is used. You cannot use any parameter group which has `cluster-enabled='yes'` when creating a cluster.", "CacheSecurityGroupNames": "A list of security group names to associate with this cluster.\n\nUse this parameter only when you are creating a cluster outside of an Amazon Virtual Private Cloud (Amazon VPC).", "CacheSubnetGroupName": "The name of the subnet group to be used for the cluster.\n\nUse this parameter only when you are creating a cluster in an Amazon Virtual Private Cloud (Amazon VPC).\n\n> If you're going to launch your cluster in an Amazon VPC, you need to create a subnet group before you start creating a cluster. For more information, see [AWS::ElastiCache::SubnetGroup](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-subnetgroup.html) .", @@ -15294,7 +15679,7 @@ "description": "The `AWS::ElastiCache::ReplicationGroup` resource creates an Amazon ElastiCache Redis replication group. A Redis (cluster mode disabled) replication group is a collection of cache clusters, where one of the clusters is a primary read-write cluster and the others are read-only replicas.\n\nA Redis (cluster mode enabled) cluster is comprised of from 1 to 90 shards (API/CLI: node groups). Each shard has a primary node and up to 5 read-only replica nodes. The configuration can range from 90 shards and 0 replicas to 15 shards and 5 replicas, which is the maximum number or replicas allowed.\n\nThe node or shard limit can be increased to a maximum of 500 per cluster if the Redis engine version is 5.0.6 or higher. For example, you can choose to configure a 500 node cluster that ranges between 83 shards (one primary and 5 replicas per shard) and 500 shards (single primary and no replicas). Make sure there are enough available IP addresses to accommodate the increase. Common pitfalls include the subnets in the subnet group have too small a CIDR range or the subnets are shared and heavily used by other clusters. For more information, see [Creating a Subnet Group](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/SubnetGroups.Creating.html) . For versions below 5.0.6, the limit is 250 per cluster.\n\nTo request a limit increase, see [Amazon Service Limits](https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html) and choose the limit type *Nodes per cluster per instance type* .", "properties": { "AtRestEncryptionEnabled": "A flag that enables encryption at rest when set to `true` .\n\nYou cannot modify the value of `AtRestEncryptionEnabled` after the replication group is created. To enable encryption at rest on a replication group you must set `AtRestEncryptionEnabled` to `true` when you create the replication group.\n\n*Required:* Only available when creating a replication group in an Amazon VPC using redis version `3.2.6` or `4.x` onward.\n\nDefault: `false`", - "AuthToken": "*Reserved parameter.* The password used to access a password protected server.\n\n`AuthToken` can be specified only on replication groups where `TransitEncryptionEnabled` is `true` . For more information, see [Authenticating Users with the Redis AUTH Command](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/auth.html) .\n\n> For HIPAA compliance, you must specify `TransitEncryptionEnabled` as `true` , an `AuthToken` , and a `CacheSubnetGroup` . \n\nPassword constraints:\n\n- Must be only printable ASCII characters.\n- Must be at least 16 characters and no more than 128 characters in length.\n- Cannot contain any of the following characters: '/', '\"', or '@'.\n\nFor more information, see [AUTH password](https://docs.aws.amazon.com/http://redis.io/commands/AUTH) at http://redis.io/commands/AUTH.", + "AuthToken": "*Reserved parameter.* The password used to access a password protected server.\n\n`AuthToken` can be specified only on replication groups where `TransitEncryptionEnabled` is `true` . For more information, see [Authenticating Users with the Redis AUTH Command](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/auth.html) .\n\n> For HIPAA compliance, you must specify `TransitEncryptionEnabled` as `true` , an `AuthToken` , and a `CacheSubnetGroup` . \n\nPassword constraints:\n\n- Must be only printable ASCII characters.\n- Must be at least 16 characters and no more than 128 characters in length.\n- Nonalphanumeric characters are restricted to (!, &, #, $, ^, <, >, -, ).\n\nFor more information, see [AUTH password](https://docs.aws.amazon.com/http://redis.io/commands/AUTH) at http://redis.io/commands/AUTH.", "AutoMinorVersionUpgrade": "If you are running Redis engine version 6.0 or later, set this parameter to yes if you want to opt-in to the next minor version upgrade campaign. This parameter is disabled for previous versions.", "AutomaticFailoverEnabled": "Specifies whether a read-only replica is automatically promoted to read/write primary if the existing primary fails.\n\n`AutomaticFailoverEnabled` must be enabled for Redis (cluster mode enabled) replication groups.\n\nDefault: false", "CacheNodeType": "The compute and memory capacity of the nodes in the node group (shard).\n\nThe following node types are supported by ElastiCache. Generally speaking, the current generation types provide more memory and computational power at lower cost when compared to their equivalent previous generation counterparts.\n\n- General purpose:\n\n- Current generation:\n\n*M6g node types:* `cache.m6g.large` , `cache.m6g.xlarge` , `cache.m6g.2xlarge` , `cache.m6g.4xlarge` , `cache.m6g.12xlarge` , `cache.m6g.24xlarge`\n\n*M5 node types:* `cache.m5.large` , `cache.m5.xlarge` , `cache.m5.2xlarge` , `cache.m5.4xlarge` , `cache.m5.12xlarge` , `cache.m5.24xlarge`\n\n*M4 node types:* `cache.m4.large` , `cache.m4.xlarge` , `cache.m4.2xlarge` , `cache.m4.4xlarge` , `cache.m4.10xlarge`\n\n*T4g node types:* `cache.t4g.micro` , `cache.t4g.small` , `cache.t4g.medium`\n\n*T3 node types:* `cache.t3.micro` , `cache.t3.small` , `cache.t3.medium`\n\n*T2 node types:* `cache.t2.micro` , `cache.t2.small` , `cache.t2.medium`\n- Previous generation: (not recommended)\n\n*T1 node types:* `cache.t1.micro`\n\n*M1 node types:* `cache.m1.small` , `cache.m1.medium` , `cache.m1.large` , `cache.m1.xlarge`\n\n*M3 node types:* `cache.m3.medium` , `cache.m3.large` , `cache.m3.xlarge` , `cache.m3.2xlarge`\n- Compute optimized:\n\n- Previous generation: (not recommended)\n\n*C1 node types:* `cache.c1.xlarge`\n- Memory optimized:\n\n- Current generation:\n\n*R6gd node types:* `cache.r6gd.xlarge` , `cache.r6gd.2xlarge` , `cache.r6gd.4xlarge` , `cache.r6gd.8xlarge` , `cache.r6gd.12xlarge` , `cache.r6gd.16xlarge`\n\n> The `r6gd` family is available in the following regions: `us-east-2` , `us-east-1` , `us-west-2` , `us-west-1` , `eu-west-1` , `eu-central-1` , `ap-northeast-1` , `ap-southeast-1` , `ap-southeast-2` . \n\n*R6g node types:* `cache.r6g.large` , `cache.r6g.xlarge` , `cache.r6g.2xlarge` , `cache.r6g.4xlarge` , `cache.r6g.12xlarge` , `cache.r6g.24xlarge`\n\n*R5 node types:* `cache.r5.large` , `cache.r5.xlarge` , `cache.r5.2xlarge` , `cache.r5.4xlarge` , `cache.r5.12xlarge` , `cache.r5.24xlarge`\n\n*R4 node types:* `cache.r4.large` , `cache.r4.xlarge` , `cache.r4.2xlarge` , `cache.r4.4xlarge` , `cache.r4.8xlarge` , `cache.r4.16xlarge`\n- Previous generation: (not recommended)\n\n*M2 node types:* `cache.m2.xlarge` , `cache.m2.2xlarge` , `cache.m2.4xlarge`\n\n*R3 node types:* `cache.r3.large` , `cache.r3.xlarge` , `cache.r3.2xlarge` , `cache.r3.4xlarge` , `cache.r3.8xlarge`\n\nFor region availability, see [Supported Node Types by Amazon Region](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/CacheNodes.SupportedTypes.html#CacheNodes.SupportedTypesByRegion)", @@ -16024,7 +16409,7 @@ "description": "Specifies a target group for a load balancer.\n\nBefore you register a Lambda function as a target, you must create a `AWS::Lambda::Permission` resource that grants the Elastic Load Balancing service principal permission to invoke the Lambda function.", "properties": { "HealthCheckEnabled": "Indicates whether health checks are enabled. If the target type is `lambda` , health checks are disabled by default but can be enabled. If the target type is `instance` , `ip` , or `alb` , health checks are always enabled and cannot be disabled.", - "HealthCheckIntervalSeconds": "The approximate amount of time, in seconds, between health checks of an individual target. If the target group protocol is TCP, TLS, UDP, or TCP_UDP, the supported values are 10 and 30 seconds. If the target group protocol is HTTP or HTTPS, the default is 30 seconds. If the target group protocol is GENEVE, the default is 10 seconds. If the target type is `lambda` , the default is 35 seconds.", + "HealthCheckIntervalSeconds": "The approximate amount of time, in seconds, between health checks of an individual target. If the target group protocol is HTTP or HTTPS, the default is 30 seconds. If the target group protocol is TCP, TLS, UDP, or TCP_UDP, the supported values are 10 and 30 seconds and the default is 30 seconds. If the target group protocol is GENEVE, the default is 10 seconds. If the target type is `lambda` , the default is 35 seconds.", "HealthCheckPath": "[HTTP/HTTPS health checks] The destination for health checks on the targets.\n\n[HTTP1 or HTTP2 protocol version] The ping path. The default is /.\n\n[GRPC protocol version] The path of a custom health check method with the format /package.service/method. The default is / AWS .ALB/healthcheck.", "HealthCheckPort": "The port the load balancer uses when performing health checks on targets. If the protocol is HTTP, HTTPS, TCP, TLS, UDP, or TCP_UDP, the default is `traffic-port` , which is the port on which each target receives traffic from the load balancer. If the protocol is GENEVE, the default is port 80.", "HealthCheckProtocol": "The protocol the load balancer uses when performing health checks on targets. For Application Load Balancers, the default is HTTP. For Network Load Balancers and Gateway Load Balancers, the default is TCP. The TCP protocol is not supported for health checks if the protocol of the target group is HTTP or HTTPS. The GENEVE, TLS, UDP, and TCP_UDP protocols are not supported for health checks.", @@ -16283,7 +16668,7 @@ "RegistryName": "The name of the schema registry.", "SchemaName": "The name of the schema.", "Tags": "Tags associated with the schema.", - "Type": "The type of schema." + "Type": "The type of schema.\n\nValid types include `OpenApi3` and `JSONSchemaDraft4` ." } }, "AWS::EventSchemas::Schema.TagsEntry": { @@ -16338,6 +16723,68 @@ "Name": "The name for the connection to create." } }, + "AWS::Events::Connection.ApiKeyAuthParameters": { + "attributes": {}, + "description": "", + "properties": { + "ApiKeyName": "", + "ApiKeyValue": "" + } + }, + "AWS::Events::Connection.AuthParameters": { + "attributes": {}, + "description": "", + "properties": { + "ApiKeyAuthParameters": "", + "BasicAuthParameters": "", + "InvocationHttpParameters": "", + "OAuthParameters": "" + } + }, + "AWS::Events::Connection.BasicAuthParameters": { + "attributes": {}, + "description": "", + "properties": { + "Password": "", + "Username": "" + } + }, + "AWS::Events::Connection.ClientParameters": { + "attributes": {}, + "description": "", + "properties": { + "ClientID": "", + "ClientSecret": "" + } + }, + "AWS::Events::Connection.ConnectionHttpParameters": { + "attributes": {}, + "description": "Contains additional parameters for the connection.", + "properties": { + "BodyParameters": "Contains additional body string parameters for the connection.", + "HeaderParameters": "Contains additional header parameters for the connection.", + "QueryStringParameters": "Contains additional query string parameters for the connection." + } + }, + "AWS::Events::Connection.OAuthParameters": { + "attributes": {}, + "description": "", + "properties": { + "AuthorizationEndpoint": "", + "ClientParameters": "", + "HttpMethod": "", + "OAuthHttpParameters": "" + } + }, + "AWS::Events::Connection.Parameter": { + "attributes": {}, + "description": "", + "properties": { + "IsValueSecret": "", + "Key": "", + "Value": "" + } + }, "AWS::Events::EventBus": { "attributes": { "Arn": "The ARN of the event bus, such as `arn:aws:events:us-east-2:123456789012:event-bus/aws.partner/PartnerName/acct1/repo1` .", @@ -16397,7 +16844,7 @@ "RoleArn": "The Amazon Resource Name (ARN) of the role that is used for target invocation.\n\nIf you're setting an event bus in another account as the target and that account granted permission to your account through an organization instead of directly by the account ID, you must specify a `RoleArn` with proper permissions in the `Target` structure, instead of here in this parameter.", "ScheduleExpression": "The scheduling expression. For example, \"cron(0 20 * * ? *)\", \"rate(5 minutes)\". For more information, see [Creating an Amazon EventBridge rule that runs on a schedule](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-rule-schedule.html) .", "State": "The state of the rule.", - "Targets": "Adds the specified targets to the specified rule, or updates the targets if they are already associated with the rule.\n\nTargets are the resources that are invoked when a rule is triggered.\n\n> Each rule can have up to five (5) targets associated with it at one time. \n\nYou can configure the following as targets for Events:\n\n- [API destination](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-api-destinations.html)\n- Amazon API Gateway REST API endpoints\n- API Gateway\n- AWS Batch job queue\n- CloudWatch Logs group\n- CodeBuild project\n- CodePipeline\n- Amazon EC2 `CreateSnapshot` API call\n- EC2 Image Builder\n- Amazon EC2 `RebootInstances` API call\n- Amazon EC2 `StopInstances` API call\n- Amazon EC2 `TerminateInstances` API call\n- Amazon ECS tasks\n- Event bus in a different AWS account or Region.\n\nYou can use an event bus in the US East (N. Virginia) us-east-1, US West (Oregon) us-west-2, or Europe (Ireland) eu-west-1 Regions as a target for a rule.\n- Firehose delivery stream (Kinesis Data Firehose)\n- Inspector assessment template (Amazon Inspector)\n- Kinesis stream (Kinesis Data Stream)\n- AWS Lambda function\n- Redshift clusters (Data API statement execution)\n- Amazon SNS topic\n- Amazon SQS queues (includes FIFO queues)\n- SSM Automation\n- SSM OpsItem\n- SSM Run Command\n- Step Functions state machines\n\nCreating rules with built-in targets is supported only in the AWS Management Console . The built-in targets are `EC2 CreateSnapshot API call` , `EC2 RebootInstances API call` , `EC2 StopInstances API call` , and `EC2 TerminateInstances API call` .\n\nFor some target types, `PutTargets` provides target-specific parameters. If the target is a Kinesis data stream, you can optionally specify which shard the event goes to by using the `KinesisParameters` argument. To invoke a command on multiple EC2 instances with one rule, you can use the `RunCommandParameters` field.\n\nTo be able to make API calls against the resources that you own, Amazon EventBridge needs the appropriate permissions. For AWS Lambda and Amazon SNS resources, EventBridge relies on resource-based policies. For EC2 instances, Kinesis Data Streams, AWS Step Functions state machines and API Gateway REST APIs, EventBridge relies on IAM roles that you specify in the `RoleARN` argument in `PutTargets` . For more information, see [Authentication and Access Control](https://docs.aws.amazon.com/eventbridge/latest/userguide/auth-and-access-control-eventbridge.html) in the *Amazon EventBridge User Guide* .\n\nIf another AWS account is in the same region and has granted you permission (using `PutPermission` ), you can send events to that account. Set that account's event bus as a target of the rules in your account. To send the matched events to the other account, specify that account's event bus as the `Arn` value when you run `PutTargets` . If your account sends events to another account, your account is charged for each sent event. Each event sent to another account is charged as a custom event. The account receiving the event is not charged. For more information, see [Amazon EventBridge Pricing](https://docs.aws.amazon.com/eventbridge/pricing/) .\n\n> `Input` , `InputPath` , and `InputTransformer` are not available with `PutTarget` if the target is an event bus of a different AWS account. \n\nIf you are setting the event bus of another account as the target, and that account granted permission to your account through an organization instead of directly by the account ID, then you must specify a `RoleArn` with proper permissions in the `Target` structure. For more information, see [Sending and Receiving Events Between AWS Accounts](https://docs.aws.amazon.com/eventbridge/latest/userguide/eventbridge-cross-account-event-delivery.html) in the *Amazon EventBridge User Guide* .\n\nFor more information about enabling cross-account events, see [PutPermission](https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_PutPermission.html) .\n\n*Input* , *InputPath* , and *InputTransformer* are mutually exclusive and optional parameters of a target. When a rule is triggered due to a matched event:\n\n- If none of the following arguments are specified for a target, then the entire event is passed to the target in JSON format (unless the target is Amazon EC2 Run Command or Amazon ECS task, in which case nothing from the event is passed to the target).\n- If *Input* is specified in the form of valid JSON, then the matched event is overridden with this constant.\n- If *InputPath* is specified in the form of JSONPath (for example, `$.detail` ), then only the part of the event specified in the path is passed to the target (for example, only the detail part of the event is passed).\n- If *InputTransformer* is specified, then one or more specified JSONPaths are extracted from the event and used as values in a template that you specify as the input to the target.\n\nWhen you specify `InputPath` or `InputTransformer` , you must use JSON dot notation, not bracket notation.\n\nWhen you add targets to a rule and the associated rule triggers soon after, new or updated targets might not be immediately invoked. Allow a short period of time for changes to take effect.\n\nThis action can partially fail if too many requests are made at the same time. If that happens, `FailedEntryCount` is non-zero in the response and each entry in `FailedEntries` provides the ID of the failed target and the error code." + "Targets": "Adds the specified targets to the specified rule, or updates the targets if they are already associated with the rule.\n\nTargets are the resources that are invoked when a rule is triggered.\n\n> Each rule can have up to five (5) targets associated with it at one time. \n\nYou can configure the following as targets for Events:\n\n- [API destination](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-api-destinations.html)\n- [API Gateway](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-api-gateway-target.html)\n- Batch job queue\n- CloudWatch group\n- CodeBuild project\n- CodePipeline\n- EC2 `CreateSnapshot` API call\n- EC2 Image Builder\n- EC2 `RebootInstances` API call\n- EC2 `StopInstances` API call\n- EC2 `TerminateInstances` API call\n- ECS task\n- [Event bus in a different account or Region](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cross-account.html)\n- [Event bus in the same account and Region](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-bus-to-bus.html)\n- Firehose delivery stream\n- Glue workflow\n- [Incident Manager response plan](https://docs.aws.amazon.com//incident-manager/latest/userguide/incident-creation.html#incident-tracking-auto-eventbridge)\n- Inspector assessment template\n- Kinesis stream\n- Lambda function\n- Redshift cluster\n- SageMaker Pipeline\n- SNS topic\n- SQS queue\n- Step Functions state machine\n- Systems Manager Automation\n- Systems Manager OpsItem\n- Systems Manager Run Command\n\nCreating rules with built-in targets is supported only in the AWS Management Console . The built-in targets are `EC2 CreateSnapshot API call` , `EC2 RebootInstances API call` , `EC2 StopInstances API call` , and `EC2 TerminateInstances API call` .\n\nFor some target types, `PutTargets` provides target-specific parameters. If the target is a Kinesis data stream, you can optionally specify which shard the event goes to by using the `KinesisParameters` argument. To invoke a command on multiple EC2 instances with one rule, you can use the `RunCommandParameters` field.\n\nTo be able to make API calls against the resources that you own, Amazon EventBridge needs the appropriate permissions. For AWS Lambda and Amazon SNS resources, EventBridge relies on resource-based policies. For EC2 instances, Kinesis Data Streams, AWS Step Functions state machines and API Gateway REST APIs, EventBridge relies on IAM roles that you specify in the `RoleARN` argument in `PutTargets` . For more information, see [Authentication and Access Control](https://docs.aws.amazon.com/eventbridge/latest/userguide/auth-and-access-control-eventbridge.html) in the *Amazon EventBridge User Guide* .\n\nIf another AWS account is in the same region and has granted you permission (using `PutPermission` ), you can send events to that account. Set that account's event bus as a target of the rules in your account. To send the matched events to the other account, specify that account's event bus as the `Arn` value when you run `PutTargets` . If your account sends events to another account, your account is charged for each sent event. Each event sent to another account is charged as a custom event. The account receiving the event is not charged. For more information, see [Amazon EventBridge Pricing](https://docs.aws.amazon.com/eventbridge/pricing/) .\n\n> `Input` , `InputPath` , and `InputTransformer` are not available with `PutTarget` if the target is an event bus of a different AWS account. \n\nIf you are setting the event bus of another account as the target, and that account granted permission to your account through an organization instead of directly by the account ID, then you must specify a `RoleArn` with proper permissions in the `Target` structure. For more information, see [Sending and Receiving Events Between AWS Accounts](https://docs.aws.amazon.com/eventbridge/latest/userguide/eventbridge-cross-account-event-delivery.html) in the *Amazon EventBridge User Guide* .\n\nFor more information about enabling cross-account events, see [PutPermission](https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_PutPermission.html) .\n\n*Input* , *InputPath* , and *InputTransformer* are mutually exclusive and optional parameters of a target. When a rule is triggered due to a matched event:\n\n- If none of the following arguments are specified for a target, then the entire event is passed to the target in JSON format (unless the target is Amazon EC2 Run Command or Amazon ECS task, in which case nothing from the event is passed to the target).\n- If *Input* is specified in the form of valid JSON, then the matched event is overridden with this constant.\n- If *InputPath* is specified in the form of JSONPath (for example, `$.detail` ), then only the part of the event specified in the path is passed to the target (for example, only the detail part of the event is passed).\n- If *InputTransformer* is specified, then one or more specified JSONPaths are extracted from the event and used as values in a template that you specify as the input to the target.\n\nWhen you specify `InputPath` or `InputTransformer` , you must use JSON dot notation, not bracket notation.\n\nWhen you add targets to a rule and the associated rule triggers soon after, new or updated targets might not be immediately invoked. Allow a short period of time for changes to take effect.\n\nThis action can partially fail if too many requests are made at the same time. If that happens, `FailedEntryCount` is non-zero in the response and each entry in `FailedEntries` provides the ID of the failed target and the error code." } }, "AWS::Events::Rule.AwsVpcConfiguration": { @@ -16551,6 +16998,21 @@ "Values": "If `Key` is `tag:` *tag-key* , `Values` is a list of tag values. If `Key` is `InstanceIds` , `Values` is a list of Amazon EC2 instance IDs." } }, + "AWS::Events::Rule.SageMakerPipelineParameter": { + "attributes": {}, + "description": "Name/Value pair of a parameter to start execution of a SageMaker Model Building Pipeline.", + "properties": { + "Name": "Name of parameter to start execution of a SageMaker Model Building Pipeline.", + "Value": "Value of parameter to start execution of a SageMaker Model Building Pipeline." + } + }, + "AWS::Events::Rule.SageMakerPipelineParameters": { + "attributes": {}, + "description": "These are custom parameters to use when the target is a SageMaker Model Building Pipeline that starts based on EventBridge events.", + "properties": { + "PipelineParameterList": "List of Parameter names and values for SageMaker Model Building Pipeline execution." + } + }, "AWS::Events::Rule.SqsParameters": { "attributes": {}, "description": "This structure includes the custom parameter to be used when the target is an SQS FIFO queue.", @@ -16584,6 +17046,7 @@ "RetryPolicy": "The `RetryPolicy` object that contains the retry policy configuration to use for the dead-letter queue.", "RoleArn": "The Amazon Resource Name (ARN) of the IAM role to be used for this target when the rule is triggered. If one rule triggers multiple targets, you can use a different IAM role for each target.", "RunCommandParameters": "Parameters used when you are using the rule to invoke Amazon EC2 Run Command.", + "SageMakerPipelineParameters": "Contains the SageMaker Model Building Pipeline parameters to start execution of a SageMaker Model Building Pipeline.\n\nIf you specify a SageMaker Model Building Pipeline as a target, you can use this to specify parameters to start a pipeline execution based on EventBridge events.", "SqsParameters": "Contains the message group ID to use when the target is a FIFO queue.\n\nIf you specify an SQS FIFO queue as a target, the queue must have content-based deduplication enabled." } }, @@ -16771,6 +17234,7 @@ "properties": { "Actions": "The actions for the experiment.", "Description": "A description for the experiment template.", + "LogConfiguration": "The configuration for experiment logging.", "RoleArn": "The Amazon Resource Name (ARN) of an IAM role that grants the AWS FIS service permission to perform service actions on your behalf.", "StopConditions": "The stop conditions.", "Tags": "The tags to apply to the experiment template.", @@ -16788,6 +17252,15 @@ "Targets": "The targets for the action." } }, + "AWS::FIS::ExperimentTemplate.ExperimentTemplateLogConfiguration": { + "attributes": {}, + "description": "Specifies the configuration for experiment logging.", + "properties": { + "CloudWatchLogsConfiguration": "The configuration for experiment logging to Amazon CloudWatch Logs. The supported field is `logGroupArn` . For example:\n\n`{\"logGroupArn\": \"aws:arn:logs: *region_name* : *account_id* :log-group: *log_group_name* \"}`", + "LogSchemaVersion": "The schema version. The supported value is 1.", + "S3Configuration": "The configuration for experiment logging to Amazon S3. The following fields are supported:\n\n- `bucketName` - The name of the destination bucket.\n- `prefix` - An optional bucket prefix.\n\nFor example:\n\n`{\"bucketName\": \" *my-s3-bucket* \", \"prefix\": \" *log-folder* \"}`" + } + }, "AWS::FIS::ExperimentTemplate.ExperimentTemplateStopCondition": { "attributes": {}, "description": "Specifies a stop condition for an experiment template.", @@ -16801,6 +17274,7 @@ "description": "Specifies a target for an experiment. You must specify at least one Amazon Resource Name (ARN) or at least one resource tag. You cannot specify both ARNs and tags.\n\nFor more information, see [Targets](https://docs.aws.amazon.com/fis/latest/userguide/targets.html) in the *AWS Fault Injection Simulator User Guide* .", "properties": { "Filters": "The filters to apply to identify target resources using specific attributes.", + "Parameters": "The parameters for the resource type.", "ResourceArns": "The Amazon Resource Names (ARNs) of the resources.", "ResourceTags": "The tags for the target resources.", "ResourceType": "The resource type. The resource type must be supported for the specified action.", @@ -16878,20 +17352,20 @@ "Ref": "`Ref` returns the file system resource ID. For example:\n\n`{\"Ref\":\"file_system_logical_id\"}`\n\nReturns `fs-0123456789abcdef6` .", "RootVolumeId": "Returns the root volume ID of the FSx for OpenZFS file system.\n\nExample: `fsvol-0123456789abcdefa`" }, - "description": "The `AWS::FSx::FileSystem` resource is an Amazon FSx resource type that creates an Amazon FSx file system. You can create any of the following supported file system types:\n\n- Amazon FSx for Lustre\n- Amazon FSx for NetApp ONTAP\n- Amazon FSx for OpenZFS\n- Amazon FSx for Windows File Server", + "description": "The `AWS::FSx::FileSystem` resource is an Amazon FSx resource type that specifies an Amazon FSx file system. You can create any of the following supported file system types:\n\n- Amazon FSx for Lustre\n- Amazon FSx for NetApp ONTAP\n- Amazon FSx for OpenZFS\n- Amazon FSx for Windows File Server", "properties": { - "BackupId": "The ID of the source backup. Specifies the backup that you are copying.", + "BackupId": "The ID of the file system backup that you are using to create a file system. For more information, see [CreateFileSystemFromBackup](https://docs.aws.amazon.com/fsx/latest/APIReference/API_CreateFileSystemFromBackup.html) .", "FileSystemType": "The type of Amazon FSx file system, which can be `LUSTRE` , `WINDOWS` , `ONTAP` , or `OPENZFS` .", "FileSystemTypeVersion": "(Optional) For FSx for Lustre file systems, sets the Lustre version for the file system that you're creating. Valid values are `2.10` and `2.12` :\n\n- 2.10 is supported by the Scratch and Persistent_1 Lustre deployment types.\n- 2.12 is supported by all Lustre deployment types. `2.12` is required when setting FSx for Lustre `DeploymentType` to `PERSISTENT_2` .\n\nDefault value = `2.10` , except when `DeploymentType` is set to `PERSISTENT_2` , then the default is `2.12` .\n\n> If you set `FileSystemTypeVersion` to `2.10` for a `PERSISTENT_2` Lustre deployment type, the `CreateFileSystem` operation fails.", - "KmsKeyId": "The ID of the AWS Key Management Service ( AWS KMS ) key used to encrypt the file system's data for Amazon FSx for Windows File Server file systems, Amazon FSx for NetApp ONTAP file systems, and `PERSISTENT` Amazon FSx for Lustre file systems at rest. If this ID isn't specified, the Amazon FSx-managed key for your account is used. The scratch Amazon FSx for Lustre file systems are always encrypted at rest using the Amazon FSx-managed key for your account. For more information, see [Encrypt](https://docs.aws.amazon.com//kms/latest/APIReference/API_Encrypt.html) in the *AWS Key Management Service API Reference* .", - "LustreConfiguration": "The Lustre configuration for the file system being created.\n\n> The following parameters are not supported for file systems with the `Persistent_2` deployment type. Instead, use `CreateDataRepositoryAssociation` to create a data repository association to link your Lustre file system to a data repository.\n> \n> - `AutoImportPolicy`\n> - `ExportPath`\n> - `ImportedChunkSize`\n> - `ImportPath`", + "KmsKeyId": "The ID of the AWS Key Management Service ( AWS KMS ) key used to encrypt Amazon FSx file system data. Used as follows with Amazon FSx file system types:\n\n- Amazon FSx for Lustre `PERSISTENT_1` and `PERSISTENT_2` deployment types only.\n\n`SCRATCH_1` and `SCRATCH_2` types are encrypted using the Amazon FSx service AWS KMS key for your account.\n- Amazon FSx for NetApp ONTAP\n- Amazon FSx for OpenZFS\n- Amazon FSx for Windows File Server", + "LustreConfiguration": "The Lustre configuration for the file system being created.\n\n> The following parameters are not supported for file systems with the Lustre `Persistent_2` deployment type.\n> \n> - `AutoImportPolicy`\n> - `ExportPath`\n> - `ImportedChunkSize`\n> - `ImportPath`", "OntapConfiguration": "The ONTAP configuration properties of the FSx for ONTAP file system that you are creating.", - "OpenZFSConfiguration": "The OpenZFS configuration properties for the file system that you are creating.", + "OpenZFSConfiguration": "The Amazon FSx for OpenZFS configuration properties for the file system that you are creating.", "SecurityGroupIds": "A list of IDs specifying the security groups to apply to all network interfaces created for file system access. This list isn't returned in later requests to describe the file system.", - "StorageCapacity": "Sets the storage capacity of the file system that you're creating. `StorageCapacity` is required if you are creating a new file system. Do not include `StorageCapacity` if you are creating a file system from a backup.\n\nFor Lustre file systems:", - "StorageType": "Sets the storage type for the file system that you're creating. Valid values are `SSD` and `HDD` .\n\n- Set to `SSD` to use solid state drive storage. SSD is supported on all Windows, Lustre, ONTAP, and OpenZFS deployment types.\n- Set to `HDD` to use hard disk drive storage. HDD is supported on `SINGLE_AZ_2` and `MULTI_AZ_1` Windows file system deployment types, and on `PERSISTENT` Lustre file system deployment types.\n\nDefault value is `SSD` . For more information, see [Storage type options](https://docs.aws.amazon.com/fsx/latest/WindowsGuide/optimize-fsx-costs.html#storage-type-options) in the *FSx for Windows File Server User Guide* and [Multiple storage options](https://docs.aws.amazon.com/fsx/latest/LustreGuide/what-is.html#storage-options) in the *FSx for Lustre User Guide* .", + "StorageCapacity": "Sets the storage capacity of the file system that you're creating. `StorageCapacity` is required if you are creating a new file system. Do not include `StorageCapacity` if you are creating a file system from a backup.\n\n*FSx for Lustre file systems* - The amount of storage capacity that you can configure depends on the value that you set for `StorageType` and the Lustre `DeploymentType` , as follows:\n\n- For `SCRATCH_2` , `PERSISTENT_2` and `PERSISTENT_1` deployment types using SSD storage type, the valid values are 1200 GiB, 2400 GiB, and increments of 2400 GiB.\n- For `PERSISTENT_1` HDD file systems, valid values are increments of 6000 GiB for 12 MB/s/TiB file systems and increments of 1800 GiB for 40 MB/s/TiB file systems.\n- For `SCRATCH_1` deployment type, valid values are 1200 GiB, 2400 GiB, and increments of 3600 GiB.\n\n*FSx for ONTAP file systems* - The amount of storage capacity that you can configure is from 1024 GiB up to 196,608 GiB (192 TiB).\n\n*FSx for OpenZFS file systems* - The amount of storage capacity that you can configure is from 64 GiB up to 524,288 GiB (512 TiB).\n\n*FSx for Windows File Server file systems* - The amount of storage capacity that you can configure depends on the value that you set for `StorageType` as follows:\n\n- For SSD storage, valid values are 32 GiB-65,536 GiB (64 TiB).\n- For HDD storage, valid values are 2000 GiB-65,536 GiB (64 TiB).", + "StorageType": "Sets the storage type for the file system that you're creating. Valid values are `SSD` and `HDD` .\n\n- Set to `SSD` to use solid state drive storage. SSD is supported on all Windows, Lustre, ONTAP, and OpenZFS deployment types.\n- Set to `HDD` to use hard disk drive storage. HDD is supported on `SINGLE_AZ_2` and `MULTI_AZ_1` Windows file system deployment types, and on `PERSISTENT_1` Lustre file system deployment types.\n\nDefault value is `SSD` . For more information, see [Storage type options](https://docs.aws.amazon.com/fsx/latest/WindowsGuide/optimize-fsx-costs.html#storage-type-options) in the *FSx for Windows File Server User Guide* and [Multiple storage options](https://docs.aws.amazon.com/fsx/latest/LustreGuide/what-is.html#storage-options) in the *FSx for Lustre User Guide* .", "SubnetIds": "Specifies the IDs of the subnets that the file system will be accessible from. For Windows and ONTAP `MULTI_AZ_1` deployment types,provide exactly two subnet IDs, one for the preferred file server and one for the standby file server. You specify one of these subnets as the preferred subnet using the `WindowsConfiguration > PreferredSubnetID` or `OntapConfiguration > PreferredSubnetID` properties. For more information about Multi-AZ file system configuration, see [Availability and durability: Single-AZ and Multi-AZ file systems](https://docs.aws.amazon.com/fsx/latest/WindowsGuide/high-availability-multiAZ.html) in the *Amazon FSx for Windows User Guide* and [Availability and durability](https://docs.aws.amazon.com/fsx/latest/ONTAPGuide/high-availability-multiAZ.html) in the *Amazon FSx for ONTAP User Guide* .\n\nFor Windows `SINGLE_AZ_1` and `SINGLE_AZ_2` and all Lustre deployment types, provide exactly one subnet ID. The file server is launched in that subnet's Availability Zone.", - "Tags": "The tags to associate with the file system. For more information, see [Tagging your Amazon EC2 resources](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/Using_Tags.html) in the *Amazon EC2 User Guide* .", + "Tags": "An array of key-value pairs to apply to this resource.\n\nFor more information, see [Tag](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resource-tags.html) .", "WindowsConfiguration": "The configuration object for the Microsoft Windows file system you are creating. This value is required if `FileSystemType` is set to `WINDOWS` ." } }, @@ -16906,10 +17380,10 @@ }, "AWS::FSx::FileSystem.ClientConfigurations": { "attributes": {}, - "description": "Specifies who can mount the file system and the options that can be used while mounting the file system.", + "description": "Specifies who can mount an OpenZFS file system and the options available while mounting the file system.", "properties": { - "Clients": "A value that specifies who can mount the file system. You can provide a wildcard character ( `*` ), an IP address ( `0.0.0.0` ), or a CIDR address ( `192.0.2.0/24` . By default, Amazon FSx uses the wildcard character when specifying the client.", - "Options": "The options to use when mounting the file system. For a list of options that you can use with Network File System (NFS), see the [exports(5) - Linux man page](https://docs.aws.amazon.com/https://linux.die.net/man/5/exports) . When choosing your options, consider the following:\n\n- `crossmount` is used by default. If you don't specify `crossmount` when changing the client configuration, you won't be able to see or access snapshots in your file system's snapshot directory.\n- `sync` is used by default. If you instead specify `async` , the system acknowledges writes before writing to disk. If the system crashes before the writes are finished, you lose the unwritten data." + "Clients": "A value that specifies who can mount the file system. You can provide a wildcard character ( `*` ), an IP address ( `0.0.0.0` ), or a CIDR address ( `192.0.2.0/24` ). By default, Amazon FSx uses the wildcard character when specifying the client.", + "Options": "The options to use when mounting the file system. For a list of options that you can use with Network File System (NFS), see the [exports(5) - Linux man page](https://docs.aws.amazon.com/https://linux.die.net/man/5/exports) . When choosing your options, consider the following:\n\n- `crossmnt` is used by default. If you don't specify `crossmnt` when changing the client configuration, you won't be able to see or access snapshots in your file system's snapshot directory.\n- `sync` is used by default. If you instead specify `async` , the system acknowledges writes before writing to disk. If the system crashes before the writes are finished, you lose the unwritten data." } }, "AWS::FSx::FileSystem.DiskIopsConfiguration": { @@ -16924,18 +17398,18 @@ "attributes": {}, "description": "The configuration for the Amazon FSx for Lustre file system.", "properties": { - "AutoImportPolicy": "(Optional) Available with `Scratch` and `Persistent_1` deployment types. When you create your file system, your existing S3 objects appear as file and directory listings. Use this property to choose how Amazon FSx keeps your file and directory listings up to date as you add or modify objects in your linked S3 bucket. `AutoImportPolicy` can have the following values:\n\n- `NONE` - (Default) AutoImport is off. Amazon FSx only updates file and directory listings from the linked S3 bucket when the file system is created. FSx does not update file and directory listings for any new or changed objects after choosing this option.\n- `NEW` - AutoImport is on. Amazon FSx automatically imports directory listings of any new objects added to the linked S3 bucket that do not currently exist in the FSx file system.\n- `NEW_CHANGED` - AutoImport is on. Amazon FSx automatically imports file and directory listings of any new objects added to the S3 bucket and any existing objects that are changed in the S3 bucket after you choose this option.\n- `NEW_CHANGED_DELETED` - AutoImport is on. Amazon FSx automatically imports file and directory listings of any new objects added to the S3 bucket, any existing objects that are changed in the S3 bucket, and any objects that were deleted in the S3 bucket.\n\nFor more information, see [Automatically import updates from your S3 bucket](https://docs.aws.amazon.com/fsx/latest/LustreGuide/autoimport-data-repo.html) .\n\n> This parameter is not supported for file systems with the `Persistent_2` deployment type. Instead, use `CreateDataRepositoryAssociation` to create a data repository association to link your Lustre file system to a data repository.", - "AutomaticBackupRetentionDays": "The number of days to retain automatic backups. Setting this to 0 disables automatic backups. You can retain automatic backups for a maximum of 90 days. The default is 0. Only valid for use with `PERSISTENT_1` deployment types. For more information, see [Working with backups](https://docs.aws.amazon.com/fsx/latest/LustreGuide/using-backups-fsx.html) in the *Amazon FSx for Lustre User Guide* . (Default = 0)", + "AutoImportPolicy": "(Optional) Available with `Scratch` and `Persistent_1` deployment types. When you create your file system, your existing S3 objects appear as file and directory listings. Use this property to choose how Amazon FSx keeps your file and directory listings up to date as you add or modify objects in your linked S3 bucket. `AutoImportPolicy` can have the following values:\n\n- `NONE` - (Default) AutoImport is off. Amazon FSx only updates file and directory listings from the linked S3 bucket when the file system is created. FSx does not update file and directory listings for any new or changed objects after choosing this option.\n- `NEW` - AutoImport is on. Amazon FSx automatically imports directory listings of any new objects added to the linked S3 bucket that do not currently exist in the FSx file system.\n- `NEW_CHANGED` - AutoImport is on. Amazon FSx automatically imports file and directory listings of any new objects added to the S3 bucket and any existing objects that are changed in the S3 bucket after you choose this option.\n- `NEW_CHANGED_DELETED` - AutoImport is on. Amazon FSx automatically imports file and directory listings of any new objects added to the S3 bucket, any existing objects that are changed in the S3 bucket, and any objects that were deleted in the S3 bucket.\n\nFor more information, see [Automatically import updates from your S3 bucket](https://docs.aws.amazon.com/fsx/latest/LustreGuide/autoimport-data-repo.html) .\n\n> This parameter is not supported for Lustre file systems using the `Persistent_2` deployment type.", + "AutomaticBackupRetentionDays": "The number of days to retain automatic backups. Setting this property to `0` disables automatic backups. You can retain automatic backups for a maximum of 90 days. The default is `0` .", "CopyTagsToBackups": "A Boolean flag indicating whether tags for the file system should be copied to backups. This value defaults to false. If it's set to true, all tags for the file system are copied to all automatic and user-initiated backups where the user doesn't specify tags. If this value is true, and you specify one or more tags, only the specified tags are copied to backups. If you specify one or more tags when creating a user-initiated backup, no tags are copied from the file system, regardless of this value. Only valid for use with `PERSISTENT_1` deployment types.", - "DailyAutomaticBackupStartTime": "A recurring daily time, in the format `HH:MM` . `HH` is the zero-padded hour of the day (0-23), and `MM` is the zero-padded minute of the hour. For example, `05:00` specifies 5 AM daily. Only valid for use with `PERSISTENT_1` deployment types.", + "DailyAutomaticBackupStartTime": "A recurring daily time, in the format `HH:MM` . `HH` is the zero-padded hour of the day (0-23), and `MM` is the zero-padded minute of the hour. For example, `05:00` specifies 5 AM daily.", "DataCompressionType": "Sets the data compression configuration for the file system. `DataCompressionType` can have the following values:\n\n- `NONE` - (Default) Data compression is turned off when the file system is created.\n- `LZ4` - Data compression is turned on with the LZ4 algorithm.\n\nFor more information, see [Lustre data compression](https://docs.aws.amazon.com/fsx/latest/LustreGuide/data-compression.html) in the *Amazon FSx for Lustre User Guide* .", "DeploymentType": "(Optional) Choose `SCRATCH_1` and `SCRATCH_2` deployment types when you need temporary storage and shorter-term processing of data. The `SCRATCH_2` deployment type provides in-transit encryption of data and higher burst throughput capacity than `SCRATCH_1` .\n\nChoose `PERSISTENT_1` for longer-term storage and for throughput-focused workloads that aren\u2019t latency-sensitive. `PERSISTENT_1` supports encryption of data in transit, and is available in all AWS Regions in which FSx for Lustre is available.\n\nChoose `PERSISTENT_2` for longer-term storage and for latency-sensitive workloads that require the highest levels of IOPS/throughput. `PERSISTENT_2` supports SSD storage, and offers higher `PerUnitStorageThroughput` (up to 1000 MB/s/TiB). `PERSISTENT_2` is available in a limited number of AWS Regions . For more information, and an up-to-date list of AWS Regions in which `PERSISTENT_2` is available, see [File system deployment options for FSx for Lustre](https://docs.aws.amazon.com/fsx/latest/LustreGuide/using-fsx-lustre.html#lustre-deployment-types) in the *Amazon FSx for Lustre User Guide* .\n\n> If you choose `PERSISTENT_2` , and you set `FileSystemTypeVersion` to `2.10` , the `CreateFileSystem` operation fails. \n\nEncryption of data in transit is automatically turned on when you access `SCRATCH_2` , `PERSISTENT_1` and `PERSISTENT_2` file systems from Amazon EC2 instances that [support automatic encryption](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/data- protection.html) in the AWS Regions where they are available. For more information about encryption in transit for FSx for Lustre file systems, see [Encrypting data in transit](https://docs.aws.amazon.com/fsx/latest/LustreGuide/encryption-in-transit-fsxl.html) in the *Amazon FSx for Lustre User Guide* .\n\n(Default = `SCRATCH_1` )", - "DriveCacheType": "The type of drive cache used by `PERSISTENT_1` file systems that are provisioned with HDD storage devices. This parameter is required when storage type is HDD. Set this property to `READ` to improve the performance for frequently accessed files by caching up to 20% of the total storage capacity of the file system.\n\nThis parameter is required when `StorageType` is set to `HDD` .", - "ExportPath": "(Optional) Available with `Scratch` and `Persistent_1` deployment types. Specifies the path in the Amazon S3 bucket where the root of your Amazon FSx file system is exported. The path must use the same Amazon S3 bucket as specified in ImportPath. You can provide an optional prefix to which new and changed data is to be exported from your Amazon FSx for Lustre file system. If an `ExportPath` value is not provided, Amazon FSx sets a default export path, `s3://import-bucket/FSxLustre[creation-timestamp]` . The timestamp is in UTC format, for example `s3://import-bucket/FSxLustre20181105T222312Z` .\n\nThe Amazon S3 export bucket must be the same as the import bucket specified by `ImportPath` . If you specify only a bucket name, such as `s3://import-bucket` , you get a 1:1 mapping of file system objects to S3 bucket objects. This mapping means that the input data in S3 is overwritten on export. If you provide a custom prefix in the export path, such as `s3://import-bucket/[custom-optional-prefix]` , Amazon FSx exports the contents of your file system to that export prefix in the Amazon S3 bucket.\n\n> This parameter is not supported for file systems with the `Persistent_2` deployment type. Instead, use `CreateDataRepositoryAssociation` to create a data repository association to link your Lustre file system to a data repository.", - "ImportPath": "(Optional) The path to the Amazon S3 bucket (including the optional prefix) that you're using as the data repository for your Amazon FSx for Lustre file system. The root of your FSx for Lustre file system will be mapped to the root of the Amazon S3 bucket you select. An example is `s3://import-bucket/optional-prefix` . If you specify a prefix after the Amazon S3 bucket name, only object keys with that prefix are loaded into the file system.\n\nThis parameter is not supported for file systems with the `Persistent_2` deployment type. Instead, use `CreateDataRepositoryAssociation` to create a data repository association to link your Lustre file system to a data repository.", - "ImportedFileChunkSize": "(Optional) For files imported from a data repository, this value determines the stripe count and maximum amount of data per file (in MiB) stored on a single physical disk. The maximum number of disks that a single file can be striped across is limited by the total number of disks that make up the file system.\n\nThe default chunk size is 1,024 MiB (1 GiB) and can go as high as 512,000 MiB (500 GiB). Amazon S3 objects have a maximum size of 5 TB.\n\nThis parameter is not supported for file systems with the `Persistent_2` deployment type. Instead, use `CreateDataRepositoryAssociation` to create a data repository association to link your Lustre file system to a data repository.", + "DriveCacheType": "The type of drive cache used by `PERSISTENT_1` file systems that are provisioned with HDD storage devices. This parameter is required when storage type is HDD. Set this property to `READ` to improve the performance for frequently accessed files by caching up to 20% of the total storage capacity of the file system.\n\nThis parameter is required when `StorageType` is set to `HDD` and `DeploymentType` is `PERSISTENT_1` .", + "ExportPath": "(Optional) Available with `Scratch` and `Persistent_1` deployment types. Specifies the path in the Amazon S3 bucket where the root of your Amazon FSx file system is exported. The path must use the same Amazon S3 bucket as specified in ImportPath. You can provide an optional prefix to which new and changed data is to be exported from your Amazon FSx for Lustre file system. If an `ExportPath` value is not provided, Amazon FSx sets a default export path, `s3://import-bucket/FSxLustre[creation-timestamp]` . The timestamp is in UTC format, for example `s3://import-bucket/FSxLustre20181105T222312Z` .\n\nThe Amazon S3 export bucket must be the same as the import bucket specified by `ImportPath` . If you specify only a bucket name, such as `s3://import-bucket` , you get a 1:1 mapping of file system objects to S3 bucket objects. This mapping means that the input data in S3 is overwritten on export. If you provide a custom prefix in the export path, such as `s3://import-bucket/[custom-optional-prefix]` , Amazon FSx exports the contents of your file system to that export prefix in the Amazon S3 bucket.\n\n> This parameter is not supported for file systems using the `Persistent_2` deployment type.", + "ImportPath": "(Optional) The path to the Amazon S3 bucket (including the optional prefix) that you're using as the data repository for your Amazon FSx for Lustre file system. The root of your FSx for Lustre file system will be mapped to the root of the Amazon S3 bucket you select. An example is `s3://import-bucket/optional-prefix` . If you specify a prefix after the Amazon S3 bucket name, only object keys with that prefix are loaded into the file system.\n\n> This parameter is not supported for Lustre file systems using the `Persistent_2` deployment type.", + "ImportedFileChunkSize": "(Optional) For files imported from a data repository, this value determines the stripe count and maximum amount of data per file (in MiB) stored on a single physical disk. The maximum number of disks that a single file can be striped across is limited by the total number of disks that make up the file system.\n\nThe default chunk size is 1,024 MiB (1 GiB) and can go as high as 512,000 MiB (500 GiB). Amazon S3 objects have a maximum size of 5 TB.\n\n> This parameter is not supported for Lustre file systems using the `Persistent_2` deployment type.", "PerUnitStorageThroughput": "Required with `PERSISTENT_1` and `PERSISTENT_2` deployment types, provisions the amount of read and write throughput for each 1 tebibyte (TiB) of file system storage capacity, in MB/s/TiB. File system throughput capacity is calculated by multiplying \ufb01le system storage capacity (TiB) by the `PerUnitStorageThroughput` (MB/s/TiB). For a 2.4-TiB \ufb01le system, provisioning 50 MB/s/TiB of `PerUnitStorageThroughput` yields 120 MB/s of \ufb01le system throughput. You pay for the amount of throughput that you provision.\n\nValid values:\n\n- For `PERSISTENT_1` SSD storage: 50, 100, 200 MB/s/TiB.\n- For `PERSISTENT_1` HDD storage: 12, 40 MB/s/TiB.\n- For `PERSISTENT_2` SSD storage: 125, 250, 500, 1000 MB/s/TiB.", - "WeeklyMaintenanceStartTime": "(Optional) The preferred start time to perform weekly maintenance, formatted d:HH:MM in the UTC time zone, where d is the weekday number, from 1 through 7, beginning with Monday and ending with Sunday." + "WeeklyMaintenanceStartTime": "A recurring weekly time, in the format `D:HH:MM` .\n\n`D` is the day of the week, for which 1 represents Monday and 7 represents Sunday. For further details, see [the ISO-8601 spec as described on Wikipedia](https://docs.aws.amazon.com/https://en.wikipedia.org/wiki/ISO_week_date) .\n\n`HH` is the zero-padded hour of the day (0-23), and `MM` is the zero-padded minute of the hour.\n\nFor example, `1:05:00` specifies maintenance at 5 AM Monday." } }, "AWS::FSx::FileSystem.NfsExports": { @@ -16947,13 +17421,13 @@ }, "AWS::FSx::FileSystem.OntapConfiguration": { "attributes": {}, - "description": "The configuration for this FSx for ONTAP file system.", + "description": "The configuration for this Amazon FSx for NetApp ONTAP file system.", "properties": { "AutomaticBackupRetentionDays": "The number of days to retain automatic backups. Setting this property to `0` disables automatic backups. You can retain automatic backups for a maximum of 90 days. The default is `0` .", "DailyAutomaticBackupStartTime": "A recurring daily time, in the format `HH:MM` . `HH` is the zero-padded hour of the day (0-23), and `MM` is the zero-padded minute of the hour. For example, `05:00` specifies 5 AM daily.", "DeploymentType": "Specifies the FSx for ONTAP file system deployment type to use in creating the file system. `MULTI_AZ_1` is the supported ONTAP deployment type.", "DiskIopsConfiguration": "The SSD IOPS configuration for the FSx for ONTAP file system.", - "EndpointIpAddressRange": "Specifies the IP address range in which the endpoints to access your file system will be created. By default, Amazon FSx selects an unused IP address range for you from the 198.19.* range.", + "EndpointIpAddressRange": "Specifies the IP address range in which the endpoints to access your file system will be created. By default, Amazon FSx selects an unused IP address range for you from the 198.19.* range.\n\n> The Endpoint IP address range you select for your file system must exist outside the VPC's CIDR range and must be at least /30 or larger.", "FsxAdminPassword": "The ONTAP administrative password for the `fsxadmin` user with which you administer your file system using the NetApp ONTAP CLI and REST API.", "PreferredSubnetId": "Required when `DeploymentType` is set to `MULTI_AZ_1` . This specifies the subnet in which you want the preferred file server to be located.", "RouteTableIds": "Specifies the virtual private cloud (VPC) route tables in which your file system's endpoints will be created. You should specify all VPC route tables associated with the subnets in which your clients are located. By default, Amazon FSx selects your VPC's default route table.", @@ -16969,8 +17443,9 @@ "CopyTagsToBackups": "A Boolean value indicating whether tags for the file system should be copied to backups. This value defaults to `false` . If it's set to `true` , all tags for the file system are copied to all automatic and user-initiated backups where the user doesn't specify tags. If this value is `true` , and you specify one or more tags, only the specified tags are copied to backups. If you specify one or more tags when creating a user-initiated backup, no tags are copied from the file system, regardless of this value.", "CopyTagsToVolumes": "A Boolean value indicating whether tags for the volume should be copied to snapshots. This value defaults to `false` . If it's set to `true` , all tags for the volume are copied to snapshots where the user doesn't specify tags. If this value is `true` , and you specify one or more tags, only the specified tags are copied to snapshots. If you specify one or more tags when creating the snapshot, no tags are copied from the volume, regardless of this value.", "DailyAutomaticBackupStartTime": "A recurring daily time, in the format `HH:MM` . `HH` is the zero-padded hour of the day (0-23), and `MM` is the zero-padded minute of the hour. For example, `05:00` specifies 5 AM daily.", - "DeploymentType": "Specifies the file system deployment type. Amazon FSx for OpenZFS supports `SINGLE_AZ_1` . `SINGLE_AZ_1` is a file system configured for a single Availability Zone (AZ) of redundancy.", + "DeploymentType": "Specifies the file system deployment type. Amazon FSx for OpenZFS supports `SINGLE_AZ_1` . `SINGLE_AZ_1` deployment type is configured for redundancy within a single Availability Zone.", "DiskIopsConfiguration": "The SSD IOPS (input/output operations per second) configuration for an Amazon FSx for NetApp ONTAP or Amazon FSx for OpenZFS file system. The default is 3 IOPS per GB of storage capacity, but you can provision additional IOPS per GB of storage. The configuration consists of the total number of provisioned SSD IOPS and how the amount was provisioned (by the customer or by the system).", + "Options": "To delete a file system if there are child volumes present below the root volume, use the string `DELETE_CHILD_VOLUMES_AND_SNAPSHOTS` . If your file system has child volumes and you don't use this option, the delete request will fail.", "RootVolumeConfiguration": "The configuration Amazon FSx uses when creating the root value of the Amazon FSx for OpenZFS file system. All volumes are children of the root volume.", "ThroughputCapacity": "Specifies the throughput of an Amazon FSx for OpenZFS file system, measured in megabytes per second (MB/s). Valid values are 64, 128, 256, 512, 1024, 2048, 3072, or 4096 MB/s. You pay for additional throughput capacity that you provision.", "WeeklyMaintenanceStartTime": "A recurring weekly time, in the format `D:HH:MM` .\n\n`D` is the day of the week, for which 1 represents Monday and 7 represents Sunday. For further details, see [the ISO-8601 spec as described on Wikipedia](https://docs.aws.amazon.com/https://en.wikipedia.org/wiki/ISO_week_date) .\n\n`HH` is the zero-padded hour of the day (0-23), and `MM` is the zero-padded minute of the hour.\n\nFor example, `1:05:00` specifies maintenance at 5 AM Monday." @@ -16980,10 +17455,11 @@ "attributes": {}, "description": "The configuration of an Amazon FSx for OpenZFS root volume.", "properties": { - "CopyTagsToSnapshots": "A Boolean value indicating whether tags for the volume should be copied to snapshots. This value defaults to `false` . If it's set to `true` , all tags for the volume are copied to snapshots where the user doesn't specify tags. If this value is `true` and you specify one or more tags, only the specified tags are copied to snapshots. If you specify one or more tags when creating the snapshot, no tags are copied from the volume, regardless of this value.", - "DataCompressionType": "Specifies the method used to compress the data on the volume. Unless the compression type is specified, volumes inherit the `DataCompressionType` value of their parent volume.\n\n- `NONE` - Doesn't compress the data on the volume.\n- `ZSTD` - Compresses the data in the volume using the ZStandard (ZSTD) compression algorithm. This algorithm reduces the amount of space used on your volume and has very little impact on compute resources.", + "CopyTagsToSnapshots": "A Boolean value indicating whether tags for the volume should be copied to snapshots of the volume. This value defaults to `false` . If it's set to `true` , all tags for the volume are copied to snapshots where the user doesn't specify tags. If this value is `true` and you specify one or more tags, only the specified tags are copied to snapshots. If you specify one or more tags when creating the snapshot, no tags are copied from the volume, regardless of this value.", + "DataCompressionType": "Specifies the method used to compress the data on the volume. The compression type is `NONE` by default.\n\n- `NONE` - Doesn't compress the data on the volume. `NONE` is the default.\n- `ZSTD` - Compresses the data in the volume using the Zstandard (ZSTD) compression algorithm. Compared to LZ4, Z-Standard provides a better compression ratio to minimize on-disk storage utilization.\n- `LZ4` - Compresses the data in the volume using the LZ4 compression algorithm. Compared to Z-Standard, LZ4 is less compute-intensive and delivers higher write throughput speeds.", "NfsExports": "The configuration object for mounting a file system.", "ReadOnly": "A Boolean value indicating whether the volume is read-only. Setting this value to `true` can be useful after you have completed changes to a volume and no longer want changes to occur.", + "RecordSizeKiB": "Specifies the record size of an OpenZFS root volume, in kibibytes (KiB). Valid values are 4, 8, 16, 32, 64, 128, 256, 512, or 1024 KiB. The default is 128 KiB. Most workloads should use the default record size. Database workflows can benefit from a smaller record size, while streaming workflows can benefit from a larger record size. For additional guidance on setting a custom record size, see [Tips for maximizing performance](https://docs.aws.amazon.com/fsx/latest/OpenZFSGuide/performance.html#performance-tips-zfs) in the *Amazon FSx for OpenZFS User Guide* .", "UserAndGroupQuotas": "An object specifying how much storage users or groups can use on the volume." } }, @@ -16995,7 +17471,7 @@ "DomainName": "The fully qualified domain name of the self-managed AD directory, such as `corp.example.com` .", "FileSystemAdministratorsGroup": "(Optional) The name of the domain group whose members are granted administrative privileges for the file system. Administrative privileges include taking ownership of files and folders, setting audit controls (audit ACLs) on files and folders, and administering the file system remotely by using the FSx Remote PowerShell. The group that you specify must already exist in your domain. If you don't provide one, your AD domain's Domain Admins group is used.", "OrganizationalUnitDistinguishedName": "(Optional) The fully qualified distinguished name of the organizational unit within your self-managed AD directory. Amazon FSx only accepts OU as the direct parent of the file system. An example is `OU=FSx,DC=yourdomain,DC=corp,DC=com` . To learn more, see [RFC 2253](https://docs.aws.amazon.com/https://tools.ietf.org/html/rfc2253) . If none is provided, the FSx file system is created in the default location of your self-managed AD directory.\n\n> Only Organizational Unit (OU) objects can be the direct parent of the file system that you're creating.", - "Password": "The password for the service account on your self-managed AD domain that Amazon FSx will use to join to your AD domain. We strongly suggest that you follow best practices and *do not* embed passwords in your CFN templates.\n\nThe recommended approach is to use AWS Secrets Manager to store your passwords. You can retrieve them for use in your templates using the `secretsmanager` dynamic reference. There are additional costs associated with using AWS Secrets Manager . To learn more, see [Secrets Manager secrets](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html#dynamic-references-secretsmanager) in the *AWS CloudFormation User Guide* .\n\nAlternatively, you can use the `NoEcho` property to obfuscate the password parameter value. For more information, see [Do Not Embed Credentials in Your Templates](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html#creds) in the *AWS CloudFormation User Guide* .", + "Password": "The password for the service account on your self-managed AD domain that Amazon FSx will use to join to your AD domain.", "UserName": "The user name for the service account on your self-managed AD domain that Amazon FSx will use to join to your AD domain. This account must have the permission to join computers to the domain in the organizational unit provided in `OrganizationalUnitDistinguishedName` , or in the default location of your AD domain." } }, @@ -17012,17 +17488,17 @@ "attributes": {}, "description": "The Microsoft Windows configuration for the file system that's being created.", "properties": { - "ActiveDirectoryId": "The ID for an existing AWS Managed Microsoft Active Directory (AD) instance that the file system should join when it's created.", + "ActiveDirectoryId": "The ID for an existing AWS Managed Microsoft Active Directory (AD) instance that the file system should join when it's created. Required if you are joining the file system to an existing AWS Managed Microsoft AD.", "Aliases": "An array of one or more DNS alias names that you want to associate with the Amazon FSx file system. Aliases allow you to use existing DNS names to access the data in your Amazon FSx file system. You can associate up to 50 aliases with a file system at any time.\n\nFor more information, see [Working with DNS Aliases](https://docs.aws.amazon.com/fsx/latest/WindowsGuide/managing-dns-aliases.html) and [Walkthrough 5: Using DNS aliases to access your file system](https://docs.aws.amazon.com/fsx/latest/WindowsGuide/walkthrough05-file-system-custom-CNAME.html) , including additional steps you must take to be able to access your file system using a DNS alias.\n\nAn alias name has to meet the following requirements:\n\n- Formatted as a fully-qualified domain name (FQDN), `hostname.domain` , for example, `accounting.example.com` .\n- Can contain alphanumeric characters, the underscore (_), and the hyphen (-).\n- Cannot start or end with a hyphen.\n- Can start with a numeric.\n\nFor DNS alias names, Amazon FSx stores alphabetical characters as lowercase letters (a-z), regardless of how you specify them: as uppercase letters, lowercase letters, or the corresponding letters in escape codes.", "AuditLogConfiguration": "The configuration that Amazon FSx for Windows File Server uses to audit and log user accesses of files, folders, and file shares on the Amazon FSx for Windows File Server file system.", - "AutomaticBackupRetentionDays": "The number of days to retain automatic backups. The default is to retain backups for 7 days. Setting this value to 0 disables the creation of automatic backups. The maximum retention period for backups is 90 days.", - "CopyTagsToBackups": "A Boolean flag indicating whether tags for the file system should be copied to backups. This value defaults to false. If it's set to true, all tags for the file system are copied to all automatic and user-initiated backups where the user doesn't specify tags. If this value is true, and you specify one or more tags, only the specified tags are copied to backups. If you specify one or more tags when creating a user-initiated backup, no tags are copied from the file system, regardless of this value.", - "DailyAutomaticBackupStartTime": "The preferred time to take daily automatic backups, formatted HH:MM in the UTC time zone.", + "AutomaticBackupRetentionDays": "The number of days to retain automatic backups. Setting this property to `0` disables automatic backups. You can retain automatic backups for a maximum of 90 days. The default is `0` .", + "CopyTagsToBackups": "A boolean flag indicating whether tags for the file system should be copied to backups. This value defaults to false. If it's set to true, all tags for the file system are copied to all automatic and user-initiated backups where the user doesn't specify tags. If this value is true, and you specify one or more tags, only the specified tags are copied to backups. If you specify one or more tags when creating a user-initiated backup, no tags are copied from the file system, regardless of this value.", + "DailyAutomaticBackupStartTime": "A recurring daily time, in the format `HH:MM` . `HH` is the zero-padded hour of the day (0-23), and `MM` is the zero-padded minute of the hour. For example, `05:00` specifies 5 AM daily.", "DeploymentType": "Specifies the file system deployment type, valid values are the following:\n\n- `MULTI_AZ_1` - Deploys a high availability file system that is configured for Multi-AZ redundancy to tolerate temporary Availability Zone (AZ) unavailability. You can only deploy a Multi-AZ file system in AWS Regions that have a minimum of three Availability Zones. Also supports HDD storage type\n- `SINGLE_AZ_1` - (Default) Choose to deploy a file system that is configured for single AZ redundancy.\n- `SINGLE_AZ_2` - The latest generation Single AZ file system. Specifies a file system that is configured for single AZ redundancy and supports HDD storage type.\n\nFor more information, see [Availability and Durability: Single-AZ and Multi-AZ File Systems](https://docs.aws.amazon.com/fsx/latest/WindowsGuide/high-availability-multiAZ.html) .", - "PreferredSubnetId": "Required when `DeploymentType` is set to `MULTI_AZ_1` . This specifies the subnet in which you want the preferred file server to be located. For in- AWS applications, we recommend that you launch your clients in the same Availability Zone (AZ) as your preferred file server to reduce cross-AZ data transfer costs and minimize latency.", + "PreferredSubnetId": "Required when `DeploymentType` is set to `MULTI_AZ_1` . This specifies the subnet in which you want the preferred file server to be located. For in- AWS applications, we recommend that you launch your clients in the same availability zone as your preferred file server to reduce cross-availability zone data transfer costs and minimize latency.", "SelfManagedActiveDirectoryConfiguration": "The configuration that Amazon FSx uses to join a FSx for Windows File Server file system or an ONTAP storage virtual machine (SVM) to a self-managed (including on-premises) Microsoft Active Directory (AD) directory. For more information, see [Using Amazon FSx with your self-managed Microsoft Active Directory](https://docs.aws.amazon.com/fsx/latest/WindowsGuide/self-managed-AD.html) or [Managing SVMs](https://docs.aws.amazon.com/fsx/latest/ONTAPGuide/managing-svms.html) .", "ThroughputCapacity": "Sets the throughput capacity of an Amazon FSx file system, measured in megabytes per second (MB/s), in 2 to the *n* th increments, between 2^3 (8) and 2^11 (2048).", - "WeeklyMaintenanceStartTime": "The preferred start time to perform weekly maintenance, formatted d:HH:MM in the UTC time zone, where d is the weekday number, from 1 through 7, beginning with Monday and ending with Sunday." + "WeeklyMaintenanceStartTime": "A recurring weekly time, in the format `D:HH:MM` .\n\n`D` is the day of the week, for which 1 represents Monday and 7 represents Sunday. For further details, see [the ISO-8601 spec as described on Wikipedia](https://docs.aws.amazon.com/https://en.wikipedia.org/wiki/ISO_week_date) .\n\n`HH` is the zero-padded hour of the day (0-23), and `MM` is the zero-padded minute of the hour.\n\nFor example, `1:05:00` specifies maintenance at 5 AM Monday." } }, "AWS::FSx::Snapshot": { @@ -17047,10 +17523,10 @@ "description": "Creates a storage virtual machine (SVM) for an Amazon FSx for ONTAP file system.", "properties": { "ActiveDirectoryConfiguration": "Describes the Microsoft Active Directory configuration to which the SVM is joined, if applicable.", - "FileSystemId": "The system-generated, unique 17-digit ID of the file system.", - "Name": "The name of the SVM, if provisioned.", + "FileSystemId": "Specifies the FSx for ONTAP file system on which to create the SVM.", + "Name": "The name of the SVM.", "RootVolumeSecurityStyle": "The security style of the root volume of the SVM. Specify one of the following values:\n\n- `UNIX` if the file system is managed by a UNIX administrator, the majority of users are NFS clients, and an application accessing the data uses a UNIX user as the service account.\n- `NTFS` if the file system is managed by a Windows administrator, the majority of users are SMB clients, and an application accessing the data uses a Windows user as the service account.\n- `MIXED` if the file system is managed by both UNIX and Windows administrators and users consist of both NFS and SMB clients.", - "SvmAdminPassword": "The password to use when managing the SVM using the NetApp ONTAP CLI or REST API. If you do not specify a password, you can still use the file system's `fsxadmin` user to manage the SVM.", + "SvmAdminPassword": "Specifies the password to use when logging on to the SVM using a secure shell (SSH) connection to the SVM's management endpoint. Doing so enables you to manage the SVM using the NetApp ONTAP CLI or REST API. If you do not specify a password, you can still use the file system's `fsxadmin` user to manage the SVM. For more information, see [Managing SVMs using the NetApp ONTAP CLI](https://docs.aws.amazon.com/fsx/latest/ONTAPGuide/managing-resources-ontap-apps.html#vsadmin-ontap-cli) in the *FSx for ONTAP User Guide* .", "Tags": "An array of key-value pairs to apply to this resource.\n\nFor more information, see [Tag](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resource-tags.html) ." } }, @@ -17081,24 +17557,22 @@ "UUID": "Returns the volume's universally unique identifier (UUID).\n\nExample: `abcd0123-cd45-ef67-11aa-1111aaaa23bc`", "VolumeId": "Returns the volume's ID.\n\nExample: `fsvol-0123456789abcdefa`" }, - "description": "Creates an Amazon FSx for NetApp ONTAP or Amazon FSx for OpenZFS storage volume.", + "description": "Creates an FSx for ONTAP or Amazon FSx for OpenZFS storage volume.", "properties": { - "BackupId": "The ID of the source backup. Specifies the backup that you are copying.", + "BackupId": "Specifies the ID of the volume backup to use to create a new volume.", "Name": "The name of the volume.", "OntapConfiguration": "The configuration of an Amazon FSx for NetApp ONTAP volume.", - "OpenZFSConfiguration": "Specifies the configuration of the OpenZFS volume that you are creating.", - "Options": "To delete the volume's child volumes, snapshots, and clones, use the string `DELETE_CHILD_VOLUMES_AND_SNAPSHOTS` .", - "SnapshotId": "A unique ID that represents the snapshot.", + "OpenZFSConfiguration": "The configuration of an Amazon FSx for OpenZFS volume.", "Tags": "An array of key-value pairs to apply to this resource.\n\nFor more information, see [Tag](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resource-tags.html) .", "VolumeType": "The type of the volume." } }, "AWS::FSx::Volume.ClientConfigurations": { "attributes": {}, - "description": "Specifies who can mount the file system and the options that can be used while mounting the file system.", + "description": "Specifies who can mount an OpenZFS file system and the options available while mounting the file system.", "properties": { - "Clients": "A value that specifies who can mount the file system. You can provide a wildcard character ( `*` ), an IP address ( `0.0.0.0` ), or a CIDR address ( `192.0.2.0/24` . By default, Amazon FSx uses the wildcard character when specifying the client.", - "Options": "The options to use when mounting the file system. For a list of options that you can use with Network File System (NFS), see the [exports(5) - Linux man page](https://docs.aws.amazon.com/https://linux.die.net/man/5/exports) . When choosing your options, consider the following:\n\n- `crossmount` is used by default. If you don't specify `crossmount` when changing the client configuration, you won't be able to see or access snapshots in your file system's snapshot directory.\n- `sync` is used by default. If you instead specify `async` , the system acknowledges writes before writing to disk. If the system crashes before the writes are finished, you lose the unwritten data." + "Clients": "A value that specifies who can mount the file system. You can provide a wildcard character ( `*` ), an IP address ( `0.0.0.0` ), or a CIDR address ( `192.0.2.0/24` ). By default, Amazon FSx uses the wildcard character when specifying the client.", + "Options": "The options to use when mounting the file system. For a list of options that you can use with Network File System (NFS), see the [exports(5) - Linux man page](https://docs.aws.amazon.com/https://linux.die.net/man/5/exports) . When choosing your options, consider the following:\n\n- `crossmnt` is used by default. If you don't specify `crossmnt` when changing the client configuration, you won't be able to see or access snapshots in your file system's snapshot directory.\n- `sync` is used by default. If you instead specify `async` , the system acknowledges writes before writing to disk. If the system crashes before the writes are finished, you lose the unwritten data." } }, "AWS::FSx::Volume.NfsExports": { @@ -17122,16 +17596,18 @@ }, "AWS::FSx::Volume.OpenZFSConfiguration": { "attributes": {}, - "description": "Specifies the configuration of the OpenZFS volume that you are creating.", + "description": "Specifies the configuration of the Amazon FSx for OpenZFS volume that you are creating.", "properties": { "CopyTagsToSnapshots": "A Boolean value indicating whether tags for the volume should be copied to snapshots. This value defaults to `false` . If it's set to `true` , all tags for the volume are copied to snapshots where the user doesn't specify tags. If this value is `true` , and you specify one or more tags, only the specified tags are copied to snapshots. If you specify one or more tags when creating the snapshot, no tags are copied from the volume, regardless of this value.", - "DataCompressionType": "The method used to compress the data on the volume. Unless a compression type is specified, volumes inherit the `DataCompressionType` value of their parent volume.\n\n- `NONE` - Doesn't compress the data on the volume.\n- `ZSTD` - Compresses the data in the volume using the Zstandard (ZSTD) compression algorithm. This algorithm reduces the amount of space used on your volume and has very little impact on compute resources.", + "DataCompressionType": "Specifies the method used to compress the data on the volume. The compression type is `NONE` by default.\n\n- `NONE` - Doesn't compress the data on the volume. `NONE` is the default.\n- `ZSTD` - Compresses the data in the volume using the Zstandard (ZSTD) compression algorithm. Compared to LZ4, Z-Standard provides a better compression ratio to minimize on-disk storage utilization.\n- `LZ4` - Compresses the data in the volume using the LZ4 compression algorithm. Compared to Z-Standard, LZ4 is less compute-intensive and delivers higher write throughput speeds.", "NfsExports": "The configuration object for mounting a Network File System (NFS) file system.", + "Options": "To delete the volume's child volumes, snapshots, and clones, use the string `DELETE_CHILD_VOLUMES_AND_SNAPSHOTS` .", "OriginSnapshot": "The configuration object that specifies the snapshot to use as the origin of the data for the volume.", - "ParentVolumeId": "The ID of the volume to use as the parent volume.", + "ParentVolumeId": "The ID of the volume to use as the parent volume of the volume that you are creating.", "ReadOnly": "A Boolean value indicating whether the volume is read-only.", - "StorageCapacityQuotaGiB": "The maximum amount of storage in gibibytes (GiB) that the volume can use from its parent. You can specify a quota larger than the storage on the parent volume.", - "StorageCapacityReservationGiB": "The amount of storage in gibibytes (GiB) to reserve from the parent volume. You can't reserve more storage than the parent volume has reserved.", + "RecordSizeKiB": "Specifies the suggested block size for a volume in a ZFS dataset, in kibibytes (KiB). Valid values are 4, 8, 16, 32, 64, 128, 256, 512, or 1024 KiB. The default is 128 KiB. We recommend using the default setting for the majority of use cases. Generally, workloads that write in fixed small or large record sizes may benefit from setting a custom record size, like database workloads (small record size) or media streaming workloads (large record size). For additional guidance on when to set a custom record size, see [ZFS Record size](https://docs.aws.amazon.com/fsx/latest/OpenZFSGuide/performance.html#record-size-performance) in the *Amazon FSx for OpenZFS User Guide* .", + "StorageCapacityQuotaGiB": "Sets the maximum storage size in gibibytes (GiB) for the volume. You can specify a quota that is larger than the storage on the parent volume. A volume quota limits the amount of storage that the volume can consume to the configured amount, but does not guarantee the space will be available on the parent volume. To guarantee quota space, you must also set `StorageCapacityReservationGiB` . To *not* specify a storage capacity quota, set this to `-1` .\n\nFor more information, see [Volume properties](https://docs.aws.amazon.com/fsx/latest/OpenZFSGuide/managing-volumes.html#volume-properties) in the *Amazon FSx for OpenZFS User Guide* .", + "StorageCapacityReservationGiB": "Specifies the amount of storage in gibibytes (GiB) to reserve from the parent volume. Setting `StorageCapacityReservationGiB` guarantees that the specified amount of storage space on the parent volume will always be available for the volume. You can't reserve more storage than the parent volume has. To *not* specify a storage capacity reservation, set this to `0` or `-1` . For more information, see [Volume properties](https://docs.aws.amazon.com/fsx/latest/OpenZFSGuide/managing-volumes.html#volume-properties) in the *Amazon FSx for OpenZFS User Guide* .", "UserAndGroupQuotas": "An object specifying how much storage users or groups can use on the volume." } }, @@ -17140,7 +17616,7 @@ "description": "The configuration object that specifies the snapshot to use as the origin of the data for the volume.", "properties": { "CopyStrategy": "The strategy used when copying data from the snapshot to the new volume.\n\n- `CLONE` - The new volume references the data in the origin snapshot. Cloning a snapshot is faster than copying data from the snapshot to a new volume and doesn't consume disk throughput. However, the origin snapshot can't be deleted if there is a volume using its copied data.\n- `FULL_COPY` - Copies all data from the snapshot to the new volume.", - "SnapshotARN": "The Amazon Resource Name (ARN) for a given resource. ARNs uniquely identify AWS resources. We require an ARN when you need to specify a resource unambiguously across all of AWS . For more information, see [Amazon Resource Names (ARNs)](https://docs.aws.amazon.com//general/latest/gr/aws-arns-and-namespaces.html) in the *AWS General Reference* ." + "SnapshotARN": "Specifies the snapshot to use when creating an OpenZFS volume from a snapshot." } }, "AWS::FSx::Volume.TieringPolicy": { @@ -17444,14 +17920,14 @@ }, "AWS::GameLift::Alias": { "attributes": { - "AliasId": "", + "AliasId": "A unique identifier for the alias. For example, `arn:aws:gamelift:us-west-1::alias/alias-a1234567-b8c9-0d1e-2fa3-b45c6d7e8912`\n\nAlias IDs are unique within a Region.", "Ref": "`Ref` returns the alias ID, such as `alias-1111aaaa-22bb-33cc-44dd-5555eeee66ff` ." }, "description": "The `AWS::GameLift::Alias` resource creates an alias for an Amazon GameLift (GameLift) fleet destination. There are two types of routing strategies for aliases: simple and terminal. A simple alias points to an active fleet. A terminal alias displays a message instead of routing players to an active fleet. For example, a terminal alias might display a URL link that directs players to an upgrade site. You can use aliases to define destinations in a game session queue or when requesting new game sessions.", "properties": { "Description": "A human-readable description of the alias.", "Name": "A descriptive label that is associated with an alias. Alias names do not need to be unique.", - "RoutingStrategy": "A routing configuration that specifies where traffic is directed for this alias, such as to a fleet or to a message." + "RoutingStrategy": "The routing configuration, including routing type and fleet target, for the alias." } }, "AWS::GameLift::Alias.RoutingStrategy": { @@ -17487,47 +17963,47 @@ }, "AWS::GameLift::Fleet": { "attributes": { - "FleetId": "", + "FleetId": "A unique identifier for the fleet.", "Ref": "`Ref` returns the fleet ID, such as `fleet-1111aaaa-22bb-33cc-44dd-5555eeee66ff` ." }, "description": "The `AWS::GameLift::Fleet` resource creates an Amazon GameLift (GameLift) fleet to host game servers. A fleet is a set of EC2 instances, each of which can host multiple game sessions.", "properties": { "BuildId": "A unique identifier for a build to be deployed on the new fleet. If you are deploying the fleet with a custom game build, you must specify this property. The build must have been successfully uploaded to Amazon GameLift and be in a `READY` status. This fleet setting cannot be changed once the fleet is created.", - "CertificateConfiguration": "Indicates whether to generate a TLS/SSL certificate for the new fleet. TLS certificates are used for encrypting traffic between game clients and game servers running on GameLift. If this parameter is not set, certificate generation is disabled. This fleet setting cannot be changed once the fleet is created. Learn more at [Securing Client/Server Communication](https://docs.aws.amazon.com/gamelift/latest/developerguide/gamelift-howitworks.html#gamelift-howitworks-security) .\n\nNote: This feature requires the AWS Certificate Manager service, which is available in the AWS global partition but not in all other partitions. When working in a partition that does not support this feature, a request for a new fleet with certificate generation results fails with a 4xx unsupported region error.", + "CertificateConfiguration": "Prompts GameLift to generate a TLS/SSL certificate for the fleet. TLS certificates are used for encrypting traffic between game clients and the game servers that are running on GameLift. By default, the `CertificateConfiguration` is set to `DISABLED` . This property cannot be changed after the fleet is created.\n\nNote: This feature requires the AWS Certificate Manager (ACM) service, which is not available in all AWS regions. When working in a region that does not support this feature, a fleet creation request with certificate generation fails with a 4xx error.", "Description": "A human-readable description of the fleet.", "DesiredEC2Instances": "The number of EC2 instances that you want this fleet to host. When creating a new fleet, GameLift automatically sets this value to \"1\" and initiates a single instance. Once the fleet is active, update this value to trigger GameLift to add or remove instances from the fleet.", - "EC2InboundPermissions": "A range of IP addresses and port settings that allow inbound traffic to connect to server processes on an Amazon GameLift server.", + "EC2InboundPermissions": "The allowed IP address ranges and port settings that allow inbound traffic to access game sessions on this fleet. If the fleet is hosting a custom game build, this property must be set before players can connect to game sessions. For Realtime Servers fleets, GameLift automatically sets TCP and UDP ranges.", "EC2InstanceType": "The GameLift-supported Amazon EC2 instance type to use for all fleet instances. Instance type determines the computing resources that will be used to host your game servers, including CPU, memory, storage, and networking capacity. See [Amazon Elastic Compute Cloud Instance Types](https://docs.aws.amazon.com/ec2/instance-types/) for detailed descriptions of Amazon EC2 instance types.", "FleetType": "Indicates whether to use On-Demand or Spot instances for this fleet. By default, this property is set to `ON_DEMAND` . Learn more about when to use [On-Demand versus Spot Instances](https://docs.aws.amazon.com/gamelift/latest/developerguide/gamelift-ec2-instances.html#gamelift-ec2-instances-spot) . This property cannot be changed after the fleet is created.", "InstanceRoleARN": "A unique identifier for an IAM role that manages access to your AWS services. With an instance role ARN set, any application that runs on an instance in this fleet can assume the role, including install scripts, server processes, and daemons (background processes). Create a role or look up a role's ARN by using the [IAM dashboard](https://docs.aws.amazon.com/iam/) in the AWS Management Console . Learn more about using on-box credentials for your game servers at [Access external resources from a game server](https://docs.aws.amazon.com/gamelift/latest/developerguide/gamelift-sdk-server-resources.html) . This property cannot be changed after the fleet is created.", "Locations": "A set of remote locations to deploy additional instances to and manage as part of the fleet. This parameter can only be used when creating fleets in AWS Regions that support multiple locations. You can add any GameLift-supported AWS Region as a remote location, in the form of an AWS Region code such as `us-west-2` . To create a fleet with instances in the home Region only, omit this parameter.", - "MaxSize": "The maximum value that is allowed for the fleet's instance count. When creating a new fleet, GameLift automatically sets this value to \"1\". Once the fleet is active, you can change this value.", - "MetricGroups": "The name of an Amazon CloudWatch metric group. A metric group aggregates the metrics for all fleets in the group. Specify a string containing the metric group name. You can use an existing name or use a new name to create a new metric group. Currently, this parameter can have only one string.", - "MinSize": "The minimum value allowed for the fleet's instance count. When creating a new fleet, GameLift automatically sets this value to \"0\". After the fleet is active, you can change this value.", + "MaxSize": "The maximum number of instances that are allowed in the specified fleet location. If this parameter is not set, the default is 1.", + "MetricGroups": "The name of an AWS CloudWatch metric group to add this fleet to. A metric group is used to aggregate the metrics for multiple fleets. You can specify an existing metric group name or set a new name to create a new metric group. A fleet can be included in only one metric group at a time.", + "MinSize": "The minimum number of instances that are allowed in the specified fleet location. If this parameter is not set, the default is 0.", "Name": "A descriptive label that is associated with a fleet. Fleet names do not need to be unique.", - "NewGameSessionProtectionPolicy": "A game session protection policy to apply to all game sessions hosted on instances in this fleet. When protected, active game sessions cannot be terminated during a scale-down event. If this parameter is not set, instances in this fleet default to no protection. You can change a fleet's protection policy to affect future game sessions on the fleet. You can also set protection for individual game sessions.", + "NewGameSessionProtectionPolicy": "The status of termination protection for active game sessions on the fleet. By default, this property is set to `NoProtection` .\n\n- *NoProtection* - Game sessions can be terminated during active gameplay as a result of a scale-down event.\n- *FullProtection* - Game sessions in `ACTIVE` status cannot be terminated during a scale-down event.", "PeerVpcAwsAccountId": "Used when peering your GameLift fleet with a VPC, the unique identifier for the AWS account that owns the VPC. You can find your account ID in the AWS Management Console under account settings.", "PeerVpcId": "A unique identifier for a VPC with resources to be accessed by your GameLift fleet. The VPC must be in the same Region as your fleet. To look up a VPC ID, use the [VPC Dashboard](https://docs.aws.amazon.com/vpc/) in the AWS Management Console . Learn more about VPC peering in [VPC Peering with GameLift Fleets](https://docs.aws.amazon.com/gamelift/latest/developerguide/vpc-peering.html) .", "ResourceCreationLimitPolicy": "A policy that limits the number of game sessions that an individual player can create on instances in this fleet within a specified span of time.", - "RuntimeConfiguration": "Instructions for launching server processes on each instance in the fleet. Server processes run either a custom game build executable or a Realtime script. The runtime configuration defines the server executables or launch script file, launch parameters, and the number of processes to run concurrently on each instance. When creating a fleet, the runtime configuration must have at least one server process configuration; otherwise the request fails with an invalid request exception.\n\nThis parameter is required unless the parameters `ServerLaunchPath` and `ServerLaunchParameters` are defined. Runtime configuration has replaced these parameters, but fleets that use them will continue to work.", - "ScriptId": "A unique identifier for a Realtime script to be deployed on a new Realtime Servers fleet. The script must have been successfully uploaded to Amazon GameLift. This fleet setting cannot be changed once the fleet is created.\n\nNote: It is not currently possible to use the `!Ref` command to reference a script created with a CloudFormation template for the fleet property `ScriptId` . Instead, use `Fn::GetAtt Script.Arn` or `Fn::GetAtt Script.Id` to retrieve either of these properties as input for `ScriptId` . Alternatively, enter a `ScriptId` string manually." + "RuntimeConfiguration": "Instructions for how to launch and maintain server processes on instances in the fleet. The runtime configuration defines one or more server process configurations, each identifying a build executable or Realtime script file and the number of processes of that type to run concurrently.\n\n> The `RuntimeConfiguration` parameter is required unless the fleet is being configured using the older parameters `ServerLaunchPath` and `ServerLaunchParameters` , which are still supported for backward compatibility.", + "ScriptId": "The unique identifier for a Realtime configuration script to be deployed on fleet instances. You can use either the script ID or ARN. Scripts must be uploaded to GameLift prior to creating the fleet. This fleet property cannot be changed later.\n\n> You can't use the `!Ref` command to reference a script created with a CloudFormation template for the fleet property `ScriptId` . Instead, use `Fn::GetAtt Script.Arn` or `Fn::GetAtt Script.Id` to retrieve either of these properties as input for `ScriptId` . Alternatively, enter a `ScriptId` string manually." } }, "AWS::GameLift::Fleet.CertificateConfiguration": { "attributes": {}, - "description": "Information about the use of a TLS/SSL certificate for a fleet. TLS certificate generation is enabled at the fleet level, with one certificate generated for the fleet. When this feature is enabled, the certificate can be retrieved using the GameLift Server SDK call `GetInstanceCertificate` . All instances in a fleet share the same certificate.", + "description": "Determines whether a TLS/SSL certificate is generated for a fleet. This feature must be enabled when creating the fleet. All instances in a fleet share the same certificate. The certificate can be retrieved by calling the [GameLift Server SDK](https://docs.aws.amazon.com/gamelift/latest/developerguide/reference-serversdk.html) operation `GetInstanceCertificate` .", "properties": { - "CertificateType": "Indicates whether a TLS/SSL certificate is generated for the fleet." + "CertificateType": "Indicates whether a TLS/SSL certificate is generated for a fleet.\n\nValid values include:\n\n- *GENERATED* - Generate a TLS/SSL certificate for this fleet.\n- *DISABLED* - (default) Do not generate a TLS/SSL certificate for this fleet." } }, "AWS::GameLift::Fleet.IpPermission": { "attributes": {}, - "description": "A range of IP addresses and port settings that allow inbound traffic to connect to server processes on an Amazon GameLift hosting resource. New game sessions that are started on the fleet are assigned an IP address/port number combination, which must fall into the fleet's allowed ranges. For fleets created with a custom game server, the ranges reflect the server's game session assignments. For Realtime Servers fleets, Amazon GameLift automatically opens two port ranges, one for TCP messaging and one for UDP, for use by the Realtime servers.", + "description": "A range of IP addresses and port settings that allow inbound traffic to connect to server processes on an instance in a fleet. New game sessions are assigned an IP address/port number combination, which must fall into the fleet's allowed ranges. Fleets with custom game builds must have permissions explicitly set. For Realtime Servers fleets, GameLift automatically opens two port ranges, one for TCP messaging and one for UDP.", "properties": { - "FromPort": "A starting value for a range of allowed port numbers.\n\nFor fleets using Linux builds, only port 22, 443, 1026-60000 are valid. For fleets using Windows builds, only port 443, 1026-60000 are valid.", + "FromPort": "A starting value for a range of allowed port numbers.\n\nFor fleets using Windows and Linux builds, only ports 1026-60000 are valid.", "IpRange": "A range of allowed IP addresses. This value must be expressed in CIDR notation. Example: \" `000.000.000.000/[subnet mask]` \" or optionally the shortened version \" `0.0.0.0/[subnet mask]` \".", "Protocol": "The network communication protocol used by the fleet.", - "ToPort": "An ending value for a range of allowed port numbers. Port numbers are end-inclusive. This value must be higher than `FromPort` .\n\nFor fleets using Linux builds, only port 22, 443, 1026-60000 are valid. For fleets using Windows builds, only port 443, 1026-60000 are valid." + "ToPort": "An ending value for a range of allowed port numbers. Port numbers are end-inclusive. This value must be higher than `FromPort` .\n\nFor fleets using Windows and Linux builds, only ports 1026-60000 are valid." } }, "AWS::GameLift::Fleet.LocationCapacity": { @@ -17557,7 +18033,7 @@ }, "AWS::GameLift::Fleet.RuntimeConfiguration": { "attributes": {}, - "description": "A collection of server process configurations that describe the processes to run on each instance in a fleet. All fleets must have a runtime configuration. Each instance in the fleet maintains server processes as specified in the runtime configuration, launching new ones as existing processes end. Each instance regularly checks for an updated runtime configuration makes adjustments as called for.\n\nThe runtime configuration enables the instances in a fleet to run multiple processes simultaneously. Potential scenarios are as follows: (1) Run multiple processes of a single game server executable to maximize usage of your hosting resources. (2) Run one or more processes of different executables, such as your game server and a metrics tracking program. (3) Run multiple processes of a single game server but with different launch parameters, for example to run one process on each instance in debug mode.\n\nAn Amazon GameLift instance is limited to 50 processes running simultaneously. A runtime configuration must specify fewer than this limit. To calculate the total number of processes specified in a runtime configuration, add the values of the `ConcurrentExecutions` parameter for each `ServerProcess` object in the runtime configuration.", + "description": "A collection of server process configurations that describe the set of processes to run on each instance in a fleet. Server processes run either an executable in a custom game build or a Realtime Servers script. GameLift launches the configured processes, manages their life cycle, and replaces them as needed. Each instance checks regularly for an updated runtime configuration.\n\nA GameLift instance is limited to 50 processes running concurrently. To calculate the total number of processes in a runtime configuration, add the values of the `ConcurrentExecutions` parameter for each ServerProcess. Learn more about [Running Multiple Processes on a Fleet](https://docs.aws.amazon.com/gamelift/latest/developerguide/fleets-multiprocess.html) .", "properties": { "GameSessionActivationTimeoutSeconds": "The maximum amount of time (in seconds) allowed to launch a new game session and have it report ready to host players. During this time, the game session is in status `ACTIVATING` . If the game session does not become active before the timeout, it is ended and the game session status is changed to `TERMINATED` .", "MaxConcurrentGameSessionActivations": "The number of game sessions in status `ACTIVATING` to allow on an instance. This setting limits the instance resources that can be used for new game activations at any one time.", @@ -17566,7 +18042,7 @@ }, "AWS::GameLift::Fleet.ServerProcess": { "attributes": {}, - "description": "A set of instructions for launching server processes on each instance in a fleet. Each instruction set identifies the location of the server executable, optional launch parameters, and the number of server processes with this configuration to maintain concurrently on the instance. Server process configurations make up a fleet's `RuntimeConfiguration` .", + "description": "A set of instructions for launching server processes on each instance in a fleet. Server processes run either an executable in a custom game build or a Realtime Servers script.", "properties": { "ConcurrentExecutions": "The number of server processes using this configuration that run concurrently on each instance.", "LaunchPath": "The location of a game build executable or the Realtime script file that contains the `Init()` function. Game builds and Realtime scripts are installed on instances at the root:\n\n- Windows (custom game builds only): `C:\\game` . Example: \" `C:\\game\\MyGame\\server.exe` \"\n- Linux: `/local/game` . Examples: \" `/local/game/MyGame/server.exe` \" or \" `/local/game/MyRealtimeScript.js` \"", @@ -17575,32 +18051,32 @@ }, "AWS::GameLift::GameServerGroup": { "attributes": { - "AutoScalingGroupArn": "", - "GameServerGroupArn": "", + "AutoScalingGroupArn": "A unique identifier for the auto scaling group.", + "GameServerGroupArn": "A unique identifier for the game server group.", "Ref": "" }, "description": "*This operation is used with the Amazon GameLift FleetIQ solution and game server groups.*\n\nCreates a GameLift FleetIQ game server group for managing game hosting on a collection of Amazon EC2 instances for game hosting. This operation creates the game server group, creates an Auto Scaling group in your AWS account , and establishes a link between the two groups. You can view the status of your game server groups in the GameLift console. Game server group metrics and events are emitted to Amazon CloudWatch.\n\nBefore creating a new game server group, you must have the following:\n\n- An Amazon EC2 launch template that specifies how to launch Amazon EC2 instances with your game server build. For more information, see [Launching an Instance from a Launch Template](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-templates.html) in the *Amazon EC2 User Guide* .\n- An IAM role that extends limited access to your AWS account to allow GameLift FleetIQ to create and interact with the Auto Scaling group. For more information, see [Create IAM roles for cross-service interaction](https://docs.aws.amazon.com/gamelift/latest/fleetiqguide/gsg-iam-permissions-roles.html) in the *GameLift FleetIQ Developer Guide* .\n\nTo create a new game server group, specify a unique group name, IAM role and Amazon EC2 launch template, and provide a list of instance types that can be used in the group. You must also set initial maximum and minimum limits on the group's instance count. You can optionally set an Auto Scaling policy with target tracking based on a GameLift FleetIQ metric.\n\nOnce the game server group and corresponding Auto Scaling group are created, you have full access to change the Auto Scaling group's configuration as needed. Several properties that are set when creating a game server group, including maximum/minimum size and auto-scaling policy settings, must be updated directly in the Auto Scaling group. Keep in mind that some Auto Scaling group properties are periodically updated by GameLift FleetIQ as part of its balancing activities to optimize for availability and cost.\n\n*Learn more*\n\n[GameLift FleetIQ Guide](https://docs.aws.amazon.com/gamelift/latest/fleetiqguide/gsg-intro.html)", "properties": { - "AutoScalingPolicy": "", + "AutoScalingPolicy": "Configuration settings to define a scaling policy for the Auto Scaling group that is optimized for game hosting. The scaling policy uses the metric `\"PercentUtilizedGameServers\"` to maintain a buffer of idle game servers that can immediately accommodate new games and players. After the Auto Scaling group is created, update this value directly in the Auto Scaling group using the AWS console or APIs.", "BalancingStrategy": "Indicates how GameLift FleetIQ balances the use of Spot Instances and On-Demand Instances in the game server group. Method options include the following:\n\n- `SPOT_ONLY` - Only Spot Instances are used in the game server group. If Spot Instances are unavailable or not viable for game hosting, the game server group provides no hosting capacity until Spot Instances can again be used. Until then, no new instances are started, and the existing nonviable Spot Instances are terminated (after current gameplay ends) and are not replaced.\n- `SPOT_PREFERRED` - (default value) Spot Instances are used whenever available in the game server group. If Spot Instances are unavailable, the game server group continues to provide hosting capacity by falling back to On-Demand Instances. Existing nonviable Spot Instances are terminated (after current gameplay ends) and are replaced with new On-Demand Instances.\n- `ON_DEMAND_ONLY` - Only On-Demand Instances are used in the game server group. No Spot Instances are used, even when available, while this balancing strategy is in force.", - "DeleteOption": "", + "DeleteOption": "The type of delete to perform. To delete a game server group, specify the `DeleteOption` . Options include the following:\n\n- `SAFE_DELETE` \u2013 (default) Terminates the game server group and Amazon EC2 Auto Scaling group only when it has no game servers that are in `UTILIZED` status.\n- `FORCE_DELETE` \u2013 Terminates the game server group, including all active game servers regardless of their utilization status, and the Amazon EC2 Auto Scaling group.\n- `RETAIN` \u2013 Does a safe delete of the game server group but retains the Amazon EC2 Auto Scaling group as is.", "GameServerGroupName": "A developer-defined identifier for the game server group. The name is unique for each Region in each AWS account.", "GameServerProtectionPolicy": "A flag that indicates whether instances in the game server group are protected from early termination. Unprotected instances that have active game servers running might be terminated during a scale-down event, causing players to be dropped from the game. Protected instances cannot be terminated while there are active game servers running except in the event of a forced game server group deletion (see ). An exception to this is with Spot Instances, which can be terminated by AWS regardless of protection status.", "InstanceDefinitions": "The set of Amazon EC2 instance types that GameLift FleetIQ can use when balancing and automatically scaling instances in the corresponding Auto Scaling group.", - "LaunchTemplate": "", - "MaxSize": "", - "MinSize": "", + "LaunchTemplate": "The Amazon EC2 launch template that contains configuration settings and game server code to be deployed to all instances in the game server group. You can specify the template using either the template name or ID. For help with creating a launch template, see [Creating a Launch Template for an Auto Scaling Group](https://docs.aws.amazon.com/autoscaling/ec2/userguide/create-launch-template.html) in the *Amazon Elastic Compute Cloud Auto Scaling User Guide* . After the Auto Scaling group is created, update this value directly in the Auto Scaling group using the AWS console or APIs.\n\n> If you specify network interfaces in your launch template, you must explicitly set the property `AssociatePublicIpAddress` to \"true\". If no network interface is specified in the launch template, GameLift FleetIQ uses your account's default VPC.", + "MaxSize": "The maximum number of instances allowed in the Amazon EC2 Auto Scaling group. During automatic scaling events, GameLift FleetIQ and EC2 do not scale up the group above this maximum. After the Auto Scaling group is created, update this value directly in the Auto Scaling group using the AWS console or APIs.", + "MinSize": "The minimum number of instances allowed in the Amazon EC2 Auto Scaling group. During automatic scaling events, GameLift FleetIQ and Amazon EC2 do not scale down the group below this minimum. In production, this value should be set to at least 1. After the Auto Scaling group is created, update this value directly in the Auto Scaling group using the AWS console or APIs.", "RoleArn": "The Amazon Resource Name ( [ARN](https://docs.aws.amazon.com/AmazonS3/latest/dev/s3-arn-format.html) ) for an IAM role that allows Amazon Web Services to access your Amazon EC2 Auto Scaling groups.", - "Tags": "", - "VpcSubnets": "" + "Tags": "A list of labels to assign to the new game server group resource. Tags are developer-defined key-value pairs. Tagging AWS resources is useful for resource management, access management, and cost allocation. For more information, see [Tagging AWS Resources](https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html) in the *AWS General Reference* . Once the resource is created, you can use TagResource, UntagResource, and ListTagsForResource to add, remove, and view tags, respectively. The maximum tag limit may be lower than stated. See the AWS General Reference for actual tagging limits.", + "VpcSubnets": "A list of virtual private cloud (VPC) subnets to use with instances in the game server group. By default, all GameLift FleetIQ-supported Availability Zones are used. You can use this parameter to specify VPCs that you've set up. This property cannot be updated after the game server group is created, and the corresponding Auto Scaling group will always use the property value that is set with this request, even if the Auto Scaling group is updated directly." } }, "AWS::GameLift::GameServerGroup.AutoScalingPolicy": { "attributes": {}, - "description": "", + "description": "*This data type is used with the GameLift FleetIQ and game server groups.*\n\nConfiguration settings for intelligent automatic scaling that uses target tracking. After the Auto Scaling group is created, all updates to Auto Scaling policies, including changing this policy and adding or removing other policies, is done directly on the Auto Scaling group.", "properties": { - "EstimatedInstanceWarmup": "", - "TargetTrackingConfiguration": "" + "EstimatedInstanceWarmup": "Length of time, in seconds, it takes for a new instance to start new game server processes and register with GameLift FleetIQ. Specifying a warm-up time can be useful, particularly with game servers that take a long time to start up, because it avoids prematurely starting new instances.", + "TargetTrackingConfiguration": "Settings for a target-based scaling policy applied to Auto Scaling group. These settings are used to create a target-based policy that tracks the GameLift FleetIQ metric `PercentUtilizedGameServers` and specifies a target value for the metric. As player usage changes, the policy triggers to adjust the game server group capacity so that the metric returns to the target value." } }, "AWS::GameLift::GameServerGroup.InstanceDefinition": { @@ -17613,11 +18089,11 @@ }, "AWS::GameLift::GameServerGroup.LaunchTemplate": { "attributes": {}, - "description": "", + "description": "*This data type is used with the GameLift FleetIQ and game server groups.*\n\nAn Amazon EC2 launch template that contains configuration settings and game server code to be deployed to all instances in a game server group. The launch template is specified when creating a new game server group with `GameServerGroup` .", "properties": { - "LaunchTemplateId": "", - "LaunchTemplateName": "", - "Version": "" + "LaunchTemplateId": "A unique identifier for an existing Amazon EC2 launch template.", + "LaunchTemplateName": "A readable identifier for an existing Amazon EC2 launch template.", + "Version": "The version of the Amazon EC2 launch template to use. If no version is specified, the default version will be used. With Amazon EC2, you can specify a default version for a launch template. If none is set, the default is the first version created." } }, "AWS::GameLift::GameServerGroup.TargetTrackingConfiguration": { @@ -17642,20 +18118,20 @@ "NotificationTarget": "An SNS topic ARN that is set up to receive game session placement notifications. See [Setting up notifications for game session placement](https://docs.aws.amazon.com/gamelift/latest/developerguide/queue-notification.html) .", "PlayerLatencyPolicies": "A set of policies that act as a sliding cap on player latency. FleetIQ works to deliver low latency for most players in a game session. These policies ensure that no individual player can be placed into a game with unreasonably high latency. Use multiple policies to gradually relax latency requirements a step at a time. Multiple policies are applied based on their maximum allowed latency, starting with the lowest value.", "PriorityConfiguration": "Custom settings to use when prioritizing destinations and locations for game session placements. This configuration replaces the FleetIQ default prioritization process. Priority types that are not explicitly named will be automatically applied at the end of the prioritization process.", - "Tags": "A list of labels to assign to the new game session queue resource. Tags are developer-defined key-value pairs. Tagging AWS resources are useful for resource management, access management and cost allocation. For more information, see [Tagging AWS Resources](https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html) in the *AWS General Reference* . Once the resource is created, you can use `TagResource` , `UntagResource` , and `ListTagsForResource` to add, remove, and view tags. The maximum tag limit may be lower than stated. See the AWS General Reference for actual tagging limits.", + "Tags": "A list of labels to assign to the new game session queue resource. Tags are developer-defined key-value pairs. Tagging AWS resources are useful for resource management, access management and cost allocation. For more information, see [Tagging AWS Resources](https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html) in the *AWS General Reference* . Once the resource is created, you can use TagResource, UntagResource, and ListTagsForResource to add, remove, and view tags. The maximum tag limit may be lower than stated. See the AWS General Reference for actual tagging limits.", "TimeoutInSeconds": "The maximum time, in seconds, that a new game session placement request remains in the queue. When a request exceeds this time, the game session placement changes to a `TIMED_OUT` status." } }, "AWS::GameLift::GameSessionQueue.Destination": { "attributes": {}, - "description": "The fleet designated in a game session queue. Requests for new game sessions in the queue are fulfilled by starting a new game session on any destination that is configured for a queue.", + "description": "A fleet or alias designated in a game session queue. Queues fulfill requests for new game sessions by placing a new game session on any of the queue's destinations.", "properties": { "DestinationArn": "The Amazon Resource Name (ARN) that is assigned to fleet or fleet alias. ARNs, which include a fleet ID or alias ID and a Region name, provide a unique identifier across all Regions." } }, "AWS::GameLift::GameSessionQueue.FilterConfiguration": { "attributes": {}, - "description": "A list of fleet locations where a game session queue can place new game sessions. You can use a filter to temporarily turn off placements for specific locations. For queues that have multi-location fleets, you can use a filter configuration allow placement with some, but not all of these locations.\n\nFilter configurations are part of a `GameSessionQueue` .", + "description": "A list of fleet locations where a game session queue can place new game sessions. You can use a filter to temporarily turn off placements for specific locations. For queues that have multi-location fleets, you can use a filter configuration allow placement with some, but not all of these locations.", "properties": { "AllowedLocations": "A list of locations to allow game session placement in, in the form of AWS Region codes such as `us-west-2` ." } @@ -17670,7 +18146,7 @@ }, "AWS::GameLift::GameSessionQueue.PriorityConfiguration": { "attributes": {}, - "description": "Custom prioritization settings for use by a game session queue when placing new game sessions with available game servers. When defined, this configuration replaces the default FleetIQ prioritization process, which is as follows:\n\n- If player latency data is included in a game session request, destinations and locations are prioritized first based on lowest average latency (1), then on lowest hosting cost (2), then on destination list order (3), and finally on location (alphabetical) (4). This approach ensures that the queue's top priority is to place game sessions where average player latency is lowest, and--if latency is the same--where the hosting cost is less, etc.\n- If player latency data is not included, destinations and locations are prioritized first on destination list order (1), and then on location (alphabetical) (2). This approach ensures that the queue's top priority is to place game sessions on the first destination fleet listed. If that fleet has multiple locations, the game session is placed on the first location (when listed alphabetically).\n\nChanging the priority order will affect how game sessions are placed.\n\nPriority configurations are part of a `GameSessionQueue` .", + "description": "Custom prioritization settings for use by a game session queue when placing new game sessions with available game servers. When defined, this configuration replaces the default FleetIQ prioritization process, which is as follows:\n\n- If player latency data is included in a game session request, destinations and locations are prioritized first based on lowest average latency (1), then on lowest hosting cost (2), then on destination list order (3), and finally on location (alphabetical) (4). This approach ensures that the queue's top priority is to place game sessions where average player latency is lowest, and--if latency is the same--where the hosting cost is less, etc.\n- If player latency data is not included, destinations and locations are prioritized first on destination list order (1), and then on location (alphabetical) (2). This approach ensures that the queue's top priority is to place game sessions on the first destination fleet listed. If that fleet has multiple locations, the game session is placed on the first location (when listed alphabetically).\n\nChanging the priority order will affect how game sessions are placed.", "properties": { "LocationOrder": "The prioritization order to use for fleet locations, when the `PriorityOrder` property includes `LOCATION` . Locations are identified by AWS Region codes such as `us-west-2` . Each location can only be listed once.", "PriorityOrder": "The recommended sequence to use when prioritizing where to place new game sessions. Each type can only be listed once.\n\n- `LATENCY` -- FleetIQ prioritizes locations where the average player latency (provided in each game session request) is lowest.\n- `COST` -- FleetIQ prioritizes destinations with the lowest current hosting costs. Cost is evaluated based on the location, instance type, and fleet type (Spot or On-Demand) for each destination in the queue.\n- `DESTINATION` -- FleetIQ prioritizes based on the order that destinations are listed in the queue configuration.\n- `LOCATION` -- FleetIQ prioritizes based on the provided order of locations, as defined in `LocationOrder` ." @@ -17688,22 +18164,22 @@ "AcceptanceTimeoutSeconds": "The length of time (in seconds) to wait for players to accept a proposed match, if acceptance is required.", "AdditionalPlayerCount": "The number of player slots in a match to keep open for future players. For example, if the configuration's rule set specifies a match for a single 12-person team, and the additional player count is set to 2, only 10 players are selected for the match. This parameter is not used if `FlexMatchMode` is set to `STANDALONE` .", "BackfillMode": "The method used to backfill game sessions that are created with this matchmaking configuration. Specify `MANUAL` when your game manages backfill requests manually or does not use the match backfill feature. Specify `AUTOMATIC` to have GameLift create a `StartMatchBackfill` request whenever a game session has one or more open slots. Learn more about manual and automatic backfill in [Backfill Existing Games with FlexMatch](https://docs.aws.amazon.com/gamelift/latest/flexmatchguide/match-backfill.html) . Automatic backfill is not available when `FlexMatchMode` is set to `STANDALONE` .", - "CustomEventData": "Information that is attached to all events related to the matchmaking configuration.", + "CustomEventData": "Information to add to all events related to the matchmaking configuration.", "Description": "A descriptive label that is associated with matchmaking configuration.", - "FlexMatchMode": "Indicates whether this matchmaking configuration is being used with GameLift managed hosting or as a standalone matchmaking solution.\n\n- *STANDALONE* - FlexMatch forms matches and returns match information, including players and team assignments, in a [MatchmakingSucceeded](https://docs.aws.amazon.com/gamelift/latest/flexmatchguide/match-events.html#match-events-matchmakingsucceeded) event.\n- *WITH_QUEUE* - FlexMatch forms matches and uses the specified GameLift queue to start a game session for the match.", + "FlexMatchMode": "Indicates whether this matchmaking configuration is being used with GameLift hosting or as a standalone matchmaking solution.\n\n- *STANDALONE* - FlexMatch forms matches and returns match information, including players and team assignments, in a [MatchmakingSucceeded](https://docs.aws.amazon.com/gamelift/latest/flexmatchguide/match-events.html#match-events-matchmakingsucceeded) event.\n- *WITH_QUEUE* - FlexMatch forms matches and uses the specified GameLift queue to start a game session for the match.", "GameProperties": "A set of custom properties for a game session, formatted as key-value pairs. These properties are passed to a game server process with a request to start a new game session. See [Start a Game Session](https://docs.aws.amazon.com/gamelift/latest/developerguide/gamelift-sdk-server-api.html#gamelift-sdk-server-startsession) . This parameter is not used if `FlexMatchMode` is set to `STANDALONE` .", "GameSessionData": "A set of custom game session properties, formatted as a single string value. This data is passed to a game server process with a request to start a new game session. See [Start a Game Session](https://docs.aws.amazon.com/gamelift/latest/developerguide/gamelift-sdk-server-api.html#gamelift-sdk-server-startsession) . This parameter is not used if `FlexMatchMode` is set to `STANDALONE` .", "GameSessionQueueArns": "The Amazon Resource Name ( [ARN](https://docs.aws.amazon.com/AmazonS3/latest/dev/s3-arn-format.html) ) that is assigned to a GameLift game session queue resource and uniquely identifies it. ARNs are unique across all Regions. Format is `arn:aws:gamelift:::gamesessionqueue/` . Queues can be located in any Region. Queues are used to start new GameLift-hosted game sessions for matches that are created with this matchmaking configuration. If `FlexMatchMode` is set to `STANDALONE` , do not set this parameter.", - "Name": "A unique identifier for a matchmaking configuration. Matchmaking requests use this name to identify which matchmaking configuration to use.", + "Name": "A unique identifier for the matchmaking configuration. This name is used to identify the configuration associated with a matchmaking request or ticket.", "NotificationTarget": "An SNS topic ARN that is set up to receive matchmaking notifications. See [Setting up notifications for matchmaking](https://docs.aws.amazon.com/gamelift/latest/flexmatchguide/match-notification.html) for more information.", "RequestTimeoutSeconds": "The maximum duration, in seconds, that a matchmaking ticket can remain in process before timing out. Requests that fail due to timing out can be resubmitted as needed.", "RuleSetName": "A unique identifier for the matchmaking rule set to use with this configuration. You can use either the rule set name or ARN value. A matchmaking configuration can only use rule sets that are defined in the same Region.", - "Tags": "A list of labels to assign to the new matchmaking configuration resource. Tags are developer-defined key-value pairs. Tagging AWS resources are useful for resource management, access management and cost allocation. For more information, see [Tagging AWS Resources](https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html) in the *AWS General Reference* . Once the resource is created, you can use `TagResource` , `UntagResource` , and `ListTagsForResource` to add, remove, and view tags. The maximum tag limit may be lower than stated. See the AWS General Reference for actual tagging limits." + "Tags": "A list of labels to assign to the new matchmaking configuration resource. Tags are developer-defined key-value pairs. Tagging AWS resources are useful for resource management, access management and cost allocation. For more information, see [Tagging AWS Resources](https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html) in the *AWS General Reference* . Once the resource is created, you can use TagResource, UntagResource, and ListTagsForResource to add, remove, and view tags. The maximum tag limit may be lower than stated. See the AWS General Reference for actual tagging limits." } }, "AWS::GameLift::MatchmakingConfiguration.GameProperty": { "attributes": {}, - "description": "A set of key-value pairs that contain information about a game session. When included in a game session request, these properties communicate details to be used when setting up the new game session. For example, a property might specify a game mode, level, or map. Game properties are passed to the game server process when initiating a new game session.", + "description": "Set of key-value pairs that contain information about a game session. When included in a game session request, these properties communicate details to be used when setting up the new game session. For example, a game property might specify a game mode, level, or map. Game properties are passed to the game server process when initiating a new game session. For more information, see the [GameLift Developer Guide](https://docs.aws.amazon.com/gamelift/latest/developerguide/gamelift-sdk-client-api.html#gamelift-sdk-client-api-create) .", "properties": { "Key": "The game property identifier.", "Value": "The game property value." @@ -17715,11 +18191,11 @@ "Name": "The unique name of the rule set.", "Ref": "`Ref` returns the rule set name, which is unique within each Region." }, - "description": "The `AWS::GameLift::MatchmakingRuleSet` resource creates a new rule set for FlexMatch matchmaking. A rule set describes the type of match to create, such as the number and size of teams. It also sets the parameters for acceptable player matches, such as minimum skill level or character type. A rule set is used by a matchmaking configuration.", + "description": "Creates a new rule set for FlexMatch matchmaking. A rule set describes the type of match to create, such as the number and size of teams. It also sets the parameters for acceptable player matches, such as minimum skill level or character type.\n\nTo create a matchmaking rule set, provide unique rule set name and the rule set body in JSON format. Rule sets must be defined in the same Region as the matchmaking configuration they are used with.\n\nSince matchmaking rule sets cannot be edited, it is a good idea to check the rule set syntax.\n\n*Learn more*\n\n- [Build a rule set](https://docs.aws.amazon.com/gamelift/latest/flexmatchguide/match-rulesets.html)\n- [Design a matchmaker](https://docs.aws.amazon.com/gamelift/latest/flexmatchguide/match-configuration.html)\n- [Matchmaking with FlexMatch](https://docs.aws.amazon.com/gamelift/latest/flexmatchguide/match-intro.html)", "properties": { "Name": "A unique identifier for the matchmaking rule set. A matchmaking configuration identifies the rule set it uses by this name value. Note that the rule set name is different from the optional `name` field in the rule set body.", "RuleSetBody": "A collection of matchmaking rules, formatted as a JSON string. Comments are not allowed in JSON, but most elements support a description field.", - "Tags": "A list of labels to assign to the new matchmaking rule set resource. Tags are developer-defined key-value pairs. Tagging AWS resources are useful for resource management, access management and cost allocation. For more information, see [Tagging AWS Resources](https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html) in the *AWS General Reference* . Once the resource is created, you can use `TagResource` , `UntagResource` , and `ListTagsForResource` to add, remove, and view tags. The maximum tag limit may be lower than stated. See the AWS General Reference for actual tagging limits." + "Tags": "A list of labels to assign to the new matchmaking rule set resource. Tags are developer-defined key-value pairs. Tagging AWS resources are useful for resource management, access management and cost allocation. For more information, see [Tagging AWS Resources](https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html) in the *AWS General Reference* . Once the resource is created, you can use TagResource, UntagResource, and ListTagsForResource to add, remove, and view tags. The maximum tag limit may be lower than stated. See the AWS General Reference for actual tagging limits." } }, "AWS::GameLift::Script": { @@ -17731,8 +18207,8 @@ "description": "The `AWS::GameLift::Script` resource creates a new script record for your Realtime Servers script. Realtime scripts are JavaScript that provide configuration settings and optional custom game logic for your game. The script is deployed when you create a Realtime Servers fleet to host your game sessions. Script logic is executed during an active game session.", "properties": { "Name": "A descriptive label that is associated with a script. Script names do not need to be unique.", - "StorageLocation": "The location in Amazon S3 where build or script files are stored for access by Amazon GameLift.", - "Tags": "", + "StorageLocation": "The location of the Amazon S3 bucket where a zipped file containing your Realtime scripts is stored. The storage location must specify the Amazon S3 bucket name, the zip file name (the \"key\"), and a role ARN that allows Amazon Web Services to access the Amazon S3 storage location. The S3 bucket must be in the same Region where you want to create a new script. By default, Amazon Web Services uploads the latest version of the zip file; if you have S3 object versioning turned on, you can use the `ObjectVersion` parameter to specify an earlier version.", + "Tags": "A list of labels to assign to the new script resource. Tags are developer-defined key-value pairs. Tagging AWS resources are useful for resource management, access management and cost allocation. For more information, see [Tagging AWS Resources](https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html) in the *AWS General Reference* . Once the resource is created, you can use TagResource, UntagResource, and ListTagsForResource to add, remove, and view tags. The maximum tag limit may be lower than stated. See the AWS General Reference for actual tagging limits.", "Version": "The version that is associated with a build or script. Version strings do not need to be unique." } }, @@ -20059,7 +20535,7 @@ "Platform": "The platform of the component. For example, `Windows` .", "SupportedOsVersions": "The operating system (OS) version supported by the component. If the OS information is available, a prefix match is performed against the base image OS version during image recipe creation.", "Tags": "The tags associated with the component.", - "Uri": "The uri of the component. Must be an Amazon S3 URL and the requester must have permission to access the Amazon S3 bucket. If you use Amazon S3, you can specify component content up to your service quota. Either `data` or `uri` can be used to specify the data within the component.", + "Uri": "The `uri` of a YAML component document file. This must be an S3 URL ( `s3://bucket/key` ), and the requester must have permission to access the S3 bucket it points to. If you use Amazon S3, you can specify component content up to your service quota.\n\nAlternatively, you can specify the YAML document inline, using the component `data` property. You cannot specify both properties.", "Version": "The component version. For example, `1.0.0` ." } }, @@ -20173,6 +20649,7 @@ "attributes": { "Arn": "Returns the Amazon Resource Name (ARN) of the image. For example, `arn:aws:imagebuilder:us-west-2:123456789012:image/mybasicrecipe/2019.12.03/1` .", "ImageId": "Returns the AMI ID of the Amazon EC2 AMI in the Region in which you are using Image Builder.", + "ImageUri": "", "Name": "Returns the name of the image.", "Ref": "`Ref` returns the resource ARN, such as `arn:aws:imagebuilder:us-west-2:123456789012:image/my-example-image` ." }, @@ -20256,7 +20733,7 @@ "description": "In addition to your infrastruction configuration, these settings provide an extra layer of control over your build instances. For instances where Image Builder installs the Systems Manager agent, you can choose whether to keep it for the AMI that you create. You can also specify commands to run on launch for all of your build instances.", "properties": { "SystemsManagerAgent": "Contains settings for the Systems Manager agent on your build instance.", - "UserDataOverride": "Use this property to provide commands or a command script to run when you launch your build instance.\n\n> The userDataOverride property replaces any commands that Image Builder might have added to ensure that Systems Manager is installed on your Linux build instance. If you override the user data, make sure that you add commands to install Systems Manager, if it is not pre-installed on your base image." + "UserDataOverride": "Use this property to provide commands or a command script to run when you launch your build instance.\n\nThe userDataOverride property replaces any commands that Image Builder might have added to ensure that Systems Manager is installed on your Linux build instance. If you override the user data, make sure that you add commands to install Systems Manager, if it is not pre-installed on your base image.\n\n> The user data is always base 64 encoded. For example, the following commands are encoded as `IyEvYmluL2Jhc2gKbWtkaXIgLXAgL3Zhci9iYi8KdG91Y2ggL3Zhci$` :\n> \n> *#!/bin/bash*\n> \n> mkdir -p /var/bb/\n> \n> touch /var" } }, "AWS::ImageBuilder::ImageRecipe.ComponentConfiguration": { @@ -20507,6 +20984,7 @@ "properties": { "AuthorizerFunctionArn": "The authorizer's Lambda function ARN.", "AuthorizerName": "The authorizer name.", + "EnableCachingForHttp": "", "SigningDisabled": "Specifies whether AWS IoT validates the token signature in an authorization request.", "Status": "The status of the authorizer.\n\nValid values: `ACTIVE` | `INACTIVE`", "Tags": "Metadata which can be used to manage the custom authorizer.\n\n> For URI Request parameters use format: ...key1=value1&key2=value2...\n> \n> For the CLI command-line parameter use format: &&tags \"key1=value1&key2=value2...\"\n> \n> For the cli-input-json file use format: \"tags\": \"key1=value1&key2=value2...\"", @@ -20536,9 +21014,9 @@ }, "description": "Use the `AWS::IoT::CustomMetric` resource to define a custom metric published by your devices to Device Defender. For API reference, see [CreateCustomMetric](https://docs.aws.amazon.com/iot/latest/apireference/API_CreateCustomMetric.html) and for general information, see [Custom metrics](https://docs.aws.amazon.com/iot/latest/developerguide/dd-detect-custom-metrics.html) .", "properties": { - "DisplayName": "Field that represents a friendly name in the console for the custom metric; it doesn't have to be unique. Don't use this name as the metric identifier in the device metric report. Can be updated.", - "MetricName": "The name of the custom metric. This will be used in the metric report submitted from the device/thing. It shouldn't begin with `aws:` . Cannot be updated once it's defined.", - "MetricType": "The type of the custom metric. Types include `string-list` , `ip-address-list` , and `number-list` .", + "DisplayName": "The friendly name in the console for the custom metric. This name doesn't have to be unique. Don't use this name as the metric identifier in the device metric report. You can update the friendly name after you define it.", + "MetricName": "The name of the custom metric. This will be used in the metric report submitted from the device/thing. The name can't begin with `aws:` . You can\u2019t change the name after you define it.", + "MetricType": "The type of the custom metric. Types include `string-list` , `ip-address-list` , `number-list` , and `number` .\n\n> The type `number` only takes a single metric value as an input, but when you submit the metrics value in the DeviceMetrics report, you must pass it as an array with a single value.", "Tags": "Metadata that can be used to manage the custom metric." } }, @@ -21767,6 +22245,203 @@ "Tags": "Metadata that can be used to manage the the Suite Definition." } }, + "AWS::IoTEvents::AlarmModel": { + "attributes": { + "Ref": "`Ref` returns the name of the alarm model. For example:\n\n`{\"Ref\": \"myAlarmModel\"}`\n\nFor the AWS IoT Events alarm model `myAlarmModel` , `Ref` returns the name of the alarm model." + }, + "description": "Represents an alarm model to monitor an AWS IoT Events input attribute. You can use the alarm to get notified when the value is outside a specified range. For more information, see [Create an alarm model](https://docs.aws.amazon.com/iotevents/latest/developerguide/create-alarms.html) in the *AWS IoT Events Developer Guide* .", + "properties": { + "AlarmCapabilities": "Contains the configuration information of alarm state changes.", + "AlarmEventActions": "Contains information about one or more alarm actions.", + "AlarmModelDescription": "The description of the alarm model.", + "AlarmModelName": "The name of the alarm model.", + "AlarmRule": "Defines when your alarm is invoked.", + "Key": "An input attribute used as a key to create an alarm. AWS IoT Events routes [inputs](https://docs.aws.amazon.com/iotevents/latest/apireference/API_Input.html) associated with this key to the alarm.", + "RoleArn": "The ARN of the IAM role that allows the alarm to perform actions and access AWS resources. For more information, see [Amazon Resource Names (ARNs)](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) in the *AWS General Reference* .", + "Severity": "A non-negative integer that reflects the severity level of the alarm.", + "Tags": "A list of key-value pairs that contain metadata for the alarm model. The tags help you manage the alarm model. For more information, see [Tagging your AWS IoT Events resources](https://docs.aws.amazon.com/iotevents/latest/developerguide/tagging-iotevents.html) in the *AWS IoT Events Developer Guide* .\n\nYou can create up to 50 tags for one alarm model." + } + }, + "AWS::IoTEvents::AlarmModel.AcknowledgeFlow": { + "attributes": {}, + "description": "Specifies whether to get notified for alarm state changes.", + "properties": { + "Enabled": "The value must be `TRUE` or `FALSE` . If `TRUE` , you receive a notification when the alarm state changes. You must choose to acknowledge the notification before the alarm state can return to `NORMAL` . If `FALSE` , you won't receive notifications. The alarm automatically changes to the `NORMAL` state when the input property value returns to the specified range." + } + }, + "AWS::IoTEvents::AlarmModel.AlarmAction": { + "attributes": {}, + "description": "Specifies one of the following actions to receive notifications when the alarm state changes.", + "properties": { + "DynamoDB": "Defines an action to write to the Amazon DynamoDB table that you created. The standard action payload contains all the information about the detector model instance and the event that triggered the action. You can customize the [payload](https://docs.aws.amazon.com/iotevents/latest/apireference/API_Payload.html) . One column of the DynamoDB table receives all attribute-value pairs in the payload that you specify.\n\nYou must use expressions for all parameters in `DynamoDBAction` . The expressions accept literals, operators, functions, references, and substitution templates.\n\n**Examples** - For literal values, the expressions must contain single quotes. For example, the value for the `hashKeyType` parameter can be `'STRING'` .\n- For references, you must specify either variables or input values. For example, the value for the `hashKeyField` parameter can be `$input.GreenhouseInput.name` .\n- For a substitution template, you must use `${}` , and the template must be in single quotes. A substitution template can also contain a combination of literals, operators, functions, references, and substitution templates.\n\nIn the following example, the value for the `hashKeyValue` parameter uses a substitution template.\n\n`'${$input.GreenhouseInput.temperature * 6 / 5 + 32} in Fahrenheit'`\n- For a string concatenation, you must use `+` . A string concatenation can also contain a combination of literals, operators, functions, references, and substitution templates.\n\nIn the following example, the value for the `tableName` parameter uses a string concatenation.\n\n`'GreenhouseTemperatureTable ' + $input.GreenhouseInput.date`\n\nFor more information, see [Expressions](https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-expressions.html) in the *AWS IoT Events Developer Guide* .\n\nIf the defined payload type is a string, `DynamoDBAction` writes non-JSON data to the DynamoDB table as binary data. The DynamoDB console displays the data as Base64-encoded text. The value for the `payloadField` parameter is `_raw` .", + "DynamoDBv2": "Defines an action to write to the Amazon DynamoDB table that you created. The default action payload contains all the information about the detector model instance and the event that triggered the action. You can customize the [payload](https://docs.aws.amazon.com/iotevents/latest/apireference/API_Payload.html) . A separate column of the DynamoDB table receives one attribute-value pair in the payload that you specify.\n\nYou must use expressions for all parameters in `DynamoDBv2Action` . The expressions accept literals, operators, functions, references, and substitution templates.\n\n**Examples** - For literal values, the expressions must contain single quotes. For example, the value for the `tableName` parameter can be `'GreenhouseTemperatureTable'` .\n- For references, you must specify either variables or input values. For example, the value for the `tableName` parameter can be `$variable.ddbtableName` .\n- For a substitution template, you must use `${}` , and the template must be in single quotes. A substitution template can also contain a combination of literals, operators, functions, references, and substitution templates.\n\nIn the following example, the value for the `contentExpression` parameter in `Payload` uses a substitution template.\n\n`'{\\\"sensorID\\\": \\\"${$input.GreenhouseInput.sensor_id}\\\", \\\"temperature\\\": \\\"${$input.GreenhouseInput.temperature * 9 / 5 + 32}\\\"}'`\n- For a string concatenation, you must use `+` . A string concatenation can also contain a combination of literals, operators, functions, references, and substitution templates.\n\nIn the following example, the value for the `tableName` parameter uses a string concatenation.\n\n`'GreenhouseTemperatureTable ' + $input.GreenhouseInput.date`\n\nFor more information, see [Expressions](https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-expressions.html) in the *AWS IoT Events Developer Guide* .\n\nThe value for the `type` parameter in `Payload` must be `JSON` .", + "Firehose": "Sends information about the detector model instance and the event that triggered the action to an Amazon Kinesis Data Firehose delivery stream.", + "IotEvents": "Sends an AWS IoT Events input, passing in information about the detector model instance and the event that triggered the action.", + "IotSiteWise": "Sends information about the detector model instance and the event that triggered the action to a specified asset property in AWS IoT SiteWise .\n\nYou must use expressions for all parameters in `IotSiteWiseAction` . The expressions accept literals, operators, functions, references, and substitutions templates.\n\n**Examples** - For literal values, the expressions must contain single quotes. For example, the value for the `propertyAlias` parameter can be `'/company/windfarm/3/turbine/7/temperature'` .\n- For references, you must specify either variables or input values. For example, the value for the `assetId` parameter can be `$input.TurbineInput.assetId1` .\n- For a substitution template, you must use `${}` , and the template must be in single quotes. A substitution template can also contain a combination of literals, operators, functions, references, and substitution templates.\n\nIn the following example, the value for the `propertyAlias` parameter uses a substitution template.\n\n`'company/windfarm/${$input.TemperatureInput.sensorData.windfarmID}/turbine/ ${$input.TemperatureInput.sensorData.turbineID}/temperature'`\n\nYou must specify either `propertyAlias` or both `assetId` and `propertyId` to identify the target asset property in AWS IoT SiteWise .\n\nFor more information, see [Expressions](https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-expressions.html) in the *AWS IoT Events Developer Guide* .", + "IotTopicPublish": "Information required to publish the MQTT message through the AWS IoT message broker.", + "Lambda": "Calls a Lambda function, passing in information about the detector model instance and the event that triggered the action.", + "Sns": "", + "Sqs": "Sends information about the detector model instance and the event that triggered the action to an Amazon SQS queue." + } + }, + "AWS::IoTEvents::AlarmModel.AlarmCapabilities": { + "attributes": {}, + "description": "Contains the configuration information of alarm state changes.", + "properties": { + "AcknowledgeFlow": "Specifies whether to get notified for alarm state changes.", + "InitializationConfiguration": "Specifies the default alarm state. The configuration applies to all alarms that were created based on this alarm model." + } + }, + "AWS::IoTEvents::AlarmModel.AlarmEventActions": { + "attributes": {}, + "description": "Contains information about one or more alarm actions.", + "properties": { + "AlarmActions": "Specifies one or more supported actions to receive notifications when the alarm state changes." + } + }, + "AWS::IoTEvents::AlarmModel.AlarmRule": { + "attributes": {}, + "description": "Defines when your alarm is invoked.", + "properties": { + "SimpleRule": "A rule that compares an input property value to a threshold value with a comparison operator." + } + }, + "AWS::IoTEvents::AlarmModel.AssetPropertyTimestamp": { + "attributes": {}, + "description": "A structure that contains timestamp information. For more information, see [TimeInNanos](https://docs.aws.amazon.com/iot-sitewise/latest/APIReference/API_TimeInNanos.html) in the *AWS IoT SiteWise API Reference* .\n\nYou must use expressions for all parameters in `AssetPropertyTimestamp` . The expressions accept literals, operators, functions, references, and substitution templates.\n\n**Examples** - For literal values, the expressions must contain single quotes. For example, the value for the `timeInSeconds` parameter can be `'1586400675'` .\n- For references, you must specify either variables or input values. For example, the value for the `offsetInNanos` parameter can be `$variable.time` .\n- For a substitution template, you must use `${}` , and the template must be in single quotes. A substitution template can also contain a combination of literals, operators, functions, references, and substitution templates.\n\nIn the following example, the value for the `timeInSeconds` parameter uses a substitution template.\n\n`'${$input.TemperatureInput.sensorData.timestamp / 1000}'`\n\nFor more information, see [Expressions](https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-expressions.html) in the *AWS IoT Events Developer Guide* .", + "properties": { + "OffsetInNanos": "The nanosecond offset converted from `timeInSeconds` . The valid range is between 0-999999999.", + "TimeInSeconds": "The timestamp, in seconds, in the Unix epoch format. The valid range is between 1-31556889864403199." + } + }, + "AWS::IoTEvents::AlarmModel.AssetPropertyValue": { + "attributes": {}, + "description": "A structure that contains value information. For more information, see [AssetPropertyValue](https://docs.aws.amazon.com/iot-sitewise/latest/APIReference/API_AssetPropertyValue.html) in the *AWS IoT SiteWise API Reference* .\n\nYou must use expressions for all parameters in `AssetPropertyValue` . The expressions accept literals, operators, functions, references, and substitution templates.\n\n**Examples** - For literal values, the expressions must contain single quotes. For example, the value for the `quality` parameter can be `'GOOD'` .\n- For references, you must specify either variables or input values. For example, the value for the `quality` parameter can be `$input.TemperatureInput.sensorData.quality` .\n\nFor more information, see [Expressions](https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-expressions.html) in the *AWS IoT Events Developer Guide* .", + "properties": { + "Quality": "The quality of the asset property value. The value must be `'GOOD'` , `'BAD'` , or `'UNCERTAIN'` .", + "Timestamp": "The timestamp associated with the asset property value. The default is the current event time.", + "Value": "The value to send to an asset property." + } + }, + "AWS::IoTEvents::AlarmModel.AssetPropertyVariant": { + "attributes": {}, + "description": "A structure that contains an asset property value. For more information, see [Variant](https://docs.aws.amazon.com/iot-sitewise/latest/APIReference/API_Variant.html) in the *AWS IoT SiteWise API Reference* .\n\nYou must use expressions for all parameters in `AssetPropertyVariant` . The expressions accept literals, operators, functions, references, and substitution templates.\n\n**Examples** - For literal values, the expressions must contain single quotes. For example, the value for the `integerValue` parameter can be `'100'` .\n- For references, you must specify either variables or parameters. For example, the value for the `booleanValue` parameter can be `$variable.offline` .\n- For a substitution template, you must use `${}` , and the template must be in single quotes. A substitution template can also contain a combination of literals, operators, functions, references, and substitution templates.\n\nIn the following example, the value for the `doubleValue` parameter uses a substitution template.\n\n`'${$input.TemperatureInput.sensorData.temperature * 6 / 5 + 32}'`\n\nFor more information, see [Expressions](https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-expressions.html) in the *AWS IoT Events Developer Guide* .\n\nYou must specify one of the following value types, depending on the `dataType` of the specified asset property. For more information, see [AssetProperty](https://docs.aws.amazon.com/iot-sitewise/latest/APIReference/API_AssetProperty.html) in the *AWS IoT SiteWise API Reference* .", + "properties": { + "BooleanValue": "The asset property value is a Boolean value that must be `'TRUE'` or `'FALSE'` . You must use an expression, and the evaluated result should be a Boolean value.", + "DoubleValue": "The asset property value is a double. You must use an expression, and the evaluated result should be a double.", + "IntegerValue": "The asset property value is an integer. You must use an expression, and the evaluated result should be an integer.", + "StringValue": "The asset property value is a string. You must use an expression, and the evaluated result should be a string." + } + }, + "AWS::IoTEvents::AlarmModel.DynamoDB": { + "attributes": {}, + "description": "Defines an action to write to the Amazon DynamoDB table that you created. The standard action payload contains all the information about the detector model instance and the event that triggered the action. You can customize the [payload](https://docs.aws.amazon.com/iotevents/latest/apireference/API_Payload.html) . One column of the DynamoDB table receives all attribute-value pairs in the payload that you specify.\n\nYou must use expressions for all parameters in `DynamoDBAction` . The expressions accept literals, operators, functions, references, and substitution templates.\n\n**Examples** - For literal values, the expressions must contain single quotes. For example, the value for the `hashKeyType` parameter can be `'STRING'` .\n- For references, you must specify either variables or input values. For example, the value for the `hashKeyField` parameter can be `$input.GreenhouseInput.name` .\n- For a substitution template, you must use `${}` , and the template must be in single quotes. A substitution template can also contain a combination of literals, operators, functions, references, and substitution templates.\n\nIn the following example, the value for the `hashKeyValue` parameter uses a substitution template.\n\n`'${$input.GreenhouseInput.temperature * 6 / 5 + 32} in Fahrenheit'`\n- For a string concatenation, you must use `+` . A string concatenation can also contain a combination of literals, operators, functions, references, and substitution templates.\n\nIn the following example, the value for the `tableName` parameter uses a string concatenation.\n\n`'GreenhouseTemperatureTable ' + $input.GreenhouseInput.date`\n\nFor more information, see [Expressions](https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-expressions.html) in the *AWS IoT Events Developer Guide* .\n\nIf the defined payload type is a string, `DynamoDBAction` writes non-JSON data to the DynamoDB table as binary data. The DynamoDB console displays the data as Base64-encoded text. The value for the `payloadField` parameter is `_raw` .", + "properties": { + "HashKeyField": "The name of the hash key (also called the partition key). The `hashKeyField` value must match the partition key of the target DynamoDB table.", + "HashKeyType": "The data type for the hash key (also called the partition key). You can specify the following values:\n\n- `'STRING'` - The hash key is a string.\n- `'NUMBER'` - The hash key is a number.\n\nIf you don't specify `hashKeyType` , the default value is `'STRING'` .", + "HashKeyValue": "The value of the hash key (also called the partition key).", + "Operation": "The type of operation to perform. You can specify the following values:\n\n- `'INSERT'` - Insert data as a new item into the DynamoDB table. This item uses the specified hash key as a partition key. If you specified a range key, the item uses the range key as a sort key.\n- `'UPDATE'` - Update an existing item of the DynamoDB table with new data. This item's partition key must match the specified hash key. If you specified a range key, the range key must match the item's sort key.\n- `'DELETE'` - Delete an existing item of the DynamoDB table. This item's partition key must match the specified hash key. If you specified a range key, the range key must match the item's sort key.\n\nIf you don't specify this parameter, AWS IoT Events triggers the `'INSERT'` operation.", + "Payload": "Information needed to configure the payload.\n\nBy default, AWS IoT Events generates a standard payload in JSON for any action. This action payload contains all attribute-value pairs that have the information about the detector model instance and the event triggered the action. To configure the action payload, you can use `contentExpression` .", + "PayloadField": "The name of the DynamoDB column that receives the action payload.\n\nIf you don't specify this parameter, the name of the DynamoDB column is `payload` .", + "RangeKeyField": "The name of the range key (also called the sort key). The `rangeKeyField` value must match the sort key of the target DynamoDB table.", + "RangeKeyType": "The data type for the range key (also called the sort key), You can specify the following values:\n\n- `'STRING'` - The range key is a string.\n- `'NUMBER'` - The range key is number.\n\nIf you don't specify `rangeKeyField` , the default value is `'STRING'` .", + "RangeKeyValue": "The value of the range key (also called the sort key).", + "TableName": "The name of the DynamoDB table. The `tableName` value must match the table name of the target DynamoDB table." + } + }, + "AWS::IoTEvents::AlarmModel.DynamoDBv2": { + "attributes": {}, + "description": "Defines an action to write to the Amazon DynamoDB table that you created. The default action payload contains all the information about the detector model instance and the event that triggered the action. You can customize the [payload](https://docs.aws.amazon.com/iotevents/latest/apireference/API_Payload.html) . A separate column of the DynamoDB table receives one attribute-value pair in the payload that you specify.\n\nYou must use expressions for all parameters in `DynamoDBv2Action` . The expressions accept literals, operators, functions, references, and substitution templates.\n\n**Examples** - For literal values, the expressions must contain single quotes. For example, the value for the `tableName` parameter can be `'GreenhouseTemperatureTable'` .\n- For references, you must specify either variables or input values. For example, the value for the `tableName` parameter can be `$variable.ddbtableName` .\n- For a substitution template, you must use `${}` , and the template must be in single quotes. A substitution template can also contain a combination of literals, operators, functions, references, and substitution templates.\n\nIn the following example, the value for the `contentExpression` parameter in `Payload` uses a substitution template.\n\n`'{\\\"sensorID\\\": \\\"${$input.GreenhouseInput.sensor_id}\\\", \\\"temperature\\\": \\\"${$input.GreenhouseInput.temperature * 9 / 5 + 32}\\\"}'`\n- For a string concatenation, you must use `+` . A string concatenation can also contain a combination of literals, operators, functions, references, and substitution templates.\n\nIn the following example, the value for the `tableName` parameter uses a string concatenation.\n\n`'GreenhouseTemperatureTable ' + $input.GreenhouseInput.date`\n\nFor more information, see [Expressions](https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-expressions.html) in the *AWS IoT Events Developer Guide* .\n\nThe value for the `type` parameter in `Payload` must be `JSON` .", + "properties": { + "Payload": "", + "TableName": "The name of the DynamoDB table." + } + }, + "AWS::IoTEvents::AlarmModel.Firehose": { + "attributes": {}, + "description": "Sends information about the detector model instance and the event that triggered the action to an Amazon Kinesis Data Firehose delivery stream.", + "properties": { + "DeliveryStreamName": "The name of the Kinesis Data Firehose delivery stream where the data is written.", + "Payload": "You can configure the action payload when you send a message to an Amazon Kinesis Data Firehose delivery stream.", + "Separator": "A character separator that is used to separate records written to the Kinesis Data Firehose delivery stream. Valid values are: '\\n' (newline), '\\t' (tab), '\\r\\n' (Windows newline), ',' (comma)." + } + }, + "AWS::IoTEvents::AlarmModel.InitializationConfiguration": { + "attributes": {}, + "description": "Specifies the default alarm state. The configuration applies to all alarms that were created based on this alarm model.", + "properties": { + "DisabledOnInitialization": "The value must be `TRUE` or `FALSE` . If `FALSE` , all alarm instances created based on the alarm model are activated. The default value is `TRUE` ." + } + }, + "AWS::IoTEvents::AlarmModel.IotEvents": { + "attributes": {}, + "description": "Sends an AWS IoT Events input, passing in information about the detector model instance and the event that triggered the action.", + "properties": { + "InputName": "The name of the AWS IoT Events input where the data is sent.", + "Payload": "You can configure the action payload when you send a message to an AWS IoT Events input." + } + }, + "AWS::IoTEvents::AlarmModel.IotSiteWise": { + "attributes": {}, + "description": "Sends information about the detector model instance and the event that triggered the action to a specified asset property in AWS IoT SiteWise .\n\nYou must use expressions for all parameters in `IotSiteWiseAction` . The expressions accept literals, operators, functions, references, and substitutions templates.\n\n**Examples** - For literal values, the expressions must contain single quotes. For example, the value for the `propertyAlias` parameter can be `'/company/windfarm/3/turbine/7/temperature'` .\n- For references, you must specify either variables or input values. For example, the value for the `assetId` parameter can be `$input.TurbineInput.assetId1` .\n- For a substitution template, you must use `${}` , and the template must be in single quotes. A substitution template can also contain a combination of literals, operators, functions, references, and substitution templates.\n\nIn the following example, the value for the `propertyAlias` parameter uses a substitution template.\n\n`'company/windfarm/${$input.TemperatureInput.sensorData.windfarmID}/turbine/ ${$input.TemperatureInput.sensorData.turbineID}/temperature'`\n\nYou must specify either `propertyAlias` or both `assetId` and `propertyId` to identify the target asset property in AWS IoT SiteWise .\n\nFor more information, see [Expressions](https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-expressions.html) in the *AWS IoT Events Developer Guide* .", + "properties": { + "AssetId": "The ID of the asset that has the specified property.", + "EntryId": "A unique identifier for this entry. You can use the entry ID to track which data entry causes an error in case of failure. The default is a new unique identifier.", + "PropertyAlias": "The alias of the asset property.", + "PropertyId": "The ID of the asset property.", + "PropertyValue": "The value to send to the asset property. This value contains timestamp, quality, and value (TQV) information." + } + }, + "AWS::IoTEvents::AlarmModel.IotTopicPublish": { + "attributes": {}, + "description": "Information required to publish the MQTT message through the AWS IoT message broker.", + "properties": { + "MqttTopic": "The MQTT topic of the message. You can use a string expression that includes variables ( `$variable.` ) and input values ( `$input..` ) as the topic string.", + "Payload": "You can configure the action payload when you publish a message to an AWS IoT Core topic." + } + }, + "AWS::IoTEvents::AlarmModel.Lambda": { + "attributes": {}, + "description": "Calls a Lambda function, passing in information about the detector model instance and the event that triggered the action.", + "properties": { + "FunctionArn": "The ARN of the Lambda function that is executed.", + "Payload": "You can configure the action payload when you send a message to a Lambda function." + } + }, + "AWS::IoTEvents::AlarmModel.Payload": { + "attributes": {}, + "description": "Information needed to configure the payload.\n\nBy default, AWS IoT Events generates a standard payload in JSON for any action. This action payload contains all attribute-value pairs that have the information about the detector model instance and the event triggered the action. To configure the action payload, you can use `contentExpression` .", + "properties": { + "ContentExpression": "The content of the payload. You can use a string expression that includes quoted strings ( `''` ), variables ( `$variable.` ), input values ( `$input..` ), string concatenations, and quoted strings that contain `${}` as the content. The recommended maximum size of a content expression is 1 KB.", + "Type": "The value of the payload type can be either `STRING` or `JSON` ." + } + }, + "AWS::IoTEvents::AlarmModel.SimpleRule": { + "attributes": {}, + "description": "A rule that compares an input property value to a threshold value with a comparison operator.", + "properties": { + "ComparisonOperator": "The comparison operator.", + "InputProperty": "The value on the left side of the comparison operator. You can specify an AWS IoT Events input attribute as an input property.", + "Threshold": "The value on the right side of the comparison operator. You can enter a number or specify an AWS IoT Events input attribute." + } + }, + "AWS::IoTEvents::AlarmModel.Sns": { + "attributes": {}, + "description": "Information required to publish the Amazon SNS message.", + "properties": { + "Payload": "You can configure the action payload when you send a message as an Amazon SNS push notification.", + "TargetArn": "The ARN of the Amazon SNS target where the message is sent." + } + }, + "AWS::IoTEvents::AlarmModel.Sqs": { + "attributes": {}, + "description": "Sends information about the detector model instance and the event that triggered the action to an Amazon SQS queue.", + "properties": { + "Payload": "You can configure the action payload when you send a message to an Amazon SQS queue.", + "QueueUrl": "The URL of the SQS queue where the data is written.", + "UseBase64": "Set this to TRUE if you want the data to be base-64 encoded before it is written to the queue. Otherwise, set this to FALSE." + } + }, "AWS::IoTEvents::DetectorModel": { "attributes": { "Ref": "`Ref` returns the name of the detector model. For example:\n\n`{\"Ref\": \"myDetectorModel\"}`\n\nFor the AWS IoT Events detector model `myDetectorModel` , `Ref` returns the name of the detector model." @@ -22124,8 +22799,9 @@ }, "AWS::IoTSiteWise::Asset": { "attributes": { - "AssetId": "", - "Ref": "`Ref` returns the `AssetId` ." + "AssetArn": "The ARN of the asset.", + "AssetId": "The ID of the asset.", + "Ref": "`Ref` returns `AssetId` and `AssetArn` ." }, "description": "Creates an asset from an existing asset model. For more information, see [Creating assets](https://docs.aws.amazon.com/iot-sitewise/latest/userguide/create-assets.html) in the *AWS IoT SiteWise User Guide* .", "properties": { @@ -22253,7 +22929,7 @@ "description": "Contains a tumbling window, which is a repeating fixed-sized, non-overlapping, and contiguous time window. You can use this window in metrics to aggregate data from properties and other assets.\n\nYou can use `m` , `h` , `d` , and `w` when you specify an interval or offset. Note that `m` represents minutes, `h` represents hours, `d` represents days, and `w` represents weeks. You can also use `s` to represent seconds in `offset` .\n\nThe `interval` and `offset` parameters support the [ISO 8601 format](https://docs.aws.amazon.com/https://en.wikipedia.org/wiki/ISO_8601) . For example, `PT5S` represents 5 seconds, `PT5M` represents 5 minutes, and `PT5H` represents 5 hours.", "properties": { "Interval": "The time interval for the tumbling window. The interval time must be between 1 minute and 1 week.\n\nAWS IoT SiteWise computes the `1w` interval the end of Sunday at midnight each week (UTC), the `1d` interval at the end of each day at midnight (UTC), the `1h` interval at the end of each hour, and so on.\n\nWhen AWS IoT SiteWise aggregates data points for metric computations, the start of each interval is exclusive and the end of each interval is inclusive. AWS IoT SiteWise places the computed data point at the end of the interval.", - "Offset": "" + "Offset": "The offset for the tumbling window. The `offset` parameter accepts the following:\n\n- The offset time.\n\nFor example, if you specify `18h` for `offset` and `1d` for `interval` , AWS IoT SiteWise aggregates data in one of the following ways:\n\n- If you create the metric before or at 6 PM (UTC), you get the first aggregation result at 6 PM (UTC) on the day when you create the metric.\n- If you create the metric after 6 PM (UTC), you get the first aggregation result at 6 PM (UTC) the next day.\n- The ISO 8601 format.\n\nFor example, if you specify `PT18H` for `offset` and `1d` for `interval` , AWS IoT SiteWise aggregates data in one of the following ways:\n\n- If you create the metric before or at 6 PM (UTC), you get the first aggregation result at 6 PM (UTC) on the day when you create the metric.\n- If you create the metric after 6 PM (UTC), you get the first aggregation result at 6 PM (UTC) the next day.\n- The 24-hour clock.\n\nFor example, if you specify `00:03:00` for `offset` , `5m` for `interval` , and you create the metric at 2 PM (UTC), you get the first aggregation result at 2:03 PM (UTC). You get the second aggregation result at 2:08 PM (UTC).\n- The offset time zone.\n\nFor example, if you specify `2021-07-23T18:00-08` for `offset` and `1d` for `interval` , AWS IoT SiteWise aggregates data in one of the following ways:\n\n- If you create the metric before or at 6 PM (PST), you get the first aggregation result at 6 PM (PST) on the day when you create the metric.\n- If you create the metric after 6 PM (PST), you get the first aggregation result at 6 PM (PST) the next day." } }, "AWS::IoTSiteWise::AssetModel.VariableValue": { @@ -22305,7 +22981,7 @@ "description": "Contains a gateway's platform information.", "properties": { "Greengrass": "A gateway that runs on AWS IoT Greengrass .", - "GreengrassV2": "" + "GreengrassV2": "A gateway that runs on AWS IoT Greengrass V2." } }, "AWS::IoTSiteWise::Gateway.Greengrass": { @@ -22317,9 +22993,9 @@ }, "AWS::IoTSiteWise::Gateway.GreengrassV2": { "attributes": {}, - "description": "", + "description": "Contains details for a gateway that runs on AWS IoT Greengrass V2. To create a gateway that runs on AWS IoT Greengrass V2, you must deploy the IoT SiteWise Edge component to your gateway device. Your [Greengrass device role](https://docs.aws.amazon.com/greengrass/v2/developerguide/device-service-role.html) must use the `AWSIoTSiteWiseEdgeAccess` policy. For more information, see [Using AWS IoT SiteWise at the edge](https://docs.aws.amazon.com/iot-sitewise/latest/userguide/sw-gateways.html) in the *AWS IoT SiteWise User Guide* .", "properties": { - "CoreDeviceThingName": "" + "CoreDeviceThingName": "The name of the AWS IoT thing for your AWS IoT Greengrass V2 core device." } }, "AWS::IoTSiteWise::Portal": { @@ -22350,7 +23026,7 @@ }, "description": "Creates a project in the specified portal.\n\n> Make sure that the project name and description don't contain confidential information.", "properties": { - "AssetIds": "", + "AssetIds": "A list that contains the IDs of each asset associated with the project.", "PortalId": "The ID of the portal in which to create the project.", "ProjectDescription": "A description for the project.", "ProjectName": "A friendly name for the project.", @@ -22776,6 +23452,7 @@ }, "description": "Specifies a data source that you use to with an Amazon Kendra index.\n\nYou specify a name, connector type and description for your data source.", "properties": { + "CustomDocumentEnrichmentConfiguration": "", "DataSourceConfiguration": "Configuration information for an Amazon Kendra data source. The contents of the configuration depend on the type of data source. You can only specify one type of data source in the configuration. Choose from one of the following data sources.\n\n- Amazon S3\n- Confluence\n- Custom\n- Database\n- Microsoft OneDrive\n- Microsoft SharePoint\n- Salesforce\n- ServiceNow\n\nYou can't specify the `Configuration` parameter when the `Type` parameter is set to `CUSTOM` .\n\nThe `Configuration` parameter is required for all other data sources.", "Description": "A description of the data source.", "IndexId": "The identifier of the index that should be associated with this data source.", @@ -22813,31 +23490,31 @@ }, "AWS::Kendra::DataSource.ConfluenceAttachmentConfiguration": { "attributes": {}, - "description": "Specifies the attachment settings for the Confluence data source. Attachment settings are optional, if you don't specify settings attachments, Amazon Kendra won't index them.", + "description": "Configuration of attachment settings for the Confluence data source. Attachment settings are optional, if you don't specify settings attachments, Amazon Kendra won't index them.", "properties": { - "AttachmentFieldMappings": "Defines how attachment metadata fields should be mapped to index fields. Before you can map a field, you must first create an index field with a matching type using the console or the `UpdateIndex` operation.\n\nIf you specify the `AttachentFieldMappings` parameter, you must specify at least one field mapping.", + "AttachmentFieldMappings": "Maps attributes or field names of Confluence attachments to Amazon Kendra index field names. To create custom fields, use the `UpdateIndex` API before you map to Confluence fields. For more information, see [Mapping data source fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The Confluence data source field names must exist in your Confluence custom metadata.\n\nIf you specify the `AttachentFieldMappings` parameter, you must specify at least one field mapping.", "CrawlAttachments": "Indicates whether Amazon Kendra indexes attachments to the pages and blogs in the Confluence data source." } }, "AWS::Kendra::DataSource.ConfluenceAttachmentToIndexFieldMapping": { "attributes": {}, - "description": "Defines the mapping between a field in the Confluence data source to a Amazon Kendra index field.\n\nYou must first create the index field using the `UpdateIndex` operation.", + "description": "Maps attributes or field names of Confluence attachments to Amazon Kendra index field names. To create custom fields, use the `UpdateIndex` API before you map to Confluence fields. For more information, see [Mapping data source fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The Confuence data source field names must exist in your Confluence custom metadata.", "properties": { - "DataSourceFieldName": "The name of the field in the data source.\n\nYou must first create the index field using the `UpdateIndex` operation.", + "DataSourceFieldName": "The name of the field in the data source.\n\nYou must first create the index field using the `UpdateIndex` API.", "DateFieldFormat": "The format for date fields in the data source. If the field specified in `DataSourceFieldName` is a date field you must specify the date format. If the field is not a date field, an exception is thrown.", "IndexFieldName": "The name of the index field to map to the Confluence data source field. The index field type must match the Confluence field type." } }, "AWS::Kendra::DataSource.ConfluenceBlogConfiguration": { "attributes": {}, - "description": "Specifies the blog settings for the Confluence data source. Blogs are always indexed unless filtered from the index by the `ExclusionPatterns` or `InclusionPatterns` fields in the `ConfluenceConfiguration` type.", + "description": "Configuration of blog settings for the Confluence data source. Blogs are always indexed unless filtered from the index by the `ExclusionPatterns` or `InclusionPatterns` fields in the `ConfluenceConfiguration` object.", "properties": { - "BlogFieldMappings": "Defines how blog metadata fields should be mapped to index fields. Before you can map a field, you must first create an index field with a matching type using the console or the `UpdateIndex` operation.\n\nIf you specify the `BlogFieldMappings` parameter, you must specify at least one field mapping." + "BlogFieldMappings": "Maps attributes or field names of Confluence blogs to Amazon Kendra index field names. To create custom fields, use the `UpdateIndex` API before you map to Confluence fields. For more information, see [Mapping data source fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The Confluence data source field names must exist in your Confluence custom metadata.\n\nIf you specify the `BlogFieldMappings` parameter, you must specify at least one field mapping." } }, "AWS::Kendra::DataSource.ConfluenceBlogToIndexFieldMapping": { "attributes": {}, - "description": "Defines the mapping between a blog field in the Confluence data source to a Amazon Kendra index field.\n\nYou must first create the index field using the `UpdateIndex` operation.", + "description": "Maps attributes or field names of Confluence blog to Amazon Kendra index field names. To create custom fields, use the `UpdateIndex` API before you map to Confluence fields. For more information, see [Mapping data source fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The Confluence data source field names must exist in your Confluence custom metadata.", "properties": { "DataSourceFieldName": "The name of the field in the data source.", "DateFieldFormat": "The format for date fields in the data source. If the field specified in `DataSourceFieldName` is a date field you must specify the date format. If the field is not a date field, an exception is thrown.", @@ -22846,30 +23523,30 @@ }, "AWS::Kendra::DataSource.ConfluenceConfiguration": { "attributes": {}, - "description": "Provides configuration information for data sources that connect to Confluence.", + "description": "Provides the configuration information to connect to Confluence as your data source.", "properties": { - "AttachmentConfiguration": "Specifies configuration information for indexing attachments to Confluence blogs and pages.", - "BlogConfiguration": "Specifies configuration information for indexing Confluence blogs.", - "ExclusionPatterns": "A list of regular expression patterns that apply to a URL on the Confluence server. An exclusion pattern can apply to a blog post, a page, a space, or an attachment. Items that match the pattern are excluded from the index. Items that don't match the pattern are included in the index. If a item matches both an exclusion pattern and an inclusion pattern, the item isn't included in the index.", - "InclusionPatterns": "A list of regular expression patterns that apply to a URL on the Confluence server. An inclusion pattern can apply to a blog post, a page, a space, or an attachment. Items that match the patterns are included in the index. Items that don't match the pattern are excluded from the index. If an item matches both an inclusion pattern and an exclusion pattern, the item isn't included in the index.", - "PageConfiguration": "Specifies configuration information for indexing Confluence pages.", - "SecretArn": "The Amazon Resource Name (ARN) of an AWS Secrets Manager secret that contains the key/value pairs required to connect to your Confluence server. The secret must contain a JSON structure with the following keys:\n\n- username - The user name or email address of a user with administrative privileges for the Confluence server.\n- password - The password associated with the user logging in to the Confluence server.", - "ServerUrl": "The URL of your Confluence instance. Use the full URL of the server. For example, `https://server.example.com:port/` . You can also use an IP address, for example, `https://192.168.1.113/` .", - "SpaceConfiguration": "Specifies configuration information for indexing Confluence spaces.", + "AttachmentConfiguration": "Configuration information for indexing attachments to Confluence blogs and pages.", + "BlogConfiguration": "Configuration information for indexing Confluence blogs.", + "ExclusionPatterns": ">A list of regular expression patterns to exclude certain blog posts, pages, spaces, or attachments in your Confluence. Content that matches the patterns are excluded from the index. Content that doesn't match the patterns is included in the index. If content matches both an inclusion and exclusion pattern, the exclusion pattern takes precedence and the content isn't included in the index.", + "InclusionPatterns": "A list of regular expression patterns to include certain blog posts, pages, spaces, or attachments in your Confluence. Content that matches the patterns are included in the index. Content that doesn't match the patterns is excluded from the index. If content matches both an inclusion and exclusion pattern, the exclusion pattern takes precedence and the content isn't included in the index.", + "PageConfiguration": "Configuration information for indexing Confluence pages.", + "SecretArn": "The Amazon Resource Name (ARN) of an AWS Secrets Manager secret that contains the key-value pairs required to connect to your Confluence server. The secret must contain a JSON structure with the following keys:\n\n- username\u2014The user name or email address of a user with administrative privileges for the Confluence server.\n- password\u2014The password associated with the user logging in to the Confluence server.", + "ServerUrl": "The URL of your Confluence instance. Use the full URL of the server. For example, *https://server.example.com:port/* . You can also use an IP address, for example, *https://192.168.1.113/* .", + "SpaceConfiguration": "Configuration information for indexing Confluence spaces.", "Version": "Specifies the version of the Confluence installation that you are connecting to.", - "VpcConfiguration": "Specifies the information for connecting to an Amazon VPC." + "VpcConfiguration": "Configuration information for an Amazon Virtual Private Cloud to connect to your Confluence. For more information, see [Configuring a VPC](https://docs.aws.amazon.com/kendra/latest/dg/vpc-configuration.html) ." } }, "AWS::Kendra::DataSource.ConfluencePageConfiguration": { "attributes": {}, - "description": "Specifies the page settings for the Confluence data source.", + "description": "Configuration of the page settings for the Confluence data source.", "properties": { - "PageFieldMappings": "Defines how page metadata fields should be mapped to index fields. Before you can map a field, you must first create an index field with a matching type using the console or the `UpdateIndex` operation.\n\nIf you specify the `PageFieldMappings` parameter, you must specify at least one field mapping." + "PageFieldMappings": ">Maps attributes or field names of Confluence pages to Amazon Kendra index field names. To create custom fields, use the `UpdateIndex` API before you map to Confluence fields. For more information, see [Mapping data source fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The Confluence data source field names must exist in your Confluence custom metadata.\n\nIf you specify the `PageFieldMappings` parameter, you must specify at least one field mapping." } }, "AWS::Kendra::DataSource.ConfluencePageToIndexFieldMapping": { "attributes": {}, - "description": "Defines the mapping between a field in the Confluence data source to a Amazon Kendra index field.\n\nYou must first create the index field using the `UpdateIndex` operation.", + "description": ">Maps attributes or field names of Confluence pages to Amazon Kendra index field names. To create custom fields, use the `UpdateIndex` API before you map to Confluence fields. For more information, see [Mapping data source fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The Confluence data source field names must exist in your Confluence custom metadata.", "properties": { "DataSourceFieldName": "The name of the field in the data source.", "DateFieldFormat": "The format for date fields in the data source. If the field specified in `DataSourceFieldName` is a date field you must specify the date format. If the field is not a date field, an exception is thrown.", @@ -22878,18 +23555,18 @@ }, "AWS::Kendra::DataSource.ConfluenceSpaceConfiguration": { "attributes": {}, - "description": "Specifies the configuration for indexing Confluence spaces.", + "description": "Configuration information for indexing Confluence spaces.", "properties": { "CrawlArchivedSpaces": "Specifies whether Amazon Kendra should index archived spaces.", "CrawlPersonalSpaces": "Specifies whether Amazon Kendra should index personal spaces. Users can add restrictions to items in personal spaces. If personal spaces are indexed, queries without user context information may return restricted items from a personal space in their results. For more information, see [Filtering on user context](https://docs.aws.amazon.com/kendra/latest/dg/user-context-filter.html) .", "ExcludeSpaces": "A list of space keys of Confluence spaces. If you include a key, the blogs, documents, and attachments in the space are not indexed. If a space is in both the `ExcludeSpaces` and the `IncludeSpaces` list, the space is excluded.", "IncludeSpaces": "A list of space keys for Confluence spaces. If you include a key, the blogs, documents, and attachments in the space are indexed. Spaces that aren't in the list aren't indexed. A space in the list must exist. Otherwise, Amazon Kendra logs an error when the data source is synchronized. If a space is in both the `IncludeSpaces` and the `ExcludeSpaces` list, the space is excluded.", - "SpaceFieldMappings": "Defines how space metadata fields should be mapped to index fields. Before you can map a field, you must first create an index field with a matching type using the console or the `UpdateIndex` operation.\n\nIf you specify the `SpaceFieldMappings` parameter, you must specify at least one field mapping." + "SpaceFieldMappings": "Maps attributes or field names of Confluence spaces to Amazon Kendra index field names. To create custom fields, use the `UpdateIndex` API before you map to Confluence fields. For more information, see [Mapping data source fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The Confluence data source field names must exist in your Confluence custom metadata.\n\nIf you specify the `SpaceFieldMappings` parameter, you must specify at least one field mapping." } }, "AWS::Kendra::DataSource.ConfluenceSpaceToIndexFieldMapping": { "attributes": {}, - "description": "Defines the mapping between a field in the Confluence data source to a Amazon Kendra index field.\n\nYou must first create the index field using the `UpdateIndex` operation.", + "description": ">Maps attributes or field names of Confluence spaces to Amazon Kendra index field names. To create custom fields, use the `UpdateIndex` API before you map to Confluence fields. For more information, see [Mapping data source fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The Confluence data source field names must exist in your Confluence custom metadata.", "properties": { "DataSourceFieldName": "The name of the field in the data source.", "DateFieldFormat": "The format for date fields in the data source. If the field specified in `DataSourceFieldName` is a date field you must specify the date format. If the field is not a date field, an exception is thrown.", @@ -22898,7 +23575,7 @@ }, "AWS::Kendra::DataSource.ConnectionConfiguration": { "attributes": {}, - "description": "Provides the information necessary to connect to a database.", + "description": "Provides the configuration information that's required to connect to a database.", "properties": { "DatabaseHost": "The name of the host for the database. Can be either a string (host.subdomain.domain.tld) or an IPv4 or IPv6 address.", "DatabaseName": "The name of the database containing the document data.", @@ -22907,20 +23584,30 @@ "TableName": "The name of the table that contains the document data." } }, + "AWS::Kendra::DataSource.CustomDocumentEnrichmentConfiguration": { + "attributes": {}, + "description": "Provides the configuration information for altering document metadata and content during the document ingestion process.\n\nFor more information, see [Customizing document metadata during the ingestion process](https://docs.aws.amazon.com/kendra/latest/dg/custom-document-enrichment.html) .", + "properties": { + "InlineConfigurations": "Configuration information to alter document attributes or metadata fields and content when ingesting documents into Amazon Kendra.", + "PostExtractionHookConfiguration": "Configuration information for invoking a Lambda function in AWS Lambda on the structured documents with their metadata and text extracted. You can use a Lambda function to apply advanced logic for creating, modifying, or deleting document metadata and content. For more information, see [Advanced data manipulation](https://docs.aws.amazon.com/kendra/latest/dg/custom-document-enrichment.html#advanced-data-manipulation) .", + "PreExtractionHookConfiguration": "Configuration information for invoking a Lambda function in AWS Lambda on the original or raw documents before extracting their metadata and text. You can use a Lambda function to apply advanced logic for creating, modifying, or deleting document metadata and content. For more information, see [Advanced data manipulation](https://docs.aws.amazon.com/kendra/latest/dg/custom-document-enrichment.html#advanced-data-manipulation) .", + "RoleArn": "The Amazon Resource Name (ARN) of a role with permission to run `PreExtractionHookConfiguration` and `PostExtractionHookConfiguration` for altering document metadata and content during the document ingestion process. For more information, see [IAM roles for Amazon Kendra](https://docs.aws.amazon.com/kendra/latest/dg/iam-roles.html) ." + } + }, "AWS::Kendra::DataSource.DataSourceConfiguration": { "attributes": {}, - "description": "Configuration information for an Amazon Kendra data source.", + "description": "Provides the configuration information for an Amazon Kendra data source.", "properties": { - "ConfluenceConfiguration": "Provides configuration information for connecting to a Confluence data source.", - "DatabaseConfiguration": "Provides information necessary to create a data source connector for a database.", - "GoogleDriveConfiguration": "Provides configuration for data sources that connect to Google Drive.", - "OneDriveConfiguration": "Provides configuration for data sources that connect to Microsoft OneDrive.", - "S3Configuration": "Provides information to create a data source connector for a document repository in an Amazon S3 bucket.", - "SalesforceConfiguration": "Provides configuration information for data sources that connect to a Salesforce site.", - "ServiceNowConfiguration": "Provides configuration for data sources that connect to ServiceNow instances.", - "SharePointConfiguration": "Provides information necessary to create a data source connector for a Microsoft SharePoint site.", + "ConfluenceConfiguration": "Provides the configuration information to connect to Confluence as your data source.", + "DatabaseConfiguration": "Provides the configuration information to connect to a database as your data source.", + "GoogleDriveConfiguration": "Provides the configuration information to connect to Google Drive as your data source.", + "OneDriveConfiguration": "Provides the configuration information to connect to Microsoft OneDrive as your data source.", + "S3Configuration": "Provides the configuration information to connect to an Amazon S3 bucket as your data source.", + "SalesforceConfiguration": "Provides the configuration information to connect to Salesforce as your data source.", + "ServiceNowConfiguration": "Provides the configuration information to connect to ServiceNow as your data source.", + "SharePointConfiguration": "Provides the configuration information to connect to Microsoft SharePoint as your data source.", "WebCrawlerConfiguration": "Provides the configuration information required for Amazon Kendra Web Crawler.", - "WorkDocsConfiguration": "Provides the configuration information to connect to WorkDocs as your data source." + "WorkDocsConfiguration": "Provides the configuration information to connect to Amazon WorkDocs as your data source." } }, "AWS::Kendra::DataSource.DataSourceToIndexFieldMapping": { @@ -22934,7 +23621,7 @@ }, "AWS::Kendra::DataSource.DataSourceVpcConfiguration": { "attributes": {}, - "description": "Provides information for connecting to an Amazon VPC.", + "description": "Provides the configuration information to connect to an Amazon VPC.", "properties": { "SecurityGroupIds": "A list of identifiers of security groups within your Amazon VPC. The security groups should enable Amazon Kendra to connect to the data source.", "SubnetIds": "A list of identifiers for subnets within your Amazon VPC. The subnets should be able to connect to each other in the VPC, and they should have outgoing access to the Internet through a NAT device." @@ -22942,16 +23629,44 @@ }, "AWS::Kendra::DataSource.DatabaseConfiguration": { "attributes": {}, - "description": "Provides the information necessary to connect a database to an index.", + "description": "Provides the configuration information to connect to a index.", "properties": { "AclConfiguration": "Information about the database column that provides information for user context filtering.", "ColumnConfiguration": "Information about where the index should get the document information from the database.", - "ConnectionConfiguration": "The information necessary to connect to a database.", + "ConnectionConfiguration": "Configuration information that's required to connect to a database.", "DatabaseEngineType": "The type of database engine that runs the database.", "SqlConfiguration": "Provides information about how Amazon Kendra uses quote marks around SQL identifiers when querying a database data source.", "VpcConfiguration": "Provides information for connecting to an Amazon VPC." } }, + "AWS::Kendra::DataSource.DocumentAttributeCondition": { + "attributes": {}, + "description": "The condition used for the target document attribute or metadata field when ingesting documents into Amazon Kendra. You use this with [DocumentAttributeTarget to apply the condition](https://docs.aws.amazon.com/kendra/latest/dg/API_DocumentAttributeTarget.html) .\n\nFor example, you can create the 'Department' target field and have it prefill department names associated with the documents based on information in the 'Source_URI' field. Set the condition that if the 'Source_URI' field contains 'financial' in its URI value, then prefill the target field 'Department' with the target value 'Finance' for the document.\n\nAmazon Kendra cannot create a target field if it has not already been created as an index field. After you create your index field, you can create a document metadata field using `DocumentAttributeTarget` . Amazon Kendra then will map your newly created metadata field to your index field.", + "properties": { + "ConditionDocumentAttributeKey": "The identifier of the document attribute used for the condition.\n\nFor example, 'Source_URI' could be an identifier for the attribute or metadata field that contains source URIs associated with the documents.\n\nAmazon Kendra currently does not support `_document_body` as an attribute key used for the condition.", + "ConditionOnValue": "The value used by the operator.\n\nFor example, you can specify the value 'financial' for strings in the 'Source_URI' field that partially match or contain this value.", + "Operator": "The condition operator.\n\nFor example, you can use 'Contains' to partially match a string." + } + }, + "AWS::Kendra::DataSource.DocumentAttributeTarget": { + "attributes": {}, + "description": "The target document attribute or metadata field you want to alter when ingesting documents into Amazon Kendra.\n\nFor example, you can delete customer identification numbers associated with the documents, stored in the document metadata field called 'Customer_ID'. You set the target key as 'Customer_ID' and the deletion flag to `TRUE` . This removes all customer ID values in the field 'Customer_ID'. This would scrub personally identifiable information from each document's metadata.\n\nAmazon Kendra cannot create a target field if it has not already been created as an index field. After you create your index field, you can create a document metadata field using `DocumentAttributeTarget` . Amazon Kendra then will map your newly created metadata field to your index field.\n\nYou can also use this with [DocumentAttributeCondition](https://docs.aws.amazon.com/kendra/latest/dg/API_DocumentAttributeCondition.html) .", + "properties": { + "TargetDocumentAttributeKey": "The identifier of the target document attribute or metadata field.\n\nFor example, 'Department' could be an identifier for the target attribute or metadata field that includes the department names associated with the documents.", + "TargetDocumentAttributeValue": "The target value you want to create for the target attribute.\n\nFor example, 'Finance' could be the target value for the target attribute key 'Department'.", + "TargetDocumentAttributeValueDeletion": "`TRUE` to delete the existing target value for your specified target attribute key. You cannot create a target value and set this to `TRUE` . To create a target value ( `TargetDocumentAttributeValue` ), set this to `FALSE` ." + } + }, + "AWS::Kendra::DataSource.DocumentAttributeValue": { + "attributes": {}, + "description": "The value of a custom document attribute. You can only provide one value for a custom attribute.", + "properties": { + "DateValue": "A date expressed as an ISO 8601 string.\n\nIt is important for the time zone to be included in the ISO 8601 date-time format. For example, 2012-03-25T12:30:10+01:00 is the ISO 8601 date-time format for March 25th 2012 at 12:30PM (plus 10 seconds) in Central European Time.", + "LongValue": "A long integer value.", + "StringListValue": "A list of strings.", + "StringValue": "A string, such as \"department\"." + } + }, "AWS::Kendra::DataSource.DocumentsMetadataConfiguration": { "attributes": {}, "description": "Document metadata files that contain information such as the document access control information, source URI, document author, and custom attributes. Each metadata file contains metadata about a single document.", @@ -22961,25 +23676,43 @@ }, "AWS::Kendra::DataSource.GoogleDriveConfiguration": { "attributes": {}, - "description": "Provides configuration information for data sources that connect to Google Drive.", + "description": "Provides the configuration information to connect to Google Drive as your data source.", "properties": { "ExcludeMimeTypes": "A list of MIME types to exclude from the index. All documents matching the specified MIME type are excluded.\n\nFor a list of MIME types, see [Using a Google Workspace Drive data source](https://docs.aws.amazon.com/kendra/latest/dg/data-source-google-drive.html) .", "ExcludeSharedDrives": "A list of identifiers or shared drives to exclude from the index. All files and folders stored on the shared drive are excluded.", "ExcludeUserAccounts": "A list of email addresses of the users. Documents owned by these users are excluded from the index. Documents shared with excluded users are indexed unless they are excluded in another way.", - "ExclusionPatterns": "A list of regular expression patterns that apply to the path on Google Drive. Items that match the pattern are excluded from the index from both shared drives and users' My Drives. Items that don't match the pattern are included in the index. If an item matches both an exclusion pattern and an inclusion pattern, it is excluded from the index.", - "FieldMappings": "Defines mapping between a field in the Google Drive and a Amazon Kendra index field.\n\nIf you are using the console, you can define index fields when creating the mapping. If you are using the API, you must first create the field using the `UpdateIndex` operation.", - "InclusionPatterns": "A list of regular expression patterns that apply to path on Google Drive. Items that match the pattern are included in the index from both shared drives and users' My Drives. Items that don't match the pattern are excluded from the index. If an item matches both an inclusion pattern and an exclusion pattern, it is excluded from the index.", + "ExclusionPatterns": "A list of regular expression patterns to exclude certain items in your Google Drive, including shared drives and users' My Drives. Items that match the patterns are excluded from the index. Items that don't match the patterns are included in the index. If an item matches both an inclusion and exclusion pattern, the exclusion pattern takes precedence and the item isn't included in the index.", + "FieldMappings": "Maps Google Drive data source attributes or field names to Amazon Kendra index field names. To create custom fields, use the `UpdateIndex` API before you map to Google Drive fields. For more information, see [Mapping data source fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The Google Drive data source field names must exist in your Google Drive custom metadata.", + "InclusionPatterns": "A list of regular expression patterns to include certain items in your Google Drive, including shared drives and users' My Drives. Items that match the patterns are included in the index. Items that don't match the patterns are excluded from the index. If an item matches both an inclusion and exclusion pattern, the exclusion pattern takes precedence and the item isn't included in the index.", "SecretArn": "The Amazon Resource Name (ARN) of a AWS Secrets Manager secret that contains the credentials required to connect to Google Drive. For more information, see [Using a Google Workspace Drive data source](https://docs.aws.amazon.com/kendra/latest/dg/data-source-google-drive.html) ." } }, + "AWS::Kendra::DataSource.HookConfiguration": { + "attributes": {}, + "description": "Provides the configuration information for invoking a Lambda function in AWS Lambda to alter document metadata and content when ingesting documents into Amazon Kendra. You can configure your Lambda function using [PreExtractionHookConfiguration](https://docs.aws.amazon.com/kendra/latest/dg/API_CustomDocumentEnrichmentConfiguration.html) if you want to apply advanced alterations on the original or raw documents. If you want to apply advanced alterations on the Amazon Kendra structured documents, you must configure your Lambda function using [PostExtractionHookConfiguration](https://docs.aws.amazon.com/kendra/latest/dg/API_CustomDocumentEnrichmentConfiguration.html) . You can only invoke one Lambda function. However, this function can invoke other functions it requires.\n\nFor more information, see [Customizing document metadata during the ingestion process](https://docs.aws.amazon.com/kendra/latest/dg/custom-document-enrichment.html) .", + "properties": { + "InvocationCondition": "The condition used for when a Lambda function should be invoked.\n\nFor example, you can specify a condition that if there are empty date-time values, then Amazon Kendra should invoke a function that inserts the current date-time.", + "LambdaArn": "The Amazon Resource Name (ARN) of a role with permission to run a Lambda function during ingestion. For more information, see [IAM roles for Amazon Kendra](https://docs.aws.amazon.com/kendra/latest/dg/iam-roles.html) .", + "S3Bucket": "Stores the original, raw documents or the structured, parsed documents before and after altering them. For more information, see [Data contracts for Lambda functions](https://docs.aws.amazon.com/kendra/latest/dg/custom-document-enrichment.html#cde-data-contracts-lambda) ." + } + }, + "AWS::Kendra::DataSource.InlineCustomDocumentEnrichmentConfiguration": { + "attributes": {}, + "description": "Provides the configuration information for applying basic logic to alter document metadata and content when ingesting documents into Amazon Kendra. To apply advanced logic, to go beyond what you can do with basic logic, see [HookConfiguration](https://docs.aws.amazon.com/kendra/latest/dg/API_HookConfiguration.html) .\n\nFor more information, see [Customizing document metadata during the ingestion process](https://docs.aws.amazon.com/kendra/latest/dg/custom-document-enrichment.html) .", + "properties": { + "Condition": "Configuration of the condition used for the target document attribute or metadata field when ingesting documents into Amazon Kendra.", + "DocumentContentDeletion": "`TRUE` to delete content if the condition used for the target attribute is met.", + "Target": "Configuration of the target document attribute or metadata field when ingesting documents into Amazon Kendra. You can also include a value." + } + }, "AWS::Kendra::DataSource.OneDriveConfiguration": { "attributes": {}, - "description": "Provides configuration information for data sources that connect to OneDrive.", + "description": "Provides the configuration information to connect to OneDrive as your data source.", "properties": { "DisableLocalGroups": "A Boolean value that specifies whether local groups are disabled ( `True` ) or enabled ( `False` ).", - "ExclusionPatterns": "List of regular expressions applied to documents. Items that match the exclusion pattern are not indexed. If you provide both an inclusion pattern and an exclusion pattern, any item that matches the exclusion pattern isn't indexed.\n\nThe exclusion pattern is applied to the file name.", - "FieldMappings": "A list of `DataSourceToIndexFieldMapping` objects that map Microsoft OneDrive fields to custom fields in the Amazon Kendra index. You must first create the index fields before you map OneDrive fields.", - "InclusionPatterns": "A list of regular expression patterns. Documents that match the pattern are included in the index. Documents that don't match the pattern are excluded from the index. If a document matches both an inclusion pattern and an exclusion pattern, the document is not included in the index.\n\nThe exclusion pattern is applied to the file name.", + "ExclusionPatterns": "A list of regular expression patterns to exclude certain documents in your OneDrive. Documents that match the patterns are excluded from the index. Documents that don't match the patterns are included in the index. If a document matches both an inclusion and exclusion pattern, the exclusion pattern takes precedence and the document isn't included in the index.\n\nThe pattern is applied to the file name.", + "FieldMappings": "A list of `DataSourceToIndexFieldMapping` objects that map OneDrive data source attributes or field names to Amazon Kendra index field names. To create custom fields, use the `UpdateIndex` API before you map to OneDrive fields. For more information, see [Mapping data source fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The OneDrive data source field names must exist in your OneDrive custom metadata.", + "InclusionPatterns": "A list of regular expression patterns to include certain documents in your OneDrive. Documents that match the patterns are included in the index. Documents that don't match the patterns are excluded from the index. If a document matches both an inclusion and exclusion pattern, the exclusion pattern takes precedence and the document isn't included in the index.\n\nThe pattern is applied to the file name.", "OneDriveUsers": "A list of user accounts whose documents should be indexed.", "SecretArn": "The Amazon Resource Name (ARN) of an AWS Secrets Manager secret that contains the user name and password to connect to OneDrive. The user named should be the application ID for the OneDrive application, and the password is the application key for the OneDrive application.", "TenantDomain": "The Azure Active Directory domain of the organization." @@ -23004,7 +23737,7 @@ }, "AWS::Kendra::DataSource.S3DataSourceConfiguration": { "attributes": {}, - "description": "Provides configuration information for a data source to index documents in an Amazon S3 bucket.", + "description": "Provides the configuration information to connect to an Amazon S3 bucket.", "properties": { "AccessControlListConfiguration": "Provides the path to the S3 bucket that contains the user context filtering files for the data source. For the format of the file, see [Access control for S3 data sources](https://docs.aws.amazon.com/kendra/latest/dg/s3-acl.html) .", "BucketName": "The name of the bucket that contains the documents.", @@ -23024,7 +23757,7 @@ }, "AWS::Kendra::DataSource.SalesforceChatterFeedConfiguration": { "attributes": {}, - "description": "Defines configuration for syncing a Salesforce chatter feed. The contents of the object comes from the Salesforce FeedItem table.", + "description": "The configuration information for syncing a Salesforce chatter feed. The contents of the object comes from the Salesforce FeedItem table.", "properties": { "DocumentDataFieldName": "The name of the column in the Salesforce FeedItem table that contains the content to index. Typically this is the `Body` column.", "DocumentTitleFieldName": "The name of the column in the Salesforce FeedItem table that contains the title of the document. This is typically the `Title` column.", @@ -23034,50 +23767,50 @@ }, "AWS::Kendra::DataSource.SalesforceConfiguration": { "attributes": {}, - "description": "Provides configuration information for connecting to a Salesforce data source.", + "description": "Provides the configuration information to connect to Salesforce as your data source.", "properties": { - "ChatterFeedConfiguration": "Specifies configuration information for Salesforce chatter feeds.", + "ChatterFeedConfiguration": "Configuration information for Salesforce chatter feeds.", "CrawlAttachments": "Indicates whether Amazon Kendra should index attachments to Salesforce objects.", - "ExcludeAttachmentFilePatterns": "A list of regular expression patterns. Documents that match the patterns are excluded from the index. Documents that don't match the patterns are included in the index. If a document matches both an exclusion pattern and an inclusion pattern, the document is not included in the index.\n\nThe regex is applied to the name of the attached file.", - "IncludeAttachmentFilePatterns": "A list of regular expression patterns. Documents that match the patterns are included in the index. Documents that don't match the patterns are excluded from the index. If a document matches both an inclusion pattern and an exclusion pattern, the document is not included in the index.\n\nThe regex is applied to the name of the attached file.", - "KnowledgeArticleConfiguration": "Specifies configuration information for the knowledge article types that Amazon Kendra indexes. Amazon Kendra indexes standard knowledge articles and the standard fields of knowledge articles, or the custom fields of custom knowledge articles, but not both.", + "ExcludeAttachmentFilePatterns": "A list of regular expression patterns to exclude certain documents in your Salesforce. Documents that match the patterns are excluded from the index. Documents that don't match the patterns are included in the index. If a document matches both an inclusion and exclusion pattern, the exclusion pattern takes precedence and the document isn't included in the index.\n\nThe pattern is applied to the name of the attached file.", + "IncludeAttachmentFilePatterns": "A list of regular expression patterns to include certain documents in your Salesforce. Documents that match the patterns are included in the index. Documents that don't match the patterns are excluded from the index. If a document matches both an inclusion and exclusion pattern, the exclusion pattern takes precedence and the document isn't included in the index.\n\nThe pattern is applied to the name of the attached file.", + "KnowledgeArticleConfiguration": "Configuration information for the knowledge article types that Amazon Kendra indexes. Amazon Kendra indexes standard knowledge articles and the standard fields of knowledge articles, or the custom fields of custom knowledge articles, but not both.", "SecretArn": "The Amazon Resource Name (ARN) of an AWS Secrets Manager secret that contains the key/value pairs required to connect to your Salesforce instance. The secret must contain a JSON structure with the following keys:\n\n- authenticationUrl - The OAUTH endpoint that Amazon Kendra connects to get an OAUTH token.\n- consumerKey - The application public key generated when you created your Salesforce application.\n- consumerSecret - The application private key generated when you created your Salesforce application.\n- password - The password associated with the user logging in to the Salesforce instance.\n- securityToken - The token associated with the user account logging in to the Salesforce instance.\n- username - The user name of the user logging in to the Salesforce instance.", "ServerUrl": "The instance URL for the Salesforce site that you want to index.", - "StandardObjectAttachmentConfiguration": "Provides configuration information for processing attachments to Salesforce standard objects.", - "StandardObjectConfigurations": "Specifies the Salesforce standard objects that Amazon Kendra indexes." + "StandardObjectAttachmentConfiguration": "Configuration information for processing attachments to Salesforce standard objects.", + "StandardObjectConfigurations": "Configuration of the Salesforce standard objects that Amazon Kendra indexes." } }, "AWS::Kendra::DataSource.SalesforceCustomKnowledgeArticleTypeConfiguration": { "attributes": {}, - "description": "Provides configuration information for indexing Salesforce custom articles.", + "description": "Provides the configuration information for indexing Salesforce custom articles.", "properties": { "DocumentDataFieldName": "The name of the field in the custom knowledge article that contains the document data to index.", "DocumentTitleFieldName": "The name of the field in the custom knowledge article that contains the document title.", - "FieldMappings": "One or more objects that map fields in the custom knowledge article to fields in the Amazon Kendra index.", + "FieldMappings": "Maps attributes or field names of the custom knowledge article to Amazon Kendra index field names. To create custom fields, use the `UpdateIndex` API before you map to Salesforce fields. For more information, see [Mapping data source fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The Salesforce data source field names must exist in your Salesforce custom metadata.", "Name": "The name of the configuration." } }, "AWS::Kendra::DataSource.SalesforceKnowledgeArticleConfiguration": { "attributes": {}, - "description": "Specifies configuration information for the knowledge article types that Amazon Kendra indexes. Amazon Kendra indexes standard knowledge articles and the standard fields of knowledge articles, or the custom fields of custom knowledge articles, but not both", + "description": "Provides the configuration information for the knowledge article types that Amazon Kendra indexes. Amazon Kendra indexes standard knowledge articles and the standard fields of knowledge articles, or the custom fields of custom knowledge articles, but not both", "properties": { - "CustomKnowledgeArticleTypeConfigurations": "Provides configuration information for custom Salesforce knowledge articles.", + "CustomKnowledgeArticleTypeConfigurations": "Configuration information for custom Salesforce knowledge articles.", "IncludedStates": "Specifies the document states that should be included when Amazon Kendra indexes knowledge articles. You must specify at least one state.", - "StandardKnowledgeArticleTypeConfiguration": "Provides configuration information for standard Salesforce knowledge articles." + "StandardKnowledgeArticleTypeConfiguration": "Configuration information for standard Salesforce knowledge articles." } }, "AWS::Kendra::DataSource.SalesforceStandardKnowledgeArticleTypeConfiguration": { "attributes": {}, - "description": "Provides configuration information for standard Salesforce knowledge articles.", + "description": "Provides the configuration information for standard Salesforce knowledge articles.", "properties": { "DocumentDataFieldName": "The name of the field that contains the document data to index.", "DocumentTitleFieldName": "The name of the field that contains the document title.", - "FieldMappings": "One or more objects that map fields in the knowledge article to Amazon Kendra index fields. The index field must exist before you can map a Salesforce field to it." + "FieldMappings": "Maps attributes or field names of the knowledge article to Amazon Kendra index field names. To create custom fields, use the `UpdateIndex` API before you map to Salesforce fields. For more information, see [Mapping data source fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The Salesforce data source field names must exist in your Salesforce custom metadata." } }, "AWS::Kendra::DataSource.SalesforceStandardObjectAttachmentConfiguration": { "attributes": {}, - "description": "Provides configuration information for processing attachments to Salesforce standard objects.", + "description": "Provides the configuration information for processing attachments to Salesforce standard objects.", "properties": { "DocumentTitleFieldName": "The name of the field used for the document title.", "FieldMappings": "One or more objects that map fields in attachments to Amazon Kendra index fields." @@ -23089,62 +23822,62 @@ "properties": { "DocumentDataFieldName": "The name of the field in the standard object table that contains the document contents.", "DocumentTitleFieldName": "The name of the field in the standard object table that contains the document title.", - "FieldMappings": "One or more objects that map fields in the standard object to Amazon Kendra index fields. The index field must exist before you can map a Salesforce field to it.", + "FieldMappings": "Maps attributes or field names of the standard object to Amazon Kendra index field names. To create custom fields, use the `UpdateIndex` API before you map to Salesforce fields. For more information, see [Mapping data source fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The Salesforce data source field names must exist in your Salesforce custom metadata.", "Name": "The name of the standard object." } }, "AWS::Kendra::DataSource.ServiceNowConfiguration": { "attributes": {}, - "description": "Provides configuration information required to connect to a ServiceNow data source.", + "description": "Provides the configuration information to connect to ServiceNow as your data source.", "properties": { - "AuthenticationType": "Determines the type of authentication used to connect to the ServiceNow instance. If you choose `HTTP_BASIC` , Amazon Kendra is authenticated using the user name and password provided in the AWS Secrets Manager secret in the `SecretArn` field. When you choose `OAUTH2` , Amazon Kendra is authenticated using the OAuth token and secret provided in the Secrets Manager secret, and the user name and password are used to determine which information Amazon Kendra has access to.\n\nWhen you use `OAUTH2` authentication, you must generate a token and a client secret using the ServiceNow console. For more information, see [Using a ServiceNow data source](https://docs.aws.amazon.com/kendra/latest/dg/data-source-servicenow.html) .", - "HostUrl": "The ServiceNow instance that the data source connects to. The host endpoint should look like the following: `{instance}.service-now.com.`", - "KnowledgeArticleConfiguration": "Provides configuration information for crawling knowledge articles in the ServiceNow site.", + "AuthenticationType": "The type of authentication used to connect to the ServiceNow instance. If you choose `HTTP_BASIC` , Amazon Kendra is authenticated using the user name and password provided in the AWS Secrets Manager secret in the `SecretArn` field. When you choose `OAUTH2` , Amazon Kendra is authenticated using the OAuth token and secret provided in the Secrets Manager secret, and the user name and password are used to determine which information Amazon Kendra has access to.\n\nWhen you use `OAUTH2` authentication, you must generate a token and a client secret using the ServiceNow console. For more information, see [Using a ServiceNow data source](https://docs.aws.amazon.com/kendra/latest/dg/data-source-servicenow.html) .", + "HostUrl": "The ServiceNow instance that the data source connects to. The host endpoint should look like the following: *{instance}.service-now.com.*", + "KnowledgeArticleConfiguration": "Configuration information for crawling knowledge articles in the ServiceNow site.", "SecretArn": "The Amazon Resource Name (ARN) of the AWS Secrets Manager secret that contains the user name and password required to connect to the ServiceNow instance.", - "ServiceCatalogConfiguration": "Provides configuration information for crawling service catalogs in the ServiceNow site.", + "ServiceCatalogConfiguration": "Configuration information for crawling service catalogs in the ServiceNow site.", "ServiceNowBuildVersion": "The identifier of the release that the ServiceNow host is running. If the host is not running the `LONDON` release, use `OTHERS` ." } }, "AWS::Kendra::DataSource.ServiceNowKnowledgeArticleConfiguration": { "attributes": {}, - "description": "Provides configuration information for crawling knowledge articles in the ServiceNow site.", + "description": "Provides the configuration information for crawling knowledge articles in the ServiceNow site.", "properties": { "CrawlAttachments": "Indicates whether Amazon Kendra should index attachments to knowledge articles.", "DocumentDataFieldName": "The name of the ServiceNow field that is mapped to the index document contents field in the Amazon Kendra index.", "DocumentTitleFieldName": "The name of the ServiceNow field that is mapped to the index document title field.", - "ExcludeAttachmentFilePatterns": "List of regular expressions applied to knowledge articles. Items that don't match the inclusion pattern are not indexed. The regex is applied to the field specified in the `PatternTargetField`", - "FieldMappings": "Mapping between ServiceNow fields and Amazon Kendra index fields. You must create the index field before you map the field.", + "ExcludeAttachmentFilePatterns": "A list of regular expression patterns to exclude certain attachments of knowledge articles in your ServiceNow. Item that match the patterns are excluded from the index. Items that don't match the patterns are included in the index. If an item matches both an inclusion and exclusion pattern, the exclusion pattern takes precedence and the item isn't included in the index.\n\nThe regex is applied to the field specified in the `PatternTargetField` .", + "FieldMappings": "Maps attributes or field names of knoweldge articles to Amazon Kendra index field names. To create custom fields, use the `UpdateIndex` API before you map to ServiceNow fields. For more information, see [Mapping data source fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The ServiceNow data source field names must exist in your ServiceNow custom metadata.", "FilterQuery": "A query that selects the knowledge articles to index. The query can return articles from multiple knowledge bases, and the knowledge bases can be public or private.\n\nThe query string must be one generated by the ServiceNow console. For more information, see [Specifying documents to index with a query](https://docs.aws.amazon.com/kendra/latest/dg/servicenow-query.html) .", - "IncludeAttachmentFilePatterns": "List of regular expressions applied to knowledge articles. Items that don't match the inclusion pattern are not indexed. The regex is applied to the field specified in the `PatternTargetField` ." + "IncludeAttachmentFilePatterns": "A list of regular expression patterns to include certain attachments of knowledge articles in your ServiceNow. Item that match the patterns are included in the index. Items that don't match the patterns are excluded from the index. If an item matches both an inclusion and exclusion pattern, the exclusion pattern takes precedence and the item isn't included in the index.\n\nThe regex is applied to the field specified in the `PatternTargetField` ." } }, "AWS::Kendra::DataSource.ServiceNowServiceCatalogConfiguration": { "attributes": {}, - "description": "Provides configuration information for crawling service catalog items in the ServiceNow site", + "description": "Provides the configuration information for crawling service catalog items in the ServiceNow site", "properties": { "CrawlAttachments": "Indicates whether Amazon Kendra should crawl attachments to the service catalog items.", "DocumentDataFieldName": "The name of the ServiceNow field that is mapped to the index document contents field in the Amazon Kendra index.", "DocumentTitleFieldName": "The name of the ServiceNow field that is mapped to the index document title field.", - "ExcludeAttachmentFilePatterns": "A list of regular expression patterns. Documents that match the patterns are excluded from the index. Documents that don't match the patterns are included in the index. If a document matches both an exclusion pattern and an inclusion pattern, the document is not included in the index.\n\nThe regex is applied to the file name of the attachment.", - "FieldMappings": "Mapping between ServiceNow fields and Amazon Kendra index fields. You must create the index field before you map the field.", - "IncludeAttachmentFilePatterns": "A list of regular expression patterns. Documents that match the patterns are included in the index. Documents that don't match the patterns are excluded from the index. If a document matches both an exclusion pattern and an inclusion pattern, the document is not included in the index.\n\nThe regex is applied to the file name of the attachment." + "ExcludeAttachmentFilePatterns": "A list of regular expression patterns to exclude certain attachments of catalogs in your ServiceNow. Item that match the patterns are excluded from the index. Items that don't match the patterns are included in the index. If an item matches both an inclusion and exclusion pattern, the exclusion pattern takes precedence and the item isn't included in the index.\n\nThe regex is applied to the file name of the attachment.", + "FieldMappings": "Maps attributes or field names of catalogs to Amazon Kendra index field names. To create custom fields, use the `UpdateIndex` API before you map to ServiceNow fields. For more information, see [Mapping data source fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The ServiceNow data source field names must exist in your ServiceNow custom metadata.", + "IncludeAttachmentFilePatterns": "A list of regular expression patterns to include certain attachments of catalogs in your ServiceNow. Item that match the patterns are included in the index. Items that don't match the patterns are excluded from the index. If an item matches both an inclusion and exclusion pattern, the exclusion pattern takes precedence and the item isn't included in the index.\n\nThe regex is applied to the file name of the attachment." } }, "AWS::Kendra::DataSource.SharePointConfiguration": { "attributes": {}, - "description": "Provides configuration information for connecting to a Microsoft SharePoint data source.", + "description": "Provides the configuration information to connect to Microsoft SharePoint as your data source.", "properties": { "CrawlAttachments": "`TRUE` to include attachments to documents stored in your Microsoft SharePoint site in the index; otherwise, `FALSE` .", "DisableLocalGroups": "A Boolean value that specifies whether local groups are disabled ( `True` ) or enabled ( `False` ).", "DocumentTitleFieldName": "The Microsoft SharePoint attribute field that contains the title of the document.", "ExclusionPatterns": "A list of regular expression patterns. Documents that match the patterns are excluded from the index. Documents that don't match the patterns are included in the index. If a document matches both an exclusion pattern and an inclusion pattern, the document is not included in the index.\n\nThe regex is applied to the display URL of the SharePoint document.", "FieldMappings": "A list of `DataSourceToIndexFieldMapping` objects that map Microsoft SharePoint attributes to custom fields in the Amazon Kendra index. You must first create the index fields using the [UpdateIndex](https://docs.aws.amazon.com/kendra/latest/dg/API_UpdateIndex.html) operation before you map SharePoint attributes. For more information, see [Mapping Data Source Fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) .", - "InclusionPatterns": "A list of regular expression patterns. Documents that match the patterns are included in the index. Documents that don't match the patterns are excluded from the index. If a document matches both an inclusion pattern and an exclusion pattern, the document is not included in the index.\n\nThe regex is applied to the display URL of the SharePoint document.", + "InclusionPatterns": "A list of regular expression patterns to include certain documents in your SharePoint. Documents that match the patterns are included in the index. Documents that don't match the patterns are excluded from the index. If a document matches both an inclusion and exclusion pattern, the exclusion pattern takes precedence and the document isn't included in the index.\n\nThe regex is applied to the display URL of the SharePoint document.", "SecretArn": "The Amazon Resource Name (ARN) of credentials stored in AWS Secrets Manager . The credentials should be a user/password pair. If you use SharePoint Server, you also need to provide the sever domain name as part of the credentials. For more information, see [Using a Microsoft SharePoint Data Source](https://docs.aws.amazon.com/kendra/latest/dg/data-source-sharepoint.html) . For more information about AWS Secrets Manager see [What Is AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) in the *AWS Secrets Manager* user guide.", "SharePointVersion": "The version of Microsoft SharePoint that you are using as a data source.", "SslCertificateS3Path": "Information required to find a specific file in an Amazon S3 bucket.", "Urls": "The URLs of the Microsoft SharePoint site that contains the documents that should be indexed.", - "UseChangeLog": "Set to `TRUE` to use the Microsoft SharePoint change log to determine the documents that need to be updated in the index. Depending on the size of the SharePoint change log, it may take longer for Amazon Kendra to use the change log than it takes it to determine the changed documents using the Amazon Kendra document crawler.", + "UseChangeLog": "`TRUE` to use the SharePoint change log to determine which documents require updating in the index. Depending on the change log's size, it may take longer for Amazon Kendra to use the change log than to scan all of your documents in SharePoint.", "VpcConfiguration": "Provides information for connecting to an Amazon VPC." } }, @@ -23175,14 +23908,14 @@ "attributes": {}, "description": "Provides the configuration information required for Amazon Kendra Web Crawler.", "properties": { - "AuthenticationConfiguration": "Provides configuration information required to connect to websites using authentication.\n\nYou can connect to websites using basic authentication of user name and password.\n\nYou must provide the website host name and port number. For example, the host name of https://a.example.com/page1.html is \"a.example.com\" and the port is 443, the standard port for HTTPS. You use a secret in [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) to store your authentication credentials.", + "AuthenticationConfiguration": "Configuration information required to connect to websites using authentication.\n\nYou can connect to websites using basic authentication of user name and password.\n\nYou must provide the website host name and port number. For example, the host name of https://a.example.com/page1.html is \"a.example.com\" and the port is 443, the standard port for HTTPS. You use a secret in [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) to store your authentication credentials.", "CrawlDepth": "Specifies the number of levels in a website that you want to crawl.\n\nThe first level begins from the website seed or starting point URL. For example, if a website has 3 levels \u2013 index level (i.e. seed in this example), sections level, and subsections level \u2013 and you are only interested in crawling information up to the sections level (i.e. levels 0-1), you can set your depth to 1.\n\nThe default crawl depth is set to 2.", "MaxContentSizePerPageInMegaBytes": "The maximum size (in MB) of a webpage or attachment to crawl.\n\nFiles larger than this size (in MB) are skipped/not crawled.\n\nThe default maximum size of a webpage or attachment is set to 50 MB.", "MaxLinksPerPage": "The maximum number of URLs on a webpage to include when crawling a website. This number is per webpage.\n\nAs a website\u2019s webpages are crawled, any URLs the webpages link to are also crawled. URLs on a webpage are crawled in order of appearance.\n\nThe default maximum links per page is 100.", "MaxUrlsPerMinuteCrawlRate": "The maximum number of URLs crawled per website host per minute.\n\nA minimum of one URL is required.\n\nThe default maximum number of URLs crawled per website host per minute is 300.", - "ProxyConfiguration": "Provides configuration information required to connect to your internal websites via a web proxy.\n\nYou must provide the website host name and port number. For example, the host name of https://a.example.com/page1.html is \"a.example.com\" and the port is 443, the standard port for HTTPS.\n\nWeb proxy credentials are optional and you can use them to connect to a web proxy server that requires basic authentication. To store web proxy credentials, you use a secret in [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) .", - "UrlExclusionPatterns": "The regular expression pattern to exclude certain URLs to crawl.\n\nIf there is a regular expression pattern to include certain URLs that conflicts with the exclude pattern, the exclude pattern takes precedence.", - "UrlInclusionPatterns": "The regular expression pattern to include certain URLs to crawl.\n\nIf there is a regular expression pattern to exclude certain URLs that conflicts with the include pattern, the exclude pattern takes precedence.", + "ProxyConfiguration": "Configuration information required to connect to your internal websites via a web proxy.\n\nYou must provide the website host name and port number. For example, the host name of https://a.example.com/page1.html is \"a.example.com\" and the port is 443, the standard port for HTTPS.\n\nWeb proxy credentials are optional and you can use them to connect to a web proxy server that requires basic authentication. To store web proxy credentials, you use a secret in [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) .", + "UrlExclusionPatterns": "A list of regular expression patterns to exclude certain URLs to crawl. URLs that match the patterns are excluded from the index. URLs that don't match the patterns are included in the index. If a URL matches both an inclusion and exclusion pattern, the exclusion pattern takes precedence and the URL file isn't included in the index.", + "UrlInclusionPatterns": "A list of regular expression patterns to include certain URLs to crawl. URLs that match the patterns are included in the index. URLs that don't match the patterns are excluded from the index. If a URL matches both an inclusion and exclusion pattern, the exclusion pattern takes precedence and the URL file isn't included in the index.", "Urls": "Specifies the seed or starting point URLs of the websites or the sitemap URLs of the websites you want to crawl.\n\nYou can include website subdomains. You can list up to 100 seed URLs and up to three sitemap URLs.\n\nYou can only crawl websites that use the secure communication protocol, Hypertext Transfer Protocol Secure (HTTPS). If you receive an error when crawling a website, it could be that the website is blocked from crawling.\n\n*When selecting websites to index, you must adhere to the [Amazon Acceptable Use Policy](https://docs.aws.amazon.com/aup/) and all other Amazon terms. Remember that you must only use Amazon Kendra Web Crawler to index your own webpages, or webpages that you have authorization to index.*" } }, @@ -23205,8 +23938,8 @@ "attributes": {}, "description": "Specifies the seed or starting point URLs of the websites or the sitemap URLs of the websites you want to crawl.\n\nYou can include website subdomains. You can list up to 100 seed URLs and up to three sitemap URLs.\n\nYou can only crawl websites that use the secure communication protocol, Hypertext Transfer Protocol Secure (HTTPS). If you receive an error when crawling a website, it could be that the website is blocked from crawling.\n\n*When selecting websites to index, you must adhere to the [Amazon Acceptable Use Policy](https://docs.aws.amazon.com/aup/) and all other Amazon terms. Remember that you must only use the Amazon Kendra web crawler to index your own webpages, or webpages that you have authorization to index.*", "properties": { - "SeedUrlConfiguration": "Provides the configuration of the seed or starting point URLs of the websites you want to crawl.\n\nYou can choose to crawl only the website host names, or the website host names with subdomains, or the website host names with subdomains and other domains that the webpages link to.\n\nYou can list up to 100 seed URLs.", - "SiteMapsConfiguration": "Provides the configuration of the sitemap URLs of the websites you want to crawl.\n\nOnly URLs belonging to the same website host names are crawled. You can list up to three sitemap URLs." + "SeedUrlConfiguration": "Configuration of the seed or starting point URLs of the websites you want to crawl.\n\nYou can choose to crawl only the website host names, or the website host names with subdomains, or the website host names with subdomains and other domains that the webpages link to.\n\nYou can list up to 100 seed URLs.", + "SiteMapsConfiguration": "Configuration of the sitemap URLs of the websites you want to crawl.\n\nOnly URLs belonging to the same website host names are crawled. You can list up to three sitemap URLs." } }, "AWS::Kendra::DataSource.WorkDocsConfiguration": { @@ -23214,11 +23947,11 @@ "description": "Provides the configuration information to connect to Amazon WorkDocs as your data source.\n\nAmazon WorkDocs connector is available in Oregon, North Virginia, Sydney, Singapore and Ireland regions.", "properties": { "CrawlComments": "`TRUE` to include comments on documents in your index. Including comments in your index means each comment is a document that can be searched on.\n\nThe default is set to `FALSE` .", - "ExclusionPatterns": "A list of regular expression patterns to exclude certain files in your Amazon WorkDocs site repository. Files that match the patterns are excluded from the index. Files that don\u2019t match the patterns are included in the index. If a file matches both an inclusion pattern and an exclusion pattern, the exclusion pattern takes precedence and the file isn\u2019t included in the index.", - "FieldMappings": "A list of `DataSourceToIndexFieldMapping` objects that map Amazon WorkDocs field names to custom index field names in Amazon Kendra. You must first create the custom index fields using the `UpdateIndex` operation before you map to Amazon WorkDocs fields. For more information, see [Mapping Data Source Fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The Amazon WorkDocs data source field names need to exist in your Amazon WorkDocs custom metadata.", - "InclusionPatterns": "A list of regular expression patterns to include certain files in your Amazon WorkDocs site repository. Files that match the patterns are included in the index. Files that don't match the patterns are excluded from the index. If a file matches both an inclusion pattern and an exclusion pattern, the exclusion pattern takes precedence and the file isn\u2019t included in the index.", + "ExclusionPatterns": "A list of regular expression patterns to exclude certain files in your Amazon WorkDocs site repository. Files that match the patterns are excluded from the index. Files that don\u2019t match the patterns are included in the index. If a file matches both an inclusion and exclusion pattern, the exclusion pattern takes precedence and the file isn't included in the index.", + "FieldMappings": "A list of `DataSourceToIndexFieldMapping` objects that map Amazon WorkDocs data source attributes or field names to Amazon Kendra index field names. To create custom fields, use the `UpdateIndex` API before you map to Amazon WorkDocs fields. For more information, see [Mapping data source fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The Amazon WorkDocs data source field names must exist in your Amazon WorkDocs custom metadata.", + "InclusionPatterns": "A list of regular expression patterns to include certain files in your Amazon WorkDocs site repository. Files that match the patterns are included in the index. Files that don't match the patterns are excluded from the index. If a file matches both an inclusion and exclusion pattern, the exclusion pattern takes precedence and the file isn't included in the index.", "OrganizationId": "The identifier of the directory corresponding to your Amazon WorkDocs site repository.\n\nYou can find the organization ID in the [AWS Directory Service](https://docs.aws.amazon.com/directoryservicev2/) by going to *Active Directory* , then *Directories* . Your Amazon WorkDocs site directory has an ID, which is the organization ID. You can also set up a new Amazon WorkDocs directory in the AWS Directory Service console and enable a Amazon WorkDocs site for the directory in the Amazon WorkDocs console.", - "UseChangeLog": "`TRUE` to use the change logs to update documents in your index instead of scanning all documents.\n\nIf you are syncing your Amazon WorkDocs data source with your index for the first time, all documents are scanned. After your first sync, you can use the change logs to update your documents in your index for future syncs.\n\nThe default is set to `FALSE` ." + "UseChangeLog": "`TRUE` to use the Amazon WorkDocs change log to determine which documents require updating in the index. Depending on the change log's size, it may take longer for Amazon Kendra to use the change log than to scan all of your documents in Amazon WorkDocs." } }, "AWS::Kendra::Faq": { @@ -23258,7 +23991,7 @@ "Description": "A description of the index.", "DocumentMetadataConfigurations": "Specifies the properties of an index field. You can add either a custom or a built-in field. You can add and remove built-in fields at any time. When a built-in field is removed it's configuration reverts to the default for the field. Custom fields can't be removed from an index after they are added.", "Edition": "Indicates whether the index is a enterprise edition index or a developer edition index. Valid values are `DEVELOPER_EDITION` and `ENTERPRISE_EDITION` .", - "Name": "The name of the index.", + "Name": "The identifier of the index.", "RoleArn": "An IAM role that gives Amazon Kendra permissions to access your Amazon CloudWatch logs and metrics. This is also the role used when you use the [BatchPutDocument](https://docs.aws.amazon.com/kendra/latest/dg/BatchPutDocument.html) operation to index documents from an Amazon S3 bucket.", "ServerSideEncryptionConfiguration": "The identifier of the AWS KMS customer managed key (CMK) to use to encrypt data indexed by Amazon Kendra. Amazon Kendra doesn't support asymmetric CMKs.", "Tags": "An array of key-value pairs to apply to this resource.\n\nFor more information, see [Tag](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resource-tags.html) .", @@ -23268,7 +24001,7 @@ }, "AWS::Kendra::Index.CapacityUnitsConfiguration": { "attributes": {}, - "description": "Specifies capacity units configured for your enterprise edition index. You can add and remove capacity units to tune an index to your requirements.", + "description": "Specifies additional capacity units configured for your Enterprise Edition index. You can add and remove capacity units to fit your usage requirements.", "properties": { "QueryCapacityUnits": "The amount of extra query capacity for an index and [GetQuerySuggestions](https://docs.aws.amazon.com/kendra/latest/dg/API_GetQuerySuggestions.html) capacity.\n\nA single extra capacity unit for an index provides 0.1 queries per second or approximately 8,000 queries per day.\n\n`GetQuerySuggestions` capacity is five times the provisioned query capacity for an index, or the base capacity of 2.5 calls per second, whichever is higher. For example, the base capacity for an index is 0.1 queries per second, and `GetQuerySuggestions` capacity has a base of 2.5 calls per second. If you add another 0.1 queries per second to total 0.2 queries per second for an index, the `GetQuerySuggestions` capacity is 2.5 calls per second (higher than five times 0.2 queries per second).", "StorageCapacityUnits": "The amount of extra storage capacity for an index. A single capacity unit provides 30 GB of storage space or 100,000 documents, whichever is reached first." @@ -23286,7 +24019,7 @@ }, "AWS::Kendra::Index.JsonTokenTypeConfiguration": { "attributes": {}, - "description": "Configuration information for the JSON token type.", + "description": "Provides the configuration information for the JSON token type.", "properties": { "GroupAttributeField": "The group attribute field.", "UserNameAttributeField": "The user name attribute field." @@ -23294,7 +24027,7 @@ }, "AWS::Kendra::Index.JwtTokenTypeConfiguration": { "attributes": {}, - "description": "Configuration information for the JWT token type.", + "description": "Provides the configuration information for the JWT token type.", "properties": { "ClaimRegex": "The regular expression that identifies the claim.", "GroupAttributeField": "The group attribute field.", @@ -23335,7 +24068,7 @@ }, "AWS::Kendra::Index.UserTokenConfiguration": { "attributes": {}, - "description": "Provides configuration information for a token configuration.", + "description": "Provides the configuration information for a token.", "properties": { "JsonTokenTypeConfiguration": "Information about the JSON token type configuration.", "JwtTokenTypeConfiguration": "Information about the JWT token type configuration." @@ -24696,6 +25429,20 @@ "KafkaBootstrapServers": "The list of bootstrap servers for your Kafka brokers in the following format: `\"KafkaBootstrapServers\": [\"abc.xyz.com:xxxx\",\"abc2.xyz.com:xxxx\"]` ." } }, + "AWS::Lambda::EventSourceMapping.Filter": { + "attributes": {}, + "description": "A structure within a `FilterCriteria` object that defines an event filtering pattern.", + "properties": { + "Pattern": "A filter pattern. For more information on the syntax of a filter pattern, see [Filter rule syntax](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html#filtering-syntax) ." + } + }, + "AWS::Lambda::EventSourceMapping.FilterCriteria": { + "attributes": {}, + "description": "An object that contains the filters for an event source.", + "properties": { + "Filters": "A list of filters." + } + }, "AWS::Lambda::EventSourceMapping.OnFailure": { "attributes": {}, "description": "A destination for events that failed processing.", @@ -24731,6 +25478,7 @@ "DeadLetterConfig": "A dead letter queue configuration that specifies the queue or topic where Lambda sends asynchronous events when they fail processing. For more information, see [Dead Letter Queues](https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html#dlq) .", "Description": "A description of the function.", "Environment": "Environment variables that are accessible from function code during execution.", + "EphemeralStorage": "The size of the function\u2019s /tmp directory in MB. The default value is 512, but can be any whole number between 512 and 10240 MB.", "FileSystemConfigs": "Connection settings for an Amazon EFS file system. To connect a function to a file system, a mount target must be available in every Availability Zone that your function connects to. If your template contains an [AWS::EFS::MountTarget](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-efs-mounttarget.html) resource, you must also specify a `DependsOn` attribute to ensure that the mount target is created or updated before the function.\n\nFor more information about using the `DependsOn` attribute, see [DependsOn Attribute](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-dependson.html) .", "FunctionName": "The name of the Lambda function, up to 64 characters in length. If you don't specify a name, AWS CloudFormation generates one.\n\nIf you specify a name, you cannot perform updates that require replacement of this resource. You can perform updates that require no or some interruption. If you must replace the resource, specify a new name.", "Handler": "The name of the method within your code that Lambda calls to execute your function. Handler is required if the deployment package is a .zip file archive. The format includes the file name. It can also include namespaces and other qualifiers, depending on the runtime. For more information, see [Programming Model](https://docs.aws.amazon.com/lambda/latest/dg/programming-model-v2.html) .", @@ -24773,6 +25521,13 @@ "Variables": "Environment variable key-value pairs. For more information, see [Using Lambda environment variables](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html) ." } }, + "AWS::Lambda::Function.EphemeralStorage": { + "attributes": {}, + "description": "The size of the function\u2019s /tmp directory in MB. The default value is 512, but can be any whole number between 512 and 10240 MB.", + "properties": { + "Size": "The size of the function\u2019s /tmp directory." + } + }, "AWS::Lambda::Function.FileSystemConfig": { "attributes": {}, "description": "Details about the connection between a Lambda function and an [Amazon EFS file system](https://docs.aws.amazon.com/lambda/latest/dg/configuration-filesystem.html) .", @@ -24888,13 +25643,53 @@ "IdleSessionTTLInSeconds": "The time, in seconds, that Amazon Lex should keep information about a user's conversation with the bot.\n\nA user interaction remains active for the amount of time specified. If no conversation occurs during this time, the session expires and Amazon Lex deletes any data provided before the timeout.\n\nYou can specify between 60 (1 minute) and 86,400 (24 hours) seconds.", "Name": "The name of the field to filter the list of bots.", "RoleArn": "The Amazon Resource Name (ARN) of the IAM role used to build and run the bot.", + "TestBotAliasSettings": "Specifies configuration settings for the alias used to test the bot. If the `TestBotAliasSettings` property is not specified, the settings are configured with default values.", "TestBotAliasTags": "A list of tags to add to the test alias for a bot. You can only add tags when you import a bot. You can't use the `UpdateAlias` operation to update tags. To update tags on the test alias, use the `TagResource` operation." } }, + "AWS::Lex::Bot.AdvancedRecognitionSetting": { + "attributes": {}, + "description": "Specifies settings that enable advanced audio recognition for slot values.", + "properties": { + "AudioRecognitionStrategy": "Specifies that Amazon Lex should use slot values as a custom vocabulary when recognizing user utterances." + } + }, + "AWS::Lex::Bot.AudioLogDestination": { + "attributes": {}, + "description": "Specifies the location of audio log files collected when conversation logging is enabled for a bot.", + "properties": { + "S3Bucket": "Specifies the Amazon S3 bucket where the audio files are stored." + } + }, + "AWS::Lex::Bot.AudioLogSetting": { + "attributes": {}, + "description": "Specifies settings for logging the audio of conversations between Amazon Lex and a user. You specify whether to log audio and the Amazon S3 bucket where the audio file is stored.", + "properties": { + "Destination": "Specifies the location of the audio log files collected when conversation logging is enabled for a bot.", + "Enabled": "Specifies whether audio logging is enabled for the bot." + } + }, + "AWS::Lex::Bot.BotAliasLocaleSettings": { + "attributes": {}, + "description": "Specifies settings that are unique to a locale. For example, you can use a different Lambda function for each locale.", + "properties": { + "CodeHookSpecification": "Specifies the Lambda function to use in this locale.", + "Enabled": "Specifies whether the locale is enabled for the bot. If the value is false, the locale isn't available for use." + } + }, + "AWS::Lex::Bot.BotAliasLocaleSettingsItem": { + "attributes": {}, + "description": "Specifies locale settings for a single locale.", + "properties": { + "BotAliasLocaleSetting": "Specifies locale settings for a locale.", + "LocaleId": "Specifies the locale that the settings apply to." + } + }, "AWS::Lex::Bot.BotLocale": { "attributes": {}, "description": "Provides configuration information for a locale.", "properties": { + "CustomVocabulary": "Specifies a custom vocabulary to use with a specific locale.", "Description": "A description of the bot locale. Use this to help identify the bot locale in lists.", "Intents": "One or more intents defined for the locale.", "LocaleId": "The identifier of the language and locale that the bot will be used in. The string must match one of the supported locales.", @@ -24911,6 +25706,29 @@ "Value": "The value returned to Amazon Lex when the user chooses this button. This must be one of the slot values configured for the slot." } }, + "AWS::Lex::Bot.CloudWatchLogGroupLogDestination": { + "attributes": {}, + "description": "Specifies the Amazon CloudWatch Logs log group where text and metadata logs are delivered. The log group must exist before you enable logging.", + "properties": { + "CloudWatchLogGroupArn": "Specifies the Amazon Resource Name (ARN) of the log group where text and metadata logs are delivered.", + "LogPrefix": "Specifies the prefix of the log stream name within the log group that you specified." + } + }, + "AWS::Lex::Bot.CodeHookSpecification": { + "attributes": {}, + "description": "Specifies information about code hooks that Amazon Lex calls during a conversation.", + "properties": { + "LambdaCodeHook": "Specifies a Lambda function that verifies requests to a bot or fulfills the user's request to a bot." + } + }, + "AWS::Lex::Bot.ConversationLogSettings": { + "attributes": {}, + "description": "Specifies settings that manage logging that saves audio, text, and metadata for the conversations with your users.", + "properties": { + "AudioLogSettings": "Specifies the Amazon S3 settings for logging audio to an S3 bucket.", + "TextLogSettings": "Specifies settings to enable text conversation logs. You specify the Amazon CloudWatch Logs log group and whether logs should be stored for an alias." + } + }, "AWS::Lex::Bot.CustomPayload": { "attributes": {}, "description": "A custom response string that Amazon Lex sends to your application. You define the content and structure of the string.", @@ -24918,6 +25736,21 @@ "Value": "The string that is sent to your application." } }, + "AWS::Lex::Bot.CustomVocabulary": { + "attributes": {}, + "description": "Specifies a custom vocabulary. A custom vocabulary is a list of words that you expect to be used during a conversation with your bot.", + "properties": { + "CustomVocabularyItems": "Specifies a list of words that you expect to be used during a conversation with your bot." + } + }, + "AWS::Lex::Bot.CustomVocabularyItem": { + "attributes": {}, + "description": "Specifies an entry in a custom vocabulary.", + "properties": { + "Phrase": "Specifies 1 - 4 words that should be recognized.", + "Weight": "Specifies the degree to which the phrase recognition is boosted. The default value is 1." + } + }, "AWS::Lex::Bot.DialogCodeHookSetting": { "attributes": {}, "description": "Specifies whether an intent uses the dialog code hook during conversations with a user.", @@ -25047,6 +25880,14 @@ "QueryFilterStringEnabled": "Determines whether the AMAZON.KendraSearchIntent intent uses a custom query string to query the Amazon Kendra index." } }, + "AWS::Lex::Bot.LambdaCodeHook": { + "attributes": {}, + "description": "Specifies a Lambda function that verifies requests to a bot or fulfills the user's request to a bot.", + "properties": { + "CodeHookInterfaceVersion": "Specifies the version of the request-response that you want Amazon Lex to use to invoke your Lambda function.", + "LambdaArn": "Specifies the Amazon Resource Name (ARN) of the Lambda function." + } + }, "AWS::Lex::Bot.Message": { "attributes": {}, "description": "The object that provides message text and it's type.", @@ -25097,7 +25938,7 @@ }, "AWS::Lex::Bot.PostFulfillmentStatusSpecification": { "attributes": {}, - "description": "Provides a setting that determines whether the post-fulfillment response is sent to the user. For more information, see [Post-fulfillment response](https://docs.aws.amazon.com/latest/dg/streaming-progress.html#progress-complete) in the *Amazon Lex developer guide* .", + "description": "Provides a setting that determines whether the post-fulfillment response is sent to the user. For more information, see [Post-fulfillment response](https://docs.aws.amazon.com/lex/latest/dg/streaming-progress.html#progress-complete) in the *Amazon Lex developer guide* .", "properties": { "FailureResponse": "Specifies a list of message groups that Amazon Lex uses to respond when fulfillment isn't successful.", "SuccessResponse": "Specifies a list of message groups that Amazon Lex uses to respond when the fulfillment is successful.", @@ -25121,6 +25962,15 @@ "MessageGroupsList": "A collection of responses that Amazon Lex can send to the user. Amazon Lex chooses the actual response to send at runtime." } }, + "AWS::Lex::Bot.S3BucketLogDestination": { + "attributes": {}, + "description": "Specifies an Amazon S3 bucket for logging audio conversations.", + "properties": { + "KmsKeyArn": "Specifies the Amazon Resource Name (ARN) of an AWS Key Management Service key for encrypting audio log files stored in an Amazon S3 bucket.", + "LogPrefix": "Specifies the Amazon S3 prefix to assign to audio log files.", + "S3BucketArn": "Specifies the Amazon Resource Name (ARN) of the Amazon S3 bucket where audio files are stored." + } + }, "AWS::Lex::Bot.S3Location": { "attributes": {}, "description": "Defines an Amazon S3 bucket location.", @@ -25227,6 +26077,7 @@ "attributes": {}, "description": "Contains settings used by Amazon Lex to select a slot value.", "properties": { + "AdvancedRecognitionSetting": "Specifies settings that enable advanced recognition settings for slot values. You can use this to enable using slot values as a custom vocabulary for recognizing user utterances.", "RegexFilter": "A regular expression used to validate the value of a slot.", "ResolutionStrategy": "Determines the slot resolution strategy that Amazon Lex uses to return slot type values. The field can be set to one of the following values:\n\n- OriginalValue - Returns the value entered by the user, if the user value is similar to a slot value.\n- TopResolution - If there is a resolution list for the slot, return the first value in the resolution list as the slot type value. If there is no resolution list, null is returned.\n\nIf you don't specify the valueSelectionStrategy, the default is OriginalValue." } @@ -25241,6 +26092,31 @@ "TimeoutInSeconds": "If Amazon Lex waits longer than this length of time for a response, it will stop sending messages." } }, + "AWS::Lex::Bot.TestBotAliasSettings": { + "attributes": {}, + "description": "Specifies configuration settings for the alias used to test the bot. If the `TestBotAliasSettings` property is not specified, the settings are configured with default values.", + "properties": { + "BotAliasLocaleSettings": "Specifies settings that are unique to a locale. For example, you can use a different Lambda function depending on the bot's locale.", + "ConversationLogSettings": "Specifies settings for conversation logs that save audio, text, and metadata information for conversations with your users.", + "Description": "Specifies a description for the test bot alias.", + "SentimentAnalysisSettings": "Specifies whether Amazon Lex will use Amazon Comprehend to detect the sentiment of user utterances." + } + }, + "AWS::Lex::Bot.TextLogDestination": { + "attributes": {}, + "description": "Specifies the Amazon CloudWatch Logs destination log group for conversation text logs.", + "properties": { + "CloudWatch": "Specifies the Amazon CloudWatch Logs log group where text and metadata logs are delivered." + } + }, + "AWS::Lex::Bot.TextLogSetting": { + "attributes": {}, + "description": "Specifies settings to enable conversation logs.", + "properties": { + "Destination": "Specifies the Amazon CloudWatch Logs destination log group for conversation text logs.", + "Enabled": "Specifies whether conversation logs should be stored for an alias." + } + }, "AWS::Lex::Bot.VoiceSettings": { "attributes": {}, "description": "Identifies the Amazon Polly voice used for audio interaction with the user.", @@ -25388,17 +26264,10 @@ "LocaleId": "The identifier of the locale to add to the version." } }, - "AWS::Lex::BotVersion.BotVersionLocaleSpecificationItem": { - "attributes": {}, - "description": "Specifies the details of a locale in a bot version.", - "properties": { - "BotVersionLocaleDetails": "Information about the version of a bot used in a locale.", - "LocaleId": "The identifier of a specific bot locale." - } - }, "AWS::Lex::ResourcePolicy": { "attributes": { - "Id": "The identifier of the resource policy." + "Id": "The identifier of the resource policy.", + "RevisionId": "Specifies the current revision of a resource policy." }, "description": "Specifies a new resource policy with the specified policy statements.", "properties": { @@ -25977,7 +26846,7 @@ "Arn": "The Amazon Resource Name (ARN) for the geofence collection resource. Used when you need to specify a resource across all AWS .\n\n- Format example: `arn:aws:geo:region:account-id:geofence-collection/ExampleGeofenceCollection`", "CollectionArn": "Synonym for `Arn` . The Amazon Resource Name (ARN) for the geofence collection resource. Used when you need to specify a resource across all AWS .\n\n- Format example: `arn:aws:geo:region:account-id:geofence-collection/ExampleGeofenceCollection`", "CreateTime": "The timestamp for when the geofence collection resource was created in [ISO 8601](https://docs.aws.amazon.com/https://www.iso.org/iso-8601-date-and-time-format.html) format: `YYYY-MM-DDThh:mm:ss.sssZ` .", - "Ref": "`Ref` returns the `GeofenceCollection` ARN.", + "Ref": "`Ref` returns the `GeofenceCollection` name.", "UpdateTime": "The timestamp for when the geofence collection resource was last updated in [ISO 8601](https://docs.aws.amazon.com/https://www.iso.org/iso-8601-date-and-time-format.html) format: `YYYY-MM-DDThh:mm:ss.sssZ` ." }, "description": "The `AWS::Location::GeofenceCollection` resource specifies the ability to detect and act when a tracked device enters or exits a defined geographical boundary known as a geofence.", @@ -25995,7 +26864,7 @@ "CreateTime": "The timestamp for when the map resource was created in [ISO 8601](https://docs.aws.amazon.com/https://www.iso.org/iso-8601-date-and-time-format.html) format: `YYYY-MM-DDThh:mm:ss.sssZ` .", "DataSource": "The data provider for the associated map tiles.", "MapArn": "Synonym for `Arn` . The Amazon Resource Name (ARN) for the map resource. Used to specify a resource across all AWS .\n\n- Format example: `arn:aws:geo:region:account-id:maps/ExampleMap`", - "Ref": "`Ref` returns the `Map` ARN.", + "Ref": "`Ref` returns the `Map` name.", "UpdateTime": "The timestamp for when the map resource was last updated in [ISO 8601](https://docs.aws.amazon.com/https://www.iso.org/iso-8601-date-and-time-format.html) format: `YYYY-MM-DDThh:mm:ss.sssZ` ." }, "description": "The `AWS::Location::Map` resource specifies a map resource in your AWS account, which provides map tiles of different styles sourced from global location data providers.", @@ -26018,7 +26887,7 @@ "Arn": "The Amazon Resource Name (ARN) for the place index resource. Used to specify a resource across AWS .\n\n- Format example: `arn:aws:geo:region:account-id:place-index/ExamplePlaceIndex`", "CreateTime": "The timestamp for when the place index resource was created in [ISO 8601](https://docs.aws.amazon.com/https://www.iso.org/iso-8601-date-and-time-format.html) format: `YYYY-MM-DDThh:mm:ss.sssZ` .", "IndexArn": "Synonym for `Arn` . The Amazon Resource Name (ARN) for the place index resource. Used to specify a resource across AWS .\n\n- Format example: `arn:aws:geo:region:account-id:place-index/ExamplePlaceIndex`", - "Ref": "`Ref` returns the `PlaceIndex` ARN.", + "Ref": "`Ref` returns the `PlaceIndex` name.", "UpdateTime": "The timestamp for when the place index resource was last updated in [ISO 8601](https://docs.aws.amazon.com/https://www.iso.org/iso-8601-date-and-time-format.html) format: `YYYY-MM-DDThh:mm:ss.sssZ` ." }, "description": "The `AWS::Location::PlaceIndex` resource specifies a place index resource in your AWS account, which supports Places functions with geospatial data sourced from your chosen data provider.", @@ -26042,7 +26911,7 @@ "Arn": "The Amazon Resource Name (ARN) for the route calculator resource. Use the ARN when you specify a resource across all AWS .\n\n- Format example: `arn:aws:geo:region:account-id:route-calculator/ExampleCalculator`", "CalculatorArn": "Synonym for `Arn` . The Amazon Resource Name (ARN) for the route calculator resource. Use the ARN when you specify a resource across all AWS .\n\n- Format example: `arn:aws:geo:region:account-id:route-calculator/ExampleCalculator`", "CreateTime": "The timestamp for when the route calculator resource was created in [ISO 8601](https://docs.aws.amazon.com/https://www.iso.org/iso-8601-date-and-time-format.html) format: `YYYY-MM-DDThh:mm:ss.sssZ` .", - "Ref": "`Ref` returns the `RouteCalculator` ARN.", + "Ref": "`Ref` returns the `RouteCalculator` name.", "UpdateTime": "The timestamp for when the route calculator resource was last updated in [ISO 8601](https://docs.aws.amazon.com/https://www.iso.org/iso-8601-date-and-time-format.html) format: `YYYY-MM-DDThh:mm:ss.sssZ` ." }, "description": "The `AWS::Location::RouteCalculator` resource specifies a route calculator resource in your AWS account.\n\nYou can send requests to a route calculator resource to estimate travel time, distance, and get directions. A route calculator sources traffic and road network data from your chosen data provider.", @@ -26057,7 +26926,7 @@ "attributes": { "Arn": "The Amazon Resource Name (ARN) for the tracker resource. Used when you need to specify a resource across all AWS .\n\n- Format example: `arn:aws:geo:region:account-id:tracker/ExampleTracker`", "CreateTime": "The timestamp for when the tracker resource was created in [ISO 8601](https://docs.aws.amazon.com/https://www.iso.org/iso-8601-date-and-time-format.html) format: `YYYY-MM-DDThh:mm:ss.sssZ` .", - "Ref": "`Ref` returns the `Tracker` ARN.", + "Ref": "`Ref` returns the `Tracker` name.", "TrackerArn": "Synonym for `Arn` . The Amazon Resource Name (ARN) for the tracker resource. Used when you need to specify a resource across all AWS .\n\n- Format example: `arn:aws:geo:region:account-id:tracker/ExampleTracker`", "UpdateTime": "The timestamp for when the tracker resource was last updated in [ISO 8601](https://docs.aws.amazon.com/https://www.iso.org/iso-8601-date-and-time-format.html) format: `YYYY-MM-DDThh:mm:ss.sssZ` ." }, @@ -26073,7 +26942,7 @@ }, "AWS::Location::TrackerConsumer": { "attributes": { - "Ref": "`Ref` returns the `GeofenceCollection` ARN." + "Ref": "`Ref` returns the `GeofenceCollection` name." }, "description": "The `AWS::Location::TrackerConsumer` resource specifies an association between a geofence collection and a tracker resource. The geofence collection is referred to as the *consumer* of the tracker. This allows the tracker resource to communicate location data to the linked geofence collection.\n\n> Currently not supported \u2014 Cross-account configurations, such as creating associations between a tracker resource in one account and a geofence collection in another account.", "properties": { @@ -26101,7 +26970,7 @@ }, "description": "The `AWS::Logs::LogGroup` resource specifies a log group. A log group defines common properties for log streams, such as their retention and access control rules. Each log stream must belong to one log group.\n\nYou can create up to 1,000,000 log groups per Region per account. You must use the following guidelines when naming a log group:\n\n- Log group names must be unique within a Region for an AWS account.\n- Log group names can be between 1 and 512 characters long.\n- Log group names consist of the following characters: a-z, A-Z, 0-9, '_' (underscore), '-' (hyphen), '/' (forward slash), and '.' (period).", "properties": { - "KmsKeyId": "The Amazon Resource Name (ARN) of the CMK to use when encrypting log data.", + "KmsKeyId": "The Amazon Resource Name (ARN) of the AWS KMS key to use when encrypting log data.\n\nTo associate an AWS KMS key with the log group, specify the ARN of that KMS key here. If you do so, ingested data is encrypted using this key. This association is stored as long as the data encrypted with the KMS key is still within CloudWatch Logs . This enables CloudWatch Logs to decrypt this data whenever it is requested.\n\nIf you attempt to associate a KMS key with the log group but the KMS key doesn't exist or is deactivated, you will receive an `InvalidParameterException` error.\n\nLog group data is always encrypted in CloudWatch Logs . If you omit this key, the encryption does not use AWS KMS . For more information, see [Encrypt log data in CloudWatch Logs using AWS Key Management Service](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/encrypt-log-data-kms.html)", "LogGroupName": "The name of the log group. If you don't specify a name, AWS CloudFormation generates a unique ID for the log group.", "RetentionInDays": "The number of days to retain the log events in the specified log group. Possible values are: 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653.\n\nTo set a log group to never have log events expire, use [DeleteRetentionPolicy](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_DeleteRetentionPolicy.html) .", "Tags": "An array of key-value pairs to apply to the log group.\n\nFor more information, see [Tag](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resource-tags.html) ." @@ -26133,7 +27002,7 @@ "DefaultValue": "(Optional) The value to emit when a filter pattern does not match a log event. This value can be null.", "MetricName": "The name of the CloudWatch metric.", "MetricNamespace": "A custom namespace to contain your metric in CloudWatch. Use namespaces to group together metrics that are similar. For more information, see [Namespaces](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_concepts.html#Namespace) .", - "MetricValue": "The value that is published to the CloudWatch metric. For example, if you're counting the occurrences of a particular term like `Error` , specify 1 for the metric value. If you're counting the number of bytes transferred, reference the value that is in the log event by using $ followed by the name of the field that you specified in the filter pattern, such as `$size` ." + "MetricValue": "The value that is published to the CloudWatch metric. For example, if you're counting the occurrences of a particular term like `Error` , specify 1 for the metric value. If you're counting the number of bytes transferred, reference the value that is in the log event by using $ followed by the name of the field that you specified in the filter pattern, such as `$.size` ." } }, "AWS::Logs::QueryDefinition": { @@ -26378,8 +27247,19 @@ "SubnetIdList": "An array of strings containing the Amazon VPC subnet IDs (e.g., `subnet-0bb1c79de3EXAMPLE` ." } }, + "AWS::MSK::BatchScramSecret": { + "attributes": { + "Ref": "The ARN of the cluster." + }, + "description": "Represents a secret stored in the Amazon Secrets Manager that can be used to authenticate with a cluster using a user name and a password.", + "properties": { + "ClusterArn": "The Amazon Resource Name (ARN) of the MSK cluster.", + "SecretArnList": "A list of Amazon Secrets Manager secret ARNs." + } + }, "AWS::MSK::Cluster": { "attributes": { + "Arn": "", "Ref": "`Ref` returns the Amazon MSK cluster ARN. For example:\n\n`REF MyTestCluster`\n\nFor the Amazon MSK cluster `MyTestCluster` , Ref returns the ARN of the cluster." }, "description": "The `AWS::MSK::Cluster` resource creates an Amazon MSK cluster . For more information, see [What Is Amazon MSK?](https://docs.aws.amazon.com/msk/latest/developerguide/what-is-msk.html) in the *Amazon MSK Developer Guide* .", @@ -26388,6 +27268,7 @@ "ClientAuthentication": "Includes information related to client authentication.", "ClusterName": "The name of the cluster.", "ConfigurationInfo": "The Amazon MSK configuration to use for the cluster.", + "CurrentVersion": "The version of the cluster that you want to update.", "EncryptionInfo": "Includes all encryption-related information.", "EnhancedMonitoring": "Specifies the level of monitoring for the MSK cluster. The possible values are `DEFAULT` , `PER_BROKER` , and `PER_TOPIC_PER_BROKER` .", "KafkaVersion": "The version of Apache Kafka. For more information, see [Supported Apache Kafka versions](https://docs.aws.amazon.com/msk/latest/developerguide/supported-kafka-versions.html) in the Amazon MSK Developer Guide.", @@ -26454,7 +27335,7 @@ "attributes": {}, "description": "Contains information about the EBS storage volumes attached to brokers.", "properties": { - "ProvisionedThroughput": "", + "ProvisionedThroughput": "Specifies whether provisioned throughput is turned on and the volume throughput target.", "VolumeSize": "The size in GiB of the EBS volume for the data drive on each broker node." } }, @@ -26534,10 +27415,10 @@ }, "AWS::MSK::Cluster.ProvisionedThroughput": { "attributes": {}, - "description": "", + "description": "Specifies whether provisioned throughput is turned on and the volume throughput target.", "properties": { - "Enabled": "", - "VolumeThroughput": "" + "Enabled": "Specifies whether provisioned throughput is turned on for the cluster.", + "VolumeThroughput": "The provisioned throughput rate in MiB per second." } }, "AWS::MSK::Cluster.PublicAccess": { @@ -26593,6 +27474,19 @@ "Enabled": "Unauthenticated is enabled or not." } }, + "AWS::MSK::Configuration": { + "attributes": { + "Arn": "The ARN of the configuration.", + "Ref": "The ARN of the configuration." + }, + "description": "Creates a new MSK configuration.", + "properties": { + "Description": "The description of the configuration.", + "KafkaVersionsList": "A list of the versions of Apache Kafka with which you can use this MSK configuration. You can use this configuration for an MSK cluster only if the Apache Kafka version specified for the cluster appears in this list.", + "Name": "The name of the configuration. Configuration names are strings that match the regex \"^[0-9A-Za-z][0-9A-Za-z-]{0,}$\".", + "ServerProperties": "Contents of the server.properties file. When using the API, you must ensure that the contents of the file are base64 encoded. When using the console, the SDK, or the CLI, the contents of server.properties can be in plaintext." + } + }, "AWS::MWAA::Environment": { "attributes": { "Arn": "The ARN for the Amazon MWAA environment.", @@ -27874,7 +28768,7 @@ "Mode": "If \"vod,\" all segments are indexed and kept permanently in the destination and manifest. If \"live,\" only the number segments specified in keepSegments and indexNSegments are kept. Newer segments replace older segments, which might prevent players from rewinding all the way to the beginning of the channel. VOD mode uses HLS EXT-X-PLAYLIST-TYPE of EVENT while the channel is running, converting it to a \"VOD\" type manifest on completion of the stream.", "OutputSelection": "MANIFESTSANDSEGMENTS: Generates manifests (the master manifest, if applicable, and media manifests) for this output group. SEGMENTSONLY: Doesn't generate any manifests for this output group.", "ProgramDateTime": "Includes or excludes the EXT-X-PROGRAM-DATE-TIME tag in .m3u8 manifest files. The value is calculated as follows: Either the program date and time are initialized using the input timecode source, or the time is initialized using the input timecode source and the date is initialized using the timestampOffset.", - "ProgramDateTimeClock": "", + "ProgramDateTimeClock": "Specifies the algorithm used to drive the HLS EXT-X-PROGRAM-DATE-TIME clock. Options include: INITIALIZE_FROM_OUTPUT_TIMECODE: The PDT clock is initialized as a function of the first output timecode, then incremented by the EXTINF duration of each encoded segment. SYSTEM_CLOCK: The PDT clock is initialized as a function of the UTC wall clock, then incremented by the EXTINF duration of each encoded segment. If the PDT clock diverges from the wall clock by more than 500ms, it is resynchronized to the wall clock.", "ProgramDateTimePeriod": "The period of insertion of the EXT-X-PROGRAM-DATE-TIME entry, in seconds.", "RedundantManifest": "ENABLED: The master manifest (.m3u8 file) for each pipeline includes information about both pipelines: first its own media files, then the media files of the other pipeline. This feature allows a playout device that supports stale manifest detection to switch from one manifest to the other, when the current manifest seems to be stale. There are still two destinations and two master manifests, but both master manifests reference the media files from both pipelines. DISABLED: The master manifest (.m3u8 file) for each pipeline includes information about its own pipeline only. For an HLS output group with MediaPackage as the destination, the DISABLED behavior is always followed. MediaPackage regenerates the manifests it serves to players, so a redundant manifest from MediaLive is irrelevant.", "SegmentLength": "The length of the MPEG-2 Transport Stream segments to create, in seconds. Note that segments will end on the next keyframe after this number of seconds, so the actual segment length might be longer.", @@ -29950,12 +30844,12 @@ "description": "The AWS::OpenSearchService::Domain resource creates an Amazon OpenSearch Service (successor to Amazon Elasticsearch Service) domain.\n\n> The `AWS::OpenSearchService::Domain` resource replaces the legacy [AWS::Elasticsearch::Domain](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticsearch-domain.html) resource. While the Elasticsearch resource and options are still supported, we recommend modifying your existing Cloudformation templates to use the new OpenSearch Service resource, which supports both OpenSearch and legacy Elasticsearch engines. For instructions to upgrade domains defined within CloudFormation from Elasticsearch to OpenSearch, see [Remarks](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#aws-resource-opensearchservice-domain--remarks) .", "properties": { "AccessPolicies": "An AWS Identity and Access Management ( IAM ) policy document that specifies who can access the OpenSearch Service domain and their permissions. For more information, see [Configuring access policies](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/ac.html#ac-creating) in the *Amazon OpenSearch Service Developer Guide* .", - "AdvancedOptions": "Additional options to specify for the OpenSearch Service domain. For more information, see [Advanced cluster parameters](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/createupdatedomains.html#createdomain-configure-advanced-options) in the *Amazon OpenSearch Service Developer Guide* .", + "AdvancedOptions": "Additional options to specify for the OpenSearch Service domain. For more information, see [AdvancedOptions](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/configuration-api.html#configuration-api-datatypes-advancedoptions) in the OpenSearch Service configuration API reference.", "AdvancedSecurityOptions": "Specifies options for fine-grained access control.", "ClusterConfig": "`ClusterConfig` is a property of the AWS::OpenSearchService::Domain resource that configures an Amazon OpenSearch Service cluster.", "CognitoOptions": "Configures OpenSearch Service to use Amazon Cognito authentication for OpenSearch Dashboards.", "DomainEndpointOptions": "Specifies additional options for the domain endpoint, such as whether to require HTTPS for all traffic or whether to use a custom endpoint rather than the default endpoint.", - "DomainName": "A name for the OpenSearch Service domain. For valid values, see the [DomainName](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/configuration-api.html#configuration-api-datatypes-domainname) data type in the *Amazon OpenSearch Service Developer Guide* . If you don't specify a name, AWS CloudFormation generates a unique physical ID and uses that ID for the domain name. For more information, see [Name Type](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-name.html) .\n\n> If you specify a name, you can't perform updates that require replacement of this resource. You can perform updates that require no or some interruption. If you must replace the resource, specify a new name.", + "DomainName": "A name for the OpenSearch Service domain. For valid values, see the [DomainName](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/configuration-api.html#configuration-api-datatypes-domainname) data type in the *Amazon OpenSearch Service Developer Guide* . If you don't specify a name, AWS CloudFormation generates a unique physical ID and uses that ID for the domain name. For more information, see [Name Type](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-name.html) .\n\nRequired when creating a new domain.\n\n> If you specify a name, you can't perform updates that require replacement of this resource. You can perform updates that require no or some interruption. If you must replace the resource, specify a new name.", "EBSOptions": "The configurations of Amazon Elastic Block Store (Amazon EBS) volumes that are attached to data nodes in the OpenSearch Service domain. For more information, see [EBS volume size limits](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/limits.html#ebsresource) in the *Amazon OpenSearch Service Developer Guide* .", "EncryptionAtRestOptions": "Whether the domain should encrypt data at rest, and if so, the AWS KMS key to use. See [Encryption of data at rest for Amazon OpenSearch Service](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/encryption-at-rest.html) .", "EngineVersion": "The version of OpenSearch to use. The value must be in the format `OpenSearch_X.Y` or `Elasticsearch_X.Y` . If not specified, the latest version of OpenSearch is used. For information about the versions that OpenSearch Service supports, see [Supported versions of OpenSearch and Elasticsearch](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/what-is.html#choosing-version) in the *Amazon OpenSearch Service Developer Guide* .\n\nIf you set the [EnableVersionUpgrade](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-updatepolicy.html#cfn-attributes-updatepolicy-upgradeopensearchdomain) update policy to `true` , you can update `EngineVersion` without interruption. When `EnableVersionUpgrade` is set to `false` , or is not specified, updating `EngineVersion` results in [replacement](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-replacement) .", @@ -29996,17 +30890,17 @@ "description": "Configures OpenSearch Service to use Amazon Cognito authentication for OpenSearch Dashboards.", "properties": { "Enabled": "Whether to enable or disable Amazon Cognito authentication for OpenSearch Dashboards. See [Amazon Cognito authentication for OpenSearch Dashboards](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/cognito-auth.html) .", - "IdentityPoolId": "The Amazon Cognito identity pool ID that you want OpenSearch Service to use for OpenSearch Dashboards authentication.", - "RoleArn": "The `AmazonESCognitoAccess` role that allows OpenSearch Service to configure your user pool and identity pool.", - "UserPoolId": "The Amazon Cognito user pool ID that you want OpenSearch Service to use for OpenSearch Dashboards authentication." + "IdentityPoolId": "The Amazon Cognito identity pool ID that you want OpenSearch Service to use for OpenSearch Dashboards authentication.\n\nRequired if you enabled Cognito Authentication for OpenSearch Dashboards.", + "RoleArn": "The `AmazonOpenSearchServiceCognitoAccess` role that allows OpenSearch Service to configure your user pool and identity pool.\n\nRequired if you enabled Cognito Authentication for OpenSearch Dashboards.", + "UserPoolId": "The Amazon Cognito user pool ID that you want OpenSearch Service to use for OpenSearch Dashboards authentication.\n\nRequired if you enabled Cognito Authentication for OpenSearch Dashboards." } }, "AWS::OpenSearchService::Domain.DomainEndpointOptions": { "attributes": {}, "description": "Specifies additional options for the domain endpoint, such as whether to require HTTPS for all traffic or whether to use a custom endpoint rather than the default endpoint.", "properties": { - "CustomEndpoint": "The fully qualified URL for your custom endpoint.", - "CustomEndpointCertificateArn": "The AWS Certificate Manager ARN for your domain's SSL/TLS certificate.", + "CustomEndpoint": "The fully qualified URL for your custom endpoint. Required if you enabled a custom endpoint for the domain.", + "CustomEndpointCertificateArn": "The AWS Certificate Manager ARN for your domain's SSL/TLS certificate. Required if you enabled a custom endpoint for the domain.", "CustomEndpointEnabled": "True to enable a custom endpoint for the domain. If enabled, you must also provide values for `CustomEndpoint` and `CustomEndpointCertificateArn` .", "EnforceHTTPS": "True to require that all traffic to the domain arrive over HTTPS.", "TLSSecurityPolicy": "The minimum TLS version required for traffic to the domain. Valid values are TLS 1.0 (default) or 1.2:\n\n- `Policy-Min-TLS-1-0-2019-07`\n- `Policy-Min-TLS-1-2-2019-07`" @@ -30027,24 +30921,24 @@ "description": "Whether the domain should encrypt data at rest, and if so, the AWS Key Management Service key to use.", "properties": { "Enabled": "Specify `true` to enable encryption at rest.", - "KmsKeyId": "The KMS key ID. Takes the form `1a2a3a4-1a2a-3a4a-5a6a-1a2a3a4a5a6a` ." + "KmsKeyId": "The KMS key ID. Takes the form `1a2a3a4-1a2a-3a4a-5a6a-1a2a3a4a5a6a` . Required if you enable encryption at rest." } }, "AWS::OpenSearchService::Domain.LogPublishingOption": { "attributes": {}, - "description": "Specifies whether the OpenSearch Service domain publishes the OpenSearch application, search slow logs, or index slow logs to Amazon CloudWatch. Each option must be an object of name `SEARCH_SLOW_LOGS` , `ES_APPLICATION_LOGS` , `INDEX_SLOW_LOGS` , or `AUDIT_LOGS` depending on the type of logs you want to publish. For the full syntax, see the [examples](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#aws-resource-opensearchservice-domain--examples) .\n\nIf you enable a slow log, you still have to enable the *collection* of slow logs using the OpenSearch REST API. To learn more, see [Enabling log publishing ( AWS CLI)](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/createdomain-configure-slow-logs.html#createdomain-configure-slow-logs-cli) .", + "description": "Specifies whether the OpenSearch Service domain publishes application, search slow logs, or index slow logs to Amazon CloudWatch. Each option must be an object of name `SEARCH_SLOW_LOGS` , `ES_APPLICATION_LOGS` , `INDEX_SLOW_LOGS` , or `AUDIT_LOGS` depending on the type of logs you want to publish. For the full syntax, see the [examples](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#aws-resource-opensearchservice-domain--examples) .\n\nBefore you enable log publishing, you need to create a CloudWatch log group and provide OpenSearch Service the correct permissions to write to it. To learn more, see [Enabling log publishing ( AWS CloudFormation)](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/createdomain-configure-slow-logs.html#createdomain-configure-slow-logs-cfn) .", "properties": { - "CloudWatchLogsLogGroupArn": "Specifies the CloudWatch log group to publish to.", + "CloudWatchLogsLogGroupArn": "Specifies the CloudWatch log group to publish to. Required if you enable log publishing.", "Enabled": "If `true` , enables the publishing of logs to CloudWatch.\n\nDefault: `false` ." } }, "AWS::OpenSearchService::Domain.MasterUserOptions": { "attributes": {}, - "description": "Specifies information about the master user.", + "description": "Specifies information about the master user.\n\nRequired if if `InternalUserDatabaseEnabled` is true in `AdvancedSecurityOptions` .", "properties": { "MasterUserARN": "ARN for the master user. Only specify if `InternalUserDatabaseEnabled` is false in `AdvancedSecurityOptions` .", - "MasterUserName": "Username for the master user. Only specify if `InternalUserDatabaseEnabled` is true in `AdvancedSecurityOptions` .", - "MasterUserPassword": "Password for the master user. Only specify if `InternalUserDatabaseEnabled` is true in `AdvancedSecurityOptions` ." + "MasterUserName": "Username for the master user. Only specify if `InternalUserDatabaseEnabled` is true in `AdvancedSecurityOptions` . If you don't want to specify this value directly within the template, you can use a [dynamic reference](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html) instead.", + "MasterUserPassword": "Password for the master user. Only specify if `InternalUserDatabaseEnabled` is true in `AdvancedSecurityOptions` . If you don't want to specify this value directly within the template, you can use a [dynamic reference](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html) instead." } }, "AWS::OpenSearchService::Domain.NodeToNodeEncryptionOptions": { @@ -31958,20 +32852,20 @@ "Permissions": "A list of resource permissions on the data source.", "SslProperties": "Secure Socket Layer (SSL) properties that apply when Amazon QuickSight connects to your underlying source.", "Tags": "Contains a map of the key-value pairs for the resource tag or tags assigned to the data source.", - "Type": "The type of the data source. To return a list of all data sources, use `ListDataSources` .\n\nUse `AMAZON_ELASTICSEARCH` for Amazon OpenSearch Service .", + "Type": "The type of the data source. To return a list of all data sources, use `ListDataSources` .\n\nUse `AMAZON_ELASTICSEARCH` for Amazon OpenSearch Service.", "VpcConnectionProperties": "Use this parameter only when you want Amazon QuickSight to use a VPC connection when connecting to your underlying source." } }, "AWS::QuickSight::DataSource.AmazonElasticsearchParameters": { "attributes": {}, - "description": "The parameters for OpenSearch .", + "description": "The parameters for OpenSearch.", "properties": { "Domain": "The OpenSearch domain." } }, "AWS::QuickSight::DataSource.AmazonOpenSearchParameters": { "attributes": {}, - "description": "The parameters for OpenSearch .", + "description": "The parameters for OpenSearch.", "properties": { "Domain": "The OpenSearch domain." } @@ -32030,8 +32924,8 @@ "attributes": {}, "description": "The parameters that Amazon QuickSight uses to connect to your underlying data source. This is a variant type structure. For this structure to be valid, only one of the attributes can be non-null.", "properties": { - "AmazonElasticsearchParameters": "The parameters for OpenSearch .", - "AmazonOpenSearchParameters": "The parameters for OpenSearch .", + "AmazonElasticsearchParameters": "The parameters for OpenSearch.", + "AmazonOpenSearchParameters": "The parameters for OpenSearch.", "AthenaParameters": "The parameters for Amazon Athena.", "AuroraParameters": "The parameters for Amazon Aurora MySQL.", "AuroraPostgreSqlParameters": "The parameters for Amazon Aurora.", @@ -32398,7 +33292,7 @@ "DBClusterIdentifier": "The DB cluster identifier. This parameter is stored as a lowercase string.\n\nConstraints:\n\n- Must contain from 1 to 63 letters, numbers, or hyphens.\n- First character must be a letter.\n- Can't end with a hyphen or contain two consecutive hyphens.\n\nExample: `my-cluster1`", "DBClusterParameterGroupName": "The name of the DB cluster parameter group to associate with this DB cluster.\n\n> If you apply a parameter group to an existing DB cluster, then its DB instances might need to reboot. This can result in an outage while the DB instances are rebooting.\n> \n> If you apply a change to parameter group associated with a stopped DB cluster, then the update stack waits until the DB cluster is started. \n\nTo list all of the available DB cluster parameter group names, use the following command:\n\n`aws rds describe-db-cluster-parameter-groups --query \"DBClusterParameterGroups[].DBClusterParameterGroupName\" --output text`", "DBSubnetGroupName": "A DB subnet group that you want to associate with this DB cluster.\n\nIf you are restoring a DB cluster to a point in time with `RestoreType` set to `copy-on-write` , and don't specify a DB subnet group name, then the DB cluster is restored with a default DB subnet group.", - "DatabaseName": "The name of your database. If you don't provide a name, then Amazon RDS won't create a database in this DB cluster. For naming constraints, see [Naming Constraints](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Limits.html#RDS_Limits.Constraints) in the *Amazon RDS User Guide* .", + "DatabaseName": "The name of your database. If you don't provide a name, then Amazon RDS won't create a database in this DB cluster. For naming constraints, see [Naming Constraints](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/CHAP_Limits.html#RDS_Limits.Constraints) in the *Amazon Aurora User Guide* .", "DeletionProtection": "A value that indicates whether the DB cluster has deletion protection enabled. The database can't be deleted when deletion protection is enabled. By default, deletion protection is disabled.", "EnableCloudwatchLogsExports": "The list of log types that need to be enabled for exporting to CloudWatch Logs. The values in the list depend on the DB engine being used. For more information, see [Publishing Database Logs to Amazon CloudWatch Logs](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/USER_LogAccess.html#USER_LogAccess.Procedural.UploadtoCloudWatch) in the *Amazon Aurora User Guide* .\n\n*Aurora MySQL*\n\nValid values: `audit` , `error` , `general` , `slowquery`\n\n*Aurora PostgreSQL*\n\nValid values: `postgresql`", "EnableHttpEndpoint": "A value that indicates whether to enable the HTTP endpoint for an Aurora Serverless DB cluster. By default, the HTTP endpoint is disabled.\n\nWhen enabled, the HTTP endpoint provides a connectionless web service API for running SQL queries on the Aurora Serverless DB cluster. You can also query your database from inside the RDS console with the query editor.\n\nFor more information, see [Using the Data API for Aurora Serverless](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html) in the *Amazon Aurora User Guide* .", @@ -32467,26 +33361,26 @@ "AllowMajorVersionUpgrade": "A value that indicates whether major version upgrades are allowed. Changing this parameter doesn't result in an outage and the change is asynchronously applied as soon as possible.\n\nConstraints: Major version upgrades must be allowed when specifying a value for the `EngineVersion` parameter that is a different major version than the DB instance's current version.", "AssociatedRoles": "The AWS Identity and Access Management (IAM) roles associated with the DB instance.", "AutoMinorVersionUpgrade": "A value that indicates whether minor engine upgrades are applied automatically to the DB instance during the maintenance window. By default, minor engine upgrades are applied automatically.", - "AvailabilityZone": "The Availability Zone (AZ) where the database will be created. For information on AWS Regions and Availability Zones, see [Regions and Availability Zones](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.RegionsAndAvailabilityZones.html) .\n\n*Amazon Aurora*\n\nNot applicable. Availability Zones are managed by the DB cluster.\n\nDefault: A random, system-chosen Availability Zone in the endpoint's AWS Region.\n\nExample: `us-east-1d`\n\nConstraint: The `AvailabilityZone` parameter can't be specified if the DB instance is a Multi-AZ deployment. The specified Availability Zone must be in the same AWS Region as the current endpoint.\n\n> If you're creating a DB instance in an RDS on VMware environment, specify the identifier of the custom Availability Zone to create the DB instance in.\n> \n> For more information about RDS on VMware, see the [RDS on VMware User Guide.](https://docs.aws.amazon.com/AmazonRDS/latest/RDSonVMwareUserGuide/rds-on-vmware.html)", + "AvailabilityZone": "The Availability Zone (AZ) where the database will be created. For information on AWS Regions and Availability Zones, see [Regions and Availability Zones](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.RegionsAndAvailabilityZones.html) .\n\n*Amazon Aurora*\n\nNot applicable. Availability Zones are managed by the DB cluster.\n\nDefault: A random, system-chosen Availability Zone in the endpoint's AWS Region .\n\nExample: `us-east-1d`\n\nConstraint: The `AvailabilityZone` parameter can't be specified if the DB instance is a Multi-AZ deployment. The specified Availability Zone must be in the same AWS Region as the current endpoint.\n\n> If you're creating a DB instance in an RDS on VMware environment, specify the identifier of the custom Availability Zone to create the DB instance in.\n> \n> For more information about RDS on VMware, see the [RDS on VMware User Guide.](https://docs.aws.amazon.com/AmazonRDS/latest/RDSonVMwareUserGuide/rds-on-vmware.html)", "BackupRetentionPeriod": "The number of days for which automated backups are retained. Setting this parameter to a positive number enables backups. Setting this parameter to 0 disables automated backups.\n\n*Amazon Aurora*\n\nNot applicable. The retention period for automated backups is managed by the DB cluster.\n\nDefault: 1\n\nConstraints:\n\n- Must be a value from 0 to 35\n- Can't be set to 0 if the DB instance is a source to read replicas", "CACertificateIdentifier": "The identifier of the CA certificate for this DB instance.\n\n> Specifying or updating this property triggers a reboot. \n\nFor more information about CA certificate identifiers for RDS DB engines, see [Rotating Your SSL/TLS Certificate](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL-certificate-rotation.html) in the *Amazon RDS User Guide* .\n\nFor more information about CA certificate identifiers for Aurora DB engines, see [Rotating Your SSL/TLS Certificate](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/UsingWithRDS.SSL-certificate-rotation.html) in the *Amazon Aurora User Guide* .", "CharacterSetName": "For supported engines, indicates that the DB instance should be associated with the specified character set.\n\n*Amazon Aurora*\n\nNot applicable. The character set is managed by the DB cluster. For more information, see [AWS::RDS::DBCluster](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-rds-dbcluster.html) .", "CopyTagsToSnapshot": "A value that indicates whether to copy tags from the DB instance to snapshots of the DB instance. By default, tags are not copied.\n\n*Amazon Aurora*\n\nNot applicable. Copying tags to snapshots is managed by the DB cluster. Setting this value for an Aurora DB instance has no effect on the DB cluster setting.", "DBClusterIdentifier": "The identifier of the DB cluster that the instance will belong to.", "DBInstanceClass": "The compute and memory capacity of the DB instance, for example, `db.m4.large` . Not all DB instance classes are available in all AWS Regions, or for all database engines.\n\nFor the full list of DB instance classes, and availability for your engine, see [DB Instance Class](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.DBInstanceClass.html) in the *Amazon RDS User Guide.* For more information about DB instance class pricing and AWS Region support for DB instance classes, see [Amazon RDS Pricing](https://docs.aws.amazon.com/rds/pricing/) .", - "DBInstanceIdentifier": "A name for the DB instance. If you specify a name, AWS CloudFormation converts it to lowercase. If you don't specify a name, AWS CloudFormation generates a unique physical ID and uses that ID for the DB instance. For more information, see [Name Type](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-name.html) .\n\n> If you specify a name, you cannot perform updates that require replacement of this resource. You can perform updates that require no or some interruption. If you must replace the resource, specify a new name.", + "DBInstanceIdentifier": "A name for the DB instance. If you specify a name, AWS CloudFormation converts it to lowercase. If you don't specify a name, AWS CloudFormation generates a unique physical ID and uses that ID for the DB instance. For more information, see [Name Type](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-name.html) .\n\nFor information about constraints that apply to DB instance identifiers, see [Naming constraints in Amazon RDS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Limits.html#RDS_Limits.Constraints) in the *Amazon RDS User Guide* .\n\n> If you specify a name, you can't perform updates that require replacement of this resource. You can perform updates that require no or some interruption. If you must replace the resource, specify a new name.", "DBName": "The meaning of this parameter differs according to the database engine you use.\n\n> If you specify the `[DBSnapshotIdentifier](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-database-instance.html#cfn-rds-dbinstance-dbsnapshotidentifier)` property, AWS CloudFormation ignores this property.\n> \n> If you restore DB instances from snapshots, this property doesn't apply to the MySQL, PostgreSQL, or MariaDB engines. \n\n*MySQL*\n\nThe name of the database to create when the DB instance is created. If this parameter is not specified, no database is created in the DB instance.\n\nConstraints:\n\n- Must contain 1 to 64 letters or numbers.\n- Can't be a word reserved by the specified database engine\n\n*MariaDB*\n\nThe name of the database to create when the DB instance is created. If this parameter is not specified, no database is created in the DB instance.\n\nConstraints:\n\n- Must contain 1 to 64 letters or numbers.\n- Can't be a word reserved by the specified database engine\n\n*PostgreSQL*\n\nThe name of the database to create when the DB instance is created. If this parameter is not specified, the default `postgres` database is created in the DB instance.\n\nConstraints:\n\n- Must contain 1 to 63 letters, numbers, or underscores.\n- Must begin with a letter or an underscore. Subsequent characters can be letters, underscores, or digits (0-9).\n- Can't be a word reserved by the specified database engine\n\n*Oracle*\n\nThe Oracle System ID (SID) of the created DB instance. If you specify `null` , the default value `ORCL` is used. You can't specify the string NULL, or any other reserved word, for `DBName` .\n\nDefault: `ORCL`\n\nConstraints:\n\n- Can't be longer than 8 characters\n\n*SQL Server*\n\nNot applicable. Must be null.\n\n*Amazon Aurora MySQL*\n\nThe name of the database to create when the primary DB instance of the Aurora MySQL DB cluster is created. If this parameter isn't specified for an Aurora MySQL DB cluster, no database is created in the DB cluster.\n\nConstraints:\n\n- It must contain 1 to 64 alphanumeric characters.\n- It can't be a word reserved by the database engine.\n\n*Amazon Aurora PostgreSQL*\n\nThe name of the database to create when the primary DB instance of the Aurora PostgreSQL DB cluster is created. If this parameter isn't specified for an Aurora PostgreSQL DB cluster, a database named `postgres` is created in the DB cluster.\n\nConstraints:\n\n- It must contain 1 to 63 alphanumeric characters.\n- It must begin with a letter or an underscore. Subsequent characters can be letters, underscores, or digits (0 to 9).\n- It can't be a word reserved by the database engine.", "DBParameterGroupName": "The name of an existing DB parameter group or a reference to an [AWS::RDS::DBParameterGroup](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-dbparametergroup.html) resource created in the template.\n\nTo list all of the available DB parameter group names, use the following command:\n\n`aws rds describe-db-parameter-groups --query \"DBParameterGroups[].DBParameterGroupName\" --output text`\n\n> If any of the data members of the referenced parameter group are changed during an update, the DB instance might need to be restarted, which causes some interruption. If the parameter group contains static parameters, whether they were changed or not, an update triggers a reboot. \n\nIf you don't specify a value for the `DBParameterGroupName` property, the default DB parameter group for the specified engine and engine version is used.", "DBSecurityGroups": "A list of the DB security groups to assign to the DB instance. The list can include both the name of existing DB security groups or references to AWS::RDS::DBSecurityGroup resources created in the template.\n\nIf you set DBSecurityGroups, you must not set VPCSecurityGroups, and vice versa. Also, note that the DBSecurityGroups property exists only for backwards compatibility with older regions and is no longer recommended for providing security information to an RDS DB instance. Instead, use VPCSecurityGroups.\n\n> If you specify this property, AWS CloudFormation sends only the following properties (if specified) to Amazon RDS during create operations:\n> \n> - `AllocatedStorage`\n> - `AutoMinorVersionUpgrade`\n> - `AvailabilityZone`\n> - `BackupRetentionPeriod`\n> - `CharacterSetName`\n> - `DBInstanceClass`\n> - `DBName`\n> - `DBParameterGroupName`\n> - `DBSecurityGroups`\n> - `DBSubnetGroupName`\n> - `Engine`\n> - `EngineVersion`\n> - `Iops`\n> - `LicenseModel`\n> - `MasterUsername`\n> - `MasterUserPassword`\n> - `MultiAZ`\n> - `OptionGroupName`\n> - `PreferredBackupWindow`\n> - `PreferredMaintenanceWindow`\n> \n> All other properties are ignored. Specify a virtual private cloud (VPC) security group if you want to submit other properties, such as `StorageType` , `StorageEncrypted` , or `KmsKeyId` . If you're already using the `DBSecurityGroups` property, you can't use these other properties by updating your DB instance to use a VPC security group. You must recreate the DB instance.", "DBSnapshotIdentifier": "The name or Amazon Resource Name (ARN) of the DB snapshot that's used to restore the DB instance. If you're restoring from a shared manual DB snapshot, you must specify the ARN of the snapshot.\n\nBy specifying this property, you can create a DB instance from the specified DB snapshot. If the `DBSnapshotIdentifier` property is an empty string or the `AWS::RDS::DBInstance` declaration has no `DBSnapshotIdentifier` property, AWS CloudFormation creates a new database. If the property contains a value (other than an empty string), AWS CloudFormation creates a database from the specified snapshot. If a snapshot with the specified name doesn't exist, AWS CloudFormation can't create the database and it rolls back the stack.\n\nSome DB instance properties aren't valid when you restore from a snapshot, such as the `MasterUsername` and `MasterUserPassword` properties. For information about the properties that you can specify, see the `RestoreDBInstanceFromDBSnapshot` action in the *Amazon RDS API Reference* .\n\nAfter you restore a DB instance with a `DBSnapshotIdentifier` property, you must specify the same `DBSnapshotIdentifier` property for any future updates to the DB instance. When you specify this property for an update, the DB instance is not restored from the DB snapshot again, and the data in the database is not changed. However, if you don't specify the `DBSnapshotIdentifier` property, an empty DB instance is created, and the original DB instance is deleted. If you specify a property that is different from the previous snapshot restore property, a new DB instance is restored from the specified `DBSnapshotIdentifier` property, and the original DB instance is deleted.\n\nIf you specify the `DBSnapshotIdentifier` property to restore a DB instance (as opposed to specifying it for DB instance updates), then don't specify the following properties:\n\n- `CharacterSetName`\n- `DBClusterIdentifier`\n- `DBName`\n- `DeleteAutomatedBackups`\n- `EnablePerformanceInsights`\n- `KmsKeyId`\n- `MasterUsername`\n- `MonitoringInterval`\n- `MonitoringRoleArn`\n- `PerformanceInsightsKMSKeyId`\n- `PerformanceInsightsRetentionPeriod`\n- `PromotionTier`\n- `SourceDBInstanceIdentifier`\n- `SourceRegion`\n- `StorageEncrypted`\n- `Timezone`", - "DBSubnetGroupName": "A DB subnet group to associate with the DB instance. If you update this value, the new subnet group must be a subnet group in a new VPC.\n\nIf there's no DB subnet group, then the DB instance isn't a VPC DB instance.\n\nFor more information about using Amazon RDS in a VPC, see [Using Amazon RDS with Amazon Virtual Private Cloud (VPC)](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.html) in the *Amazon Relational Database Service Developer Guide* .\n\n*Amazon Aurora*\n\nNot applicable. The DB subnet group is managed by the DB cluster. If specified, the setting must match the DB cluster setting.", + "DBSubnetGroupName": "A DB subnet group to associate with the DB instance. If you update this value, the new subnet group must be a subnet group in a new VPC.\n\nIf there's no DB subnet group, then the DB instance isn't a VPC DB instance.\n\nFor more information about using Amazon RDS in a VPC, see [Using Amazon RDS with Amazon Virtual Private Cloud (VPC)](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.html) in the *Amazon RDS User Guide* .\n\n*Amazon Aurora*\n\nNot applicable. The DB subnet group is managed by the DB cluster. If specified, the setting must match the DB cluster setting.", "DeleteAutomatedBackups": "A value that indicates whether to remove automated backups immediately after the DB instance is deleted. This parameter isn't case-sensitive. The default is to remove automated backups immediately after the DB instance is deleted.", "DeletionProtection": "A value that indicates whether the DB instance has deletion protection enabled. The database can't be deleted when deletion protection is enabled. By default, deletion protection is disabled. For more information, see [Deleting a DB Instance](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_DeleteInstance.html) .\n\n*Amazon Aurora*\n\nNot applicable. You can enable or disable deletion protection for the DB cluster. For more information, see `CreateDBCluster` . DB instances in a DB cluster can be deleted even when deletion protection is enabled for the DB cluster.", "Domain": "The Active Directory directory ID to create the DB instance in. Currently, only Microsoft SQL Server, Oracle, and PostgreSQL DB instances can be created in an Active Directory Domain.\n\nFor more information, see [Kerberos Authentication](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/kerberos-authentication.html) in the *Amazon RDS User Guide* .", "DomainIAMRoleName": "Specify the name of the IAM role to be used when making API calls to the Directory Service.\n\nThis setting doesn't apply to RDS Custom.", "EnableCloudwatchLogsExports": "The list of log types that need to be enabled for exporting to CloudWatch Logs. The values in the list depend on the DB engine being used. For more information, see [Publishing Database Logs to Amazon CloudWatch Logs](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_LogAccess.html#USER_LogAccess.Procedural.UploadtoCloudWatch) in the *Amazon Relational Database Service User Guide* .\n\n*Amazon Aurora*\n\nNot applicable. CloudWatch Logs exports are managed by the DB cluster.\n\n*MariaDB*\n\nValid values: `audit` , `error` , `general` , `slowquery`\n\n*Microsoft SQL Server*\n\nValid values: `agent` , `error`\n\n*MySQL*\n\nValid values: `audit` , `error` , `general` , `slowquery`\n\n*Oracle*\n\nValid values: `alert` , `audit` , `listener` , `trace`\n\n*PostgreSQL*\n\nValid values: `postgresql` , `upgrade`", "EnableIAMDatabaseAuthentication": "A value that indicates whether to enable mapping of AWS Identity and Access Management (IAM) accounts to database accounts. By default, mapping is disabled.\n\nFor more information, see [IAM Database Authentication for MySQL and PostgreSQL](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html) in the *Amazon RDS User Guide.*\n\n*Amazon Aurora*\n\nNot applicable. Mapping AWS IAM accounts to database accounts is managed by the DB cluster.", - "EnablePerformanceInsights": "A value that indicates whether to enable Performance Insights for the DB instance. For more information, see [Using Amazon Performance Insights](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_PerfInsights.html) in the *Amazon Relational Database Service User Guide* .\n\nThis setting doesn't apply to RDS Custom.", + "EnablePerformanceInsights": "A value that indicates whether to enable Performance Insights for the DB instance. For more information, see [Using Amazon Performance Insights](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_PerfInsights.html) in the *Amazon RDS User Guide* .\n\nThis setting doesn't apply to RDS Custom.", "Engine": "The name of the database engine that you want to use for this DB instance.\n\n> When you are creating a DB instance, the `Engine` property is required. \n\nValid Values:\n\n- `aurora` (for MySQL 5.6-compatible Aurora)\n- `aurora-mysql` (for MySQL 5.7-compatible Aurora)\n- `aurora-postgresql`\n- `mariadb`\n- `mysql`\n- `oracle-ee`\n- `oracle-se2`\n- `oracle-se1`\n- `oracle-se`\n- `postgres`\n- `sqlserver-ee`\n- `sqlserver-se`\n- `sqlserver-ex`\n- `sqlserver-web`", "EngineVersion": "The version number of the database engine to use.\n\nFor a list of valid engine versions, use the `DescribeDBEngineVersions` action.\n\nThe following are the database engines and links to information about the major and minor versions that are available with Amazon RDS. Not every database engine is available for every AWS Region.\n\n*Amazon Aurora*\n\nNot applicable. The version number of the database engine to be used by the DB instance is managed by the DB cluster.\n\n*MariaDB*\n\nSee [MariaDB on Amazon RDS Versions](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_MariaDB.html#MariaDB.Concepts.VersionMgmt) in the *Amazon RDS User Guide.*\n\n*Microsoft SQL Server*\n\nSee [Microsoft SQL Server Versions on Amazon RDS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_SQLServer.html#SQLServer.Concepts.General.VersionSupport) in the *Amazon RDS User Guide.*\n\n*MySQL*\n\nSee [MySQL on Amazon RDS Versions](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_MySQL.html#MySQL.Concepts.VersionMgmt) in the *Amazon RDS User Guide.*\n\n*Oracle*\n\nSee [Oracle Database Engine Release Notes](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.Oracle.PatchComposition.html) in the *Amazon RDS User Guide.*\n\n*PostgreSQL*\n\nSee [Supported PostgreSQL Database Versions](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_PostgreSQL.html#PostgreSQL.Concepts.General.DBVersions) in the *Amazon RDS User Guide.*", "Iops": "The number of I/O operations per second (IOPS) that the database provisions. The value must be equal to or greater than 1000.\n\nIf you specify this property, you must follow the range of allowed ratios of your requested IOPS rate to the amount of storage that you allocate (IOPS to allocated storage). For example, you can provision an Oracle database instance with 1000 IOPS and 200 GiB of storage (a ratio of 5:1), or specify 2000 IOPS with 200 GiB of storage (a ratio of 10:1). For more information, see [Amazon RDS Provisioned IOPS Storage to Improve Performance](https://docs.aws.amazon.com/AmazonRDS/latest/DeveloperGuide/CHAP_Storage.html#USER_PIOPS) in the *Amazon RDS User Guide* .\n\n> If you specify `io1` for the `StorageType` property, then you must also specify the `Iops` property.", @@ -32497,17 +33391,17 @@ "MaxAllocatedStorage": "The upper limit in gibibytes (GiB) to which Amazon RDS can automatically scale the storage of the DB instance.\n\nFor more information about this setting, including limitations that apply to it, see [Managing capacity automatically with Amazon RDS storage autoscaling](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_PIOPS.StorageTypes.html#USER_PIOPS.Autoscaling) in the *Amazon RDS User Guide* .\n\nThis setting doesn't apply to RDS Custom.", "MonitoringInterval": "The interval, in seconds, between points when Enhanced Monitoring metrics are collected for the DB instance. To disable collection of Enhanced Monitoring metrics, specify 0. The default is 0.\n\nIf `MonitoringRoleArn` is specified, then you must set `MonitoringInterval` to a value other than 0.\n\nThis setting doesn't apply to RDS Custom.\n\nValid Values: `0, 1, 5, 10, 15, 30, 60`", "MonitoringRoleArn": "The ARN for the IAM role that permits RDS to send enhanced monitoring metrics to Amazon CloudWatch Logs. For example, `arn:aws:iam:123456789012:role/emaccess` . For information on creating a monitoring role, see [Setting Up and Enabling Enhanced Monitoring](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Monitoring.OS.html#USER_Monitoring.OS.Enabling) in the *Amazon RDS User Guide* .\n\nIf `MonitoringInterval` is set to a value other than 0, then you must supply a `MonitoringRoleArn` value.\n\nThis setting doesn't apply to RDS Custom.", - "MultiAZ": "Specifies whether the database instance is a multiple Availability Zone deployment. You can't set the `AvailabilityZone` parameter if the `MultiAZ` parameter is set to true.\n\n*Amazon Aurora*\n\nNot applicable. Amazon Aurora storage is replicated across all of the Availability Zones and doesn't require the `MultiAZ` option to be set.", + "MultiAZ": "Specifies whether the database instance is a Multi-AZ DB instance deployment. You can't set the `AvailabilityZone` parameter if the `MultiAZ` parameter is set to true.\n\nCurrently, you can't use AWS CloudFormation to create a Multi-AZ DB cluster deployment.\n\nFor more information, see [Multi-AZ deployments for high availability](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.MultiAZ.html) in the *Amazon RDS User Guide* .\n\n*Amazon Aurora*\n\nNot applicable. Amazon Aurora storage is replicated across all of the Availability Zones and doesn't require the `MultiAZ` option to be set.", "OptionGroupName": "Indicates that the DB instance should be associated with the specified option group.\n\nPermanent options, such as the TDE option for Oracle Advanced Security TDE, can't be removed from an option group. Also, that option group can't be removed from a DB instance once it is associated with a DB instance.", "PerformanceInsightsKMSKeyId": "The AWS KMS key identifier for encryption of Performance Insights data.\n\nThe KMS key identifier is the key ARN, key ID, alias ARN, or alias name for the KMS key.\n\nIf you do not specify a value for `PerformanceInsightsKMSKeyId` , then Amazon RDS uses your default KMS key. There is a default KMS key for your AWS account. Your AWS account has a different default KMS key for each AWS Region.\n\nFor information about enabling Performance Insights, see [EnablePerformanceInsights](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-database-instance.html#cfn-rds-dbinstance-enableperformanceinsights) .", "PerformanceInsightsRetentionPeriod": "The amount of time, in days, to retain Performance Insights data. Valid values are 7 or 731 (2 years).\n\nFor information about enabling Performance Insights, see [EnablePerformanceInsights](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-database-instance.html#cfn-rds-dbinstance-enableperformanceinsights) .", - "Port": "The port number on which the database accepts connections.", + "Port": "The port number on which the database accepts connections.\n\n*Amazon Aurora*\n\nNot applicable. The port number is managed by the DB cluster.", "PreferredBackupWindow": "The daily time range during which automated backups are created if automated backups are enabled, using the `BackupRetentionPeriod` parameter. For more information, see [Backup Window](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_WorkingWithAutomatedBackups.html#USER_WorkingWithAutomatedBackups.BackupWindow) in the *Amazon RDS User Guide.*\n\nConstraints:\n\n- Must be in the format `hh24:mi-hh24:mi` .\n- Must be in Universal Coordinated Time (UTC).\n- Must not conflict with the preferred maintenance window.\n- Must be at least 30 minutes.\n\n*Amazon Aurora*\n\nNot applicable. The daily time range for creating automated backups is managed by the DB cluster.", "PreferredMaintenanceWindow": "The weekly time range during which system maintenance can occur, in Universal Coordinated Time (UTC).\n\nFormat: `ddd:hh24:mi-ddd:hh24:mi`\n\nThe default is a 30-minute window selected at random from an 8-hour block of time for each AWS Region, occurring on a random day of the week. To see the time blocks available, see [Adjusting the Preferred DB Instance Maintenance Window](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.Maintenance.html#AdjustingTheMaintenanceWindow) in the *Amazon RDS User Guide.*\n\n> This property applies when AWS CloudFormation initially creates the DB instance. If you use AWS CloudFormation to update the DB instance, those updates are applied immediately. \n\nConstraints: Minimum 30-minute window.", "ProcessorFeatures": "The number of CPU cores and the number of threads per core for the DB instance class of the DB instance.\n\nThis setting doesn't apply to RDS Custom.", "PromotionTier": "A value that specifies the order in which an Aurora Replica is promoted to the primary instance after a failure of the existing primary instance. For more information, see [Fault Tolerance for an Aurora DB Cluster](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Aurora.Managing.Backups.html#Aurora.Managing.FaultTolerance) in the *Amazon Aurora User Guide* .\n\nThis setting doesn't apply to RDS Custom.\n\nDefault: 1\n\nValid Values: 0 - 15", "PubliclyAccessible": "Indicates whether the DB instance is an internet-facing instance. If you specify `true` , AWS CloudFormation creates an instance with a publicly resolvable DNS name, which resolves to a public IP address. If you specify false, AWS CloudFormation creates an internal instance with a DNS name that resolves to a private IP address.\n\nThe default behavior value depends on your VPC setup and the database subnet group. For more information, see the `PubliclyAccessible` parameter in [`CreateDBInstance`](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html) in the *Amazon RDS API Reference* .\n\nIf this resource has a public IP address and is also in a VPC that is defined in the same template, you must use the *DependsOn* attribute to declare a dependency on the VPC-gateway attachment. For more information, see [DependsOn Attribute](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-dependson.html) .\n\n> If you specify DBSecurityGroups, AWS CloudFormation ignores this property. To specify a security group and this property, you must use a VPC security group. For more information about Amazon RDS and VPC, see [Using Amazon RDS with Amazon VPC](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.html) in the *Amazon RDS User Guide* .", - "SourceDBInstanceIdentifier": "If you want to create a read replica DB instance, specify the ID of the source DB instance. Each DB instance can have a limited number of read replicas. For more information, see [Working with Read Replicas](https://docs.aws.amazon.com/AmazonRDS/latest/DeveloperGuide/USER_ReadRepl.html) in the *Amazon Relational Database Service Developer Guide* .\n\nThe `SourceDBInstanceIdentifier` property determines whether a DB instance is a read replica. If you remove the `SourceDBInstanceIdentifier` property from your template and then update your stack, AWS CloudFormation deletes the Read Replica and creates a new DB instance (not a read replica).\n\n> - If you specify a source DB instance that uses VPC security groups, we recommend that you specify the `VPCSecurityGroups` property. If you don't specify the property, the read replica inherits the value of the `VPCSecurityGroups` property from the source DB when you create the replica. However, if you update the stack, AWS CloudFormation reverts the replica's `VPCSecurityGroups` property to the default value because it's not defined in the stack's template. This change might cause unexpected issues.\n> - Read replicas don't support deletion policies. AWS CloudFormation ignores any deletion policy that's associated with a read replica.\n> - If you specify `SourceDBInstanceIdentifier` , don't specify the `DBSnapshotIdentifier` property. You can't create a read replica from a snapshot.\n> - Don't set the `BackupRetentionPeriod` , `DBName` , `MasterUsername` , `MasterUserPassword` , and `PreferredBackupWindow` properties. The database attributes are inherited from the source DB instance, and backups are disabled for read replicas.\n> - If the source DB instance is in a different region than the read replica, specify the source region in `SourceRegion` , and specify an ARN for a valid DB instance in `SourceDBInstanceIdentifier` . For more information, see [Constructing a Amazon RDS Amazon Resource Name (ARN)](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Tagging.html#USER_Tagging.ARN) in the *Amazon RDS User Guide* .\n> - For DB instances in Amazon Aurora clusters, don't specify this property. Amazon RDS automatically assigns writer and reader DB instances.", + "SourceDBInstanceIdentifier": "If you want to create a read replica DB instance, specify the ID of the source DB instance. Each DB instance can have a limited number of read replicas. For more information, see [Working with Read Replicas](https://docs.aws.amazon.com/AmazonRDS/latest/DeveloperGuide/USER_ReadRepl.html) in the *Amazon RDS User Guide* .\n\nFor information about constraints that apply to DB instance identifiers, see [Naming constraints in Amazon RDS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Limits.html#RDS_Limits.Constraints) in the *Amazon RDS User Guide* .\n\nThe `SourceDBInstanceIdentifier` property determines whether a DB instance is a read replica. If you remove the `SourceDBInstanceIdentifier` property from your template and then update your stack, AWS CloudFormation deletes the Read Replica and creates a new DB instance (not a read replica).\n\n> - If you specify a source DB instance that uses VPC security groups, we recommend that you specify the `VPCSecurityGroups` property. If you don't specify the property, the read replica inherits the value of the `VPCSecurityGroups` property from the source DB when you create the replica. However, if you update the stack, AWS CloudFormation reverts the replica's `VPCSecurityGroups` property to the default value because it's not defined in the stack's template. This change might cause unexpected issues.\n> - Read replicas don't support deletion policies. AWS CloudFormation ignores any deletion policy that's associated with a read replica.\n> - If you specify `SourceDBInstanceIdentifier` , don't specify the `DBSnapshotIdentifier` property. You can't create a read replica from a snapshot.\n> - Don't set the `BackupRetentionPeriod` , `DBName` , `MasterUsername` , `MasterUserPassword` , and `PreferredBackupWindow` properties. The database attributes are inherited from the source DB instance, and backups are disabled for read replicas.\n> - If the source DB instance is in a different region than the read replica, specify the source region in `SourceRegion` , and specify an ARN for a valid DB instance in `SourceDBInstanceIdentifier` . For more information, see [Constructing a Amazon RDS Amazon Resource Name (ARN)](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Tagging.html#USER_Tagging.ARN) in the *Amazon RDS User Guide* .\n> - For DB instances in Amazon Aurora clusters, don't specify this property. Amazon RDS automatically assigns writer and reader DB instances.", "SourceRegion": "The ID of the region that contains the source DB instance for the read replica.", "StorageEncrypted": "A value that indicates whether the DB instance is encrypted. By default, it isn't encrypted.\n\nIf you specify the `KmsKeyId` property, then you must enable encryption.\n\nIf you specify the `SnapshotIdentifier` or `SourceDBInstanceIdentifier` property, don't specify this property. The value is inherited from the snapshot or source DB instance, and if the DB instance is encrypted, the specified `KmsKeyId` property is used.\n\n*Amazon Aurora*\n\nNot applicable. The encryption for DB instances is managed by the DB cluster.", "StorageType": "Specifies the storage type to be associated with the DB instance.\n\nValid values: `standard | gp2 | io1`\n\nThe `standard` value is also known as magnetic.\n\nIf you specify `io1` , you must also include a value for the `Iops` parameter.\n\nDefault: `io1` if the `Iops` parameter is specified, otherwise `standard`\n\nFor more information, see [Amazon RDS DB Instance Storage](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Storage.html) in the *Amazon RDS User Guide* .\n\n*Amazon Aurora*\n\nNot applicable. Aurora data is stored in the cluster volume, which is a single, virtual volume that uses solid state drives (SSDs).", @@ -32539,7 +33433,7 @@ }, "description": "The `AWS::RDS::DBParameterGroup` resource creates a custom parameter group for an RDS database family.\n\nThis type can be declared in a template and referenced in the `DBParameterGroupName` property of an `[AWS::RDS::DBInstance](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-database-instance.html)` resource.\n\nFor information about configuring parameters for Amazon RDS DB instances, see [Working with DB parameter groups](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_WorkingWithParamGroups.html) in the *Amazon RDS User Guide* .\n\nFor information about configuring parameters for Amazon Aurora DB instances, see [Working with DB parameter groups and DB cluster parameter groups](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/USER_WorkingWithParamGroups.html) in the *Amazon Aurora User Guide* .\n\n> Applying a parameter group to a DB instance may require the DB instance to reboot, resulting in a database outage for the duration of the reboot.", "properties": { - "Description": "Provides the customer-specified description for this DB parameter group.", + "Description": "Provides the customer-specified description for this DB Parameter Group.", "Family": "The DB parameter group family name. A DB parameter group can be associated with one and only one DB parameter group family, and can be applied only to a DB instance running a DB engine and engine version compatible with that DB parameter group family.\n\n> The DB parameter group family can't be changed when updating a DB parameter group. \n\nTo list all of the available parameter group families, use the following command:\n\n`aws rds describe-db-engine-versions --query \"DBEngineVersions[].DBParameterGroupFamily\"`\n\nThe output contains duplicates.\n\nFor more information, see `[CreateDBParameterGroup](https://docs.aws.amazon.com//AmazonRDS/latest/APIReference/API_CreateDBParameterGroup.html)` .", "Parameters": "An array of parameter names and values for the parameter update. At least one parameter name and value must be supplied. Subsequent arguments are optional.\n\nFor more information about DB parameters and DB parameter groups for Amazon RDS DB engines, see [Working with DB Parameter Groups](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_WorkingWithParamGroups.html) in the *Amazon RDS User Guide* .\n\nFor more information about DB cluster and DB instance parameters and parameter groups for Amazon Aurora DB engines, see [Working with DB Parameter Groups and DB Cluster Parameter Groups](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/USER_WorkingWithParamGroups.html) in the *Amazon Aurora User Guide* .\n\n> AWS CloudFormation doesn't support specifying an apply method for each individual parameter. The default apply method for each parameter is used.", "Tags": "Tags to assign to the DB parameter group." @@ -32554,7 +33448,7 @@ "description": "The `AWS::RDS::DBProxy` resource creates or updates a DB proxy.\n\nFor information about RDS Proxy for Amazon RDS, see [Managing Connections with Amazon RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html) in the *Amazon RDS User Guide* .\n\nFor information about RDS Proxy for Amazon Aurora, see [Managing Connections with Amazon RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/rds-proxy.html) in the *Amazon Aurora User Guide* .\n\n> Limitations apply to RDS Proxy, including DB engine version limitations and AWS Region limitations.\n> \n> For information about limitations that apply to RDS Proxy for Amazon RDS, see [Limitations for RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html#rds-proxy.limitations) in the *Amazon RDS User Guide* .\n> \n> For information about that apply to RDS Proxy for Amazon Aurora, see [Limitations for RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/rds-proxy.html#rds-proxy.limitations) in the *Amazon Aurora User Guide* .", "properties": { "Auth": "The authorization mechanism that the proxy uses.", - "DBProxyName": "The identifier for the proxy. This name must be unique for all proxies owned by your AWS account in the specified AWS Region. An identifier must begin with a letter and must contain only ASCII letters, digits, and hyphens; it can't end with a hyphen or contain two consecutive hyphens.", + "DBProxyName": "The identifier for the proxy. This name must be unique for all proxies owned by your AWS account in the specified AWS Region . An identifier must begin with a letter and must contain only ASCII letters, digits, and hyphens; it can't end with a hyphen or contain two consecutive hyphens.", "DebugLogging": "Whether the proxy includes detailed information about SQL statements in its logs. This information helps you to debug issues involving SQL behavior or the performance and scalability of the proxy connections. The debug information includes the text of SQL statements that you submit through the proxy. Thus, only enable this setting when needed for debugging, and only when you have security measures in place to safeguard any sensitive information that appears in the logs.", "EngineFamily": "The kinds of databases that the proxy can connect to. This value determines which database network protocol the proxy recognizes when it interprets network traffic to and from the database. The engine family applies to MySQL and PostgreSQL for both RDS and Aurora.\n\n*Valid values* : `MYSQL` | `POSTGRESQL`", "IdleClientTimeout": "The number of seconds that a connection to the proxy can be inactive before the proxy disconnects it. You can set this value higher or lower than the connection timeout limit for the associated database.", @@ -32643,7 +33537,7 @@ "properties": { "DBSecurityGroupIngress": "Ingress rules to be applied to the DB security group.", "EC2VpcId": "The identifier of an Amazon VPC. This property indicates the VPC that this DB security group belongs to.\n\n> The `EC2VpcId` property is for backward compatibility with older regions, and is no longer recommended for providing security information to an RDS DB instance.", - "GroupDescription": "Provides the description of the DB security group.", + "GroupDescription": "Provides the description of the DB Security Group.", "Tags": "Tags to assign to the DB security group." } }, @@ -32804,12 +33698,12 @@ "EnhancedVpcRouting": "An option that specifies whether to create the cluster with enhanced VPC routing enabled. To create a cluster that uses enhanced VPC routing, the cluster must be in a VPC. For more information, see [Enhanced VPC Routing](https://docs.aws.amazon.com/redshift/latest/mgmt/enhanced-vpc-routing.html) in the Amazon Redshift Cluster Management Guide.\n\nIf this option is `true` , enhanced VPC routing is enabled.\n\nDefault: false", "HsmClientCertificateIdentifier": "Specifies the name of the HSM client certificate the Amazon Redshift cluster uses to retrieve the data encryption keys stored in an HSM.", "HsmConfigurationIdentifier": "Specifies the name of the HSM configuration that contains the information the Amazon Redshift cluster can use to retrieve and store keys in an HSM.", - "IamRoles": "A list of AWS Identity and Access Management (IAM) roles that can be used by the cluster to access other AWS services. You must supply the IAM roles in their Amazon Resource Name (ARN) format. You can supply up to 10 IAM roles in a single request.\n\nA cluster can have up to 10 IAM roles associated with it at any time.", + "IamRoles": "A list of AWS Identity and Access Management (IAM) roles that can be used by the cluster to access other AWS services. You must supply the IAM roles in their Amazon Resource Name (ARN) format.\n\nThe maximum number of IAM roles that you can associate is subject to a quota. For more information, go to [Quotas and limits](https://docs.aws.amazon.com/redshift/latest/mgmt/amazon-redshift-limits.html) in the *Amazon Redshift Cluster Management Guide* .", "KmsKeyId": "The AWS Key Management Service (KMS) key ID of the encryption key that you want to use to encrypt data in the cluster.", "LoggingProperties": "Specifies logging information, such as queries and connection attempts, for the specified Amazon Redshift cluster.", "MaintenanceTrackName": "An optional parameter for the name of the maintenance track for the cluster. If you don't provide a maintenance track name, the cluster is assigned to the `current` track.", "ManualSnapshotRetentionPeriod": "The default number of days to retain a manual snapshot. If the value is -1, the snapshot is retained indefinitely. This setting doesn't change the retention period of existing snapshots.\n\nThe value must be either -1 or an integer between 1 and 3,653.", - "MasterUserPassword": "The password associated with the admin user account for the cluster that is being created.\n\nConstraints:\n\n- Must be between 8 and 64 characters in length.\n- Must contain at least one uppercase letter.\n- Must contain at least one lowercase letter.\n- Must contain one number.\n- Can be any printable ASCII character (ASCII code 33 to 126) except ' (single quote), \" (double quote), \\, /, @, or space.", + "MasterUserPassword": "The password associated with the admin user account for the cluster that is being created.\n\nConstraints:\n\n- Must be between 8 and 64 characters in length.\n- Must contain at least one uppercase letter.\n- Must contain at least one lowercase letter.\n- Must contain one number.\n- Can be any printable ASCII character (ASCII code 33-126) except ' (single quote), \" (double quote), \\, /, or @.", "MasterUsername": "The user name associated with the admin user account for the cluster that is being created.\n\nConstraints:\n\n- Must be 1 - 128 alphanumeric characters. The user name can't be `PUBLIC` .\n- First character must be a letter.\n- Cannot be a reserved word. A list of reserved words can be found in [Reserved Words](https://docs.aws.amazon.com/redshift/latest/dg/r_pg_keywords.html) in the Amazon Redshift Database Developer Guide.", "NodeType": "The node type to be provisioned for the cluster. For information about node types, go to [Working with Clusters](https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-clusters.html#how-many-nodes) in the *Amazon Redshift Cluster Management Guide* .\n\nValid Values: `ds2.xlarge` | `ds2.8xlarge` | `dc1.large` | `dc1.8xlarge` | `dc2.large` | `dc2.8xlarge` | `ra3.xlplus` | `ra3.4xlarge` | `ra3.16xlarge`", "NumberOfNodes": "The number of compute nodes in the cluster. This parameter is required when the *ClusterType* parameter is specified as `multi-node` .\n\nFor information about determining how many nodes you need, go to [Working with Clusters](https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-clusters.html#how-many-nodes) in the *Amazon Redshift Cluster Management Guide* .\n\nIf you don't specify this parameter, you get a single-node cluster. When requesting a multi-node cluster, you must specify the number of nodes that you want in the cluster.\n\nDefault: `1`\n\nConstraints: Value must be at least 1 and no more than 100.", @@ -32822,8 +33716,8 @@ "RotateEncryptionKey": "", "SnapshotClusterIdentifier": "The name of the cluster the source snapshot was created from. This parameter is required if your IAM user has a policy containing a snapshot resource element that specifies anything other than * for the cluster name.", "SnapshotCopyGrantName": "The name of the snapshot copy grant.", - "SnapshotCopyManual": "", - "SnapshotCopyRetentionPeriod": "", + "SnapshotCopyManual": "Indicates whether to apply the snapshot retention period to newly copied manual snapshots instead of automated snapshots.", + "SnapshotCopyRetentionPeriod": "The number of days to retain automated snapshots in the destination AWS Region after they are copied from the source AWS Region .\n\nBy default, this only changes the retention period of copied automated snapshots.\n\nIf you decrease the retention period for automated snapshots that are copied to a destination AWS Region , Amazon Redshift deletes any existing automated snapshots that were copied to the destination AWS Region and that fall outside of the new retention period.\n\nConstraints: Must be at least 1 and no more than 35 for automated snapshots.\n\nIf you specify the `manual` option, only newly copied manual snapshots will have the new retention period.\n\nIf you specify the value of -1 newly copied manual snapshots are retained indefinitely.\n\nConstraints: The number of days must be either -1 or an integer between 1 and 3,653 for manual snapshots.", "SnapshotIdentifier": "The name of the snapshot from which to create the new cluster. This parameter isn't case sensitive.\n\nExample: `my-snapshot-id`", "Tags": "A list of tag instances.", "VpcSecurityGroupIds": "A list of Virtual Private Cloud (VPC) security groups to be associated with the cluster.\n\nDefault: The default VPC security group is associated with the cluster." @@ -33289,18 +34183,19 @@ "description": "The `AWS::RoboMaker::RobotApplication` resource creates an AWS RoboMaker robot application.", "properties": { "CurrentRevisionId": "The current revision id.", + "Environment": "The environment of the robot application.", "Name": "The name of the robot application.", - "RobotSoftwareSuite": "The robot software suite (ROS distribuition) used by the robot application.", + "RobotSoftwareSuite": "The robot software suite used by the robot application.", "Sources": "The sources of the robot application.", "Tags": "A map that contains tag keys and tag values that are attached to the robot application." } }, "AWS::RoboMaker::RobotApplication.RobotSoftwareSuite": { "attributes": {}, - "description": "Information about a robot software suite (ROS distribution).", + "description": "Information about a robot software suite.", "properties": { - "Name": "The name of the robot software suite (ROS distribution).", - "Version": "The version of the robot software suite (ROS distribution)." + "Name": "The name of the robot software suite. `General` is the only supported value.", + "Version": "The version of the robot software suite. Not applicable for General software suite." } }, "AWS::RoboMaker::RobotApplication.SourceConfig": { @@ -33336,7 +34231,7 @@ "Environment": "The environment of the simulation application.", "Name": "The name of the simulation application.", "RenderingEngine": "The rendering engine for the simulation application.", - "RobotSoftwareSuite": "The robot software suite (ROS distribution) used by the simulation application.", + "RobotSoftwareSuite": "The robot software suite used by the simulation application.", "SimulationSoftwareSuite": "The simulation software suite used by the simulation application.", "Sources": "The sources of the simulation application.", "Tags": "A map that contains tag keys and tag values that are attached to the simulation application." @@ -33352,18 +34247,18 @@ }, "AWS::RoboMaker::SimulationApplication.RobotSoftwareSuite": { "attributes": {}, - "description": "Information about a robot software suite (ROS distribution).", + "description": "Information about a robot software suite.", "properties": { - "Name": "The name of the robot software suite (ROS distribution).", - "Version": "The version of the robot software suite (ROS distribution)." + "Name": "The name of the robot software suite. `General` is the only supported value.", + "Version": "The version of the robot software suite. Not applicable for General software suite." } }, "AWS::RoboMaker::SimulationApplication.SimulationSoftwareSuite": { "attributes": {}, "description": "Information about a simulation software suite.", "properties": { - "Name": "The name of the simulation software suite.", - "Version": "The version of the simulation software suite." + "Name": "The name of the simulation software suite. `SimulationRuntime` is the only supported value.", + "Version": "The version of the simulation software suite. Not applicable for `SimulationRuntime` ." } }, "AWS::RoboMaker::SimulationApplication.SourceConfig": { @@ -33421,7 +34316,7 @@ "NameServers": "Returns the set of name servers for the specific hosted zone. For example: `ns1.example.com` .\n\nThis attribute is not supported for private hosted zones.", "Ref": "`Ref` returns the hosted zone ID, such as `Z23ABC4XYZL05B` ." }, - "description": "Creates a new public or private hosted zone. You create records in a public hosted zone to define how you want to route traffic on the internet for a domain, such as example.com, and its subdomains (apex.example.com, acme.example.com). You create records in a private hosted zone to define how you want to route traffic for a domain and its subdomains within one or more Amazon Virtual Private Clouds (Amazon VPCs).\n\n> You can't convert a public hosted zone to a private hosted zone or vice versa. Instead, you must create a new hosted zone with the same name and create new resource record sets. \n\nFor more information about charges for hosted zones, see [Amazon Route 53 Pricing](https://docs.aws.amazon.com/route53/pricing/) .\n\nNote the following:\n\n- You can't create a hosted zone for a top-level domain (TLD) such as .com.\n- For public hosted zones, Route 53 automatically creates a default SOA record and four NS records for the zone. For more information about SOA and NS records, see [NS and SOA Records that Route 53 Creates for a Hosted Zone](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/SOA-NSrecords.html) in the *Amazon Route 53 Developer Guide* .\n\nIf you want to use the same name servers for multiple public hosted zones, you can optionally associate a reusable delegation set with the hosted zone. See the `DelegationSetId` element.\n- If your domain is registered with a registrar other than Route 53, you must update the name servers with your registrar to make Route 53 the DNS service for the domain. For more information, see [Migrating DNS Service for an Existing Domain to Amazon Route 53](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/MigratingDNS.html) in the *Amazon Route 53 Developer Guide* .\n\nWhen you submit a `CreateHostedZone` request, the initial status of the hosted zone is `PENDING` . For public hosted zones, this means that the NS and SOA records are not yet available on all Route 53 DNS servers. When the NS and SOA records are available, the status of the zone changes to `INSYNC` .\n\nThe `CreateHostedZone` request requires the caller to have an `ec2:DescribeVpcs` permission.", + "description": "Creates a new public or private hosted zone. You create records in a public hosted zone to define how you want to route traffic on the internet for a domain, such as example.com, and its subdomains (apex.example.com, acme.example.com). You create records in a private hosted zone to define how you want to route traffic for a domain and its subdomains within one or more Amazon Virtual Private Clouds (Amazon VPCs).\n\n> You can't convert a public hosted zone to a private hosted zone or vice versa. Instead, you must create a new hosted zone with the same name and create new resource record sets. \n\nFor more information about charges for hosted zones, see [Amazon Route 53 Pricing](https://docs.aws.amazon.com/route53/pricing/) .\n\nNote the following:\n\n- You can't create a hosted zone for a top-level domain (TLD) such as .com.\n- For public hosted zones, Route 53 automatically creates a default SOA record and four NS records for the zone. For more information about SOA and NS records, see [NS and SOA Records that Route 53 Creates for a Hosted Zone](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/SOA-NSrecords.html) in the *Amazon Route 53 Developer Guide* .\n\nIf you want to use the same name servers for multiple public hosted zones, you can optionally associate a reusable delegation set with the hosted zone. See the `DelegationSetId` element.\n- If your domain is registered with a registrar other than Route 53, you must update the name servers with your registrar to make Route 53 the DNS service for the domain. For more information, see [Migrating DNS Service for an Existing Domain to Amazon Route 53](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/MigratingDNS.html) in the *Amazon Route 53 Developer Guide* .\n\nWhen you submit a `CreateHostedZone` request, the initial status of the hosted zone is `PENDING` . For public hosted zones, this means that the NS and SOA records are not yet available on all Route 53 DNS servers. When the NS and SOA records are available, the status of the zone changes to `INSYNC` .\n\nThe `CreateHostedZone` request requires the caller to have an `ec2:DescribeVpcs` permission.\n\n> When creating private hosted zones, the Amazon VPC must belong to the same partition where the hosted zone is created. A partition is a group of AWS Regions . Each AWS account is scoped to one partition.\n> \n> The following are the supported partitions:\n> \n> - `aws` - AWS Regions\n> - `aws-cn` - China Regions\n> - `aws-us-gov` - AWS GovCloud (US) Region\n> \n> For more information, see [Access Management](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) in the *AWS General Reference* .", "properties": { "HostedZoneConfig": "A complex type that contains an optional comment.\n\nIf you don't want to specify a comment, omit the `HostedZoneConfig` and `Comment` elements.", "HostedZoneTags": "Adds, edits, or deletes tags for a health check or a hosted zone.\n\nFor information about using tags for cost allocation, see [Using Cost Allocation Tags](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html) in the *AWS Billing and Cost Management User Guide* .", @@ -33736,7 +34631,7 @@ "properties": { "ComponentId": "The component identifier of the resource, generated when DNS target resource is used.", "DnsTargetResource": "A component for DNS/routing control readiness checks. This is a required setting when `ResourceSet` `ResourceSetType` is set to `AWS::Route53RecoveryReadiness::DNSTargetResource` . Do not set it for any other `ResourceSetType` setting.", - "ReadinessScopes": "A list of recovery group Amazon Resource Names (ARNs) and cell ARNs that this resource is contained within.", + "ReadinessScopes": "The recovery group Amazon Resource Name (ARN) or the cell ARN that the readiness checks for this resource set are scoped to.", "ResourceArn": "The Amazon Resource Name (ARN) of the AWS resource. This is a required setting for all `ResourceSet` `ResourceSetType` settings except `AWS::Route53RecoveryReadiness::DNSTargetResource` . Do not set this when `ResourceSetType` is set to `AWS::Route53RecoveryReadiness::DNSTargetResource` ." } }, @@ -33975,7 +34870,7 @@ "attributes": {}, "description": "The PublicAccessBlock configuration that you want to apply to this Amazon S3 bucket. You can enable the configuration options in any combination. For more information about when Amazon S3 considers a bucket or object public, see [The Meaning of \"Public\"](https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html#access-control-block-public-access-policy-status) in the *Amazon S3 User Guide* .", "properties": { - "BlockPublicAcls": "Specifies whether Amazon S3 should block public access control lists (ACLs) for this bucket and objects in this bucket. Setting this element to `TRUE` causes the following behavior:\n\n- PUT Bucket acl and PUT Object acl calls fail if the specified ACL is public.\n- PUT Object calls fail if the request includes a public ACL.\n- PUT Bucket calls fail if the request includes a public ACL.\n\nEnabling this setting doesn't affect existing policies or ACLs.", + "BlockPublicAcls": "Specifies whether Amazon S3 should block public access control lists (ACLs) for this bucket and objects in this bucket. Setting this element to `TRUE` causes the following behavior:\n\n- PUT Bucket ACL and PUT Object ACL calls fail if the specified ACL is public.\n- PUT Object calls fail if the request includes a public ACL.\n- PUT Bucket calls fail if the request includes a public ACL.\n\nEnabling this setting doesn't affect existing policies or ACLs.", "BlockPublicPolicy": "Specifies whether Amazon S3 should block public bucket policies for this bucket. Setting this element to `TRUE` causes Amazon S3 to reject calls to PUT Bucket policy if the specified bucket policy allows public access.\n\nEnabling this setting doesn't affect existing bucket policies.", "IgnorePublicAcls": "Specifies whether Amazon S3 should ignore public ACLs for this bucket and objects in this bucket. Setting this element to `TRUE` causes Amazon S3 to ignore all public ACLs on this bucket and objects in this bucket.\n\nEnabling this setting doesn't affect the persistence of any existing ACLs and doesn't prevent new public ACLs from being set.", "RestrictPublicBuckets": "Specifies whether Amazon S3 should restrict public bucket policies for this bucket. Setting this element to `TRUE` restricts access to this bucket to only AWS service principals and authorized users within this account if the bucket has a public policy.\n\nEnabling this setting doesn't affect previously stored bucket policies, except that public and cross-account access within any public bucket policy, including non-public delegation to specific accounts, is blocked." @@ -34194,6 +35089,7 @@ "attributes": {}, "description": "Specifies a metrics configuration for the CloudWatch request metrics (specified by the metrics configuration ID) from an Amazon S3 bucket. If you're updating an existing metrics configuration, note that this is a full replacement of the existing metrics configuration. If you don't include the elements you want to keep, they are erased. For examples, see [AWS::S3::Bucket](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html#aws-properties-s3-bucket--examples) . For more information, see [PUT Bucket metrics](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTMetricConfiguration.html) in the *Amazon S3 API Reference* .", "properties": { + "AccessPointArn": "The access point that was used while performing operations on the object. The metrics configuration only includes objects that meet the filter's criteria.", "Id": "The ID used to identify the metrics configuration. This can be any value you choose that helps you identify your metrics configuration.", "Prefix": "The prefix that an object must have to be included in the metrics results.", "TagFilters": "Specifies a list of tag filters to use as a metrics configuration filter. The metrics configuration includes only objects that meet the filter's criteria." @@ -34220,6 +35116,7 @@ "attributes": {}, "description": "Describes the notification configuration for an Amazon S3 bucket.\n\n> If you create the target resource and related permissions in the same template, you might have a circular dependency.\n> \n> For example, you might use the `AWS::Lambda::Permission` resource to grant the bucket permission to invoke an AWS Lambda function. However, AWS CloudFormation can't create the bucket until the bucket has permission to invoke the function ( AWS CloudFormation checks whether the bucket can invoke the function). If you're using Refs to pass the bucket name, this leads to a circular dependency.\n> \n> To avoid this dependency, you can create all resources without specifying the notification configuration. Then, update the stack with a notification configuration.\n> \n> For more information on permissions, see [AWS::Lambda::Permission](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-permission.html) and [Granting Permissions to Publish Event Notification Messages to a Destination](https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html#grant-destinations-permissions-to-s3) .", "properties": { + "EventBridgeConfiguration": "Enables delivery of events to Amazon EventBridge.", "LambdaConfigurations": "Describes the AWS Lambda functions to invoke and the events for which to invoke them.", "QueueConfigurations": "The Amazon Simple Queue Service queues to publish messages to and the events for which to publish messages.", "TopicConfigurations": "The topic to which notifications are sent and the events for which notifications are generated." @@ -34265,7 +35162,7 @@ "attributes": {}, "description": "The PublicAccessBlock configuration that you want to apply to this Amazon S3 bucket. You can enable the configuration options in any combination. For more information about when Amazon S3 considers a bucket or object public, see [The Meaning of \"Public\"](https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html#access-control-block-public-access-policy-status) in the *Amazon S3 User Guide* .", "properties": { - "BlockPublicAcls": "Specifies whether Amazon S3 should block public access control lists (ACLs) for this bucket and objects in this bucket. Setting this element to `TRUE` causes the following behavior:\n\n- PUT Bucket acl and PUT Object acl calls fail if the specified ACL is public.\n- PUT Object calls fail if the request includes a public ACL.\n- PUT Bucket calls fail if the request includes a public ACL.\n\nEnabling this setting doesn't affect existing policies or ACLs.", + "BlockPublicAcls": "Specifies whether Amazon S3 should block public access control lists (ACLs) for this bucket and objects in this bucket. Setting this element to `TRUE` causes the following behavior:\n\n- PUT Bucket ACL and PUT Object ACL calls fail if the specified ACL is public.\n- PUT Object calls fail if the request includes a public ACL.\n- PUT Bucket calls fail if the request includes a public ACL.\n\nEnabling this setting doesn't affect existing policies or ACLs.", "BlockPublicPolicy": "Specifies whether Amazon S3 should block public bucket policies for this bucket. Setting this element to `TRUE` causes Amazon S3 to reject calls to PUT Bucket policy if the specified bucket policy allows public access.\n\nEnabling this setting doesn't affect existing bucket policies.", "IgnorePublicAcls": "Specifies whether Amazon S3 should ignore public ACLs for this bucket and objects in this bucket. Setting this element to `TRUE` causes Amazon S3 to ignore all public ACLs on this bucket and objects in this bucket.\n\nEnabling this setting doesn't affect the persistence of any existing ACLs and doesn't prevent new public ACLs from being set.", "RestrictPublicBuckets": "Specifies whether Amazon S3 should restrict public bucket policies for this bucket. Setting this element to `TRUE` restricts access to this bucket to only AWS service principals and authorized users within this account if the bucket has a public policy.\n\nEnabling this setting doesn't affect previously stored bucket policies, except that public and cross-account access within any public bucket policy, including non-public delegation to specific accounts, is blocked." @@ -34500,7 +35397,12 @@ "AWS::S3::Bucket.WebsiteConfiguration": { "attributes": {}, "description": "Specifies website configuration parameters for an Amazon S3 bucket.", - "properties": {} + "properties": { + "ErrorDocument": "The name of the error document for the website.", + "IndexDocument": "The name of the index document for the website.", + "RedirectAllRequestsTo": "The redirect behavior for every request to this bucket's website endpoint.\n\n> If you specify this property, you can't specify any other property.", + "RoutingRules": "Rules that define when a redirect is applied and the redirect behavior." + } }, "AWS::S3::BucketPolicy": { "attributes": {}, @@ -34527,7 +35429,7 @@ "attributes": {}, "description": "The PublicAccessBlock configuration that you want to apply to this Amazon S3 Multi-Region Access Point. You can enable the configuration options in any combination. For more information about when Amazon S3 considers an object public, see [The Meaning of \"Public\"](https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html#access-control-block-public-access-policy-status) in the *Amazon S3 User Guide* .", "properties": { - "BlockPublicAcls": "Specifies whether Amazon S3 should block public access control lists (ACLs) for this bucket and objects in this bucket. Setting this element to `TRUE` causes the following behavior:\n\n- PUT Bucket acl and PUT Object acl calls fail if the specified ACL is public.\n- PUT Object calls fail if the request includes a public ACL.\n- PUT Bucket calls fail if the request includes a public ACL.\n\nEnabling this setting doesn't affect existing policies or ACLs.", + "BlockPublicAcls": "Specifies whether Amazon S3 should block public access control lists (ACLs) for this bucket and objects in this bucket. Setting this element to `TRUE` causes the following behavior:\n\n- PUT Bucket ACL and PUT Object ACL calls fail if the specified ACL is public.\n- PUT Object calls fail if the request includes a public ACL.\n- PUT Bucket calls fail if the request includes a public ACL.\n\nEnabling this setting doesn't affect existing policies or ACLs.", "BlockPublicPolicy": "Specifies whether Amazon S3 should block public bucket policies for this bucket. Setting this element to `TRUE` causes Amazon S3 to reject calls to PUT Bucket policy if the specified bucket policy allows public access.\n\nEnabling this setting doesn't affect existing bucket policies.", "IgnorePublicAcls": "Specifies whether Amazon S3 should ignore public ACLs for this bucket and objects in this bucket. Setting this element to `TRUE` causes Amazon S3 to ignore all public ACLs on this bucket and objects in this bucket.\n\nEnabling this setting doesn't affect the persistence of any existing ACLs and doesn't prevent new public ACLs from being set.", "RestrictPublicBuckets": "Specifies whether Amazon S3 should restrict public bucket policies for this bucket. Setting this element to `TRUE` restricts access to this bucket to only AWS service principals and authorized users within this account if the bucket has a public policy.\n\nEnabling this setting doesn't affect previously stored bucket policies, except that public and cross-account access within any public bucket policy, including non-public delegation to specific accounts, is blocked." @@ -34819,11 +35721,13 @@ }, "description": "The name of the configuration set.\n\nConfiguration sets let you create groups of rules that you can apply to the emails you send using Amazon SES. For more information about using configuration sets, see [Using Amazon SES Configuration Sets](https://docs.aws.amazon.com/ses/latest/dg/using-configuration-sets.html) in the [Amazon SES Developer Guide](https://docs.aws.amazon.com/ses/latest/dg/) .", "properties": { - "Name": "" + "Name": "The name of the configuration set. The name must meet the following requirements:\n\n- Contain only letters (a-z, A-Z), numbers (0-9), underscores (_), or dashes (-).\n- Contain 64 characters or fewer." } }, "AWS::SES::ConfigurationSetEventDestination": { - "attributes": {}, + "attributes": { + "Id": "" + }, "description": "Specifies a configuration set event destination. An event destination is an AWS service that Amazon SES publishes email sending events to. When you specify an event destination, you provide one, and only one, destination. You can send event data to Amazon CloudWatch or Amazon Kinesis Data Firehose.\n\n> You can't specify Amazon SNS event destinations in CloudFormation templates.", "properties": { "ConfigurationSetName": "The name of the configuration set that contains the event destination.", @@ -35018,7 +35922,9 @@ } }, "AWS::SES::Template": { - "attributes": {}, + "attributes": { + "Id": "" + }, "description": "Specifies an email template. Email templates enable you to send personalized email to one or more destinations in a single API operation.", "properties": { "Template": "The content of the email, composed of a subject line and either an HTML part or a text-only part." @@ -35085,6 +35991,7 @@ "attributes": { "Arn": "Returns the Amazon Resource Name (ARN) of the queue. For example: `arn:aws:sqs:us-east-2:123456789012:mystack-myqueue-15PG5C2FC1CW8` .", "QueueName": "Returns the queue name. For example: `mystack-myqueue-1VF9BKQH5BJVI` .", + "QueueUrl": "", "Ref": "`Ref` returns the queue URL. For example:\n\n`{ \"Ref\": \"https://sqs.us-east-2.amazonaws.com/123456789012/ab1-MyQueue-A2BCDEF3GHI4\" }`" }, "description": "The `AWS::SQS::Queue` resource creates an Amazon SQS standard or FIFO queue.\n\nKeep the following caveats in mind:\n\n- If you don't specify the `FifoQueue` property, Amazon SQS creates a standard queue.\n\n> You can't change the queue type after you create it and you can't convert an existing standard queue into a FIFO queue. You must either create a new FIFO queue for your application or delete your existing standard queue and recreate it as a FIFO queue. For more information, see [Moving from a standard queue to a FIFO queue](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues-moving.html) in the *Amazon SQS Developer Guide* .\n- If you don't provide a value for a property, the queue is created with the default value for the property.\n- If you delete a queue, you must wait at least 60 seconds before creating a queue with the same name.\n- To successfully create a new queue, you must provide a queue name that adheres to the [limits related to queues](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/limits-queues.html) and is unique within the scope of your queues.\n\nFor more information about creating FIFO (first-in-first-out) queues, see [Creating an Amazon SQS queue ( AWS CloudFormation )](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/screate-queue-cloudformation.html) in the *Amazon SQS Developer Guide* .", @@ -35172,7 +36079,7 @@ "properties": { "Attachments": "A list of key-value pairs that describe attachments to a version of a document.", "Content": "The content for the new SSM document in JSON or YAML.\n\n> This parameter also supports `String` data types.", - "DocumentFormat": "Specify the document format for the request. The document format can be JSON or YAML. JSON is the default format.\n\n> `TEXT` is not supported, even though it is listed in the `Allowed values` .", + "DocumentFormat": "Specify the document format for the request. JSON is the default format.", "DocumentType": "The type of document to create.\n\n*Allowed Values* : `ApplicationConfigurationSchema` | `Automation` | `Automation.ChangeTemplate` | `Command` | `DeploymentStrategy` | `Package` | `Policy` | `Session`", "Name": "A name for the SSM document.\n\n> You can't use the following strings as document name prefixes. These are reserved by AWS for use as document name prefixes:\n> \n> - `aws-`\n> - `amazon`\n> - `amzn`", "Requires": "A list of SSM documents required by a document. This parameter is used exclusively by AWS AppConfig . When a user creates an AWS AppConfig configuration in an SSM document, the user must also specify a required document for validation purposes. In this case, an `ApplicationConfiguration` document requires an `ApplicationConfigurationSchema` document for validation purposes. For more information, see [What is AWS AppConfig ?](https://docs.aws.amazon.com/appconfig/latest/userguide/what-is-appconfig.html) in the *AWS AppConfig User Guide* .", @@ -35702,7 +36609,7 @@ "attributes": {}, "description": "Specifies the ARN's of a SageMaker image and SageMaker image version, and the instance type that the version runs on.", "properties": { - "InstanceType": "The instance type that the image version runs on.", + "InstanceType": "The instance type that the image version runs on.\n\n> JupyterServer Apps only support the `system` value.", "SageMakerImageArn": "The ARN of the SageMaker image that the image version belongs to.", "SageMakerImageVersionArn": "The ARN of the image version created on the instance." } @@ -35749,7 +36656,7 @@ "CodeRepositoryName": "The name of the code repository, such as `myCodeRepo` .", "Ref": "`Ref` returns the Amazon Resource Name (ARN) of the code repository." }, - "description": "Creates a Git repository as a resource in your Amazon SageMaker account. You can associate the repository with notebook instances so that you can use Git source control for the notebooks you create. The Git repository is a resource in your Amazon SageMaker account, so it can be associated with more than one notebook instance, and it persists independently from the lifecycle of any notebook instances it is associated with.\n\nThe repository can be hosted either in [AWS CodeCommit](https://docs.aws.amazon.com/codecommit/latest/userguide/welcome.html) or in any other Git repository.", + "description": "Creates a Git repository as a resource in your SageMaker account. You can associate the repository with notebook instances so that you can use Git source control for the notebooks you create. The Git repository is a resource in your SageMaker account, so it can be associated with more than one notebook instance, and it persists independently from the lifecycle of any notebook instances it is associated with.\n\nThe repository can be hosted either in [AWS CodeCommit](https://docs.aws.amazon.com/codecommit/latest/userguide/welcome.html) or in any other Git repository.", "properties": { "CodeRepositoryName": "The name of the Git repository.", "GitConfig": "Configuration details for the Git repository, including the URL where it is located and the ARN of the AWS Secrets Manager secret that contains the credentials used to access the repository.", @@ -35889,9 +36796,9 @@ }, "AWS::SageMaker::DataQualityJobDefinition.StoppingCondition": { "attributes": {}, - "description": "Specifies a limit to how long a model training job or model compilation job can run. It also specifies how long a managed spot training job has to complete. When the job reaches the time limit, Amazon SageMaker ends the training or compilation job. Use this API to cap model training costs.\n\nTo stop a training job, Amazon SageMaker sends the algorithm the `SIGTERM` signal, which delays job termination for 120 seconds. Algorithms can use this 120-second window to save the model artifacts, so the results of training are not lost.\n\nThe training algorithms provided by Amazon SageMaker automatically save the intermediate results of a model training job when possible. This attempt to save artifacts is only a best effort case as model might not be in a state from which it can be saved. For example, if training has just started, the model might not be ready to save. When saved, this intermediate data is a valid model artifact. You can use it to create a model with `CreateModel` .\n\n> The Neural Topic Model (NTM) currently does not support saving intermediate model artifacts. When training NTMs, make sure that the maximum runtime is sufficient for the training job to complete.", + "description": "Specifies a limit to how long a model training job or model compilation job can run. It also specifies how long a managed spot training job has to complete. When the job reaches the time limit, SageMaker ends the training or compilation job. Use this API to cap model training costs.\n\nTo stop a training job, SageMaker sends the algorithm the `SIGTERM` signal, which delays job termination for 120 seconds. Algorithms can use this 120-second window to save the model artifacts, so the results of training are not lost.\n\nThe training algorithms provided by SageMaker automatically save the intermediate results of a model training job when possible. This attempt to save artifacts is only a best effort case as model might not be in a state from which it can be saved. For example, if training has just started, the model might not be ready to save. When saved, this intermediate data is a valid model artifact. You can use it to create a model with `CreateModel` .\n\n> The Neural Topic Model (NTM) currently does not support saving intermediate model artifacts. When training NTMs, make sure that the maximum runtime is sufficient for the training job to complete.", "properties": { - "MaxRuntimeInSeconds": "The maximum length of time, in seconds, that a training or compilation job can run.\n\nFor compilation jobs, if the job does not complete during this time, you will receive a `TimeOut` error. We recommend starting with 900 seconds and increase as necessary based on your model.\n\nFor all other jobs, if the job does not complete during this time, Amazon SageMaker ends the job. When `RetryStrategy` is specified in the job request, `MaxRuntimeInSeconds` specifies the maximum time for all of the attempts in total, not each individual attempt. The default value is 1 day. The maximum value is 28 days." + "MaxRuntimeInSeconds": "The maximum length of time, in seconds, that a training or compilation job can run.\n\nFor compilation jobs, if the job does not complete during this time, a `TimeOut` error is generated. We recommend starting with 900 seconds and increasing as necessary based on your model.\n\nFor all other jobs, if the job does not complete during this time, SageMaker ends the job. When `RetryStrategy` is specified in the job request, `MaxRuntimeInSeconds` specifies the maximum time for all of the attempts in total, not each individual attempt. The default value is 1 day. The maximum value is 28 days." } }, "AWS::SageMaker::DataQualityJobDefinition.VpcConfig": { @@ -35985,14 +36892,14 @@ "description": "The KernelGateway app settings.", "properties": { "CustomImages": "A list of custom SageMaker images that are configured to run as a KernelGateway app.", - "DefaultResourceSpec": "The default instance type and the Amazon Resource Name (ARN) of the default SageMaker image used by the KernelGateway app." + "DefaultResourceSpec": "The default instance type and the Amazon Resource Name (ARN) of the default SageMaker image used by the KernelGateway app.\n\n> The Amazon SageMaker Studio UI does not use the default instance type value set here. The default instance type set here is used when Apps are created using the AWS Command Line Interface or AWS CloudFormation and the instance type parameter value is not passed." } }, "AWS::SageMaker::Domain.ResourceSpec": { "attributes": {}, "description": "Specifies the ARN's of a SageMaker image and SageMaker image version, and the instance type that the version runs on.", "properties": { - "InstanceType": "The instance type that the image version runs on.", + "InstanceType": "The instance type that the image version runs on.\n\n> JupyterServer Apps only support the `system` value.", "SageMakerImageArn": "The ARN of the SageMaker image that the image version belongs to.", "SageMakerImageVersionArn": "The ARN of the image version created on the instance." } @@ -36214,7 +37121,7 @@ "ImageArn": "The Amazon Resource Name (ARN) of the image.\n\n*Type* : String\n\n*Length Constraints* : Maximum length of 256.\n\n*Pattern* : `^arn:aws(-[\\w]+)*:sagemaker:.+:[0-9]{12}:image/[a-z0-9]([-.]?[a-z0-9])*$`", "Ref": "`Ref` returns the ImageArn." }, - "description": "Creates a custom SageMaker image. A SageMaker image is a set of image versions. Each image version represents a container image stored in Amazon Container Registry (ECR). For more information, see [Bring your own SageMaker image](https://docs.aws.amazon.com/sagemaker/latest/dg/studio-byoi.html) .", + "description": "Creates a custom SageMaker image. A SageMaker image is a set of image versions. Each image version represents a container image stored in Amazon Elastic Container Registry (ECR). For more information, see [Bring your own SageMaker image](https://docs.aws.amazon.com/sagemaker/latest/dg/studio-byoi.html) .", "properties": { "ImageDescription": "The description of the image.\n\n*Length Constraints* : Minimum length of 1. Maximum length of 512.\n\n*Pattern* : `.*`", "ImageDisplayName": "The display name of the image.\n\n*Length Constraints* : Minimum length of 1. Maximum length of 128.\n\n*Pattern* : `^\\S(.*\\S)?$`", @@ -36246,7 +37153,7 @@ "properties": { "Containers": "Specifies the containers in the inference pipeline.", "EnableNetworkIsolation": "Isolates the model container. No inbound or outbound network calls can be made to or from the model container.", - "ExecutionRoleArn": "The Amazon Resource Name (ARN) of the IAM role that Amazon SageMaker can assume to access model artifacts and docker image for deployment on ML compute instances or for batch transform jobs. Deploying on ML compute instances is part of model hosting. For more information, see [Amazon SageMaker Roles](https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-roles.html) .\n\n> To be able to pass this role to Amazon SageMaker, the caller of this API must have the `iam:PassRole` permission.", + "ExecutionRoleArn": "The Amazon Resource Name (ARN) of the IAM role that SageMaker can assume to access model artifacts and docker image for deployment on ML compute instances or for batch transform jobs. Deploying on ML compute instances is part of model hosting. For more information, see [SageMaker Roles](https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-roles.html) .\n\n> To be able to pass this role to SageMaker, the caller of this API must have the `iam:PassRole` permission.", "InferenceExecutionConfig": "Specifies details of how containers in a multi-container endpoint are called.", "ModelName": "The name of the new model.", "PrimaryContainer": "The location of the primary docker image containing inference code, associated artifacts, and custom environment map that the inference code uses when the model is deployed for predictions.", @@ -36260,11 +37167,11 @@ "properties": { "ContainerHostname": "This parameter is ignored for models that contain only a `PrimaryContainer` .\n\nWhen a `ContainerDefinition` is part of an inference pipeline, the value of the parameter uniquely identifies the container for the purposes of logging and metrics. For information, see [Use Logs and Metrics to Monitor an Inference Pipeline](https://docs.aws.amazon.com/sagemaker/latest/dg/inference-pipeline-logs-metrics.html) . If you don't specify a value for this parameter for a `ContainerDefinition` that is part of an inference pipeline, a unique name is automatically assigned based on the position of the `ContainerDefinition` in the pipeline. If you specify a value for the `ContainerHostName` for any `ContainerDefinition` that is part of an inference pipeline, you must specify a value for the `ContainerHostName` parameter of every `ContainerDefinition` in that pipeline.", "Environment": "The environment variables to set in the Docker container. Each key and value in the `Environment` string to string map can have length of up to 1024. We support up to 16 entries in the map.", - "Image": "The path where inference code is stored. This can be either in Amazon EC2 Container Registry or in a Docker registry that is accessible from the same VPC that you configure for your endpoint. If you are using your own custom algorithm instead of an algorithm provided by Amazon SageMaker, the inference code must meet Amazon SageMaker requirements. Amazon SageMaker supports both `registry/repository[:tag]` and `registry/repository[@digest]` image path formats. For more information, see [Using Your Own Algorithms with Amazon SageMaker](https://docs.aws.amazon.com/sagemaker/latest/dg/your-algorithms.html)", + "Image": "The path where inference code is stored. This can be either in Amazon EC2 Container Registry or in a Docker registry that is accessible from the same VPC that you configure for your endpoint. If you are using your own custom algorithm instead of an algorithm provided by SageMaker, the inference code must meet SageMaker requirements. SageMaker supports both `registry/repository[:tag]` and `registry/repository[@digest]` image path formats. For more information, see [Using Your Own Algorithms with Amazon SageMaker](https://docs.aws.amazon.com/sagemaker/latest/dg/your-algorithms.html)", "ImageConfig": "Specifies whether the model container is in Amazon ECR or a private Docker registry accessible from your Amazon Virtual Private Cloud (VPC). For information about storing containers in a private Docker registry, see [Use a Private Docker Registry for Real-Time Inference Containers](https://docs.aws.amazon.com/sagemaker/latest/dg/your-algorithms-containers-inference-private.html)", "InferenceSpecificationName": "The inference specification name in the model package version.", "Mode": "Whether the container hosts a single model or multiple models.", - "ModelDataUrl": "The S3 path where the model artifacts, which result from model training, are stored. This path must point to a single gzip compressed tar archive (.tar.gz suffix). The S3 path is required for Amazon SageMaker built-in algorithms, but not if you use your own algorithms. For more information on built-in algorithms, see [Common Parameters](https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-algo-docker-registry-paths.html) .\n\n> The model artifacts must be in an S3 bucket that is in the same region as the model or endpoint you are creating. \n\nIf you provide a value for this parameter, Amazon SageMaker uses AWS Security Token Service to download model artifacts from the S3 path you provide. AWS STS is activated in your IAM user account by default. If you previously deactivated AWS STS for a region, you need to reactivate AWS STS for that region. For more information, see [Activating and Deactivating AWS STS in an AWS Region](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) in the *AWS Identity and Access Management User Guide* .\n\n> If you use a built-in algorithm to create a model, Amazon SageMaker requires that you provide a S3 path to the model artifacts in `ModelDataUrl` .", + "ModelDataUrl": "The S3 path where the model artifacts, which result from model training, are stored. This path must point to a single gzip compressed tar archive (.tar.gz suffix). The S3 path is required for SageMaker built-in algorithms, but not if you use your own algorithms. For more information on built-in algorithms, see [Common Parameters](https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-algo-docker-registry-paths.html) .\n\n> The model artifacts must be in an S3 bucket that is in the same region as the model or endpoint you are creating. \n\nIf you provide a value for this parameter, SageMaker uses AWS Security Token Service to download model artifacts from the S3 path you provide. AWS STS is activated in your IAM user account by default. If you previously deactivated AWS STS for a region, you need to reactivate AWS STS for that region. For more information, see [Activating and Deactivating AWS STS in an AWS Region](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) in the *AWS Identity and Access Management User Guide* .\n\n> If you use a built-in algorithm to create a model, SageMaker requires that you provide a S3 path to the model artifacts in `ModelDataUrl` .", "ModelPackageName": "The name or Amazon Resource Name (ARN) of the model package to use to create the model.", "MultiModelConfig": "Specifies additional configuration for multi-model endpoints." } @@ -36433,9 +37340,9 @@ }, "AWS::SageMaker::ModelBiasJobDefinition.StoppingCondition": { "attributes": {}, - "description": "Specifies a limit to how long a model training job or model compilation job can run. It also specifies how long a managed spot training job has to complete. When the job reaches the time limit, Amazon SageMaker ends the training or compilation job. Use this API to cap model training costs.\n\nTo stop a training job, Amazon SageMaker sends the algorithm the `SIGTERM` signal, which delays job termination for 120 seconds. Algorithms can use this 120-second window to save the model artifacts, so the results of training are not lost.\n\nThe training algorithms provided by Amazon SageMaker automatically save the intermediate results of a model training job when possible. This attempt to save artifacts is only a best effort case as model might not be in a state from which it can be saved. For example, if training has just started, the model might not be ready to save. When saved, this intermediate data is a valid model artifact. You can use it to create a model with `CreateModel` .\n\n> The Neural Topic Model (NTM) currently does not support saving intermediate model artifacts. When training NTMs, make sure that the maximum runtime is sufficient for the training job to complete.", + "description": "Specifies a limit to how long a model training job or model compilation job can run. It also specifies how long a managed spot training job has to complete. When the job reaches the time limit, SageMaker ends the training or compilation job. Use this API to cap model training costs.\n\nTo stop a training job, SageMaker sends the algorithm the `SIGTERM` signal, which delays job termination for 120 seconds. Algorithms can use this 120-second window to save the model artifacts, so the results of training are not lost.\n\nThe training algorithms provided by SageMaker automatically save the intermediate results of a model training job when possible. This attempt to save artifacts is only a best effort case as model might not be in a state from which it can be saved. For example, if training has just started, the model might not be ready to save. When saved, this intermediate data is a valid model artifact. You can use it to create a model with `CreateModel` .\n\n> The Neural Topic Model (NTM) currently does not support saving intermediate model artifacts. When training NTMs, make sure that the maximum runtime is sufficient for the training job to complete.", "properties": { - "MaxRuntimeInSeconds": "The maximum length of time, in seconds, that a training or compilation job can run.\n\nFor compilation jobs, if the job does not complete during this time, you will receive a `TimeOut` error. We recommend starting with 900 seconds and increase as necessary based on your model.\n\nFor all other jobs, if the job does not complete during this time, Amazon SageMaker ends the job. When `RetryStrategy` is specified in the job request, `MaxRuntimeInSeconds` specifies the maximum time for all of the attempts in total, not each individual attempt. The default value is 1 day. The maximum value is 28 days." + "MaxRuntimeInSeconds": "The maximum length of time, in seconds, that a training or compilation job can run.\n\nFor compilation jobs, if the job does not complete during this time, a `TimeOut` error is generated. We recommend starting with 900 seconds and increasing as necessary based on your model.\n\nFor all other jobs, if the job does not complete during this time, SageMaker ends the job. When `RetryStrategy` is specified in the job request, `MaxRuntimeInSeconds` specifies the maximum time for all of the attempts in total, not each individual attempt. The default value is 1 day. The maximum value is 28 days." } }, "AWS::SageMaker::ModelBiasJobDefinition.VpcConfig": { @@ -36562,9 +37469,9 @@ }, "AWS::SageMaker::ModelExplainabilityJobDefinition.StoppingCondition": { "attributes": {}, - "description": "Specifies a limit to how long a model training job or model compilation job can run. It also specifies how long a managed spot training job has to complete. When the job reaches the time limit, Amazon SageMaker ends the training or compilation job. Use this API to cap model training costs.\n\nTo stop a training job, Amazon SageMaker sends the algorithm the `SIGTERM` signal, which delays job termination for 120 seconds. Algorithms can use this 120-second window to save the model artifacts, so the results of training are not lost.\n\nThe training algorithms provided by Amazon SageMaker automatically save the intermediate results of a model training job when possible. This attempt to save artifacts is only a best effort case as model might not be in a state from which it can be saved. For example, if training has just started, the model might not be ready to save. When saved, this intermediate data is a valid model artifact. You can use it to create a model with `CreateModel` .\n\n> The Neural Topic Model (NTM) currently does not support saving intermediate model artifacts. When training NTMs, make sure that the maximum runtime is sufficient for the training job to complete.", + "description": "Specifies a limit to how long a model training job or model compilation job can run. It also specifies how long a managed spot training job has to complete. When the job reaches the time limit, SageMaker ends the training or compilation job. Use this API to cap model training costs.\n\nTo stop a training job, SageMaker sends the algorithm the `SIGTERM` signal, which delays job termination for 120 seconds. Algorithms can use this 120-second window to save the model artifacts, so the results of training are not lost.\n\nThe training algorithms provided by SageMaker automatically save the intermediate results of a model training job when possible. This attempt to save artifacts is only a best effort case as model might not be in a state from which it can be saved. For example, if training has just started, the model might not be ready to save. When saved, this intermediate data is a valid model artifact. You can use it to create a model with `CreateModel` .\n\n> The Neural Topic Model (NTM) currently does not support saving intermediate model artifacts. When training NTMs, make sure that the maximum runtime is sufficient for the training job to complete.", "properties": { - "MaxRuntimeInSeconds": "The maximum length of time, in seconds, that a training or compilation job can run.\n\nFor compilation jobs, if the job does not complete during this time, you will receive a `TimeOut` error. We recommend starting with 900 seconds and increase as necessary based on your model.\n\nFor all other jobs, if the job does not complete during this time, Amazon SageMaker ends the job. When `RetryStrategy` is specified in the job request, `MaxRuntimeInSeconds` specifies the maximum time for all of the attempts in total, not each individual attempt. The default value is 1 day. The maximum value is 28 days." + "MaxRuntimeInSeconds": "The maximum length of time, in seconds, that a training or compilation job can run.\n\nFor compilation jobs, if the job does not complete during this time, a `TimeOut` error is generated. We recommend starting with 900 seconds and increasing as necessary based on your model.\n\nFor all other jobs, if the job does not complete during this time, SageMaker ends the job. When `RetryStrategy` is specified in the job request, `MaxRuntimeInSeconds` specifies the maximum time for all of the attempts in total, not each individual attempt. The default value is 1 day. The maximum value is 28 days." } }, "AWS::SageMaker::ModelExplainabilityJobDefinition.VpcConfig": { @@ -36720,9 +37627,9 @@ }, "AWS::SageMaker::ModelQualityJobDefinition.StoppingCondition": { "attributes": {}, - "description": "Specifies a limit to how long a model training job or model compilation job can run. It also specifies how long a managed spot training job has to complete. When the job reaches the time limit, Amazon SageMaker ends the training or compilation job. Use this API to cap model training costs.\n\nTo stop a training job, Amazon SageMaker sends the algorithm the `SIGTERM` signal, which delays job termination for 120 seconds. Algorithms can use this 120-second window to save the model artifacts, so the results of training are not lost.\n\nThe training algorithms provided by Amazon SageMaker automatically save the intermediate results of a model training job when possible. This attempt to save artifacts is only a best effort case as model might not be in a state from which it can be saved. For example, if training has just started, the model might not be ready to save. When saved, this intermediate data is a valid model artifact. You can use it to create a model with `CreateModel` .\n\n> The Neural Topic Model (NTM) currently does not support saving intermediate model artifacts. When training NTMs, make sure that the maximum runtime is sufficient for the training job to complete.", + "description": "Specifies a limit to how long a model training job or model compilation job can run. It also specifies how long a managed spot training job has to complete. When the job reaches the time limit, SageMaker ends the training or compilation job. Use this API to cap model training costs.\n\nTo stop a training job, SageMaker sends the algorithm the `SIGTERM` signal, which delays job termination for 120 seconds. Algorithms can use this 120-second window to save the model artifacts, so the results of training are not lost.\n\nThe training algorithms provided by SageMaker automatically save the intermediate results of a model training job when possible. This attempt to save artifacts is only a best effort case as model might not be in a state from which it can be saved. For example, if training has just started, the model might not be ready to save. When saved, this intermediate data is a valid model artifact. You can use it to create a model with `CreateModel` .\n\n> The Neural Topic Model (NTM) currently does not support saving intermediate model artifacts. When training NTMs, make sure that the maximum runtime is sufficient for the training job to complete.", "properties": { - "MaxRuntimeInSeconds": "The maximum length of time, in seconds, that a training or compilation job can run.\n\nFor compilation jobs, if the job does not complete during this time, you will receive a `TimeOut` error. We recommend starting with 900 seconds and increase as necessary based on your model.\n\nFor all other jobs, if the job does not complete during this time, Amazon SageMaker ends the job. When `RetryStrategy` is specified in the job request, `MaxRuntimeInSeconds` specifies the maximum time for all of the attempts in total, not each individual attempt. The default value is 1 day. The maximum value is 28 days." + "MaxRuntimeInSeconds": "The maximum length of time, in seconds, that a training or compilation job can run.\n\nFor compilation jobs, if the job does not complete during this time, a `TimeOut` error is generated. We recommend starting with 900 seconds and increasing as necessary based on your model.\n\nFor all other jobs, if the job does not complete during this time, SageMaker ends the job. When `RetryStrategy` is specified in the job request, `MaxRuntimeInSeconds` specifies the maximum time for all of the attempts in total, not each individual attempt. The default value is 1 day. The maximum value is 28 days." } }, "AWS::SageMaker::ModelQualityJobDefinition.VpcConfig": { @@ -36899,9 +37806,9 @@ }, "AWS::SageMaker::MonitoringSchedule.StoppingCondition": { "attributes": {}, - "description": "Specifies a limit to how long a model training job or model compilation job can run. It also specifies how long a managed spot training job has to complete. When the job reaches the time limit, Amazon SageMaker ends the training or compilation job. Use this API to cap model training costs.\n\nTo stop a training job, Amazon SageMaker sends the algorithm the `SIGTERM` signal, which delays job termination for 120 seconds. Algorithms can use this 120-second window to save the model artifacts, so the results of training are not lost.\n\nThe training algorithms provided by Amazon SageMaker automatically save the intermediate results of a model training job when possible. This attempt to save artifacts is only a best effort case as model might not be in a state from which it can be saved. For example, if training has just started, the model might not be ready to save. When saved, this intermediate data is a valid model artifact. You can use it to create a model with `CreateModel` .\n\n> The Neural Topic Model (NTM) currently does not support saving intermediate model artifacts. When training NTMs, make sure that the maximum runtime is sufficient for the training job to complete.", + "description": "Specifies a limit to how long a model training job or model compilation job can run. It also specifies how long a managed spot training job has to complete. When the job reaches the time limit, SageMaker ends the training or compilation job. Use this API to cap model training costs.\n\nTo stop a training job, SageMaker sends the algorithm the `SIGTERM` signal, which delays job termination for 120 seconds. Algorithms can use this 120-second window to save the model artifacts, so the results of training are not lost.\n\nThe training algorithms provided by SageMaker automatically save the intermediate results of a model training job when possible. This attempt to save artifacts is only a best effort case as model might not be in a state from which it can be saved. For example, if training has just started, the model might not be ready to save. When saved, this intermediate data is a valid model artifact. You can use it to create a model with `CreateModel` .\n\n> The Neural Topic Model (NTM) currently does not support saving intermediate model artifacts. When training NTMs, make sure that the maximum runtime is sufficient for the training job to complete.", "properties": { - "MaxRuntimeInSeconds": "The maximum length of time, in seconds, that a training or compilation job can run.\n\nFor compilation jobs, if the job does not complete during this time, you will receive a `TimeOut` error. We recommend starting with 900 seconds and increase as necessary based on your model.\n\nFor all other jobs, if the job does not complete during this time, Amazon SageMaker ends the job. When `RetryStrategy` is specified in the job request, `MaxRuntimeInSeconds` specifies the maximum time for all of the attempts in total, not each individual attempt. The default value is 1 day. The maximum value is 28 days." + "MaxRuntimeInSeconds": "The maximum length of time, in seconds, that a training or compilation job can run.\n\nFor compilation jobs, if the job does not complete during this time, a `TimeOut` error is generated. We recommend starting with 900 seconds and increasing as necessary based on your model.\n\nFor all other jobs, if the job does not complete during this time, SageMaker ends the job. When `RetryStrategy` is specified in the job request, `MaxRuntimeInSeconds` specifies the maximum time for all of the attempts in total, not each individual attempt. The default value is 1 day. The maximum value is 28 days." } }, "AWS::SageMaker::MonitoringSchedule.VpcConfig": { @@ -36920,15 +37827,15 @@ "description": "The `AWS::SageMaker::NotebookInstance` resource creates an Amazon SageMaker notebook instance. A notebook instance is a machine learning (ML) compute instance running on a Jupyter notebook. For more information, see [Use Notebook Instances](https://docs.aws.amazon.com/sagemaker/latest/dg/nbi.html) .", "properties": { "AcceleratorTypes": "A list of Amazon Elastic Inference (EI) instance types to associate with the notebook instance. Currently, only one instance type can be associated with a notebook instance. For more information, see [Using Elastic Inference in Amazon SageMaker](https://docs.aws.amazon.com/sagemaker/latest/dg/ei.html) .\n\n*Valid Values:* `ml.eia1.medium | ml.eia1.large | ml.eia1.xlarge | ml.eia2.medium | ml.eia2.large | ml.eia2.xlarge` .", - "AdditionalCodeRepositories": "An array of up to three Git repositories associated with the notebook instance. These can be either the names of Git repositories stored as resources in your account, or the URL of Git repositories in [AWS CodeCommit](https://docs.aws.amazon.com/codecommit/latest/userguide/welcome.html) or in any other Git repository. These repositories are cloned at the same level as the default repository of your notebook instance. For more information, see [Associating Git Repositories with Amazon SageMaker Notebook Instances](https://docs.aws.amazon.com/sagemaker/latest/dg/nbi-git-repo.html) .", - "DefaultCodeRepository": "The Git repository associated with the notebook instance as its default code repository. This can be either the name of a Git repository stored as a resource in your account, or the URL of a Git repository in [AWS CodeCommit](https://docs.aws.amazon.com/codecommit/latest/userguide/welcome.html) or in any other Git repository. When you open a notebook instance, it opens in the directory that contains this repository. For more information, see [Associating Git Repositories with Amazon SageMaker Notebook Instances](https://docs.aws.amazon.com/sagemaker/latest/dg/nbi-git-repo.html) .", - "DirectInternetAccess": "Sets whether Amazon SageMaker provides internet access to the notebook instance. If you set this to `Disabled` this notebook instance is able to access resources only in your VPC, and is not be able to connect to Amazon SageMaker training and endpoint services unless you configure a NAT Gateway in your VPC.\n\nFor more information, see [Notebook Instances Are Internet-Enabled by Default](https://docs.aws.amazon.com/sagemaker/latest/dg/appendix-additional-considerations.html#appendix-notebook-and-internet-access) . You can set the value of this parameter to `Disabled` only if you set a value for the `SubnetId` parameter.", + "AdditionalCodeRepositories": "An array of up to three Git repositories associated with the notebook instance. These can be either the names of Git repositories stored as resources in your account, or the URL of Git repositories in [AWS CodeCommit](https://docs.aws.amazon.com/codecommit/latest/userguide/welcome.html) or in any other Git repository. These repositories are cloned at the same level as the default repository of your notebook instance. For more information, see [Associating Git Repositories with SageMaker Notebook Instances](https://docs.aws.amazon.com/sagemaker/latest/dg/nbi-git-repo.html) .", + "DefaultCodeRepository": "The Git repository associated with the notebook instance as its default code repository. This can be either the name of a Git repository stored as a resource in your account, or the URL of a Git repository in [AWS CodeCommit](https://docs.aws.amazon.com/codecommit/latest/userguide/welcome.html) or in any other Git repository. When you open a notebook instance, it opens in the directory that contains this repository. For more information, see [Associating Git Repositories with SageMaker Notebook Instances](https://docs.aws.amazon.com/sagemaker/latest/dg/nbi-git-repo.html) .", + "DirectInternetAccess": "Sets whether SageMaker provides internet access to the notebook instance. If you set this to `Disabled` this notebook instance is able to access resources only in your VPC, and is not be able to connect to SageMaker training and endpoint services unless you configure a NAT Gateway in your VPC.\n\nFor more information, see [Notebook Instances Are Internet-Enabled by Default](https://docs.aws.amazon.com/sagemaker/latest/dg/appendix-additional-considerations.html#appendix-notebook-and-internet-access) . You can set the value of this parameter to `Disabled` only if you set a value for the `SubnetId` parameter.", "InstanceType": "The type of ML compute instance to launch for the notebook instance.\n\n> Expect some interruption of service if this parameter is changed as CloudFormation stops a notebook instance and starts it up again to update it.", - "KmsKeyId": "The Amazon Resource Name (ARN) of a AWS Key Management Service key that Amazon SageMaker uses to encrypt data on the storage volume attached to your notebook instance. The KMS key you provide must be enabled. For information, see [Enabling and Disabling Keys](https://docs.aws.amazon.com/kms/latest/developerguide/enabling-keys.html) in the *AWS Key Management Service Developer Guide* .", + "KmsKeyId": "The Amazon Resource Name (ARN) of a AWS Key Management Service key that SageMaker uses to encrypt data on the storage volume attached to your notebook instance. The KMS key you provide must be enabled. For information, see [Enabling and Disabling Keys](https://docs.aws.amazon.com/kms/latest/developerguide/enabling-keys.html) in the *AWS Key Management Service Developer Guide* .", "LifecycleConfigName": "The name of a lifecycle configuration to associate with the notebook instance. For information about lifecycle configurations, see [Customize a Notebook Instance](https://docs.aws.amazon.com/sagemaker/latest/dg/notebook-lifecycle-config.html) in the *Amazon SageMaker Developer Guide* .", "NotebookInstanceName": "The name of the new notebook instance.", "PlatformIdentifier": "The platform identifier of the notebook instance runtime environment.", - "RoleArn": "When you send any requests to AWS resources from the notebook instance, Amazon SageMaker assumes this role to perform tasks on your behalf. You must grant this role necessary permissions so Amazon SageMaker can perform these tasks. The policy must allow the Amazon SageMaker service principal (sagemaker.amazonaws.com) permissions to assume this role. For more information, see [Amazon SageMaker Roles](https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-roles.html) .\n\n> To be able to pass this role to Amazon SageMaker, the caller of this API must have the `iam:PassRole` permission.", + "RoleArn": "When you send any requests to AWS resources from the notebook instance, SageMaker assumes this role to perform tasks on your behalf. You must grant this role necessary permissions so SageMaker can perform these tasks. The policy must allow the SageMaker service principal (sagemaker.amazonaws.com) permissions to assume this role. For more information, see [SageMaker Roles](https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-roles.html) .\n\n> To be able to pass this role to SageMaker, the caller of this API must have the `iam:PassRole` permission.", "RootAccess": "Whether root access is enabled or disabled for users of the notebook instance. The default value is `Enabled` .\n\n> Lifecycle configurations need root access to be able to set up a notebook instance. Because of this, lifecycle configurations associated with a notebook instance always run with root access even if you disable root access for users.", "SecurityGroupIds": "The VPC security group IDs, in the form sg-xxxxxxxx. The security groups must be for the same VPC as specified in the subnet.", "SubnetId": "The ID of the subnet in a VPC to which you would like to have a connectivity from your ML compute instance.", @@ -37022,14 +37929,14 @@ "description": "The KernelGateway app settings.", "properties": { "CustomImages": "A list of custom SageMaker images that are configured to run as a KernelGateway app.", - "DefaultResourceSpec": "The default instance type and the Amazon Resource Name (ARN) of the default SageMaker image used by the KernelGateway app." + "DefaultResourceSpec": "The default instance type and the Amazon Resource Name (ARN) of the default SageMaker image used by the KernelGateway app.\n\n> The Amazon SageMaker Studio UI does not use the default instance type value set here. The default instance type set here is used when Apps are created using the AWS Command Line Interface or AWS CloudFormation and the instance type parameter value is not passed." } }, "AWS::SageMaker::UserProfile.ResourceSpec": { "attributes": {}, "description": "Specifies the ARN's of a SageMaker image and SageMaker image version, and the instance type that the version runs on.", "properties": { - "InstanceType": "The instance type that the image version runs on.", + "InstanceType": "The instance type that the image version runs on.\n\n> JupyterServer Apps only support the `system` value.", "SageMakerImageArn": "The ARN of the SageMaker image that the image version belongs to.", "SageMakerImageVersionArn": "The ARN of the image version created on the instance." } @@ -37057,14 +37964,14 @@ "AWS::SageMaker::Workteam": { "attributes": { "Ref": "", - "WorkteamName": "" + "WorkteamName": "The name of the work team." }, "description": "Creates a new work team for labeling your data. A work team is defined by one or more Amazon Cognito user pools. You must first create the user pools before you can create a work team.\n\nYou cannot create more than 25 work teams in an account and region.", "properties": { "Description": "A description of the work team.", "MemberDefinitions": "A list of `MemberDefinition` objects that contains objects that identify the workers that make up the work team.\n\nWorkforces can be created using Amazon Cognito or your own OIDC Identity Provider (IdP). For private workforces created using Amazon Cognito use `CognitoMemberDefinition` . For workforces created using your own OIDC identity provider (IdP) use `OidcMemberDefinition` .", "NotificationConfiguration": "Configures SNS notifications of available or expiring work items for work teams.", - "Tags": "", + "Tags": "An array of key-value pairs.", "WorkteamName": "The name of the work team." } }, @@ -37072,9 +37979,9 @@ "attributes": {}, "description": "Identifies a Amazon Cognito user group. A user group can be used in on or more work teams.", "properties": { - "CognitoClientId": "", - "CognitoUserGroup": "", - "CognitoUserPool": "" + "CognitoClientId": "An identifier for an application client. You must create the app client ID using Amazon Cognito.", + "CognitoUserGroup": "An identifier for a user group.", + "CognitoUserPool": "An identifier for a user pool. The user pool must be in the same region as the service that you are calling." } }, "AWS::SageMaker::Workteam.MemberDefinition": { @@ -37106,25 +38013,25 @@ "attributes": { "Ref": "When you pass the logical ID of an `AWS::SecretsManager::RotationSchedule` resource to the intrinsic `Ref` function, the function returns the ARN of the secret being configured, such as:\n\n*arn:aws:secretsmanager: us-west-2* : *123456789012* :secret: *my-path/my-secret-name* - *1a2b3c*\n\nYou can use the ARN to reference a secret you create in one part of the stack template from within the definition of another resource later, in the same template. You typically do this when you define the [AWS::SecretsManager::SecretTargetAttachment](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-secretsmanager-secrettargetattachment.html) resource type.\n\nFor more information about using the `Ref` function, see [Ref](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) ." }, - "description": "Configures rotation for a secret. You must already configure the secret with the details of the database or service. If you define both the secret and the database or service in an AWS CloudFormation template, then define the [AWS::SecretsManager::SecretTargetAttachment](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-secretsmanager-secrettargetattachment.html) resource to populate the secret with the connection details of the database or service before you attempt to configure rotation.\n\n> When you configure rotation for a secret, AWS CloudFormation automatically rotates the secret one time.", + "description": "Sets the rotation schedule and Lambda rotation function for a secret. For more information, see [How rotation works](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotate-secrets_how.html) . For the rotation function, you have two options:\n\n- You can create a new rotation function based on one of the [Secrets Manager rotation function templates](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html) by using `HostedRotationLambda` .\n- You can choose an existing rotation function by using `RotationLambdaARN` .\n\nFor Amazon RDS , Amazon Redshift , Amazon DocumentDB secrets, if you define both the secret and the database or service in the AWS CloudFormation template, then you need to define the [AWS::SecretsManager::SecretTargetAttachment](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-secretsmanager-secrettargetattachment.html) resource to populate the secret with the connection details of the database or service before you attempt to configure rotation.", "properties": { - "HostedRotationLambda": "To use these values, you must specify `Transform: AWS::SecretsManager-2020-07-23` at the beginning of the CloudFormation template.\n\nWhen you enter valid values for `RotationSchedule.HostedRotationLambda` , Secrets Manager launches a Lambda that performs rotation on the secret specified in the `secret-id` property. The template creates a Lambda as part of a nested stack within the current stack.", - "RotateImmediatelyOnUpdate": "", - "RotationLambdaARN": "The ARN of the Lambda function that can rotate the secret. If you don't specify this parameter, then the secret must already have the ARN of a Lambda function configured.\n\nTo reference a Lambda function also created in this template, use the [Ref](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) function with the function's logical ID.", + "HostedRotationLambda": "Creates a new Lambda rotation function based on one of the [Secrets Manager rotation function templates](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html) . To use a rotation function that already exists, specify `RotationLambdaARN` instead.", + "RotateImmediatelyOnUpdate": "Specifies whether to rotate the secret immediately or wait until the next scheduled rotation window. The rotation schedule is defined in `RotationRules` .\n\nIf you don't immediately rotate the secret, Secrets Manager tests the rotation configuration by running the [`testSecret` step](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotate-secrets_how.html) of the Lambda rotation function. The test creates an `AWSPENDING` version of the secret and then removes it.\n\nIf you don't specify this value, then by default, Secrets Manager rotates the secret immediately.", + "RotationLambdaARN": "The ARN of an existing Lambda rotation function. To specify a rotation function that is also defined in this template, use the [Ref](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) function.\n\nTo create a new rotation function based on one of the [Secrets Manager rotation function templates](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html) , specify `HostedRotationLambda` instead.", "RotationRules": "A structure that defines the rotation configuration for this secret.", "SecretId": "The ARN or name of the secret to rotate.\n\nTo reference a secret also created in this template, use the [Ref](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) function with the secret's logical ID." } }, "AWS::SecretsManager::RotationSchedule.HostedRotationLambda": { "attributes": {}, - "description": "Specifies that you want to create a hosted Lambda rotation function.\n\nTo use these values, you must specify `Transform: AWS::SecretsManager-2020-07-23` at the beginning of the CloudFormation template.", + "description": "Creates a new Lambda rotation function based on one of the [Secrets Manager rotation function templates](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html) .\n\nYou must specify `Transform: AWS::SecretsManager-2020-07-23` at the beginning of the CloudFormation template.", "properties": { "KmsKeyArn": "The ARN of the KMS key that Secrets Manager uses to encrypt the secret. If you don't specify this value, then Secrets Manager uses the key `aws/secretsmanager` . If `aws/secretsmanager` doesn't yet exist, then Secrets Manager creates it for you automatically the first time it encrypts the secret value.", - "MasterSecretArn": "The ARN of the secret that contains elevated credentials. The Lambda rotation function uses this secret for the [Alternating users rotation strategy](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets_strategies.html#rotating-secrets-two-users) .", + "MasterSecretArn": "The ARN of the secret that contains elevated credentials. You must create the elevated secret before you can set this property. The Lambda rotation function uses this secret for the [Alternating users rotation strategy](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets_strategies.html#rotating-secrets-two-users) .", "MasterSecretKmsKeyArn": "The ARN of the KMS key that Secrets Manager uses to encrypt the elevated secret if you use the [alternating users strategy](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets_strategies.html#rotating-secrets-two-users) . If you don't specify this value and you use the alternating users strategy, then Secrets Manager uses the key `aws/secretsmanager` . If `aws/secretsmanager` doesn't yet exist, then Secrets Manager creates it for you automatically the first time it encrypts the secret value.", "RotationLambdaName": "The name of the Lambda rotation function.", - "RotationType": "The type of rotation template to use. For more information, see [Secrets Manager rotation function templates](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html) .\n\nYou can specify one of the following `RotationTypes` :\n\n- MySQLSingleUser\n- MySQLMultiUser\n- PostgreSQLSingleUser\n- PostgreSQLMultiUser\n- OracleSingleUser\n- OracleMultiUser\n- MariaDBSingleUser\n- MariaDBMultiUser\n- SQLServerSingleUser\n- SQLServerMultiUser\n- RedshiftSingleUser\n- RedshiftMultiUser\n- MongoDBSingleUser\n- MongoDBMultiUser", - "SuperuserSecretArn": "The ARN of the secret that contains elevated credentials. The Lambda rotation function uses this secret for the [Alternating users rotation strategy](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets_strategies.html#rotating-secrets-two-users) .", + "RotationType": "The rotation template to base the rotation function on, one of the following:\n\n- `MySQLSingleUser` to use the template [SecretsManagerRDSMySQLRotationSingleUser](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html#sar-template-mysql-singleuser) .\n- `MySQLMultiUser` to use the template [SecretsManagerRDSMySQLRotationMultiUser](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html#sar-template-mysql-multiuser) .\n- `PostgreSQLSingleUser` to use the template [SecretsManagerRDSPostgreSQLRotationSingleUser](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html#sar-template-postgre-singleuser)\n- `PostgreSQLMultiUser` to use the template [SecretsManagerRDSPostgreSQLRotationMultiUser](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html#sar-template-postgre-multiuser) .\n- `OracleSingleUser` to use the template [SecretsManagerRDSOracleRotationSingleUser](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html#sar-template-oracle-singleuser) .\n- `OracleMultiUser` to use the template [SecretsManagerRDSOracleRotationMultiUser](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html#sar-template-oracle-multiuser) .\n- `MariaDBSingleUser` to use the template [SecretsManagerRDSMariaDBRotationSingleUser](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html#sar-template-mariadb-singleuser) .\n- `MariaDBMultiUser` to use the template [SecretsManagerRDSMariaDBRotationMultiUser](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html#sar-template-mariadb-multiuser) .\n- `SQLServerSingleUser` to use the template [SecretsManagerRDSSQLServerRotationSingleUser](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html#sar-template-sqlserver-singleuser) .\n- `SQLServerMultiUser` to use the template [SecretsManagerRDSSQLServerRotationMultiUser](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html#sar-template-sqlserver-multiuser) .\n- `RedshiftSingleUser` to use the template [SecretsManagerRedshiftRotationSingleUsr](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html#sar-template-redshift-singleuser) .\n- `RedshiftMultiUser` to use the template [SecretsManagerRedshiftRotationMultiUser](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html#sar-template-redshift-multiuser) .\n- `MongoDBSingleUser` to use the template [SecretsManagerMongoDBRotationSingleUser](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html#sar-template-mongodb-singleuser) .\n- `MongoDBMultiUser` to use the template [SecretsManagerMongoDBRotationMultiUser](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html#sar-template-mongodb-multiuser) .", + "SuperuserSecretArn": "The ARN of the secret that contains elevated credentials. You must create the superuser secret before you can set this property. The Lambda rotation function uses this secret for the [Alternating users rotation strategy](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets_strategies.html#rotating-secrets-two-users) .", "SuperuserSecretKmsKeyArn": "The ARN of the KMS key that Secrets Manager uses to encrypt the elevated secret if you use the [alternating users strategy](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets_strategies.html#rotating-secrets-two-users) . If you don't specify this value and you use the alternating users strategy, then Secrets Manager uses the key `aws/secretsmanager` . If `aws/secretsmanager` doesn't yet exist, then Secrets Manager creates it for you automatically the first time it encrypts the secret value.", "VpcSecurityGroupIds": "A comma-separated list of security group IDs applied to the target database.\n\nThe templates applies the same security groups as on the Lambda rotation function that is created as part of this stack.", "VpcSubnetIds": "A comma separated list of VPC subnet IDs of the target database network. The Lambda rotation function is in the same subnet group." @@ -37132,18 +38039,18 @@ }, "AWS::SecretsManager::RotationSchedule.RotationRules": { "attributes": {}, - "description": "A structure that defines the rotation configuration for the secret.", + "description": "The rotation schedule and window. We recommend you use `ScheduleExpression` to set a cron or rate expression for the schedule and `Duration` to set the length of the rotation window.", "properties": { "AutomaticallyAfterDays": "The number of days between automatic scheduled rotations of the secret. You can use this value to check that your secret meets your compliance guidelines for how often secrets must be rotated.\n\nIn `DescribeSecret` and `ListSecrets` , this value is calculated from the rotation schedule after every successful rotation. In `RotateSecret` , you can set the rotation schedule in `RotationRules` with `AutomaticallyAfterDays` or `ScheduleExpression` , but not both.", - "Duration": "", - "ScheduleExpression": "" + "Duration": "The length of the rotation window in hours, for example `3h` for a three hour window. Secrets Manager rotates your secret at any time during this window. The window must not go into the next UTC day. If you don't specify this value, the window automatically ends at the end of the UTC day. The window begins according to the `ScheduleExpression` . For more information, including examples, see [Schedule expressions in Secrets Manager rotation](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotate-secrets_schedule.html) .", + "ScheduleExpression": "A `cron()` or `rate()` expression that defines the schedule for rotating your secret. Secrets Manager rotation schedules use UTC time zone.\n\nSecrets Manager `rate()` expressions represent the interval in days that you want to rotate your secret, for example `rate(10 days)` . If you use a `rate()` expression, the rotation window opens at midnight, and Secrets Manager rotates your secret any time that day after midnight. You can set a `Duration` to shorten the rotation window.\n\nYou can use a `cron()` expression to create rotation schedules that are more detailed than a rotation interval. For more information, including examples, see [Schedule expressions in Secrets Manager rotation](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotate-secrets_schedule.html) . If you use a `cron()` expression, Secrets Manager rotates your secret any time during that day after the window opens. For example, `cron(0 8 1 * ? *)` represents a rotation window that occurs on the first day of every month beginning at 8:00 AM UTC. Secrets Manager rotates the secret any time that day after 8:00 AM. You can set a `Duration` to shorten the rotation window." } }, "AWS::SecretsManager::Secret": { "attributes": { "Ref": "When you pass the logical ID of an `AWS::SecretsManager::Secret` resource to the intrinsic `Ref` function, the function returns the ARN of the secret configured such as:\n\n`arn:aws:secretsmanager:us-west-2:123456789012:secret:my-path/my-secret-name-1a2b3c`\n\nIf you know the ARN of a secret, you can reference a secret you created in one part of the stack template from within the definition of another resource in the same template. You typically use the `Ref` function with the [AWS::SecretsManager::SecretTargetAttachment](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-secretsmanager-secrettargetattachment.html) resource type to get references to both the secret and its associated database.\n\nFor more information about using the `Ref` function, see [Ref](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) ." }, - "description": "Creates a new secret. A *secret* is a set of credentials, such as a user name and password, that you store in an encrypted form in Secrets Manager. The secret also includes the connection information to access a database or other service, which Secrets Manager doesn't encrypt. A secret in Secrets Manager consists of both the protected secret data and the important information needed to manage the secret.\n\nFor information about creating a secret in the console, see [Create a secret](https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_create-basic-secret.html) .\n\nFor information about creating a secret using the CLI or SDK, see [CreateSecret](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_CreateSecret.html) .\n\nTo specify the encrypted value for the secret, you must include either the `GenerateSecretString` or the `SecretString` property, but not both. We recommend that you use the `GenerateSecretString` property to generate a random password as shown in the examples. You can't generate a secret with a `SecretBinary` secret value using AWS CloudFormation .\n\n> Do not create a dynamic reference using a backslash `(\\)` as the final value. AWS CloudFormation cannot resolve those references, which causes a resource failure.", + "description": "Creates a new secret. A *secret* can be a password, a set of credentials such as a user name and password, an OAuth token, or other secet information that you store in an encrypted form in Secrets Manager.\n\nTo retrieve a secret in a CloudFormation template, use a *dynamic reference* . For more information, see [Retrieve a secret in an AWS CloudFormation resource](https://docs.aws.amazon.com/secretsmanager/latest/userguide/cfn-example_reference-secret.html) .\n\nA common scenario is to first create a secret with `GenerateSecretString` , which generates a password, and then use a dynamic reference to retrieve the username and password from the secret to use as credentials for a new database. Follow these steps, as shown in the examples below:\n\n- Define the secret without referencing the service or database. You can't reference the service or database because it doesn't exist yet. The secret must contain a username and password.\n- Next, define the service or database. Include the reference to the secret to use stored credentials to define the database admin user and password.\n- Finally, define a `SecretTargetAttachment` resource type to finish configuring the secret with the required database engine type and the connection details of the service or database. The rotation function requires the details, if you attach one later by defining a [AWS::SecretsManager::RotationSchedule](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-secretsmanager-rotationschedule.html) resource type.\n\nFor information about creating a secret in the console, see [Create a secret](https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_create-basic-secret.html) . For information about creating a secret using the CLI or SDK, see [CreateSecret](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_CreateSecret.html) .\n\nFor information about retrieving a secret in code, see [Retrieve secrets from Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/retrieving-secrets.html) .\n\n> Do not create a dynamic reference using a backslash `(\\)` as the final value. AWS CloudFormation cannot resolve those references, which causes a resource failure.", "properties": { "Description": "The description of the secret.", "GenerateSecretString": "A structure that specifies how to generate a password to encrypt and store in the secret.\n\nEither `GenerateSecretString` or `SecretString` must have a value, but not both. They cannot both be empty.\n\nWe recommend that you specify the maximum length and include every character type that the system you are generating a password for can support.", @@ -37172,17 +38079,17 @@ }, "AWS::SecretsManager::Secret.ReplicaRegion": { "attributes": {}, - "description": "A custom type that specifies a `Region` and the `KmsKeyId` for a replica secret.", + "description": "Specifies a `Region` and the `KmsKeyId` for a replica secret.", "properties": { "KmsKeyId": "The ARN, key ID, or alias of the KMS key to encrypt the secret. If you don't include this field, Secrets Manager uses `aws/secretsmanager` .", - "Region": "" + "Region": "(Optional) A string that represents a `Region` , for example \"us-east-1\"." } }, "AWS::SecretsManager::SecretTargetAttachment": { "attributes": { "Ref": "When you pass the logical ID of an `AWS::SecretsManager::SecretTargetAttachment` resource to the intrinsic `Ref` function, the function returns the ARN of the secret, such as:\n\n`arn:aws:secretsmanager:us-west-2:123456789012:secret:my-path/my-secret-name-1a2b3c`\n\nYou can use the ARN to reference a secret you created in one part of the stack template from within the definition of another resource from a different part of the same template.\n\nFor more information about using the `Ref` function, see [Ref](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) ." }, - "description": "The `AWS::SecretsManager::SecretTargetAttachment` resource completes the final link between a Secrets Manager secret and the associated database. This is required because each has a dependency on the other. No matter which one you create first, the other doesn't exist yet. To resolve this, you must create the resources in the following order:\n\n- Define the secret without referencing the service or database. You can't reference the service or database because it doesn't exist yet. The secret must contain a user name and password.\n- Next, define the service or database. Include the reference to the secret to use stored credentials to define the database admin user and password.\n- Finally, define a `SecretTargetAttachment` resource type to finish configuring the secret with the required database engine type and the connection details of the service or database. The rotation function requires the details, if you attach one later by defining a [AWS::SecretsManager::RotationSchedule](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-secretsmanager-rotationschedule.html) resource type.", + "description": "The `AWS::SecretsManager::SecretTargetAttachment` resource completes the final link between a Secrets Manager secret and the associated database. This is required because each has a dependency on the other.", "properties": { "SecretId": "The ARN or name of the secret. To reference a secret also created in this template, use the see [Ref](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) function with the secret's logical ID.", "TargetId": "The ID of the database or cluster.", @@ -37539,7 +38446,7 @@ "AWS::ServiceDiscovery::PrivateDnsNamespace": { "attributes": { "Arn": "The Amazon Resource Name (ARN) of the private namespace.", - "HostedZoneId": "", + "HostedZoneId": "The ID for the Route 53 hosted zone that AWS Cloud Map creates when you create a namespace.", "Id": "The ID of the private namespace.", "Ref": "`Ref` returns the value of `Id` for the namespace, such as `ns-e4anhexample0004` ." }, @@ -37576,7 +38483,7 @@ "AWS::ServiceDiscovery::PublicDnsNamespace": { "attributes": { "Arn": "The Amazon Resource Name (ARN) of the public namespace.", - "HostedZoneId": "", + "HostedZoneId": "The ID for the Route 53 hosted zone that AWS Cloud Map creates when you create a namespace.", "Id": "The ID of the public namespace.", "Ref": "`Ref` returns the value of `Id` for the namespace, such as `ns-e4anhexample0004` ." }, @@ -37824,7 +38731,7 @@ "attributes": {}, "description": "Use this structure to input your script code for the canary. This structure contains the Lambda handler with the location where the canary should start running the script. If the script is stored in an S3 bucket, the bucket name, key, and version are also included. If the script is passed into the canary directly, the script code is contained in the value of `Script` .", "properties": { - "Handler": "The entry point to use for the source code when running the canary. This value must end with the string `.handler` . The string is limited to 29 characters or fewer.", + "Handler": "The entry point to use for the source code when running the canary. For canaries that use the `syn-python-selenium-1.0` runtime or a `syn-nodejs.puppeteer` runtime earlier than `syn-nodejs.puppeteer-3.4` , the handler must be specified as `*fileName* .handler` . For `syn-python-selenium-1.1` , `syn-nodejs.puppeteer-3.4` , and later runtimes, the handler can be specified as `*fileName* . *functionName*` , or you can specify a folder where canary scripts reside as `*folder* / *fileName* . *functionName*` .", "S3Bucket": "If your canary script is located in S3, specify the bucket name here. The bucket must already exist.", "S3Key": "The S3 key of your script. For more information, see [Working with Amazon S3 Objects](https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html) .", "S3ObjectVersion": "The S3 version ID of your script.", @@ -38015,7 +38922,7 @@ "description": "The CreateTable operation adds a new table to an existing database in your account. In an AWS account, table names must be at least unique within each Region if they are in the same database. You may have identical table names in the same Region if the tables are in separate databases. While creating the table, you must specify the table name, database name, and the retention properties. [Service quotas apply](https://docs.aws.amazon.com/timestream/latest/developerguide/ts-limits.html) . See [code sample](https://docs.aws.amazon.com/timestream/latest/developerguide/code-samples.create-table.html) for details.", "properties": { "DatabaseName": "The name of the Timestream database that contains this table.\n\n*Length Constraints* : Minimum length of 3 bytes. Maximum length of 256 bytes.", - "MagneticStoreWriteProperties": "Contains properties to set on the table when enabling magnetic store writes.\n\nThis object has the following attributes:\n\n- *EnableMagneticStoreWrites* : A `boolean` flag to enable magnetic store writes.\n- *MagneticStoreRejectedDataLocation* : The location to write error reports for records rejected, asynchronously, during magnetic store writes. Only `S3Configuration` objects are allowed. The `S3Configuration` object has the following attributes:\n\n- *BucketName* : The bucket name of the S3 bucket.\n- *EncryptionOption* : The encryption option for the S3 location. Valid values are S3 server-side encryption with an S3 managed key ( `SSE_S3` ) or AWS managed key ( `SSE_KMS` ).\n- *KmsKeyId* : The AWS KMS key ID to use when encrypting with an AWS managed key.\n- *ObjectKeyPrefix* :The prefix to use option for the objects stored in S3.\n\nBoth `BucketName` and `EncryptionOption` are *required* when `S3Configuration` is specified. If you specify `SSE_KMS` as your `EncryptionOption` then `KmsKeyId` is *required* .\n\n`EnableMagneticStoreWrites` attribute is *required* when `MagneticStoreWriteProperties` is specified. `MagneticStoreRejectedDataLocation` attribute is *required* when `EnableMagneticStoreWrites` is set to `true` .\n\nSee the following examples:\n\n*JSON*\n\n```json\n{ \"Type\" : AWS::Timestream::Table\", \"Properties\":{ \"DatabaseName\":\"TestDatabase\", \"TableName\":\"TestTable\", \"MagneticStoreWriteProperties\":{ \"EnableMagneticStoreWrites\":true, \"MagneticStoreRejectedDataLocation\":{ \"S3Configuration\":{ \"BucketName\":\"testbucket\", \"EncryptionOption\":\"SSE_KMS\", \"KmsKeyId\":\"1234abcd-12ab-34cd-56ef-1234567890ab\", \"ObjectKeyPrefix\":\"prefix\" } } } }\n}\n```\n\n*YAML*\n\n```\nType: AWS::Timestream::Table\nDependsOn: TestDatabase\nProperties: TableName: \"TestTable\" DatabaseName: \"TestDatabase\" MagneticStoreWriteProperties: EnableMagneticStoreWrites: true MagneticStoreRejectedDataLocation: S3Configuration: BucketName: \"testbucket\" EncryptionOption: \"SSE_KMS\" BucketName: \"1234abcd-12ab-34cd-56ef-1234567890ab\" EncryptionOption: \"prefix\"\n```", + "MagneticStoreWriteProperties": "Contains properties to set on the table when enabling magnetic store writes.\n\nThis object has the following attributes:\n\n- *EnableMagneticStoreWrites* : A `boolean` flag to enable magnetic store writes.\n- *MagneticStoreRejectedDataLocation* : The location to write error reports for records rejected, asynchronously, during magnetic store writes. Only `S3Configuration` objects are allowed. The `S3Configuration` object has the following attributes:\n\n- *BucketName* : The name of the S3 bucket.\n- *EncryptionOption* : The encryption option for the S3 location. Valid values are S3 server-side encryption with an S3 managed key ( `SSE_S3` ) or AWS managed key ( `SSE_KMS` ).\n- *KmsKeyId* : The AWS KMS key ID to use when encrypting with an AWS managed key.\n- *ObjectKeyPrefix* : The prefix to use option for the objects stored in S3.\n\nBoth `BucketName` and `EncryptionOption` are *required* when `S3Configuration` is specified. If you specify `SSE_KMS` as your `EncryptionOption` then `KmsKeyId` is *required* .\n\n`EnableMagneticStoreWrites` attribute is *required* when `MagneticStoreWriteProperties` is specified. `MagneticStoreRejectedDataLocation` attribute is *required* when `EnableMagneticStoreWrites` is set to `true` .\n\nSee the following examples:\n\n*JSON*\n\n```json\n{ \"Type\" : AWS::Timestream::Table\", \"Properties\":{ \"DatabaseName\":\"TestDatabase\", \"TableName\":\"TestTable\", \"MagneticStoreWriteProperties\":{ \"EnableMagneticStoreWrites\":true, \"MagneticStoreRejectedDataLocation\":{ \"S3Configuration\":{ \"BucketName\":\"testbucket\", \"EncryptionOption\":\"SSE_KMS\", \"KmsKeyId\":\"1234abcd-12ab-34cd-56ef-1234567890ab\", \"ObjectKeyPrefix\":\"prefix\" } } } }\n}\n```\n\n*YAML*\n\n```\nType: AWS::Timestream::Table\nDependsOn: TestDatabase\nProperties: TableName: \"TestTable\" DatabaseName: \"TestDatabase\" MagneticStoreWriteProperties: EnableMagneticStoreWrites: true MagneticStoreRejectedDataLocation: S3Configuration: BucketName: \"testbucket\" EncryptionOption: \"SSE_KMS\" BucketName: \"1234abcd-12ab-34cd-56ef-1234567890ab\" EncryptionOption: \"prefix\"\n```", "RetentionProperties": "The retention duration for the memory store and magnetic store. This object has the following attributes:\n\n- *MemoryStoreRetentionPeriodInHours* : Retention duration for memory store, in hours.\n- *MagneticStoreRetentionPeriodInDays* : Retention duration for magnetic store, in days.\n\nBoth attributes are of type `string` . Both attributes are *required* when `RetentionProperties` is specified.\n\nSee the following examples:\n\n*JSON*\n\n`{ \"Type\" : AWS::Timestream::Table\", \"Properties\" : { \"DatabaseName\" : \"TestDatabase\", \"TableName\" : \"TestTable\", \"RetentionProperties\" : { \"MemoryStoreRetentionPeriodInHours\": \"24\", \"MagneticStoreRetentionPeriodInDays\": \"7\" } } }` \n\n*YAML*\n\n```\nType: AWS::Timestream::Table\nDependsOn: TestDatabase\nProperties: TableName: \"TestTable\" DatabaseName: \"TestDatabase\" RetentionProperties: MemoryStoreRetentionPeriodInHours: \"24\" MagneticStoreRetentionPeriodInDays: \"7\"\n```", "TableName": "The name of the Timestream table.\n\n*Length Constraints* : Minimum length of 3 bytes. Maximum length of 256 bytes.", "Tags": "The tags to add to the table" @@ -38031,13 +38938,15 @@ "properties": { "Certificate": "The Amazon Resource Name (ARN) of the AWS Certificate Manager (ACM) certificate. Required when `Protocols` is set to `FTPS` .\n\nTo request a new public certificate, see [Request a public certificate](https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-request-public.html) in the *AWS Certificate Manager User Guide* .\n\nTo import an existing certificate into ACM, see [Importing certificates into ACM](https://docs.aws.amazon.com/acm/latest/userguide/import-certificate.html) in the *AWS Certificate Manager User Guide* .\n\nTo request a private certificate to use FTPS through private IP addresses, see [Request a private certificate](https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-request-private.html) in the *AWS Certificate Manager User Guide* .\n\nCertificates with the following cryptographic algorithms and key sizes are supported:\n\n- 2048-bit RSA (RSA_2048)\n- 4096-bit RSA (RSA_4096)\n- Elliptic Prime Curve 256 bit (EC_prime256v1)\n- Elliptic Prime Curve 384 bit (EC_secp384r1)\n- Elliptic Prime Curve 521 bit (EC_secp521r1)\n\n> The certificate must be a valid SSL/TLS X.509 version 3 certificate with FQDN or IP address specified and information about the issuer.", "Domain": "Specifies the domain of the storage system that is used for file transfers.", - "EndpointDetails": "The virtual private cloud (VPC) endpoint settings that are configured for your server. When you host your endpoint within your VPC, you can make it accessible only to resources within your VPC, or you can attach Elastic IPs and make it accessible to clients over the internet. You VPC's default security groups are automatically assigned to your endpoint.", - "EndpointType": "The type of VPC endpoint that you want your server to connect to. You can choose to connect to the public internet or a virtual private cloud (VPC) endpoint. With a VPC endpoint, you can restrict access to your server and resources only within your VPC.\n\n> It is recommended that you use `VPC` as the `EndpointType` . With this endpoint type, you have the option to directly associate up to three Elastic IPv4 addresses (BYO IP included) with your server's endpoint and use VPC security groups to restrict traffic by the client's public IP address. This is not possible with `EndpointType` set to `VPC_ENDPOINT` .", + "EndpointDetails": "The virtual private cloud (VPC) endpoint settings that are configured for your server. When you host your endpoint within your VPC, you can make it accessible only to resources within your VPC, or you can attach Elastic IP addresses and make it accessible to clients over the internet. Your VPC's default security groups are automatically assigned to your endpoint.", + "EndpointType": "The type of endpoint that you want your server to use. You can choose to make your server's endpoint publicly accessible (PUBLIC) or host it inside your VPC. With an endpoint that is hosted in a VPC, you can restrict access to your server and resources only within your VPC or choose to make it internet facing by attaching Elastic IP addresses directly to it.", "IdentityProviderDetails": "Required when `IdentityProviderType` is set to `AWS_DIRECTORY_SERVICE` or `API_GATEWAY` . Accepts an array containing all of the information required to use a directory in `AWS_DIRECTORY_SERVICE` or invoke a customer-supplied authentication API, including the API Gateway URL. Not required when `IdentityProviderType` is set to `SERVICE_MANAGED` .", "IdentityProviderType": "Specifies the mode of authentication for a server. The default value is `SERVICE_MANAGED` , which allows you to store and access user credentials within the AWS Transfer Family service.\n\nUse `AWS_DIRECTORY_SERVICE` to provide access to Active Directory groups in AWS Managed Active Directory or Microsoft Active Directory in your on-premises environment or in AWS using AD Connectors. This option also requires you to provide a Directory ID using the `IdentityProviderDetails` parameter.\n\nUse the `API_GATEWAY` value to integrate with an identity provider of your choosing. The `API_GATEWAY` setting requires you to provide an API Gateway endpoint URL to call for authentication using the `IdentityProviderDetails` parameter.\n\nUse the `AWS_LAMBDA` value to directly use a Lambda function as your identity provider. If you choose this value, you must specify the ARN for the lambda function in the `Function` parameter for the `IdentityProviderDetails` data type.", "LoggingRole": "Specifies the Amazon Resource Name (ARN) of the AWS Identity and Access Management (IAM) role that allows a server to turn on Amazon CloudWatch logging for Amazon S3 or Amazon EFS events. When set, user activity can be viewed in your CloudWatch logs.", - "ProtocolDetails": "Protocol settings that are configured for your server.\n\n> Only valid in the `UpdateServer` API.", - "Protocols": "Specifies the file transfer protocol or protocols over which your file transfer protocol client can connect to your server's endpoint.", + "PostAuthenticationLoginBanner": "Specify a string to display when users connect to a server. This string is displayed after the user authenticates.\n\n> The SFTP protocol does not support post-authentication display banners.", + "PreAuthenticationLoginBanner": "Specify a string to display when users connect to a server. This string is displayed before the user authenticates. For example, the following banner displays details about using the system.\n\n`This system is for the use of authorized users only. Individuals using this computer system without authority, or in excess of their authority, are subject to having all of their activities on this system monitored and recorded by system personnel.`", + "ProtocolDetails": "The protocol settings that are configured for your server.\n\nUse the `PassiveIp` parameter to indicate passive mode (for FTP and FTPS protocols). Enter a single dotted-quad IPv4 address, such as the external IP address of a firewall, router, or load balancer.\n\nUse the `TlsSessionResumptionMode` parameter to determine whether or not your Transfer server resumes recent, negotiated sessions through a unique session ID.", + "Protocols": "Specifies the file transfer protocol or protocols over which your file transfer protocol client can connect to your server's endpoint. The available protocols are:\n\n- `SFTP` (Secure Shell (SSH) File Transfer Protocol): File transfer over SSH\n- `FTPS` (File Transfer Protocol Secure): File transfer with TLS encryption\n- `FTP` (File Transfer Protocol): Unencrypted file transfer\n\n> If you select `FTPS` , you must choose a certificate stored in AWS Certificate Manager (ACM) which is used to identify your server when clients connect to it over FTPS.\n> \n> If `Protocol` includes either `FTP` or `FTPS` , then the `EndpointType` must be `VPC` and the `IdentityProviderType` must be `AWS_DIRECTORY_SERVICE` or `API_GATEWAY` .\n> \n> If `Protocol` includes `FTP` , then `AddressAllocationIds` cannot be associated.\n> \n> If `Protocol` is set only to `SFTP` , the `EndpointType` can be set to `PUBLIC` and the `IdentityProviderType` can be set to `SERVICE_MANAGED` .", "SecurityPolicyName": "Specifies the name of the security policy that is attached to the server.", "Tags": "Key-value pairs that can be used to group and search for servers.", "WorkflowDetails": "Specifies the workflow ID for the workflow to assign and the execution role used for executing the workflow." @@ -38045,10 +38954,10 @@ }, "AWS::Transfer::Server.EndpointDetails": { "attributes": {}, - "description": "The virtual private cloud (VPC) endpoint settings that are configured for your server. When you host your endpoint within your VPC, you can make it accessible only to resources within your VPC, or you can attach Elastic IPs and make it accessible to clients over the internet. You VPC's default security groups are automatically assigned to your endpoint.\n\n> It is recommended that you use `VPC` as the `EndpointType` . With this endpoint type, you have the option to directly associate up to three Elastic IPv4 addresses (BYO IP included) with your server's endpoint and use VPC security groups to restrict traffic by the client's public IP address. This is not possible with `EndpointType` set to `VPC_ENDPOINT` .", + "description": "The virtual private cloud (VPC) endpoint settings that are configured for your server. When you host your endpoint within your VPC, you can make it accessible only to resources within your VPC, or you can attach Elastic IP addresses and make it accessible to clients over the internet. Your VPC's default security groups are automatically assigned to your endpoint.", "properties": { - "AddressAllocationIds": "A list of address allocation IDs that are required to attach an Elastic IP address to your server's endpoint. This is only valid in the `UpdateServer` API.\n\n> This property can only be set when `EndpointType` is set to `VPC` .", - "SecurityGroupIds": "A list of security groups IDs that are available to attach to your server's endpoint.\n\n> This property can only be set when `EndpointType` is set to `VPC` . \n\n*Maximum number of security groups* : 5", + "AddressAllocationIds": "A list of address allocation IDs that are required to attach an Elastic IP address to your server's endpoint.\n\n> This property can only be set when `EndpointType` is set to `VPC` and it is only valid in the `UpdateServer` API.", + "SecurityGroupIds": "A list of security groups IDs that are available to attach to your server's endpoint.\n\n> This property can only be set when `EndpointType` is set to `VPC` .\n> \n> You can edit the `SecurityGroupIds` property in the [UpdateServer](https://docs.aws.amazon.com/transfer/latest/userguide/API_UpdateServer.html) API only if you are changing the `EndpointType` from `PUBLIC` or `VPC_ENDPOINT` to `VPC` . To change security groups associated with your server's VPC endpoint after creation, use the Amazon EC2 [ModifyVpcEndpoint](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifyVpcEndpoint.html) API.", "SubnetIds": "A list of subnet IDs that are required to host your server endpoint in your VPC.\n\n> This property can only be set when `EndpointType` is set to `VPC` .", "VpcEndpointId": "The ID of the VPC endpoint.\n\n> This property can only be set when `EndpointType` is set to `VPC_ENDPOINT` .", "VpcId": "The VPC ID of the virtual private cloud in which the server's endpoint will be hosted.\n\n> This property can only be set when `EndpointType` is set to `VPC` ." @@ -38066,7 +38975,7 @@ }, "AWS::Transfer::Server.Protocol": { "attributes": {}, - "description": "Specifies the file transfer protocol or protocols over which your file transfer protocol client can connect to your server's endpoint. The available protocols are:\n\n- `SFTP` (Secure Shell (SSH) File Transfer Protocol): File transfer over SSH\n- `FTPS` (File Transfer Protocol Secure): File transfer with TLS encryption\n- `FTP` (File Transfer Protocol): Unencrypted file transfer\n\n> If you select `FTPS` , you must choose a certificate stored in AWS Certificate Manager (ACM) which will be used to identify your server when clients connect to it over FTPS.\n> \n> If `Protocol` includes either `FTP` or `FTPS` , then the `EndpointType` must be `VPC` and the `IdentityProviderType` must be `API_GATEWAY` .\n> \n> If `Protocol` includes `FTP` , then `AddressAllocationIds` cannot be associated.\n> \n> If `Protocol` is set only to `SFTP` , the `EndpointType` can be set to `PUBLIC` and the `IdentityProviderType` can be set to `SERVICE_MANAGED` .", + "description": "Specifies the file transfer protocol or protocols over which your file transfer protocol client can connect to your server's endpoint. The available protocols are:\n\n- `SFTP` (Secure Shell (SSH) File Transfer Protocol): File transfer over SSH\n- `FTPS` (File Transfer Protocol Secure): File transfer with TLS encryption\n- `FTP` (File Transfer Protocol): Unencrypted file transfer\n\n> If you select `FTPS` , you must choose a certificate stored in AWS Certificate Manager (ACM) which is used to identify your server when clients connect to it over FTPS.\n> \n> If `Protocol` includes either `FTP` or `FTPS` , then the `EndpointType` must be `VPC` and the `IdentityProviderType` must be `AWS_DIRECTORY_SERVICE` or `API_GATEWAY` .\n> \n> If `Protocol` includes `FTP` , then `AddressAllocationIds` cannot be associated.\n> \n> If `Protocol` is set only to `SFTP` , the `EndpointType` can be set to `PUBLIC` and the `IdentityProviderType` can be set to `SERVICE_MANAGED` .", "properties": {} }, "AWS::Transfer::Server.ProtocolDetails": { @@ -38089,7 +38998,7 @@ "attributes": {}, "description": "Container for the `WorkflowDetail` data type. It is used by actions that trigger a workflow to begin execution.", "properties": { - "OnUpload": "A trigger that starts a workflow: the workflow begins to execute after a file is uploaded." + "OnUpload": "A trigger that starts a workflow: the workflow begins to execute after a file is uploaded.\n\nTo remove an associated workflow from a server, you can provide an empty `OnUpload` object, as in the following example.\n\n`aws transfer update-server --server-id s-01234567890abcdef --workflow-details '{\"OnUpload\":[]}'`" } }, "AWS::Transfer::User": { @@ -38152,10 +39061,10 @@ "attributes": {}, "description": "The basic building block of a workflow.", "properties": { - "CopyStepDetails": "Details for a step that performs a file copy. Consists of the following values:\n\n- A description\n- An S3 location for the destination of the file copy\n- A flag that indicates whether or not to overwrite an existing file of the same name. The default is `FALSE` .", - "CustomStepDetails": "Details for a step that invokes a lambda function. Consists of the lambda function name, target, and timeout (in seconds).", + "CopyStepDetails": "Details for a step that performs a file copy.\n\nConsists of the following values:\n\n- A description\n- An S3 location for the destination of the file copy.\n- A flag that indicates whether or not to overwrite an existing file of the same name. The default is `FALSE` .", + "CustomStepDetails": "Details for a step that invokes a lambda function.\n\nConsists of the lambda function name, target, and timeout (in seconds).", "DeleteStepDetails": "Details for a step that deletes the file.", - "TagStepDetails": "Details for a step that creates one or more tags. You specify one or more tags: each tag contains a key/value pair.", + "TagStepDetails": "Details for a step that creates one or more tags.\n\nYou specify one or more tags: each tag contains a key/value pair.", "Type": "Currently, the following step types are supported.\n\n- *Copy* : copy the file to another location\n- *Custom* : custom step with a lambda target\n- *Delete* : delete the file\n- *Tag* : add a tag to the file" } }, @@ -38588,23 +39497,23 @@ "ManagedByFirewallManager": "Indicates whether the logging configuration was created by AWS Firewall Manager , as part of an AWS WAF policy configuration. If true, only Firewall Manager can modify or delete the configuration.", "Ref": "`Ref` returns the Amazon Resource Name (ARN) of the web ACL." }, - "description": "Defines an association between logging destinations and a web ACL resource, for logging from AWS WAF . As part of the association, you can specify parts of the standard logging fields to keep out of the logs and you can specify filters so that you log only a subset of the logging records.\n\nFor information about configuring web ACL logging destinations, see [Logging web ACL traffic information](https://docs.aws.amazon.com/waf/latest/developerguide/logging.html) in the *AWS WAF Developer Guide* .", + "description": "Defines an association between logging destinations and a web ACL resource, for logging from AWS WAF . As part of the association, you can specify parts of the standard logging fields to keep out of the logs and you can specify filters so that you log only a subset of the logging records.\n\n> You can define one logging destination per web ACL. \n\nYou can access information about the traffic that AWS WAF inspects using the following steps:\n\n- Create your logging destination. You can use an Amazon CloudWatch Logs log group, an Amazon Simple Storage Service (Amazon S3) bucket, or an Amazon Kinesis Data Firehose. For information about configuring logging destinations and the permissions that are required for each, see [Logging web ACL traffic information](https://docs.aws.amazon.com/waf/latest/developerguide/logging.html) in the *AWS WAF Developer Guide* .\n- Associate your logging destination to your web ACL using a `PutLoggingConfiguration` request.\n\nWhen you successfully enable logging using a `PutLoggingConfiguration` request, AWS WAF creates an additional role or policy that is required to write logs to the logging destination. For an Amazon CloudWatch Logs log group, AWS WAF creates a resource policy on the log group. For an Amazon S3 bucket, AWS WAF creates a bucket policy. For an Amazon Kinesis Data Firehose, AWS WAF creates a service-linked role.\n\nFor additional information about web ACL logging, see [Logging web ACL traffic information](https://docs.aws.amazon.com/waf/latest/developerguide/logging.html) in the *AWS WAF Developer Guide* .", "properties": { - "LogDestinationConfigs": "The Amazon Resource Names (ARNs) of the logging destinations that you want to associate with the web ACL.", + "LogDestinationConfigs": "The logging destination configuration that you want to associate with the web ACL.\n\n> You can associate one logging destination to a web ACL.", "LoggingFilter": "Filtering that specifies which web requests are kept in the logs and which are dropped. You can filter on the rule action and on the web request labels that were applied by matching rules during web ACL evaluation.", - "RedactedFields": "The parts of the request that you want to keep out of the logs. For example, if you redact the `SingleHeader` field, the `HEADER` field in the firehose will be `xxx` .\n\n> You can specify only the following fields for redaction: `UriPath` , `QueryString` , `SingleHeader` , `Method` , and `JsonBody` .", + "RedactedFields": "The parts of the request that you want to keep out of the logs. For example, if you redact the `SingleHeader` field, the `HEADER` field in the logs will be `xxx` .\n\n> You can specify only the following fields for redaction: `UriPath` , `QueryString` , `SingleHeader` , `Method` , and `JsonBody` .", "ResourceArn": "The Amazon Resource Name (ARN) of the web ACL that you want to associate with `LogDestinationConfigs` ." } }, "AWS::WAFv2::LoggingConfiguration.FieldToMatch": { "attributes": {}, - "description": "The parts of the request that you want to keep out of the logs. For example, if you redact the `SingleHeader` field, the `HEADER` field in the firehose will be `xxx` .\n\nJSON specification for a `QueryString` field to match:\n\n`\"FieldToMatch\": { \"QueryString\": {} }`\n\nExample JSON for a `Method` field to match specification:\n\n`\"FieldToMatch\": { \"Method\": { \"Name\": \"DELETE\" } }`", + "description": "The part of a web request that you want AWS WAF to inspect. Include the single `FieldToMatch` type that you want to inspect, with additional specifications as needed, according to the type. You specify a single request component in `FieldToMatch` for each rule statement that requires it. To inspect more than one component of a web request, create a separate rule statement for each component.\n\nJSON specification for a `QueryString` field to match:\n\n`\"FieldToMatch\": { \"QueryString\": {} }`\n\nExample JSON for a `Method` field to match specification:\n\n`\"FieldToMatch\": { \"Method\": { \"Name\": \"DELETE\" } }`", "properties": { - "JsonBody": "Redact the JSON body from the logs.", - "Method": "Redact the method from the logs.", - "QueryString": "Redact the query string from the logs.", - "SingleHeader": "Redact the header from the logs.", - "UriPath": "Redact the URI path from the logs." + "JsonBody": "Inspect the request body as JSON. The request body immediately follows the request headers. This is the part of a request that contains any additional data that you want to send to your web server as the HTTP request body, such as data from a form.\n\nNote that only the first 8 KB (8192 bytes) of the request body are forwarded to AWS WAF for inspection by the underlying host service. If you don't need to inspect more than 8 KB, you can guarantee that you don't allow additional bytes in by combining a statement that inspects the body of the web request, such as `ByteMatchStatement` or `RegexPatternSetReferenceStatement` , with a `SizeConstraintStatement` that enforces an 8 KB size limit on the body of the request. AWS WAF doesn't support inspecting the entire contents of web requests whose bodies exceed the 8 KB limit.", + "Method": "Inspect the HTTP method. The method indicates the type of operation that the request is asking the origin to perform.", + "QueryString": "Inspect the query string. This is the part of a URL that appears after a `?` character, if any.", + "SingleHeader": "Inspect a single header. Provide the name of the header to inspect, for example, `User-Agent` or `Referer` . This setting isn't case sensitive.\n\nExample JSON: `\"SingleHeader\": { \"Name\": \"haystack\" }`", + "UriPath": "Inspect the request URI path. This is the part of a web request that identifies a resource, for example, `/images/daily-ad.jpg` ." } }, "AWS::WAFv2::RegexPatternSet": { @@ -39017,6 +39926,13 @@ "Name": "The name of the rule to exclude." } }, + "AWS::WAFv2::WebACL.FieldIdentifier": { + "attributes": {}, + "description": "The identifier of the username or password field, used in the `ManagedRuleGroupConfig` settings.", + "properties": { + "Identifier": "The name of the username or password field, used in the `ManagedRuleGroupConfig` settings.\n\nWhen the `PayloadType` is `JSON` , the identifier must be in JSON pointer syntax. For example `/form/username` . For information about the JSON Pointer syntax, see the Internet Engineering Task Force (IETF) documentation [JavaScript Object Notation (JSON) Pointer](https://docs.aws.amazon.com/https://tools.ietf.org/html/rfc6901) .\n\nWhen the `PayloadType` is `FORM_ENCODED` , use the HTML form names. For example, `username` ." + } + }, "AWS::WAFv2::WebACL.FieldToMatch": { "attributes": {}, "description": "The part of a web request that you want AWS WAF to inspect. Include the single `FieldToMatch` type that you want to inspect, with additional specifications as needed, according to the type. You specify a single request component in `FieldToMatch` for each rule statement that requires it. To inspect more than one component of a web request, create a separate rule statement for each component.", @@ -39103,11 +40019,22 @@ "Scope": "Specify whether you want to match using the label name or just the namespace." } }, + "AWS::WAFv2::WebACL.ManagedRuleGroupConfig": { + "attributes": {}, + "description": "Additional information that's used by a managed rule group. Most managed rule groups don't require this.\n\nUse this for the account takeover prevention managed rule group `AWSManagedRulesATPRuleSet` , to provide information about the sign-in page of your application.\n\nYou can provide multiple individual `ManagedRuleGroupConfig` objects for any rule group configuration, for example `UsernameField` and `PasswordField` . The configuration that you provide depends on the needs of the managed rule group. For the ATP managed rule group, you provide the following individual configuration objects: `LoginPath` , `PasswordField` , `PayloadType` and `UsernameField` .", + "properties": { + "LoginPath": "The path of the login endpoint for your application. For example, for the URL `https://example.com/web/login` , you would provide the path `/web/login` .", + "PasswordField": "Details about your login page password field.", + "PayloadType": "The payload type for your login endpoint, either JSON or form encoded.", + "UsernameField": "Details about your login page username field." + } + }, "AWS::WAFv2::WebACL.ManagedRuleGroupStatement": { "attributes": {}, "description": "A rule statement used to run the rules that are defined in a managed rule group. To use this, provide the vendor name and the name of the rule group in this statement.\n\nYou can't nest a `ManagedRuleGroupStatement` , for example for use inside a `NotStatement` or `OrStatement` . It can only be referenced as a top-level statement within a rule.", "properties": { "ExcludedRules": "The rules whose actions are set to `COUNT` by the web ACL, regardless of the action that is configured in the rule. This effectively excludes the rule from acting on web requests.", + "ManagedRuleGroupConfigs": "Additional information that's used by a managed rule group. Most managed rule groups don't require this.\n\nUse this for the account takeover prevention managed rule group `AWSManagedRulesATPRuleSet` , to provide information about the sign-in page of your application.\n\nYou can provide multiple individual `ManagedRuleGroupConfig` objects for any rule group configuration, for example `UsernameField` and `PasswordField` . The configuration that you provide depends on the needs of the managed rule group. For the ATP managed rule group, you provide the following individual configuration objects: `LoginPath` , `PasswordField` , `PayloadType` and `UsernameField` .", "Name": "The name of the managed rule group. You use this, along with the vendor name, to identify the rule group.", "ScopeDownStatement": "Statement nested inside a managed rule group statement to narrow the scope of the requests that AWS WAF evaluates using the rule group. Requests that match the scope-down statement are evaluated using the rule group. Requests that don't match the scope-down statement are not a match for the managed rule group statement, without any further evaluation.", "VendorName": "The name of the managed rule group vendor. You use this, along with the rule group name, to identify the rule group.", @@ -39190,10 +40117,10 @@ }, "AWS::WAFv2::WebACL.RuleGroupReferenceStatement": { "attributes": {}, - "description": "A rule statement used to run the rules that are defined in a `RuleGroup` . To use this, create a rule group with your rules, then provide the ARN of the rule group in this statement.\n\nYou cannot nest a `RuleGroupReferenceStatement` , for example for use inside a `NotStatement` or `OrStatement` . It can only be referenced as a top-level statement within a rule.", + "description": "A rule statement used to run the rules that are defined in a `RuleGroup` . To use this, create a rule group with your rules, then provide the ARN of the rule group in this statement.\n\nYou cannot nest a `RuleGroupReferenceStatement` , for example for use inside a `NotStatement` or `OrStatement` . You can only use a rule group reference statement at the top level inside a web ACL.", "properties": { "Arn": "The Amazon Resource Name (ARN) of the entity.", - "ExcludedRules": "The names of rules that are in the referenced rule group, but that you want AWS WAF to exclude from processing for this rule statement." + "ExcludedRules": "The rules in the referenced rule group whose actions are set to `Count` . When you exclude a rule, AWS WAF evaluates it exactly as it would if the rule action setting were `Count` . This is a useful option for testing the rules in a rule group without modifying how they handle your web traffic." } }, "AWS::WAFv2::WebACL.SizeConstraintStatement": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ACMPCA.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ACMPCA.json index 7847c41768d90..76317d0a1eea5 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ACMPCA.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ACMPCA.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::ACMPCA::Certificate.ApiPassthrough": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-apipassthrough.html", @@ -18,6 +18,46 @@ } } }, + "AWS::ACMPCA::Certificate.CustomAttribute": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-customattribute.html", + "Properties": { + "ObjectIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-customattribute.html#cfn-acmpca-certificate-customattribute-objectidentifier", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-customattribute.html#cfn-acmpca-certificate-customattribute-value", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::ACMPCA::Certificate.CustomExtension": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-customextension.html", + "Properties": { + "Critical": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-customextension.html#cfn-acmpca-certificate-customextension-critical", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Immutable" + }, + "ObjectIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-customextension.html#cfn-acmpca-certificate-customextension-objectidentifier", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-customextension.html#cfn-acmpca-certificate-customextension-value", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::ACMPCA::Certificate.EdiPartyName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-edipartyname.html", "Properties": { @@ -62,6 +102,13 @@ "Type": "List", "UpdateType": "Immutable" }, + "CustomExtensions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-extensions.html#cfn-acmpca-certificate-extensions-customextensions", + "ItemType": "CustomExtension", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, "ExtendedKeyUsage": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-extensions.html#cfn-acmpca-certificate-extensions-extendedkeyusage", "ItemType": "ExtendedKeyUsage", @@ -274,6 +321,13 @@ "Required": false, "UpdateType": "Immutable" }, + "CustomAttributes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-subject.html#cfn-acmpca-certificate-subject-customattributes", + "ItemType": "CustomAttribute", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, "DistinguishedNameQualifier": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-subject.html#cfn-acmpca-certificate-subject-distinguishednamequalifier", "PrimitiveType": "String", @@ -452,6 +506,23 @@ } } }, + "AWS::ACMPCA::CertificateAuthority.CustomAttribute": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificateauthority-customattribute.html", + "Properties": { + "ObjectIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificateauthority-customattribute.html#cfn-acmpca-certificateauthority-customattribute-objectidentifier", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificateauthority-customattribute.html#cfn-acmpca-certificateauthority-customattribute-value", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::ACMPCA::CertificateAuthority.EdiPartyName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificateauthority-edipartyname.html", "Properties": { @@ -647,6 +718,13 @@ "Required": false, "UpdateType": "Immutable" }, + "CustomAttributes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificateauthority-subject.html#cfn-acmpca-certificateauthority-subject-customattributes", + "ItemType": "CustomAttribute", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, "DistinguishedNameQualifier": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificateauthority-subject.html#cfn-acmpca-certificateauthority-subject-distinguishednamequalifier", "PrimitiveType": "String", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_APS.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_APS.json index e34c6abd8e436..2b9e7b271d126 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_APS.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_APS.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::APS::RuleGroupsNamespace": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AccessAnalyzer.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AccessAnalyzer.json index fb43d3ff7556d..6e462f6110cc0 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AccessAnalyzer.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AccessAnalyzer.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::AccessAnalyzer::Analyzer.ArchiveRule": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-accessanalyzer-analyzer-archiverule.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AmazonMQ.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AmazonMQ.json index 13e38afa1c5b3..1346343237282 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AmazonMQ.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AmazonMQ.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::AmazonMQ::Broker.ConfigurationId": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amazonmq-broker-configurationid.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Amplify.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Amplify.json index 25e26be1921f7..3f22bd6fb2197 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Amplify.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Amplify.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Amplify::App.AutoBranchCreationConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplify-app-autobranchcreationconfig.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AmplifyUIBuilder.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AmplifyUIBuilder.json index b72589705a934..66fa567ac8f81 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AmplifyUIBuilder.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AmplifyUIBuilder.json @@ -1,6 +1,65 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { + "AWS::AmplifyUIBuilder::Component.ActionParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-actionparameters.html", + "Properties": { + "Anchor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-actionparameters.html#cfn-amplifyuibuilder-component-actionparameters-anchor", + "Required": false, + "Type": "ComponentProperty", + "UpdateType": "Mutable" + }, + "Fields": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-actionparameters.html#cfn-amplifyuibuilder-component-actionparameters-fields", + "Required": false, + "Type": "ComponentProperties", + "UpdateType": "Mutable" + }, + "Global": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-actionparameters.html#cfn-amplifyuibuilder-component-actionparameters-global", + "Required": false, + "Type": "ComponentProperty", + "UpdateType": "Mutable" + }, + "Id": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-actionparameters.html#cfn-amplifyuibuilder-component-actionparameters-id", + "Required": false, + "Type": "ComponentProperty", + "UpdateType": "Mutable" + }, + "Model": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-actionparameters.html#cfn-amplifyuibuilder-component-actionparameters-model", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "State": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-actionparameters.html#cfn-amplifyuibuilder-component-actionparameters-state", + "Required": false, + "Type": "MutationActionSetStateParameter", + "UpdateType": "Mutable" + }, + "Target": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-actionparameters.html#cfn-amplifyuibuilder-component-actionparameters-target", + "Required": false, + "Type": "ComponentProperty", + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-actionparameters.html#cfn-amplifyuibuilder-component-actionparameters-type", + "Required": false, + "Type": "ComponentProperty", + "UpdateType": "Mutable" + }, + "Url": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-actionparameters.html#cfn-amplifyuibuilder-component-actionparameters-url", + "Required": false, + "Type": "ComponentProperty", + "UpdateType": "Mutable" + } + } + }, "AWS::AmplifyUIBuilder::Component.ComponentBindingPropertiesValue": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-componentbindingpropertiesvalue.html", "Properties": { @@ -88,6 +147,12 @@ "Required": true, "UpdateType": "Mutable" }, + "Events": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-componentchild.html#cfn-amplifyuibuilder-component-componentchild-events", + "Required": false, + "Type": "ComponentEvents", + "UpdateType": "Mutable" + }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-componentchild.html#cfn-amplifyuibuilder-component-componentchild-name", "PrimitiveType": "String", @@ -123,6 +188,12 @@ "Required": false, "UpdateType": "Mutable" }, + "OperandType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-componentconditionproperty.html#cfn-amplifyuibuilder-component-componentconditionproperty-operandtype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "Operator": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-componentconditionproperty.html#cfn-amplifyuibuilder-component-componentconditionproperty-operator", "PrimitiveType": "String", @@ -174,6 +245,29 @@ } } }, + "AWS::AmplifyUIBuilder::Component.ComponentEvent": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-componentevent.html", + "Properties": { + "Action": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-componentevent.html#cfn-amplifyuibuilder-component-componentevent-action", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Parameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-componentevent.html#cfn-amplifyuibuilder-component-componentevent-parameters", + "Required": false, + "Type": "ActionParameters", + "UpdateType": "Mutable" + } + } + }, + "AWS::AmplifyUIBuilder::Component.ComponentEvents": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-componentevents.html", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + }, "AWS::AmplifyUIBuilder::Component.ComponentOverrides": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-componentoverrides.html", "PrimitiveType": "Json", @@ -213,6 +307,12 @@ "Type": "ComponentPropertyBindingProperties", "UpdateType": "Mutable" }, + "ComponentName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-componentproperty.html#cfn-amplifyuibuilder-component-componentproperty-componentname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "Concat": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-componentproperty.html#cfn-amplifyuibuilder-component-componentproperty-concat", "ItemType": "ComponentProperty", @@ -256,6 +356,12 @@ "Required": false, "UpdateType": "Mutable" }, + "Property": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-componentproperty.html#cfn-amplifyuibuilder-component-componentproperty-property", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "Type": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-componentproperty.html#cfn-amplifyuibuilder-component-componentproperty-type", "PrimitiveType": "String", @@ -322,6 +428,29 @@ "Required": false, "UpdateType": "Mutable" }, + "AWS::AmplifyUIBuilder::Component.MutationActionSetStateParameter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-mutationactionsetstateparameter.html", + "Properties": { + "ComponentName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-mutationactionsetstateparameter.html#cfn-amplifyuibuilder-component-mutationactionsetstateparameter-componentname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Property": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-mutationactionsetstateparameter.html#cfn-amplifyuibuilder-component-mutationactionsetstateparameter-property", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Set": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-mutationactionsetstateparameter.html#cfn-amplifyuibuilder-component-mutationactionsetstateparameter-set", + "Required": true, + "Type": "ComponentProperty", + "UpdateType": "Mutable" + } + } + }, "AWS::AmplifyUIBuilder::Component.Predicate": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-amplifyuibuilder-component-predicate.html", "Properties": { @@ -418,17 +547,11 @@ "AppId": { "PrimitiveType": "String" }, - "CreatedAt": { - "PrimitiveType": "String" - }, "EnvironmentName": { "PrimitiveType": "String" }, "Id": { "PrimitiveType": "String" - }, - "ModifiedAt": { - "PrimitiveType": "String" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-amplifyuibuilder-component.html", @@ -436,7 +559,7 @@ "BindingProperties": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-amplifyuibuilder-component.html#cfn-amplifyuibuilder-component-bindingproperties", "ItemType": "ComponentBindingPropertiesValue", - "Required": false, + "Required": true, "Type": "Map", "UpdateType": "Mutable" }, @@ -457,29 +580,42 @@ "ComponentType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-amplifyuibuilder-component.html#cfn-amplifyuibuilder-component-componenttype", "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Events": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-amplifyuibuilder-component.html#cfn-amplifyuibuilder-component-events", + "ItemType": "ComponentEvent", "Required": false, + "Type": "Map", "UpdateType": "Mutable" }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-amplifyuibuilder-component.html#cfn-amplifyuibuilder-component-name", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Overrides": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-amplifyuibuilder-component.html#cfn-amplifyuibuilder-component-overrides", "ItemType": "ComponentOverridesValue", - "Required": false, + "Required": true, "Type": "Map", "UpdateType": "Mutable" }, "Properties": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-amplifyuibuilder-component.html#cfn-amplifyuibuilder-component-properties", "ItemType": "ComponentProperty", - "Required": false, + "Required": true, "Type": "Map", "UpdateType": "Mutable" }, + "SchemaVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-amplifyuibuilder-component.html#cfn-amplifyuibuilder-component-schemaversion", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "SourceId": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-amplifyuibuilder-component.html#cfn-amplifyuibuilder-component-sourceid", "PrimitiveType": "String", @@ -496,7 +632,7 @@ "Variants": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-amplifyuibuilder-component.html#cfn-amplifyuibuilder-component-variants", "ItemType": "ComponentVariant", - "Required": false, + "Required": true, "Type": "List", "UpdateType": "Mutable" } diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ApiGateway.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ApiGateway.json index a77d1bda5de2c..9b91495c0562b 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ApiGateway.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ApiGateway.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::ApiGateway::ApiKey.StageKey": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigateway-apikey-stagekey.html", @@ -892,6 +892,12 @@ "Required": true, "UpdateType": "Immutable" }, + "Id": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-basepathmapping.html#cfn-apigateway-basepathmapping-id", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "RestApiId": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-basepathmapping.html#cfn-apigateway-basepathmapping-restapiid", "PrimitiveType": "String", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ApiGatewayV2.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ApiGatewayV2.json index 4448a4c0e3ef4..ce52ae104e29f 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ApiGatewayV2.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ApiGatewayV2.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::ApiGatewayV2::Api.BodyS3Location": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-api-bodys3location.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppConfig.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppConfig.json index b5c1b1db2b875..361a9d7d3c818 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppConfig.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppConfig.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::AppConfig::Application.Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appconfig-application-tags.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppFlow.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppFlow.json index 4ff1ffa287a83..6f240908c69f8 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppFlow.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppFlow.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::AppFlow::ConnectorProfile.AmplitudeConnectorProfileCredentials": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-amplitudeconnectorprofilecredentials.html", @@ -941,6 +941,12 @@ "Type": "LookoutMetricsDestinationProperties", "UpdateType": "Mutable" }, + "Marketo": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-destinationconnectorproperties.html#cfn-appflow-flow-destinationconnectorproperties-marketo", + "Required": false, + "Type": "MarketoDestinationProperties", + "UpdateType": "Mutable" + }, "Redshift": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-destinationconnectorproperties.html#cfn-appflow-flow-destinationconnectorproperties-redshift", "Required": false, @@ -953,6 +959,12 @@ "Type": "S3DestinationProperties", "UpdateType": "Mutable" }, + "SAPOData": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-destinationconnectorproperties.html#cfn-appflow-flow-destinationconnectorproperties-sapodata", + "Required": false, + "Type": "SAPODataDestinationProperties", + "UpdateType": "Mutable" + }, "Salesforce": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-destinationconnectorproperties.html#cfn-appflow-flow-destinationconnectorproperties-salesforce", "Required": false, @@ -1097,6 +1109,23 @@ } } }, + "AWS::AppFlow::Flow.MarketoDestinationProperties": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-marketodestinationproperties.html", + "Properties": { + "ErrorHandlingConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-marketodestinationproperties.html#cfn-appflow-flow-marketodestinationproperties-errorhandlingconfig", + "Required": false, + "Type": "ErrorHandlingConfig", + "UpdateType": "Mutable" + }, + "Object": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-marketodestinationproperties.html#cfn-appflow-flow-marketodestinationproperties-object", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::AppFlow::Flow.MarketoSourceProperties": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-marketosourceproperties.html", "Properties": { @@ -1234,6 +1263,42 @@ } } }, + "AWS::AppFlow::Flow.SAPODataDestinationProperties": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-sapodatadestinationproperties.html", + "Properties": { + "ErrorHandlingConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-sapodatadestinationproperties.html#cfn-appflow-flow-sapodatadestinationproperties-errorhandlingconfig", + "Required": false, + "Type": "ErrorHandlingConfig", + "UpdateType": "Mutable" + }, + "IdFieldNames": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-sapodatadestinationproperties.html#cfn-appflow-flow-sapodatadestinationproperties-idfieldnames", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "ObjectPath": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-sapodatadestinationproperties.html#cfn-appflow-flow-sapodatadestinationproperties-objectpath", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "SuccessResponseHandlingConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-sapodatadestinationproperties.html#cfn-appflow-flow-sapodatadestinationproperties-successresponsehandlingconfig", + "Required": false, + "Type": "SuccessResponseHandlingConfig", + "UpdateType": "Mutable" + }, + "WriteOperationType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-sapodatadestinationproperties.html#cfn-appflow-flow-sapodatadestinationproperties-writeoperationtype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::AppFlow::Flow.SAPODataSourceProperties": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-sapodatasourceproperties.html", "Properties": { @@ -1525,6 +1590,23 @@ } } }, + "AWS::AppFlow::Flow.SuccessResponseHandlingConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-successresponsehandlingconfig.html", + "Properties": { + "BucketName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-successresponsehandlingconfig.html#cfn-appflow-flow-successresponsehandlingconfig-bucketname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "BucketPrefix": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-successresponsehandlingconfig.html#cfn-appflow-flow-successresponsehandlingconfig-bucketprefix", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::AppFlow::Flow.Task": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-task.html", "Properties": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppIntegrations.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppIntegrations.json index fd09492304583..03e94bc384fac 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppIntegrations.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppIntegrations.json @@ -1,6 +1,29 @@ { - "$version": "53.1.0", + "$version": "62.0.0", "PropertyTypes": { + "AWS::AppIntegrations::DataIntegration.ScheduleConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appintegrations-dataintegration-scheduleconfig.html", + "Properties": { + "FirstExecutionFrom": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appintegrations-dataintegration-scheduleconfig.html#cfn-appintegrations-dataintegration-scheduleconfig-firstexecutionfrom", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Object": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appintegrations-dataintegration-scheduleconfig.html#cfn-appintegrations-dataintegration-scheduleconfig-object", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "ScheduleExpression": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appintegrations-dataintegration-scheduleconfig.html#cfn-appintegrations-dataintegration-scheduleconfig-scheduleexpression", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::AppIntegrations::EventIntegration.EventFilter": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appintegrations-eventintegration-eventfilter.html", "Properties": { @@ -67,6 +90,56 @@ } }, "ResourceTypes": { + "AWS::AppIntegrations::DataIntegration": { + "Attributes": { + "DataIntegrationArn": { + "PrimitiveType": "String" + }, + "Id": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appintegrations-dataintegration.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appintegrations-dataintegration.html#cfn-appintegrations-dataintegration-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "KmsKey": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appintegrations-dataintegration.html#cfn-appintegrations-dataintegration-kmskey", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appintegrations-dataintegration.html#cfn-appintegrations-dataintegration-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ScheduleConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appintegrations-dataintegration.html#cfn-appintegrations-dataintegration-scheduleconfig", + "Required": true, + "Type": "ScheduleConfig", + "UpdateType": "Immutable" + }, + "SourceURI": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appintegrations-dataintegration.html#cfn-appintegrations-dataintegration-sourceuri", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appintegrations-dataintegration.html#cfn-appintegrations-dataintegration-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::AppIntegrations::EventIntegration": { "Attributes": { "Associations": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppMesh.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppMesh.json index c6ff2747975a1..4d10869895be8 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppMesh.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppMesh.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::AppMesh::GatewayRoute.GatewayRouteHostnameMatch": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-gatewayroute-gatewayroutehostnamematch.html", @@ -466,6 +466,10 @@ } } }, + "AWS::AppMesh::Mesh.MeshServiceDiscovery": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-mesh-meshservicediscovery.html", + "Properties": {} + }, "AWS::AppMesh::Mesh.MeshSpec": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-mesh-meshspec.html", "Properties": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppRunner.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppRunner.json index 2838d0f148e9c..cb4b9b032c6a5 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppRunner.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppRunner.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::AppRunner::Service.AuthenticationConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-authenticationconfiguration.html", @@ -94,6 +94,23 @@ } } }, + "AWS::AppRunner::Service.EgressConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-egressconfiguration.html", + "Properties": { + "EgressType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-egressconfiguration.html#cfn-apprunner-service-egressconfiguration-egresstype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "VpcConnectorArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-egressconfiguration.html#cfn-apprunner-service-egressconfiguration-vpcconnectorarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::AppRunner::Service.EncryptionConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-encryptionconfiguration.html", "Properties": { @@ -233,6 +250,17 @@ } } }, + "AWS::AppRunner::Service.NetworkConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-networkconfiguration.html", + "Properties": { + "EgressConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-networkconfiguration.html#cfn-apprunner-service-networkconfiguration-egressconfiguration", + "Required": true, + "Type": "EgressConfiguration", + "UpdateType": "Mutable" + } + } + }, "AWS::AppRunner::Service.SourceCodeVersion": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-sourcecodeversion.html", "Properties": { @@ -322,6 +350,12 @@ "Type": "InstanceConfiguration", "UpdateType": "Mutable" }, + "NetworkConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apprunner-service.html#cfn-apprunner-service-networkconfiguration", + "Required": false, + "Type": "NetworkConfiguration", + "UpdateType": "Mutable" + }, "ServiceName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apprunner-service.html#cfn-apprunner-service-servicename", "PrimitiveType": "String", @@ -342,6 +376,48 @@ "UpdateType": "Immutable" } } + }, + "AWS::AppRunner::VpcConnector": { + "Attributes": { + "VpcConnectorArn": { + "PrimitiveType": "String" + }, + "VpcConnectorRevision": { + "PrimitiveType": "Integer" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apprunner-vpcconnector.html", + "Properties": { + "SecurityGroups": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apprunner-vpcconnector.html#cfn-apprunner-vpcconnector-securitygroups", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "Subnets": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apprunner-vpcconnector.html#cfn-apprunner-vpcconnector-subnets", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apprunner-vpcconnector.html#cfn-apprunner-vpcconnector-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "VpcConnectorName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apprunner-vpcconnector.html#cfn-apprunner-vpcconnector-vpcconnectorname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } } } } diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppStream.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppStream.json index 98946de6ca2ef..abf8603f1c8a2 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppStream.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppStream.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::AppStream::AppBlock.S3Location": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appstream-appblock-s3location.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppSync.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppSync.json index fad903a8e3c4f..0d48328fafbcc 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppSync.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AppSync.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::AppSync::DataSource.AuthorizationConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appsync-datasource-authorizationconfig.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ApplicationAutoScaling.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ApplicationAutoScaling.json index bfc094feabc47..6b783d17ad9d6 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ApplicationAutoScaling.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ApplicationAutoScaling.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::ApplicationAutoScaling::ScalableTarget.ScalableTargetAction": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationautoscaling-scalabletarget-scalabletargetaction.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ApplicationInsights.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ApplicationInsights.json index b1dd384b5592d..79405cf27def4 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ApplicationInsights.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ApplicationInsights.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::ApplicationInsights::Application.Alarm": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-alarm.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Athena.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Athena.json index 9690e8e93fa65..ad20cc5b38181 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Athena.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Athena.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Athena::WorkGroup.EncryptionConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-athena-workgroup-encryptionconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AuditManager.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AuditManager.json index 7b9b8ea70efb3..1cd0aaa2b4cba 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AuditManager.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AuditManager.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::AuditManager::Assessment.AWSAccount": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-auditmanager-assessment-awsaccount.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AutoScaling.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AutoScaling.json index 4b5d7ba53b228..7444f1351643d 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AutoScaling.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AutoScaling.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::AutoScaling::AutoScalingGroup.AcceleratorCountRequest": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-acceleratorcountrequest.html", @@ -520,101 +520,101 @@ } }, "AWS::AutoScaling::LaunchConfiguration.BlockDevice": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-template.html", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevice.html", "Properties": { "DeleteOnTermination": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-template.html#cfn-as-launchconfig-blockdev-template-deleteonterm", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevice.html#cfn-autoscaling-launchconfiguration-blockdevice-deleteontermination", "PrimitiveType": "Boolean", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "Encrypted": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-template.html#cfn-as-launchconfig-blockdev-template-encrypted", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevice.html#cfn-autoscaling-launchconfiguration-blockdevice-encrypted", "PrimitiveType": "Boolean", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "Iops": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-template.html#cfn-as-launchconfig-blockdev-template-iops", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevice.html#cfn-autoscaling-launchconfiguration-blockdevice-iops", "PrimitiveType": "Integer", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "SnapshotId": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-template.html#cfn-as-launchconfig-blockdev-template-snapshotid", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevice.html#cfn-autoscaling-launchconfiguration-blockdevice-snapshotid", "PrimitiveType": "String", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "Throughput": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-template.html#cfn-as-launchconfig-blockdev-template-throughput", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevice.html#cfn-autoscaling-launchconfiguration-blockdevice-throughput", "PrimitiveType": "Integer", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "VolumeSize": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-template.html#cfn-as-launchconfig-blockdev-template-volumesize", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevice.html#cfn-autoscaling-launchconfiguration-blockdevice-volumesize", "PrimitiveType": "Integer", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "VolumeType": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-template.html#cfn-as-launchconfig-blockdev-template-volumetype", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevice.html#cfn-autoscaling-launchconfiguration-blockdevice-volumetype", "PrimitiveType": "String", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" } } }, "AWS::AutoScaling::LaunchConfiguration.BlockDeviceMapping": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-mapping.html", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevicemapping.html", "Properties": { "DeviceName": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-mapping.html#cfn-as-launchconfig-blockdev-mapping-devicename", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevicemapping.html#cfn-autoscaling-launchconfiguration-blockdevicemapping-devicename", "PrimitiveType": "String", "Required": true, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "Ebs": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-mapping.html#cfn-as-launchconfig-blockdev-mapping-ebs", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevicemapping.html#cfn-autoscaling-launchconfiguration-blockdevicemapping-ebs", "Required": false, "Type": "BlockDevice", - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "NoDevice": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-mapping.html#cfn-as-launchconfig-blockdev-mapping-nodevice", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevicemapping.html#cfn-autoscaling-launchconfiguration-blockdevicemapping-nodevice", "PrimitiveType": "Boolean", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "VirtualName": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-mapping.html#cfn-as-launchconfig-blockdev-mapping-virtualname", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-blockdevicemapping.html#cfn-autoscaling-launchconfiguration-blockdevicemapping-virtualname", "PrimitiveType": "String", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" } } }, "AWS::AutoScaling::LaunchConfiguration.MetadataOptions": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfig-metadataoptions.html", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-metadataoptions.html", "Properties": { "HttpEndpoint": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfig-metadataoptions.html#cfn-autoscaling-launchconfig-metadataoptions-httpendpoint", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-metadataoptions.html#cfn-autoscaling-launchconfiguration-metadataoptions-httpendpoint", "PrimitiveType": "String", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "HttpPutResponseHopLimit": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfig-metadataoptions.html#cfn-autoscaling-launchconfig-metadataoptions-httpputresponsehoplimit", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-metadataoptions.html#cfn-autoscaling-launchconfiguration-metadataoptions-httpputresponsehoplimit", "PrimitiveType": "Integer", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "HttpTokens": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfig-metadataoptions.html#cfn-autoscaling-launchconfig-metadataoptions-httptokens", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-launchconfiguration-metadataoptions.html#cfn-autoscaling-launchconfiguration-metadataoptions-httptokens", "PrimitiveType": "String", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" } } }, @@ -655,6 +655,66 @@ } } }, + "AWS::AutoScaling::ScalingPolicy.Metric": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metric.html", + "Properties": { + "Dimensions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metric.html#cfn-autoscaling-scalingpolicy-metric-dimensions", + "DuplicatesAllowed": false, + "ItemType": "MetricDimension", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "MetricName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metric.html#cfn-autoscaling-scalingpolicy-metric-metricname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Namespace": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metric.html#cfn-autoscaling-scalingpolicy-metric-namespace", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::AutoScaling::ScalingPolicy.MetricDataQuery": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricdataquery.html", + "Properties": { + "Expression": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricdataquery.html#cfn-autoscaling-scalingpolicy-metricdataquery-expression", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Id": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricdataquery.html#cfn-autoscaling-scalingpolicy-metricdataquery-id", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Label": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricdataquery.html#cfn-autoscaling-scalingpolicy-metricdataquery-label", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "MetricStat": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricdataquery.html#cfn-autoscaling-scalingpolicy-metricdataquery-metricstat", + "Required": false, + "Type": "MetricStat", + "UpdateType": "Mutable" + }, + "ReturnData": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricdataquery.html#cfn-autoscaling-scalingpolicy-metricdataquery-returndata", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::AutoScaling::ScalingPolicy.MetricDimension": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricdimension.html", "Properties": { @@ -672,6 +732,29 @@ } } }, + "AWS::AutoScaling::ScalingPolicy.MetricStat": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricstat.html", + "Properties": { + "Metric": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricstat.html#cfn-autoscaling-scalingpolicy-metricstat-metric", + "Required": true, + "Type": "Metric", + "UpdateType": "Mutable" + }, + "Stat": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricstat.html#cfn-autoscaling-scalingpolicy-metricstat-stat", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Unit": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricstat.html#cfn-autoscaling-scalingpolicy-metricstat-unit", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::AutoScaling::ScalingPolicy.PredefinedMetricSpecification": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predefinedmetricspecification.html", "Properties": { @@ -726,9 +809,66 @@ } } }, + "AWS::AutoScaling::ScalingPolicy.PredictiveScalingCustomizedCapacityMetric": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingcustomizedcapacitymetric.html", + "Properties": { + "MetricDataQueries": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingcustomizedcapacitymetric.html#cfn-autoscaling-scalingpolicy-predictivescalingcustomizedcapacitymetric-metricdataqueries", + "DuplicatesAllowed": false, + "ItemType": "MetricDataQuery", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::AutoScaling::ScalingPolicy.PredictiveScalingCustomizedLoadMetric": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingcustomizedloadmetric.html", + "Properties": { + "MetricDataQueries": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingcustomizedloadmetric.html#cfn-autoscaling-scalingpolicy-predictivescalingcustomizedloadmetric-metricdataqueries", + "DuplicatesAllowed": false, + "ItemType": "MetricDataQuery", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::AutoScaling::ScalingPolicy.PredictiveScalingCustomizedScalingMetric": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingcustomizedscalingmetric.html", + "Properties": { + "MetricDataQueries": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingcustomizedscalingmetric.html#cfn-autoscaling-scalingpolicy-predictivescalingcustomizedscalingmetric-metricdataqueries", + "DuplicatesAllowed": false, + "ItemType": "MetricDataQuery", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::AutoScaling::ScalingPolicy.PredictiveScalingMetricSpecification": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingmetricspecification.html", "Properties": { + "CustomizedCapacityMetricSpecification": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingmetricspecification.html#cfn-autoscaling-scalingpolicy-predictivescalingmetricspecification-customizedcapacitymetricspecification", + "Required": false, + "Type": "PredictiveScalingCustomizedCapacityMetric", + "UpdateType": "Mutable" + }, + "CustomizedLoadMetricSpecification": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingmetricspecification.html#cfn-autoscaling-scalingpolicy-predictivescalingmetricspecification-customizedloadmetricspecification", + "Required": false, + "Type": "PredictiveScalingCustomizedLoadMetric", + "UpdateType": "Mutable" + }, + "CustomizedScalingMetricSpecification": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingmetricspecification.html#cfn-autoscaling-scalingpolicy-predictivescalingmetricspecification-customizedscalingmetricspecification", + "Required": false, + "Type": "PredictiveScalingCustomizedScalingMetric", + "UpdateType": "Mutable" + }, "PredefinedLoadMetricSpecification": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingmetricspecification.html#cfn-autoscaling-scalingpolicy-predictivescalingmetricspecification-predefinedloadmetricspecification", "Required": false, @@ -1074,16 +1214,16 @@ } }, "AWS::AutoScaling::LaunchConfiguration": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html", "Properties": { "AssociatePublicIpAddress": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cf-as-launchconfig-associatepubip", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-associatepublicipaddress", "PrimitiveType": "Boolean", "Required": false, "UpdateType": "Immutable" }, "BlockDeviceMappings": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-blockdevicemappings", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-blockdevicemappings", "DuplicatesAllowed": false, "ItemType": "BlockDeviceMapping", "Required": false, @@ -1091,107 +1231,105 @@ "UpdateType": "Immutable" }, "ClassicLinkVPCId": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-classiclinkvpcid", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-classiclinkvpcid", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" }, "ClassicLinkVPCSecurityGroups": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-classiclinkvpcsecuritygroups", - "DuplicatesAllowed": false, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-classiclinkvpcsecuritygroups", "PrimitiveItemType": "String", "Required": false, "Type": "List", "UpdateType": "Immutable" }, "EbsOptimized": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-ebsoptimized", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-ebsoptimized", "PrimitiveType": "Boolean", "Required": false, "UpdateType": "Immutable" }, "IamInstanceProfile": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-iaminstanceprofile", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-iaminstanceprofile", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" }, "ImageId": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-imageid", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-imageid", "PrimitiveType": "String", "Required": true, "UpdateType": "Immutable" }, "InstanceId": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-instanceid", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-instanceid", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" }, "InstanceMonitoring": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-instancemonitoring", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-instancemonitoring", "PrimitiveType": "Boolean", "Required": false, "UpdateType": "Immutable" }, "InstanceType": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-instancetype", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-instancetype", "PrimitiveType": "String", "Required": true, "UpdateType": "Immutable" }, "KernelId": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-kernelid", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-kernelid", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" }, "KeyName": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-keyname", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-keyname", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" }, "LaunchConfigurationName": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-autoscaling-launchconfig-launchconfigurationname", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-launchconfigurationname", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" }, "MetadataOptions": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-autoscaling-launchconfig-metadataoptions", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-metadataoptions", "Required": false, "Type": "MetadataOptions", "UpdateType": "Immutable" }, "PlacementTenancy": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-placementtenancy", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-placementtenancy", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" }, "RamDiskId": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-ramdiskid", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-ramdiskid", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" }, "SecurityGroups": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-securitygroups", - "DuplicatesAllowed": false, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-securitygroups", "PrimitiveItemType": "String", "Required": false, "Type": "List", "UpdateType": "Immutable" }, "SpotPrice": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-spotprice", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-spotprice", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" }, "UserData": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-userdata", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html#cfn-autoscaling-launchconfiguration-userdata", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AutoScalingPlans.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AutoScalingPlans.json index 39e531c2b1d40..370e90b31650d 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AutoScalingPlans.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_AutoScalingPlans.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::AutoScalingPlans::ScalingPlan.ApplicationSource": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscalingplans-scalingplan-applicationsource.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Backup.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Backup.json index 2c383379b2224..293257d7bbc6a 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Backup.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Backup.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Backup::BackupPlan.AdvancedBackupSettingResourceType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupplan-advancedbackupsettingresourcetype.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Batch.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Batch.json index 37652114b7199..24078d5eacedc 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Batch.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Batch.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Batch::ComputeEnvironment.ComputeResources": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-computeenvironment-computeresources.html", @@ -24,6 +24,7 @@ }, "Ec2Configuration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-computeenvironment-computeresources.html#cfn-batch-computeenvironment-computeresources-ec2configuration", + "DuplicatesAllowed": true, "ItemType": "Ec2ConfigurationObject", "Required": false, "Type": "List", @@ -49,6 +50,7 @@ }, "InstanceTypes": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-computeenvironment-computeresources.html#cfn-batch-computeenvironment-computeresources-instancetypes", + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": false, "Type": "List", @@ -80,6 +82,7 @@ }, "SecurityGroupIds": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-computeenvironment-computeresources.html#cfn-batch-computeenvironment-computeresources-securitygroupids", + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": false, "Type": "List", @@ -93,6 +96,7 @@ }, "Subnets": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-computeenvironment-computeresources.html#cfn-batch-computeenvironment-computeresources-subnets", + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": true, "Type": "List", @@ -100,8 +104,9 @@ }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-computeenvironment-computeresources.html#cfn-batch-computeenvironment-computeresources-tags", - "PrimitiveType": "Json", + "PrimitiveItemType": "String", "Required": false, + "Type": "Map", "UpdateType": "Immutable" }, "Type": { @@ -764,6 +769,11 @@ }, "ResourceTypes": { "AWS::Batch::ComputeEnvironment": { + "Attributes": { + "ComputeEnvironmentArn": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-batch-computeenvironment.html", "Properties": { "ComputeEnvironmentName": { @@ -792,8 +802,9 @@ }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-batch-computeenvironment.html#cfn-batch-computeenvironment-tags", - "PrimitiveType": "Json", + "PrimitiveItemType": "String", "Required": false, + "Type": "Map", "UpdateType": "Immutable" }, "Type": { @@ -883,10 +894,16 @@ } }, "AWS::Batch::JobQueue": { + "Attributes": { + "JobQueueArn": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-batch-jobqueue.html", "Properties": { "ComputeEnvironmentOrder": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-batch-jobqueue.html#cfn-batch-jobqueue-computeenvironmentorder", + "DuplicatesAllowed": true, "ItemType": "ComputeEnvironmentOrder", "Required": true, "Type": "List", @@ -918,8 +935,9 @@ }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-batch-jobqueue.html#cfn-batch-jobqueue-tags", - "PrimitiveType": "Json", + "PrimitiveItemType": "String", "Required": false, + "Type": "Map", "UpdateType": "Immutable" } } diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_BillingConductor.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_BillingConductor.json new file mode 100644 index 0000000000000..80a756f6d9a2c --- /dev/null +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_BillingConductor.json @@ -0,0 +1,304 @@ +{ + "$version": "62.0.0", + "PropertyTypes": { + "AWS::BillingConductor::BillingGroup.AccountGrouping": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-billingconductor-billinggroup-accountgrouping.html", + "Properties": { + "LinkedAccountIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-billingconductor-billinggroup-accountgrouping.html#cfn-billingconductor-billinggroup-accountgrouping-linkedaccountids", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::BillingConductor::BillingGroup.ComputationPreference": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-billingconductor-billinggroup-computationpreference.html", + "Properties": { + "PricingPlanArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-billingconductor-billinggroup-computationpreference.html#cfn-billingconductor-billinggroup-computationpreference-pricingplanarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::BillingConductor::CustomLineItem.BillingPeriodRange": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-billingconductor-customlineitem-billingperiodrange.html", + "Properties": { + "ExclusiveEndBillingPeriod": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-billingconductor-customlineitem-billingperiodrange.html#cfn-billingconductor-customlineitem-billingperiodrange-exclusiveendbillingperiod", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "InclusiveStartBillingPeriod": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-billingconductor-customlineitem-billingperiodrange.html#cfn-billingconductor-customlineitem-billingperiodrange-inclusivestartbillingperiod", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::BillingConductor::CustomLineItem.CustomLineItemChargeDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-billingconductor-customlineitem-customlineitemchargedetails.html", + "Properties": { + "Flat": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-billingconductor-customlineitem-customlineitemchargedetails.html#cfn-billingconductor-customlineitem-customlineitemchargedetails-flat", + "Required": false, + "Type": "CustomLineItemFlatChargeDetails", + "UpdateType": "Mutable" + }, + "Percentage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-billingconductor-customlineitem-customlineitemchargedetails.html#cfn-billingconductor-customlineitem-customlineitemchargedetails-percentage", + "Required": false, + "Type": "CustomLineItemPercentageChargeDetails", + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-billingconductor-customlineitem-customlineitemchargedetails.html#cfn-billingconductor-customlineitem-customlineitemchargedetails-type", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::BillingConductor::CustomLineItem.CustomLineItemFlatChargeDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-billingconductor-customlineitem-customlineitemflatchargedetails.html", + "Properties": { + "ChargeValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-billingconductor-customlineitem-customlineitemflatchargedetails.html#cfn-billingconductor-customlineitem-customlineitemflatchargedetails-chargevalue", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::BillingConductor::CustomLineItem.CustomLineItemPercentageChargeDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-billingconductor-customlineitem-customlineitempercentagechargedetails.html", + "Properties": { + "ChildAssociatedResources": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-billingconductor-customlineitem-customlineitempercentagechargedetails.html#cfn-billingconductor-customlineitem-customlineitempercentagechargedetails-childassociatedresources", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "PercentageValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-billingconductor-customlineitem-customlineitempercentagechargedetails.html#cfn-billingconductor-customlineitem-customlineitempercentagechargedetails-percentagevalue", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + } + } + } + }, + "ResourceTypes": { + "AWS::BillingConductor::BillingGroup": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "CreationTime": { + "PrimitiveType": "Integer" + }, + "LastModifiedTime": { + "PrimitiveType": "Integer" + }, + "Size": { + "PrimitiveType": "Integer" + }, + "Status": { + "PrimitiveType": "String" + }, + "StatusReason": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-billinggroup.html", + "Properties": { + "AccountGrouping": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-billinggroup.html#cfn-billingconductor-billinggroup-accountgrouping", + "Required": true, + "Type": "AccountGrouping", + "UpdateType": "Mutable" + }, + "ComputationPreference": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-billinggroup.html#cfn-billingconductor-billinggroup-computationpreference", + "Required": true, + "Type": "ComputationPreference", + "UpdateType": "Mutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-billinggroup.html#cfn-billingconductor-billinggroup-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-billinggroup.html#cfn-billingconductor-billinggroup-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "PrimaryAccountId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-billinggroup.html#cfn-billingconductor-billinggroup-primaryaccountid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::BillingConductor::CustomLineItem": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "AssociationSize": { + "PrimitiveType": "Integer" + }, + "CreationTime": { + "PrimitiveType": "Integer" + }, + "CurrencyCode": { + "PrimitiveType": "String" + }, + "LastModifiedTime": { + "PrimitiveType": "Integer" + }, + "ProductCode": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-customlineitem.html", + "Properties": { + "BillingGroupArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-customlineitem.html#cfn-billingconductor-customlineitem-billinggrouparn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "BillingPeriodRange": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-customlineitem.html#cfn-billingconductor-customlineitem-billingperiodrange", + "Required": false, + "Type": "BillingPeriodRange", + "UpdateType": "Mutable" + }, + "CustomLineItemChargeDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-customlineitem.html#cfn-billingconductor-customlineitem-customlineitemchargedetails", + "Required": false, + "Type": "CustomLineItemChargeDetails", + "UpdateType": "Mutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-customlineitem.html#cfn-billingconductor-customlineitem-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-customlineitem.html#cfn-billingconductor-customlineitem-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::BillingConductor::PricingPlan": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "CreationTime": { + "PrimitiveType": "Integer" + }, + "LastModifiedTime": { + "PrimitiveType": "Integer" + }, + "Size": { + "PrimitiveType": "Integer" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-pricingplan.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-pricingplan.html#cfn-billingconductor-pricingplan-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-pricingplan.html#cfn-billingconductor-pricingplan-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "PricingRuleArns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-pricingplan.html#cfn-billingconductor-pricingplan-pricingrulearns", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::BillingConductor::PricingRule": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "AssociatedPricingPlanCount": { + "PrimitiveType": "Integer" + }, + "CreationTime": { + "PrimitiveType": "Integer" + }, + "LastModifiedTime": { + "PrimitiveType": "Integer" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-pricingrule.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-pricingrule.html#cfn-billingconductor-pricingrule-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ModifierPercentage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-pricingrule.html#cfn-billingconductor-pricingrule-modifierpercentage", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-pricingrule.html#cfn-billingconductor-pricingrule-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Scope": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-pricingrule.html#cfn-billingconductor-pricingrule-scope", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Service": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-pricingrule.html#cfn-billingconductor-pricingrule-service", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-billingconductor-pricingrule.html#cfn-billingconductor-pricingrule-type", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + } + } +} diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Budgets.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Budgets.json index 21261ffea10a2..f34a65e4c0867 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Budgets.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Budgets.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Budgets::Budget.BudgetData": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budget-budgetdata.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CE.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CE.json index f0293b0cd1398..6580dd1621100 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CE.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CE.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::CE::AnomalySubscription.Subscriber": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ce-anomalysubscription-subscriber.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CUR.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CUR.json index 2bceb82f06a84..8a351a0396b83 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CUR.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CUR.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::CUR::ReportDefinition": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Cassandra.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Cassandra.json index 8aaab11f74153..28fd524f70e6c 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Cassandra.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Cassandra.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Cassandra::Table.BillingMode": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cassandra-table-billingmode.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CertificateManager.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CertificateManager.json index cd30618345729..c1a95b5fefbd1 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CertificateManager.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CertificateManager.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::CertificateManager::Account.ExpiryEventsConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-certificatemanager-account-expiryeventsconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Chatbot.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Chatbot.json index 3bd60f8227e27..794d021976812 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Chatbot.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Chatbot.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::Chatbot::SlackChannelConfiguration": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Cloud9.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Cloud9.json index ac93f0d610f37..5c24f8d93de7a 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Cloud9.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Cloud9.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Cloud9::EnvironmentEC2.Repository": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloud9-environmentec2-repository.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CloudFormation.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CloudFormation.json index 7fc771cfd981c..edcd2c7e5dbdc 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CloudFormation.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CloudFormation.json @@ -1,6 +1,23 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { + "AWS::CloudFormation::HookVersion.LoggingConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudformation-hookversion-loggingconfig.html", + "Properties": { + "LogGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudformation-hookversion-loggingconfig.html#cfn-cloudformation-hookversion-loggingconfig-loggroupname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "LogRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudformation-hookversion-loggingconfig.html#cfn-cloudformation-hookversion-loggingconfig-logrolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::CloudFormation::ResourceVersion.LoggingConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudformation-resourceversion-loggingconfig.html", "Properties": { @@ -173,6 +190,114 @@ } } }, + "AWS::CloudFormation::HookDefaultVersion": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-hookdefaultversion.html", + "Properties": { + "TypeName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-hookdefaultversion.html#cfn-cloudformation-hookdefaultversion-typename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TypeVersionArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-hookdefaultversion.html#cfn-cloudformation-hookdefaultversion-typeversionarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "VersionId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-hookdefaultversion.html#cfn-cloudformation-hookdefaultversion-versionid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFormation::HookTypeConfig": { + "Attributes": { + "ConfigurationArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-hooktypeconfig.html", + "Properties": { + "Configuration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-hooktypeconfig.html#cfn-cloudformation-hooktypeconfig-configuration", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ConfigurationAlias": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-hooktypeconfig.html#cfn-cloudformation-hooktypeconfig-configurationalias", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "TypeArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-hooktypeconfig.html#cfn-cloudformation-hooktypeconfig-typearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "TypeName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-hooktypeconfig.html#cfn-cloudformation-hooktypeconfig-typename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFormation::HookVersion": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "IsDefaultVersion": { + "PrimitiveType": "Boolean" + }, + "TypeArn": { + "PrimitiveType": "String" + }, + "VersionId": { + "PrimitiveType": "String" + }, + "Visibility": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-hookversion.html", + "Properties": { + "ExecutionRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-hookversion.html#cfn-cloudformation-hookversion-executionrolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "LoggingConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-hookversion.html#cfn-cloudformation-hookversion-loggingconfig", + "Required": false, + "Type": "LoggingConfig", + "UpdateType": "Immutable" + }, + "SchemaHandlerPackage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-hookversion.html#cfn-cloudformation-hookversion-schemahandlerpackage", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "TypeName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-hookversion.html#cfn-cloudformation-hookversion-typename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::CloudFormation::Macro": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-macro.html", "Properties": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CloudFront.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CloudFront.json index 049274e5e148f..25fb68fcaa39f 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CloudFront.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CloudFront.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::CloudFront::CachePolicy.CachePolicyConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-cachepolicyconfig.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CloudTrail.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CloudTrail.json index 6b28233edb585..0b4a350d5338d 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CloudTrail.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CloudTrail.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::CloudTrail::Trail.DataResource": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudtrail-trail-dataresource.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CloudWatch.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CloudWatch.json index a25319217467f..2701350772f79 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CloudWatch.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CloudWatch.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::CloudWatch::Alarm.Dimension": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cw-dimension.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeArtifact.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeArtifact.json index da001a77fb200..3579558192d45 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeArtifact.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeArtifact.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::CodeArtifact::Domain": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeBuild.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeBuild.json index 28ab944945bb8..399e9f1cf84e7 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeBuild.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeBuild.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::CodeBuild::Project.Artifacts": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-artifacts.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeCommit.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeCommit.json index 07acf888e800d..06599a720ed62 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeCommit.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeCommit.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::CodeCommit::Repository.Code": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codecommit-repository-code.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeDeploy.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeDeploy.json index 522ce15ebab12..ccd78fd04514d 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeDeploy.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeDeploy.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::CodeDeploy::DeploymentConfig.MinimumHealthyHosts": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codedeploy-deploymentconfig-minimumhealthyhosts.html", @@ -350,6 +350,14 @@ "Required": false, "Type": "List", "UpdateType": "Mutable" + }, + "TargetGroupPairInfoList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codedeploy-deploymentgroup-loadbalancerinfo.html#cfn-codedeploy-deploymentgroup-loadbalancerinfo-targetgrouppairinfolist", + "DuplicatesAllowed": false, + "ItemType": "TargetGroupPairInfo", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" } } }, @@ -471,6 +479,44 @@ } } }, + "AWS::CodeDeploy::DeploymentGroup.TargetGroupPairInfo": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codedeploy-deploymentgroup-targetgrouppairinfo.html", + "Properties": { + "ProdTrafficRoute": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codedeploy-deploymentgroup-targetgrouppairinfo.html#cfn-codedeploy-deploymentgroup-targetgrouppairinfo-prodtrafficroute", + "Required": false, + "Type": "TrafficRoute", + "UpdateType": "Mutable" + }, + "TargetGroups": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codedeploy-deploymentgroup-targetgrouppairinfo.html#cfn-codedeploy-deploymentgroup-targetgrouppairinfo-targetgroups", + "DuplicatesAllowed": false, + "ItemType": "TargetGroupInfo", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "TestTrafficRoute": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codedeploy-deploymentgroup-targetgrouppairinfo.html#cfn-codedeploy-deploymentgroup-targetgrouppairinfo-testtrafficroute", + "Required": false, + "Type": "TrafficRoute", + "UpdateType": "Mutable" + } + } + }, + "AWS::CodeDeploy::DeploymentGroup.TrafficRoute": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codedeploy-deploymentgroup-trafficroute.html", + "Properties": { + "ListenerArns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codedeploy-deploymentgroup-trafficroute.html#cfn-codedeploy-deploymentgroup-trafficroute-listenerarns", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::CodeDeploy::DeploymentGroup.TriggerConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codedeploy-deploymentgroup-triggerconfig.html", "Properties": { @@ -653,12 +699,26 @@ "Type": "OnPremisesTagSet", "UpdateType": "Mutable" }, + "OutdatedInstancesStrategy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codedeploy-deploymentgroup.html#cfn-codedeploy-deploymentgroup-outdatedinstancesstrategy", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "ServiceRoleArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codedeploy-deploymentgroup.html#cfn-codedeploy-deploymentgroup-servicerolearn", "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codedeploy-deploymentgroup.html#cfn-codedeploy-deploymentgroup-tags", + "DuplicatesAllowed": true, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "TriggerConfigurations": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codedeploy-deploymentgroup.html#cfn-codedeploy-deploymentgroup-triggerconfigurations", "DuplicatesAllowed": false, diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeGuruProfiler.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeGuruProfiler.json index e362439ed19fd..47a53e3d951a5 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeGuruProfiler.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeGuruProfiler.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::CodeGuruProfiler::ProfilingGroup.Channel": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codeguruprofiler-profilinggroup-channel.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeGuruReviewer.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeGuruReviewer.json index 88c4a8d9d6e96..1eb469e8d43b6 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeGuruReviewer.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeGuruReviewer.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::CodeGuruReviewer::RepositoryAssociation": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodePipeline.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodePipeline.json index 6c33d2ccb550c..34854e1f5929c 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodePipeline.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodePipeline.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::CodePipeline::CustomActionType.ArtifactDetails": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codepipeline-customactiontype-artifactdetails.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeStar.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeStar.json index 8240299a91d81..ff55293cd2f65 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeStar.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeStar.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::CodeStar::GitHubRepository.Code": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codestar-githubrepository-code.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeStarConnections.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeStarConnections.json index ea08c32cd3a3a..1cb961d7c1c2c 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeStarConnections.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeStarConnections.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::CodeStarConnections::Connection": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeStarNotifications.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeStarNotifications.json index f75d675f37d48..c9986ae3f028a 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeStarNotifications.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CodeStarNotifications.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::CodeStarNotifications::NotificationRule.Target": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codestarnotifications-notificationrule-target.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Cognito.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Cognito.json index 192924f768b92..27efac0ea696c 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Cognito.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Cognito.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Cognito::IdentityPool.CognitoIdentityProvider": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-identitypool-cognitoidentityprovider.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Config.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Config.json index cd3a0f1b6552c..3c6a54684a0b9 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Config.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Config.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Config::ConfigRule.Scope": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-config-configrule-scope.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Connect.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Connect.json index 63f8d669d356f..1e9d3c2ddd409 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Connect.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Connect.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Connect::HoursOfOperation.HoursOfOperationConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-hoursofoperation-hoursofoperationconfig.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CustomerProfiles.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CustomerProfiles.json index 80e718c8ac52d..0f2b10fd0389a 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CustomerProfiles.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_CustomerProfiles.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::CustomerProfiles::Integration.ConnectorOperator": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-integration-connectoroperator.html", @@ -100,6 +100,23 @@ } } }, + "AWS::CustomerProfiles::Integration.ObjectTypeMapping": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-integration-objecttypemapping.html", + "Properties": { + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-integration-objecttypemapping.html#cfn-customerprofiles-integration-objecttypemapping-key", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-integration-objecttypemapping.html#cfn-customerprofiles-integration-objecttypemapping-value", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::CustomerProfiles::Integration.S3SourceProperties": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-integration-s3sourceproperties.html", "Properties": { @@ -504,7 +521,14 @@ "ObjectTypeName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-integration.html#cfn-customerprofiles-integration-objecttypename", "PrimitiveType": "String", - "Required": true, + "Required": false, + "UpdateType": "Mutable" + }, + "ObjectTypeNames": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-integration.html#cfn-customerprofiles-integration-objecttypenames", + "ItemType": "ObjectTypeMapping", + "Required": false, + "Type": "List", "UpdateType": "Mutable" }, "Tags": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DAX.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DAX.json index 6aca476bc1f50..235e5572d7403 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DAX.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DAX.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::DAX::Cluster.SSESpecification": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dax-cluster-ssespecification.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DLM.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DLM.json index 850025ef5f6cd..b4b642e1d4f9a 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DLM.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DLM.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::DLM::LifecyclePolicy.Action": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dlm-lifecyclepolicy-action.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DMS.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DMS.json index a1d9e5ddba098..357934de20f64 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DMS.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DMS.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::DMS::Endpoint.DocDbSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-docdbsettings.html", @@ -1048,7 +1048,7 @@ "ItemType": "Tag", "Required": false, "Type": "List", - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "Username": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-username", @@ -1111,12 +1111,10 @@ "AWS::DMS::ReplicationInstance": { "Attributes": { "ReplicationInstancePrivateIpAddresses": { - "PrimitiveItemType": "String", - "Type": "List" + "PrimitiveType": "String" }, "ReplicationInstancePublicIpAddresses": { - "PrimitiveItemType": "String", - "Type": "List" + "PrimitiveType": "String" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-replicationinstance.html", @@ -1242,7 +1240,7 @@ "ItemType": "Tag", "Required": false, "Type": "List", - "UpdateType": "Immutable" + "UpdateType": "Mutable" } } }, diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DataBrew.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DataBrew.json index 8b77b5cbb9249..9e211746a1002 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DataBrew.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DataBrew.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::DataBrew::Dataset.CsvOptions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-csvoptions.html", @@ -550,6 +550,12 @@ "Type": "S3Location", "UpdateType": "Mutable" }, + "MaxOutputFiles": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-job-output.html#cfn-databrew-job-output-maxoutputfiles", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, "Overwrite": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-job-output.html#cfn-databrew-job-output-overwrite", "PrimitiveType": "Boolean", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DataPipeline.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DataPipeline.json index ff0600d17062c..08c0b91c1a9b5 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DataPipeline.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DataPipeline.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::DataPipeline::Pipeline.Field": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-datapipeline-pipeline-pipelineobjects-fields.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DataSync.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DataSync.json index 1ab4af9aea0da..6814c2f59d551 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DataSync.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DataSync.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::DataSync::LocationEFS.Ec2Config": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-datasync-locationefs-ec2config.html", @@ -309,6 +309,46 @@ } } }, + "AWS::DataSync::LocationFSxLustre": { + "Attributes": { + "LocationArn": { + "PrimitiveType": "String" + }, + "LocationUri": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationfsxlustre.html", + "Properties": { + "FsxFilesystemArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationfsxlustre.html#cfn-datasync-locationfsxlustre-fsxfilesystemarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "SecurityGroupArns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationfsxlustre.html#cfn-datasync-locationfsxlustre-securitygrouparns", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Immutable" + }, + "Subdirectory": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationfsxlustre.html#cfn-datasync-locationfsxlustre-subdirectory", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationfsxlustre.html#cfn-datasync-locationfsxlustre-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::DataSync::LocationFSxWindows": { "Attributes": { "LocationArn": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Detective.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Detective.json index 645cdbf70594b..aadbfcb5da29e 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Detective.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Detective.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::Detective::Graph": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DevOpsGuru.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DevOpsGuru.json index acfd9cc24d352..3ff862dcd90e1 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DevOpsGuru.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DevOpsGuru.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::DevOpsGuru::NotificationChannel.NotificationChannelConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-devopsguru-notificationchannel-notificationchannelconfig.html", @@ -43,6 +43,31 @@ "Required": false, "Type": "CloudFormationCollectionFilter", "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-devopsguru-resourcecollection-resourcecollectionfilter.html#cfn-devopsguru-resourcecollection-resourcecollectionfilter-tags", + "ItemType": "TagCollection", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::DevOpsGuru::ResourceCollection.TagCollection": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-devopsguru-resourcecollection-tagcollection.html", + "Properties": { + "AppBoundaryKey": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-devopsguru-resourcecollection-tagcollection.html#cfn-devopsguru-resourcecollection-tagcollection-appboundarykey", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TagValues": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-devopsguru-resourcecollection-tagcollection.html#cfn-devopsguru-resourcecollection-tagcollection-tagvalues", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" } } } diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DirectoryService.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DirectoryService.json index 9bb6e5416f015..8176716fdfebc 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DirectoryService.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DirectoryService.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::DirectoryService::MicrosoftAD.VpcSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-directoryservice-microsoftad-vpcsettings.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DocDB.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DocDB.json index 368dffa6f0364..1859ee015f0a9 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DocDB.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DocDB.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::DocDB::DBCluster": { @@ -32,6 +32,12 @@ "Required": false, "UpdateType": "Mutable" }, + "CopyTagsToSnapshot": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-docdb-dbcluster.html#cfn-docdb-dbcluster-copytagstosnapshot", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "DBClusterIdentifier": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-docdb-dbcluster.html#cfn-docdb-dbcluster-dbclusteridentifier", "PrimitiveType": "String", @@ -78,13 +84,13 @@ "MasterUserPassword": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-docdb-dbcluster.html#cfn-docdb-dbcluster-masteruserpassword", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Mutable" }, "MasterUsername": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-docdb-dbcluster.html#cfn-docdb-dbcluster-masterusername", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Immutable" }, "Port": { @@ -210,6 +216,12 @@ "Required": false, "UpdateType": "Immutable" }, + "EnablePerformanceInsights": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-docdb-dbinstance.html#cfn-docdb-dbinstance-enableperformanceinsights", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "PreferredMaintenanceWindow": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-docdb-dbinstance.html#cfn-docdb-dbinstance-preferredmaintenancewindow", "PrimitiveType": "String", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DynamoDB.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DynamoDB.json index b9ca44fbd8295..8310e71d5bcd4 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DynamoDB.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_DynamoDB.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::DynamoDB::GlobalTable.AttributeDefinition": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-globaltable-attributedefinition.html", @@ -253,6 +253,12 @@ "Type": "ReplicaSSESpecification", "UpdateType": "Mutable" }, + "TableClass": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-globaltable-replicaspecification.html#cfn-dynamodb-globaltable-replicaspecification-tableclass", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-globaltable-replicaspecification.html#cfn-dynamodb-globaltable-replicaspecification-tags", "DuplicatesAllowed": false, diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EC2.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EC2.json index 172c14bea5a1e..add912221c1d1 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EC2.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EC2.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::EC2::CapacityReservation.TagSpecification": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-capacityreservation-tagspecification.html", @@ -1171,6 +1171,29 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance-nodevice.html", "Properties": {} }, + "AWS::EC2::Instance.PrivateDnsNameOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance-privatednsnameoptions.html", + "Properties": { + "EnableResourceNameDnsAAAARecord": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance-privatednsnameoptions.html#cfn-ec2-instance-privatednsnameoptions-enableresourcenamednsaaaarecord", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "EnableResourceNameDnsARecord": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance-privatednsnameoptions.html#cfn-ec2-instance-privatednsnameoptions-enableresourcenamednsarecord", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "HostnameType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance-privatednsnameoptions.html#cfn-ec2-instance-privatednsnameoptions-hostnametype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::EC2::Instance.PrivateIpAddressSpecification": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-network-interface-privateipspec.html", "Properties": { @@ -1624,6 +1647,17 @@ } } }, + "AWS::EC2::LaunchTemplate.Ipv4PrefixSpecification": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-ipv4prefixspecification.html", + "Properties": { + "Ipv4Prefix": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-ipv4prefixspecification.html#cfn-ec2-launchtemplate-ipv4prefixspecification-ipv4prefix", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::EC2::LaunchTemplate.Ipv6Add": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-ipv6add.html", "Properties": { @@ -1635,6 +1669,17 @@ } } }, + "AWS::EC2::LaunchTemplate.Ipv6PrefixSpecification": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-ipv6prefixspecification.html", + "Properties": { + "Ipv6Prefix": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-ipv6prefixspecification.html#cfn-ec2-launchtemplate-ipv6prefixspecification-ipv6prefix", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::EC2::LaunchTemplate.LaunchTemplateData": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-launchtemplatedata.html", "Properties": { @@ -1994,6 +2039,19 @@ "Required": false, "UpdateType": "Mutable" }, + "Ipv4PrefixCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-networkinterface.html#cfn-ec2-launchtemplate-networkinterface-ipv4prefixcount", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Ipv4Prefixes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-networkinterface.html#cfn-ec2-launchtemplate-networkinterface-ipv4prefixes", + "ItemType": "Ipv4PrefixSpecification", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "Ipv6AddressCount": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-networkinterface.html#cfn-ec2-launchtemplate-networkinterface-ipv6addresscount", "PrimitiveType": "Integer", @@ -2007,6 +2065,19 @@ "Type": "List", "UpdateType": "Mutable" }, + "Ipv6PrefixCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-networkinterface.html#cfn-ec2-launchtemplate-networkinterface-ipv6prefixcount", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Ipv6Prefixes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-networkinterface.html#cfn-ec2-launchtemplate-networkinterface-ipv6prefixes", + "ItemType": "Ipv6PrefixSpecification", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "NetworkCardIndex": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-networkinterface.html#cfn-ec2-launchtemplate-networkinterface-networkcardindex", "PrimitiveType": "Integer", @@ -3664,6 +3735,12 @@ "Required": false, "UpdateType": "Immutable" }, + "Priority": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-launchtemplateoverrides.html#cfn-ec2-spotfleet-launchtemplateoverrides-priority", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Immutable" + }, "SpotPrice": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-launchtemplateoverrides.html#cfn-ec2-spotfleet-launchtemplateoverrides-spotprice", "PrimitiveType": "String", @@ -4198,17 +4275,6 @@ } } }, - "AWS::EC2::TransitGatewayPeeringAttachment.TransitGatewayPeeringAttachmentOptions": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-transitgatewaypeeringattachment-transitgatewaypeeringattachmentoptions.html", - "Properties": { - "DynamicRouting": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-transitgatewaypeeringattachment-transitgatewaypeeringattachmentoptions.html#cfn-ec2-transitgatewaypeeringattachment-transitgatewaypeeringattachmentoptions-dynamicrouting", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - } - } - }, "AWS::EC2::VPNConnection.VpnTunnelOptionsSpecification": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-vpnconnection-vpntunneloptionsspecification.html", "Properties": { @@ -5465,6 +5531,12 @@ "Required": false, "UpdateType": "Immutable" }, + "PrivateDnsNameOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-privatednsnameoptions", + "Required": false, + "Type": "PrivateDnsNameOptions", + "UpdateType": "Conditional" + }, "PrivateIpAddress": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-privateipaddress", "PrimitiveType": "String", @@ -6515,6 +6587,7 @@ "PrimitiveType": "String" }, "Ipv6CidrBlocks": { + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Type": "List" }, @@ -6524,6 +6597,9 @@ "OutpostArn": { "PrimitiveType": "String" }, + "SubnetId": { + "PrimitiveType": "String" + }, "VpcId": { "PrimitiveType": "String" } @@ -6542,18 +6618,36 @@ "Required": false, "UpdateType": "Immutable" }, + "AvailabilityZoneId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html#cfn-ec2-subnet-availabilityzoneid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "CidrBlock": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html#cfn-ec2-subnet-cidrblock", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Immutable" }, + "EnableDns64": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html#cfn-ec2-subnet-enabledns64", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "Ipv6CidrBlock": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html#cfn-ec2-subnet-ipv6cidrblock", "PrimitiveType": "String", "Required": false, "UpdateType": "Mutable" }, + "Ipv6Native": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html#cfn-ec2-subnet-ipv6native", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Immutable" + }, "MapPublicIpOnLaunch": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html#cfn-ec2-subnet-mappubliciponlaunch", "PrimitiveType": "Boolean", @@ -6566,6 +6660,12 @@ "Required": false, "UpdateType": "Immutable" }, + "PrivateDnsNameOptionsOnLaunch": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html#cfn-ec2-subnet-privatednsnameoptionsonlaunch", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html#cfn-ec2-subnet-tags", "DuplicatesAllowed": true, @@ -6575,7 +6675,7 @@ "UpdateType": "Mutable" }, "VpcId": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html#cfn-awsec2subnet-prop-vpcid", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html#cfn-ec2-subnet-vpcid", "PrimitiveType": "String", "Required": true, "UpdateType": "Immutable" @@ -7155,12 +7255,6 @@ }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaypeeringattachment.html", "Properties": { - "Options": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaypeeringattachment.html#cfn-ec2-transitgatewaypeeringattachment-options", - "Required": false, - "Type": "TransitGatewayPeeringAttachmentOptions", - "UpdateType": "Mutable" - }, "PeerAccountId": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaypeeringattachment.html#cfn-ec2-transitgatewaypeeringattachment-peeraccountid", "PrimitiveType": "String", @@ -7309,7 +7403,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewayvpcattachment.html#cfn-ec2-transitgatewayvpcattachment-subnetids", "DuplicatesAllowed": true, "PrimitiveItemType": "String", - "Required": false, + "Required": true, "Type": "List", "UpdateType": "Immutable" }, @@ -7324,13 +7418,13 @@ "TransitGatewayId": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewayvpcattachment.html#cfn-ec2-transitgatewayvpcattachment-transitgatewayid", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Immutable" }, "VpcId": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewayvpcattachment.html#cfn-ec2-transitgatewayvpcattachment-vpcid", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Immutable" } } @@ -7381,6 +7475,18 @@ "Required": false, "UpdateType": "Mutable" }, + "Ipv4IpamPoolId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpc.html#cfn-ec2-vpc-ipv4ipampoolid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Ipv4NetmaskLength": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpc.html#cfn-ec2-vpc-ipv4netmasklength", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpc.html#cfn-aws-ec2-vpc-tags", "DuplicatesAllowed": true, @@ -7406,12 +7512,36 @@ "Required": false, "UpdateType": "Immutable" }, + "Ipv4IpamPoolId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpccidrblock.html#cfn-ec2-vpccidrblock-ipv4ipampoolid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Ipv4NetmaskLength": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpccidrblock.html#cfn-ec2-vpccidrblock-ipv4netmasklength", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, "Ipv6CidrBlock": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpccidrblock.html#cfn-ec2-vpccidrblock-ipv6cidrblock", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" }, + "Ipv6IpamPoolId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpccidrblock.html#cfn-ec2-vpccidrblock-ipv6ipampoolid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Ipv6NetmaskLength": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpccidrblock.html#cfn-ec2-vpccidrblock-ipv6netmasklength", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, "Ipv6Pool": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpccidrblock.html#cfn-ec2-vpccidrblock-ipv6pool", "PrimitiveType": "String", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ECR.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ECR.json index 3b8532774b0ca..b4dbc946f2272 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ECR.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ECR.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::ECR::ReplicationConfiguration.ReplicationConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecr-replicationconfiguration-replicationconfiguration.html", @@ -149,6 +149,23 @@ } } }, + "AWS::ECR::PullThroughCacheRule": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecr-pullthroughcacherule.html", + "Properties": { + "EcrRepositoryPrefix": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecr-pullthroughcacherule.html#cfn-ecr-pullthroughcacherule-ecrrepositoryprefix", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "UpstreamRegistryUrl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecr-pullthroughcacherule.html#cfn-ecr-pullthroughcacherule-upstreamregistryurl", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::ECR::RegistryPolicy": { "Attributes": { "RegistryId": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ECS.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ECS.json index 582d346c15d1b..16b5685a9268a 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ECS.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ECS.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::ECS::CapacityProvider.AutoScalingGroupProvider": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-capacityprovider-autoscalinggroupprovider.html", @@ -297,25 +297,25 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-loadbalancer.html#cfn-ecs-service-loadbalancer-containername", "PrimitiveType": "String", "Required": false, - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "ContainerPort": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-loadbalancer.html#cfn-ecs-service-loadbalancer-containerport", "PrimitiveType": "Integer", "Required": false, - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "LoadBalancerName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-loadbalancer.html#cfn-ecs-service-loadbalancer-loadbalancername", "PrimitiveType": "String", "Required": false, - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "TargetGroupArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-loadbalancer.html#cfn-ecs-service-loadbalancer-targetgrouparn", "PrimitiveType": "String", "Required": false, - "UpdateType": "Immutable" + "UpdateType": "Mutable" } } }, @@ -371,25 +371,25 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceregistry.html#cfn-ecs-service-serviceregistry-containername", "PrimitiveType": "String", "Required": false, - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "ContainerPort": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceregistry.html#cfn-ecs-service-serviceregistry-containerport", "PrimitiveType": "Integer", "Required": false, - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "Port": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceregistry.html#cfn-ecs-service-serviceregistry-port", "PrimitiveType": "Integer", "Required": false, - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "RegistryArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceregistry.html#cfn-ecs-service-serviceregistry-registryarn", "PrimitiveType": "String", "Required": false, - "UpdateType": "Immutable" + "UpdateType": "Mutable" } } }, @@ -1565,7 +1565,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-enableecsmanagedtags", "PrimitiveType": "Boolean", "Required": false, - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "EnableExecuteCommand": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-enableexecutecommand", @@ -1590,7 +1590,7 @@ "ItemType": "LoadBalancer", "Required": false, "Type": "List", - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "NetworkConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-networkconfiguration", @@ -1622,7 +1622,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-propagatetags", "PrimitiveType": "String", "Required": false, - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "Role": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-role", @@ -1647,7 +1647,7 @@ "ItemType": "ServiceRegistry", "Required": false, "Type": "List", - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-tags", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EFS.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EFS.json index 2f26af488938a..5743efb5a34eb 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EFS.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EFS.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::EFS::AccessPoint.AccessPointTag": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-efs-accesspoint-accesspointtag.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EKS.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EKS.json index e9d8dea8f5b97..feb909598c490 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EKS.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EKS.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::EKS::Cluster.ClusterLogging": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-clusterlogging.html", @@ -149,6 +149,72 @@ } } }, + "AWS::EKS::IdentityProviderConfig.OidcIdentityProviderConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-identityproviderconfig-oidcidentityproviderconfig.html", + "Properties": { + "ClientId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-identityproviderconfig-oidcidentityproviderconfig.html#cfn-eks-identityproviderconfig-oidcidentityproviderconfig-clientid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "GroupsClaim": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-identityproviderconfig-oidcidentityproviderconfig.html#cfn-eks-identityproviderconfig-oidcidentityproviderconfig-groupsclaim", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "GroupsPrefix": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-identityproviderconfig-oidcidentityproviderconfig.html#cfn-eks-identityproviderconfig-oidcidentityproviderconfig-groupsprefix", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "IssuerUrl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-identityproviderconfig-oidcidentityproviderconfig.html#cfn-eks-identityproviderconfig-oidcidentityproviderconfig-issuerurl", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "RequiredClaims": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-identityproviderconfig-oidcidentityproviderconfig.html#cfn-eks-identityproviderconfig-oidcidentityproviderconfig-requiredclaims", + "DuplicatesAllowed": false, + "ItemType": "RequiredClaim", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "UsernameClaim": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-identityproviderconfig-oidcidentityproviderconfig.html#cfn-eks-identityproviderconfig-oidcidentityproviderconfig-usernameclaim", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "UsernamePrefix": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-identityproviderconfig-oidcidentityproviderconfig.html#cfn-eks-identityproviderconfig-oidcidentityproviderconfig-usernameprefix", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::EKS::IdentityProviderConfig.RequiredClaim": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-identityproviderconfig-requiredclaim.html", + "Properties": { + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-identityproviderconfig-requiredclaim.html#cfn-eks-identityproviderconfig-requiredclaim-key", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-identityproviderconfig-requiredclaim.html#cfn-eks-identityproviderconfig-requiredclaim-value", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::EKS::Nodegroup.LaunchTemplateSpecification": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-nodegroup-launchtemplatespecification.html", "Properties": { @@ -183,6 +249,7 @@ }, "SourceSecurityGroups": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-nodegroup-remoteaccess.html#cfn-eks-nodegroup-remoteaccess-sourcesecuritygroups", + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": false, "Type": "List", @@ -195,19 +262,19 @@ "Properties": { "DesiredSize": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-nodegroup-scalingconfig.html#cfn-eks-nodegroup-scalingconfig-desiredsize", - "PrimitiveType": "Double", + "PrimitiveType": "Integer", "Required": false, "UpdateType": "Mutable" }, "MaxSize": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-nodegroup-scalingconfig.html#cfn-eks-nodegroup-scalingconfig-maxsize", - "PrimitiveType": "Double", + "PrimitiveType": "Integer", "Required": false, "UpdateType": "Mutable" }, "MinSize": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-nodegroup-scalingconfig.html#cfn-eks-nodegroup-scalingconfig-minsize", - "PrimitiveType": "Double", + "PrimitiveType": "Integer", "Required": false, "UpdateType": "Mutable" } @@ -432,6 +499,48 @@ } } }, + "AWS::EKS::IdentityProviderConfig": { + "Attributes": { + "IdentityProviderConfigArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-identityproviderconfig.html", + "Properties": { + "ClusterName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-identityproviderconfig.html#cfn-eks-identityproviderconfig-clustername", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "IdentityProviderConfigName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-identityproviderconfig.html#cfn-eks-identityproviderconfig-identityproviderconfigname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Oidc": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-identityproviderconfig.html#cfn-eks-identityproviderconfig-oidc", + "Required": false, + "Type": "OidcIdentityProviderConfig", + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-identityproviderconfig.html#cfn-eks-identityproviderconfig-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-identityproviderconfig.html#cfn-eks-identityproviderconfig-type", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::EKS::Nodegroup": { "Attributes": { "Arn": { @@ -440,6 +549,9 @@ "ClusterName": { "PrimitiveType": "String" }, + "Id": { + "PrimitiveType": "String" + }, "NodegroupName": { "PrimitiveType": "String" } @@ -466,7 +578,7 @@ }, "DiskSize": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html#cfn-eks-nodegroup-disksize", - "PrimitiveType": "Double", + "PrimitiveType": "Integer", "Required": false, "UpdateType": "Immutable" }, @@ -478,6 +590,7 @@ }, "InstanceTypes": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html#cfn-eks-nodegroup-instancetypes", + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": false, "Type": "List", @@ -527,6 +640,7 @@ }, "Subnets": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html#cfn-eks-nodegroup-subnets", + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": true, "Type": "List", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EMR.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EMR.json index 92fa75d2b18ae..7ba86fe7a46b9 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EMR.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EMR.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::EMR::Cluster.Application": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticmapreduce-cluster-application.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EMRContainers.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EMRContainers.json index f6836df27dcbd..7d233bd95ccd6 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EMRContainers.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EMRContainers.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::EMRContainers::VirtualCluster.ContainerInfo": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-emrcontainers-virtualcluster-containerinfo.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ElastiCache.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ElastiCache.json index 17ee5a2590c97..007147c8d8854 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ElastiCache.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ElastiCache.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::ElastiCache::CacheCluster.CloudWatchLogsDestinationDetails": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-cachecluster-cloudwatchlogsdestinationdetails.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ElasticBeanstalk.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ElasticBeanstalk.json index b70b995c3aea1..ae516f1ac53db 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ElasticBeanstalk.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ElasticBeanstalk.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::ElasticBeanstalk::Application.ApplicationResourceLifecycleConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticbeanstalk-application-applicationresourcelifecycleconfig.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ElasticLoadBalancing.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ElasticLoadBalancing.json index 94bdd0778e37e..bb6cc2dce74a5 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ElasticLoadBalancing.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ElasticLoadBalancing.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::ElasticLoadBalancing::LoadBalancer.AccessLoggingPolicy": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-elb-accessloggingpolicy.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ElasticLoadBalancingV2.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ElasticLoadBalancingV2.json index bfe98c91f573c..6e5f45f6304b4 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ElasticLoadBalancingV2.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ElasticLoadBalancingV2.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::ElasticLoadBalancingV2::Listener.Action": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticloadbalancingv2-listener-action.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Elasticsearch.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Elasticsearch.json index 8e984f365afc8..c60d403cdec7f 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Elasticsearch.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Elasticsearch.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Elasticsearch::Domain.AdvancedSecurityOptionsInput": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticsearch-domain-advancedsecurityoptionsinput.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EventSchemas.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EventSchemas.json index 817118cdb1009..4c209deab4b5f 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EventSchemas.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_EventSchemas.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::EventSchemas::Discoverer.TagsEntry": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eventschemas-discoverer-tagsentry.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Events.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Events.json index c7f4c423929dd..d9bf0d2663bef 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Events.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Events.json @@ -1,6 +1,164 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { + "AWS::Events::Connection.ApiKeyAuthParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-apikeyauthparameters.html", + "Properties": { + "ApiKeyName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-apikeyauthparameters.html#cfn-events-connection-apikeyauthparameters-apikeyname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ApiKeyValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-apikeyauthparameters.html#cfn-events-connection-apikeyauthparameters-apikeyvalue", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Events::Connection.AuthParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-authparameters.html", + "Properties": { + "ApiKeyAuthParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-authparameters.html#cfn-events-connection-authparameters-apikeyauthparameters", + "Required": false, + "Type": "ApiKeyAuthParameters", + "UpdateType": "Mutable" + }, + "BasicAuthParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-authparameters.html#cfn-events-connection-authparameters-basicauthparameters", + "Required": false, + "Type": "BasicAuthParameters", + "UpdateType": "Mutable" + }, + "InvocationHttpParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-authparameters.html#cfn-events-connection-authparameters-invocationhttpparameters", + "Required": false, + "Type": "ConnectionHttpParameters", + "UpdateType": "Mutable" + }, + "OAuthParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-authparameters.html#cfn-events-connection-authparameters-oauthparameters", + "Required": false, + "Type": "OAuthParameters", + "UpdateType": "Mutable" + } + } + }, + "AWS::Events::Connection.BasicAuthParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-basicauthparameters.html", + "Properties": { + "Password": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-basicauthparameters.html#cfn-events-connection-basicauthparameters-password", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Username": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-basicauthparameters.html#cfn-events-connection-basicauthparameters-username", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Events::Connection.ClientParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-clientparameters.html", + "Properties": { + "ClientID": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-clientparameters.html#cfn-events-connection-clientparameters-clientid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ClientSecret": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-clientparameters.html#cfn-events-connection-clientparameters-clientsecret", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Events::Connection.ConnectionHttpParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-connectionhttpparameters.html", + "Properties": { + "BodyParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-connectionhttpparameters.html#cfn-events-connection-connectionhttpparameters-bodyparameters", + "ItemType": "Parameter", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "HeaderParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-connectionhttpparameters.html#cfn-events-connection-connectionhttpparameters-headerparameters", + "ItemType": "Parameter", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "QueryStringParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-connectionhttpparameters.html#cfn-events-connection-connectionhttpparameters-querystringparameters", + "ItemType": "Parameter", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Events::Connection.OAuthParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-oauthparameters.html", + "Properties": { + "AuthorizationEndpoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-oauthparameters.html#cfn-events-connection-oauthparameters-authorizationendpoint", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ClientParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-oauthparameters.html#cfn-events-connection-oauthparameters-clientparameters", + "Required": true, + "Type": "ClientParameters", + "UpdateType": "Mutable" + }, + "HttpMethod": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-oauthparameters.html#cfn-events-connection-oauthparameters-httpmethod", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "OAuthHttpParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-oauthparameters.html#cfn-events-connection-oauthparameters-oauthhttpparameters", + "Required": false, + "Type": "ConnectionHttpParameters", + "UpdateType": "Mutable" + } + } + }, + "AWS::Events::Connection.Parameter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-parameter.html", + "Properties": { + "IsValueSecret": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-parameter.html#cfn-events-connection-parameter-isvaluesecret", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-parameter.html#cfn-events-connection-parameter-key", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-connection-parameter.html#cfn-events-connection-parameter-value", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::Events::EventBus.TagEntry": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-eventbus-tagentry.html", "Properties": { @@ -707,8 +865,8 @@ "Properties": { "AuthParameters": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-events-connection.html#cfn-events-connection-authparameters", - "PrimitiveType": "Json", "Required": true, + "Type": "AuthParameters", "UpdateType": "Mutable" }, "AuthorizationType": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Evidently.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Evidently.json index de3b9b06340f1..93da0b6ed6a2a 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Evidently.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Evidently.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Evidently::Experiment.MetricGoalObject": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-evidently-experiment-metricgoalobject.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FIS.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FIS.json index 4de7c37bb7ffc..6aeb599eefd2f 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FIS.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FIS.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::FIS::ExperimentTemplate.ExperimentTemplateAction": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplateaction.html", @@ -39,6 +39,29 @@ } } }, + "AWS::FIS::ExperimentTemplate.ExperimentTemplateLogConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatelogconfiguration.html", + "Properties": { + "CloudWatchLogsConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatelogconfiguration.html#cfn-fis-experimenttemplate-experimenttemplatelogconfiguration-cloudwatchlogsconfiguration", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + }, + "LogSchemaVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatelogconfiguration.html#cfn-fis-experimenttemplate-experimenttemplatelogconfiguration-logschemaversion", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + }, + "S3Configuration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatelogconfiguration.html#cfn-fis-experimenttemplate-experimenttemplatelogconfiguration-s3configuration", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::FIS::ExperimentTemplate.ExperimentTemplateStopCondition": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatestopcondition.html", "Properties": { @@ -66,6 +89,13 @@ "Type": "List", "UpdateType": "Mutable" }, + "Parameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatetarget.html#cfn-fis-experimenttemplate-experimenttemplatetarget-parameters", + "PrimitiveItemType": "String", + "Required": false, + "Type": "Map", + "UpdateType": "Mutable" + }, "ResourceArns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatetarget.html#cfn-fis-experimenttemplate-experimenttemplatetarget-resourcearns", "PrimitiveItemType": "String", @@ -135,6 +165,12 @@ "Required": true, "UpdateType": "Mutable" }, + "LogConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fis-experimenttemplate.html#cfn-fis-experimenttemplate-logconfiguration", + "Required": false, + "Type": "ExperimentTemplateLogConfiguration", + "UpdateType": "Mutable" + }, "RoleArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fis-experimenttemplate.html#cfn-fis-experimenttemplate-rolearn", "PrimitiveType": "String", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FMS.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FMS.json index cf7a8a4deea45..46aa360260463 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FMS.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FMS.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::FMS::Policy.IEMap": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fms-policy-iemap.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FSx.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FSx.json index 2f2e73e42201e..74c31ec547be8 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FSx.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FSx.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::FSx::FileSystem.AuditLogConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-filesystem-windowsconfiguration-auditlogconfiguration.html", @@ -253,6 +253,13 @@ "Type": "DiskIopsConfiguration", "UpdateType": "Immutable" }, + "Options": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-filesystem-openzfsconfiguration.html#cfn-fsx-filesystem-openzfsconfiguration-options", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "RootVolumeConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-filesystem-openzfsconfiguration.html#cfn-fsx-filesystem-openzfsconfiguration-rootvolumeconfiguration", "Required": false, @@ -301,6 +308,12 @@ "Required": false, "UpdateType": "Immutable" }, + "RecordSizeKiB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-filesystem-openzfsconfiguration-rootvolumeconfiguration.html#cfn-fsx-filesystem-openzfsconfiguration-rootvolumeconfiguration-recordsizekib", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, "UserAndGroupQuotas": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-filesystem-openzfsconfiguration-rootvolumeconfiguration.html#cfn-fsx-filesystem-openzfsconfiguration-rootvolumeconfiguration-userandgroupquotas", "ItemType": "UserAndGroupQuotas", @@ -446,6 +459,267 @@ "UpdateType": "Mutable" } } + }, + "AWS::FSx::StorageVirtualMachine.ActiveDirectoryConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-storagevirtualmachine-activedirectoryconfiguration.html", + "Properties": { + "NetBiosName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-storagevirtualmachine-activedirectoryconfiguration.html#cfn-fsx-storagevirtualmachine-activedirectoryconfiguration-netbiosname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "SelfManagedActiveDirectoryConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-storagevirtualmachine-activedirectoryconfiguration.html#cfn-fsx-storagevirtualmachine-activedirectoryconfiguration-selfmanagedactivedirectoryconfiguration", + "Required": false, + "Type": "SelfManagedActiveDirectoryConfiguration", + "UpdateType": "Mutable" + } + } + }, + "AWS::FSx::StorageVirtualMachine.SelfManagedActiveDirectoryConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-storagevirtualmachine-activedirectoryconfiguration-selfmanagedactivedirectoryconfiguration.html", + "Properties": { + "DnsIps": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-storagevirtualmachine-activedirectoryconfiguration-selfmanagedactivedirectoryconfiguration.html#cfn-fsx-storagevirtualmachine-activedirectoryconfiguration-selfmanagedactivedirectoryconfiguration-dnsips", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "DomainName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-storagevirtualmachine-activedirectoryconfiguration-selfmanagedactivedirectoryconfiguration.html#cfn-fsx-storagevirtualmachine-activedirectoryconfiguration-selfmanagedactivedirectoryconfiguration-domainname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "FileSystemAdministratorsGroup": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-storagevirtualmachine-activedirectoryconfiguration-selfmanagedactivedirectoryconfiguration.html#cfn-fsx-storagevirtualmachine-activedirectoryconfiguration-selfmanagedactivedirectoryconfiguration-filesystemadministratorsgroup", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "OrganizationalUnitDistinguishedName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-storagevirtualmachine-activedirectoryconfiguration-selfmanagedactivedirectoryconfiguration.html#cfn-fsx-storagevirtualmachine-activedirectoryconfiguration-selfmanagedactivedirectoryconfiguration-organizationalunitdistinguishedname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Password": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-storagevirtualmachine-activedirectoryconfiguration-selfmanagedactivedirectoryconfiguration.html#cfn-fsx-storagevirtualmachine-activedirectoryconfiguration-selfmanagedactivedirectoryconfiguration-password", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "UserName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-storagevirtualmachine-activedirectoryconfiguration-selfmanagedactivedirectoryconfiguration.html#cfn-fsx-storagevirtualmachine-activedirectoryconfiguration-selfmanagedactivedirectoryconfiguration-username", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::FSx::Volume.ClientConfigurations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration-nfsexports-clientconfigurations.html", + "Properties": { + "Clients": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration-nfsexports-clientconfigurations.html#cfn-fsx-volume-openzfsconfiguration-nfsexports-clientconfigurations-clients", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Options": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration-nfsexports-clientconfigurations.html#cfn-fsx-volume-openzfsconfiguration-nfsexports-clientconfigurations-options", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::FSx::Volume.NfsExports": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration-nfsexports.html", + "Properties": { + "ClientConfigurations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration-nfsexports.html#cfn-fsx-volume-openzfsconfiguration-nfsexports-clientconfigurations", + "ItemType": "ClientConfigurations", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::FSx::Volume.OntapConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-ontapconfiguration.html", + "Properties": { + "JunctionPath": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-ontapconfiguration.html#cfn-fsx-volume-ontapconfiguration-junctionpath", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "SecurityStyle": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-ontapconfiguration.html#cfn-fsx-volume-ontapconfiguration-securitystyle", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SizeInMegabytes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-ontapconfiguration.html#cfn-fsx-volume-ontapconfiguration-sizeinmegabytes", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "StorageEfficiencyEnabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-ontapconfiguration.html#cfn-fsx-volume-ontapconfiguration-storageefficiencyenabled", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "StorageVirtualMachineId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-ontapconfiguration.html#cfn-fsx-volume-ontapconfiguration-storagevirtualmachineid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "TieringPolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-ontapconfiguration.html#cfn-fsx-volume-ontapconfiguration-tieringpolicy", + "Required": false, + "Type": "TieringPolicy", + "UpdateType": "Mutable" + } + } + }, + "AWS::FSx::Volume.OpenZFSConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration.html", + "Properties": { + "CopyTagsToSnapshots": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration.html#cfn-fsx-volume-openzfsconfiguration-copytagstosnapshots", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "DataCompressionType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration.html#cfn-fsx-volume-openzfsconfiguration-datacompressiontype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "NfsExports": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration.html#cfn-fsx-volume-openzfsconfiguration-nfsexports", + "ItemType": "NfsExports", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Options": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration.html#cfn-fsx-volume-openzfsconfiguration-options", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "OriginSnapshot": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration.html#cfn-fsx-volume-openzfsconfiguration-originsnapshot", + "Required": false, + "Type": "OriginSnapshot", + "UpdateType": "Immutable" + }, + "ParentVolumeId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration.html#cfn-fsx-volume-openzfsconfiguration-parentvolumeid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "ReadOnly": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration.html#cfn-fsx-volume-openzfsconfiguration-readonly", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "RecordSizeKiB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration.html#cfn-fsx-volume-openzfsconfiguration-recordsizekib", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "StorageCapacityQuotaGiB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration.html#cfn-fsx-volume-openzfsconfiguration-storagecapacityquotagib", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "StorageCapacityReservationGiB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration.html#cfn-fsx-volume-openzfsconfiguration-storagecapacityreservationgib", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "UserAndGroupQuotas": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration.html#cfn-fsx-volume-openzfsconfiguration-userandgroupquotas", + "ItemType": "UserAndGroupQuotas", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::FSx::Volume.OriginSnapshot": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration-originsnapshot.html", + "Properties": { + "CopyStrategy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration-originsnapshot.html#cfn-fsx-volume-openzfsconfiguration-originsnapshot-copystrategy", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "SnapshotARN": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration-originsnapshot.html#cfn-fsx-volume-openzfsconfiguration-originsnapshot-snapshotarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::FSx::Volume.TieringPolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-ontapconfiguration-tieringpolicy.html", + "Properties": { + "CoolingPeriod": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-ontapconfiguration-tieringpolicy.html#cfn-fsx-volume-ontapconfiguration-tieringpolicy-coolingperiod", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-ontapconfiguration-tieringpolicy.html#cfn-fsx-volume-ontapconfiguration-tieringpolicy-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::FSx::Volume.UserAndGroupQuotas": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration-userandgroupquotas.html", + "Properties": { + "Id": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration-userandgroupquotas.html#cfn-fsx-volume-openzfsconfiguration-userandgroupquotas-id", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + }, + "StorageCapacityQuotaGiB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration-userandgroupquotas.html#cfn-fsx-volume-openzfsconfiguration-userandgroupquotas-storagecapacityquotagib", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration-userandgroupquotas.html#cfn-fsx-volume-openzfsconfiguration-userandgroupquotas-type", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } } }, "ResourceTypes": { @@ -545,6 +819,141 @@ "UpdateType": "Mutable" } } + }, + "AWS::FSx::Snapshot": { + "Attributes": { + "ResourceARN": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-snapshot.html", + "Properties": { + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-snapshot.html#cfn-fsx-snapshot-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-snapshot.html#cfn-fsx-snapshot-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "VolumeId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-snapshot.html#cfn-fsx-snapshot-volumeid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::FSx::StorageVirtualMachine": { + "Attributes": { + "ResourceARN": { + "PrimitiveType": "String" + }, + "StorageVirtualMachineId": { + "PrimitiveType": "String" + }, + "UUID": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-storagevirtualmachine.html", + "Properties": { + "ActiveDirectoryConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-storagevirtualmachine.html#cfn-fsx-storagevirtualmachine-activedirectoryconfiguration", + "Required": false, + "Type": "ActiveDirectoryConfiguration", + "UpdateType": "Mutable" + }, + "FileSystemId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-storagevirtualmachine.html#cfn-fsx-storagevirtualmachine-filesystemid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-storagevirtualmachine.html#cfn-fsx-storagevirtualmachine-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "RootVolumeSecurityStyle": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-storagevirtualmachine.html#cfn-fsx-storagevirtualmachine-rootvolumesecuritystyle", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "SvmAdminPassword": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-storagevirtualmachine.html#cfn-fsx-storagevirtualmachine-svmadminpassword", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-storagevirtualmachine.html#cfn-fsx-storagevirtualmachine-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::FSx::Volume": { + "Attributes": { + "ResourceARN": { + "PrimitiveType": "String" + }, + "UUID": { + "PrimitiveType": "String" + }, + "VolumeId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-volume.html", + "Properties": { + "BackupId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-volume.html#cfn-fsx-volume-backupid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-volume.html#cfn-fsx-volume-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "OntapConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-volume.html#cfn-fsx-volume-ontapconfiguration", + "Required": false, + "Type": "OntapConfiguration", + "UpdateType": "Mutable" + }, + "OpenZFSConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-volume.html#cfn-fsx-volume-openzfsconfiguration", + "Required": false, + "Type": "OpenZFSConfiguration", + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-volume.html#cfn-fsx-volume-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "VolumeType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-volume.html#cfn-fsx-volume-volumetype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } } } } diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FinSpace.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FinSpace.json index 5d11dcd1b1602..a77e993af024a 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FinSpace.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FinSpace.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::FinSpace::Environment.FederationParameters": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-finspace-environment-federationparameters.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Forecast.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Forecast.json index 2ef818f59062e..88b70dfde00bc 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Forecast.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Forecast.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::Forecast::Dataset": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FraudDetector.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FraudDetector.json index 9671e0b0bb820..9771bb30f675c 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FraudDetector.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_FraudDetector.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::FraudDetector::Detector.EntityType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-frauddetector-detector-entitytype.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GameLift.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GameLift.json index b299e22fda064..3a2796ee65ff6 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GameLift.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GameLift.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::GameLift::Alias.RoutingStrategy": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-alias-routingstrategy.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GlobalAccelerator.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GlobalAccelerator.json index fedffe600290b..b40343a251538 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GlobalAccelerator.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GlobalAccelerator.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::GlobalAccelerator::EndpointGroup.EndpointConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-globalaccelerator-endpointgroup-endpointconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Glue.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Glue.json index bf2f2613a9696..cedab3e5a2544 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Glue.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Glue.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Glue::Classifier.CsvClassifier": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-glue-classifier-csvclassifier.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Greengrass.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Greengrass.json index 51a71e4447e29..2029c87073c9f 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Greengrass.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Greengrass.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Greengrass::ConnectorDefinition.Connector": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-greengrass-connectordefinition-connector.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GreengrassV2.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GreengrassV2.json index 6f418a92f1b8f..fbe11510b5b49 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GreengrassV2.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GreengrassV2.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::GreengrassV2::ComponentVersion.ComponentDependencyRequirement": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-greengrassv2-componentversion-componentdependencyrequirement.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GroundStation.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GroundStation.json index d5fc48eb14171..70f7db435f582 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GroundStation.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GroundStation.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::GroundStation::Config.AntennaDownlinkConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-antennadownlinkconfig.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GuardDuty.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GuardDuty.json index faa8e9beb5e04..61ef6e697381f 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GuardDuty.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_GuardDuty.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::GuardDuty::Detector.CFNDataSourceConfigurations": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-guardduty-detector-cfndatasourceconfigurations.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_HealthLake.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_HealthLake.json index e78912cb4f2ae..48894bc8e9b9f 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_HealthLake.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_HealthLake.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::HealthLake::FHIRDatastore.KmsEncryptionConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-healthlake-fhirdatastore-kmsencryptionconfig.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IAM.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IAM.json index fdfc72a33a635..31d55f180aa2b 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IAM.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IAM.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::IAM::Group.Policy": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iam-policy.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IVS.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IVS.json index dee910c06509e..db96adf0a36da 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IVS.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IVS.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::IVS::RecordingConfiguration.DestinationConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ivs-recordingconfiguration-destinationconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ImageBuilder.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ImageBuilder.json index 58a9df148a6c7..0fa14609abab2 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ImageBuilder.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ImageBuilder.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::ImageBuilder::ContainerRecipe.ComponentConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-componentconfiguration.html", @@ -666,6 +666,9 @@ "ImageId": { "PrimitiveType": "String" }, + "ImageUri": { + "PrimitiveType": "String" + }, "Name": { "PrimitiveType": "String" } @@ -676,7 +679,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-image.html#cfn-imagebuilder-image-containerrecipearn", "PrimitiveType": "String", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "DistributionConfigurationArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-image.html#cfn-imagebuilder-image-distributionconfigurationarn", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Inspector.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Inspector.json index 7c079f94a37ad..342159403846e 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Inspector.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Inspector.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::Inspector::AssessmentTarget": { @@ -52,6 +52,7 @@ }, "RulesPackageArns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-inspector-assessmenttemplate.html#cfn-inspector-assessmenttemplate-rulespackagearns", + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": true, "Type": "List", @@ -59,6 +60,7 @@ }, "UserAttributesForFindings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-inspector-assessmenttemplate.html#cfn-inspector-assessmenttemplate-userattributesforfindings", + "DuplicatesAllowed": true, "ItemType": "Tag", "Required": false, "Type": "List", @@ -76,6 +78,7 @@ "Properties": { "ResourceGroupTags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-inspector-resourcegroup.html#cfn-inspector-resourcegroup-resourcegrouptags", + "DuplicatesAllowed": true, "ItemType": "Tag", "Required": true, "Type": "List", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_InspectorV2.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_InspectorV2.json index e52cf56db38a4..e2c7c28637957 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_InspectorV2.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_InspectorV2.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::InspectorV2::Filter.DateFilter": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-inspectorv2-filter-datefilter.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoT.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoT.json index feed08c0da0f4..1b55d59949fa5 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoT.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoT.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::IoT::AccountAuditConfiguration.AuditCheckConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-accountauditconfiguration-auditcheckconfiguration.html", @@ -1615,6 +1615,12 @@ "Required": false, "UpdateType": "Immutable" }, + "EnableCachingForHttp": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-authorizer.html#cfn-iot-authorizer-enablecachingforhttp", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "SigningDisabled": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-authorizer.html#cfn-iot-authorizer-signingdisabled", "PrimitiveType": "Boolean", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoT1Click.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoT1Click.json index 86581d4313df9..0b45647d8018c 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoT1Click.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoT1Click.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::IoT1Click::Project.DeviceTemplate": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot1click-project-devicetemplate.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTAnalytics.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTAnalytics.json index be1e2c2c79646..32ef1ef900e3d 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTAnalytics.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTAnalytics.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::IoTAnalytics::Channel.ChannelStorage": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-channel-channelstorage.html", @@ -317,13 +317,13 @@ "NumberOfDays": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-retentionperiod.html#cfn-iotanalytics-dataset-retentionperiod-numberofdays", "PrimitiveType": "Integer", - "Required": true, + "Required": false, "UpdateType": "Mutable" }, "Unlimited": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-retentionperiod.html#cfn-iotanalytics-dataset-retentionperiod-unlimited", "PrimitiveType": "Boolean", - "Required": true, + "Required": false, "UpdateType": "Mutable" } } diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTCoreDeviceAdvisor.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTCoreDeviceAdvisor.json index 744a6724297ee..1b16fabbc6771 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTCoreDeviceAdvisor.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTCoreDeviceAdvisor.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::IoTCoreDeviceAdvisor::SuiteDefinition": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTEvents.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTEvents.json index c695af08a09de..f5c8a01e395e5 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTEvents.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTEvents.json @@ -1,6 +1,467 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { + "AWS::IoTEvents::AlarmModel.AcknowledgeFlow": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-acknowledgeflow.html", + "Properties": { + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-acknowledgeflow.html#cfn-iotevents-alarmmodel-acknowledgeflow-enabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.AlarmAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmaction.html", + "Properties": { + "DynamoDB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmaction.html#cfn-iotevents-alarmmodel-alarmaction-dynamodb", + "Required": false, + "Type": "DynamoDB", + "UpdateType": "Mutable" + }, + "DynamoDBv2": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmaction.html#cfn-iotevents-alarmmodel-alarmaction-dynamodbv2", + "Required": false, + "Type": "DynamoDBv2", + "UpdateType": "Mutable" + }, + "Firehose": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmaction.html#cfn-iotevents-alarmmodel-alarmaction-firehose", + "Required": false, + "Type": "Firehose", + "UpdateType": "Mutable" + }, + "IotEvents": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmaction.html#cfn-iotevents-alarmmodel-alarmaction-iotevents", + "Required": false, + "Type": "IotEvents", + "UpdateType": "Mutable" + }, + "IotSiteWise": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmaction.html#cfn-iotevents-alarmmodel-alarmaction-iotsitewise", + "Required": false, + "Type": "IotSiteWise", + "UpdateType": "Mutable" + }, + "IotTopicPublish": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmaction.html#cfn-iotevents-alarmmodel-alarmaction-iottopicpublish", + "Required": false, + "Type": "IotTopicPublish", + "UpdateType": "Mutable" + }, + "Lambda": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmaction.html#cfn-iotevents-alarmmodel-alarmaction-lambda", + "Required": false, + "Type": "Lambda", + "UpdateType": "Mutable" + }, + "Sns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmaction.html#cfn-iotevents-alarmmodel-alarmaction-sns", + "Required": false, + "Type": "Sns", + "UpdateType": "Mutable" + }, + "Sqs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmaction.html#cfn-iotevents-alarmmodel-alarmaction-sqs", + "Required": false, + "Type": "Sqs", + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.AlarmCapabilities": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmcapabilities.html", + "Properties": { + "AcknowledgeFlow": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmcapabilities.html#cfn-iotevents-alarmmodel-alarmcapabilities-acknowledgeflow", + "Required": false, + "Type": "AcknowledgeFlow", + "UpdateType": "Mutable" + }, + "InitializationConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmcapabilities.html#cfn-iotevents-alarmmodel-alarmcapabilities-initializationconfiguration", + "Required": false, + "Type": "InitializationConfiguration", + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.AlarmEventActions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmeventactions.html", + "Properties": { + "AlarmActions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmeventactions.html#cfn-iotevents-alarmmodel-alarmeventactions-alarmactions", + "ItemType": "AlarmAction", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.AlarmRule": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmrule.html", + "Properties": { + "SimpleRule": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmrule.html#cfn-iotevents-alarmmodel-alarmrule-simplerule", + "Required": false, + "Type": "SimpleRule", + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.AssetPropertyTimestamp": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-assetpropertytimestamp.html", + "Properties": { + "OffsetInNanos": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-assetpropertytimestamp.html#cfn-iotevents-alarmmodel-assetpropertytimestamp-offsetinnanos", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TimeInSeconds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-assetpropertytimestamp.html#cfn-iotevents-alarmmodel-assetpropertytimestamp-timeinseconds", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.AssetPropertyValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-assetpropertyvalue.html", + "Properties": { + "Quality": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-assetpropertyvalue.html#cfn-iotevents-alarmmodel-assetpropertyvalue-quality", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Timestamp": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-assetpropertyvalue.html#cfn-iotevents-alarmmodel-assetpropertyvalue-timestamp", + "Required": false, + "Type": "AssetPropertyTimestamp", + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-assetpropertyvalue.html#cfn-iotevents-alarmmodel-assetpropertyvalue-value", + "Required": true, + "Type": "AssetPropertyVariant", + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.AssetPropertyVariant": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-assetpropertyvariant.html", + "Properties": { + "BooleanValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-assetpropertyvariant.html#cfn-iotevents-alarmmodel-assetpropertyvariant-booleanvalue", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "DoubleValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-assetpropertyvariant.html#cfn-iotevents-alarmmodel-assetpropertyvariant-doublevalue", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "IntegerValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-assetpropertyvariant.html#cfn-iotevents-alarmmodel-assetpropertyvariant-integervalue", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "StringValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-assetpropertyvariant.html#cfn-iotevents-alarmmodel-assetpropertyvariant-stringvalue", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.DynamoDB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-dynamodb.html", + "Properties": { + "HashKeyField": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-dynamodb.html#cfn-iotevents-alarmmodel-dynamodb-hashkeyfield", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "HashKeyType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-dynamodb.html#cfn-iotevents-alarmmodel-dynamodb-hashkeytype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "HashKeyValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-dynamodb.html#cfn-iotevents-alarmmodel-dynamodb-hashkeyvalue", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Operation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-dynamodb.html#cfn-iotevents-alarmmodel-dynamodb-operation", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Payload": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-dynamodb.html#cfn-iotevents-alarmmodel-dynamodb-payload", + "Required": false, + "Type": "Payload", + "UpdateType": "Mutable" + }, + "PayloadField": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-dynamodb.html#cfn-iotevents-alarmmodel-dynamodb-payloadfield", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "RangeKeyField": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-dynamodb.html#cfn-iotevents-alarmmodel-dynamodb-rangekeyfield", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "RangeKeyType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-dynamodb.html#cfn-iotevents-alarmmodel-dynamodb-rangekeytype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "RangeKeyValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-dynamodb.html#cfn-iotevents-alarmmodel-dynamodb-rangekeyvalue", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TableName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-dynamodb.html#cfn-iotevents-alarmmodel-dynamodb-tablename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.DynamoDBv2": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-dynamodbv2.html", + "Properties": { + "Payload": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-dynamodbv2.html#cfn-iotevents-alarmmodel-dynamodbv2-payload", + "Required": false, + "Type": "Payload", + "UpdateType": "Mutable" + }, + "TableName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-dynamodbv2.html#cfn-iotevents-alarmmodel-dynamodbv2-tablename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.Firehose": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-firehose.html", + "Properties": { + "DeliveryStreamName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-firehose.html#cfn-iotevents-alarmmodel-firehose-deliverystreamname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Payload": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-firehose.html#cfn-iotevents-alarmmodel-firehose-payload", + "Required": false, + "Type": "Payload", + "UpdateType": "Mutable" + }, + "Separator": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-firehose.html#cfn-iotevents-alarmmodel-firehose-separator", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.InitializationConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-initializationconfiguration.html", + "Properties": { + "DisabledOnInitialization": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-initializationconfiguration.html#cfn-iotevents-alarmmodel-initializationconfiguration-disabledoninitialization", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.IotEvents": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-iotevents.html", + "Properties": { + "InputName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-iotevents.html#cfn-iotevents-alarmmodel-iotevents-inputname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Payload": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-iotevents.html#cfn-iotevents-alarmmodel-iotevents-payload", + "Required": false, + "Type": "Payload", + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.IotSiteWise": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-iotsitewise.html", + "Properties": { + "AssetId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-iotsitewise.html#cfn-iotevents-alarmmodel-iotsitewise-assetid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "EntryId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-iotsitewise.html#cfn-iotevents-alarmmodel-iotsitewise-entryid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PropertyAlias": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-iotsitewise.html#cfn-iotevents-alarmmodel-iotsitewise-propertyalias", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PropertyId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-iotsitewise.html#cfn-iotevents-alarmmodel-iotsitewise-propertyid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PropertyValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-iotsitewise.html#cfn-iotevents-alarmmodel-iotsitewise-propertyvalue", + "Required": true, + "Type": "AssetPropertyValue", + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.IotTopicPublish": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-iottopicpublish.html", + "Properties": { + "MqttTopic": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-iottopicpublish.html#cfn-iotevents-alarmmodel-iottopicpublish-mqtttopic", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Payload": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-iottopicpublish.html#cfn-iotevents-alarmmodel-iottopicpublish-payload", + "Required": false, + "Type": "Payload", + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.Lambda": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-lambda.html", + "Properties": { + "FunctionArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-lambda.html#cfn-iotevents-alarmmodel-lambda-functionarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Payload": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-lambda.html#cfn-iotevents-alarmmodel-lambda-payload", + "Required": false, + "Type": "Payload", + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.Payload": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-payload.html", + "Properties": { + "ContentExpression": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-payload.html#cfn-iotevents-alarmmodel-payload-contentexpression", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-payload.html#cfn-iotevents-alarmmodel-payload-type", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.SimpleRule": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-simplerule.html", + "Properties": { + "ComparisonOperator": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-simplerule.html#cfn-iotevents-alarmmodel-simplerule-comparisonoperator", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "InputProperty": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-simplerule.html#cfn-iotevents-alarmmodel-simplerule-inputproperty", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Threshold": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-simplerule.html#cfn-iotevents-alarmmodel-simplerule-threshold", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.Sns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-sns.html", + "Properties": { + "Payload": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-sns.html#cfn-iotevents-alarmmodel-sns-payload", + "Required": false, + "Type": "Payload", + "UpdateType": "Mutable" + }, + "TargetArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-sns.html#cfn-iotevents-alarmmodel-sns-targetarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTEvents::AlarmModel.Sqs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-sqs.html", + "Properties": { + "Payload": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-sqs.html#cfn-iotevents-alarmmodel-sqs-payload", + "Required": false, + "Type": "Payload", + "UpdateType": "Mutable" + }, + "QueueUrl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-sqs.html#cfn-iotevents-alarmmodel-sqs-queueurl", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "UseBase64": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-sqs.html#cfn-iotevents-alarmmodel-sqs-usebase64", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::IoTEvents::DetectorModel.Action": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-action.html", "Properties": { @@ -640,6 +1101,67 @@ } }, "ResourceTypes": { + "AWS::IoTEvents::AlarmModel": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotevents-alarmmodel.html", + "Properties": { + "AlarmCapabilities": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotevents-alarmmodel.html#cfn-iotevents-alarmmodel-alarmcapabilities", + "Required": false, + "Type": "AlarmCapabilities", + "UpdateType": "Mutable" + }, + "AlarmEventActions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotevents-alarmmodel.html#cfn-iotevents-alarmmodel-alarmeventactions", + "Required": false, + "Type": "AlarmEventActions", + "UpdateType": "Mutable" + }, + "AlarmModelDescription": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotevents-alarmmodel.html#cfn-iotevents-alarmmodel-alarmmodeldescription", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "AlarmModelName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotevents-alarmmodel.html#cfn-iotevents-alarmmodel-alarmmodelname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "AlarmRule": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotevents-alarmmodel.html#cfn-iotevents-alarmmodel-alarmrule", + "Required": true, + "Type": "AlarmRule", + "UpdateType": "Mutable" + }, + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotevents-alarmmodel.html#cfn-iotevents-alarmmodel-key", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotevents-alarmmodel.html#cfn-iotevents-alarmmodel-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Severity": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotevents-alarmmodel.html#cfn-iotevents-alarmmodel-severity", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotevents-alarmmodel.html#cfn-iotevents-alarmmodel-tags", + "DuplicatesAllowed": true, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::IoTEvents::DetectorModel": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotevents-detectormodel.html", "Properties": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTFleetHub.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTFleetHub.json index 45604dad3fdce..d8eb0c0f67d43 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTFleetHub.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTFleetHub.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::IoTFleetHub::Application": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTSiteWise.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTSiteWise.json index 4e1467d0124a9..89fb4b81f7b87 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTSiteWise.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTSiteWise.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::IoTSiteWise::AccessPolicy.AccessPolicyIdentity": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotsitewise-accesspolicy-accesspolicyidentity.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTThingsGraph.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTThingsGraph.json index d85a8d1db4d1a..bb44f337a5d65 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTThingsGraph.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTThingsGraph.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::IoTThingsGraph::FlowTemplate.DefinitionDocument": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotthingsgraph-flowtemplate-definitiondocument.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTWireless.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTWireless.json index 72ab331a5718f..3a1bc624604a4 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTWireless.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_IoTWireless.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::IoTWireless::DeviceProfile.LoRaWANDeviceProfile": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-deviceprofile-lorawandeviceprofile.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KMS.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KMS.json index 05b8211e21f51..9a8c5dc81c899 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KMS.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KMS.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::KMS::Alias": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KafkaConnect.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KafkaConnect.json index 4b7ffef482351..4bd53485ff89c 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KafkaConnect.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KafkaConnect.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::KafkaConnect::Connector.ApacheKafkaCluster": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kafkaconnect-connector-apachekafkacluster.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Kendra.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Kendra.json index 492d83b6f59f5..844f658a4d28d 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Kendra.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Kendra.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Kendra::DataSource.AccessControlListConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-accesscontrollistconfiguration.html", @@ -334,6 +334,36 @@ } } }, + "AWS::Kendra::DataSource.CustomDocumentEnrichmentConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-customdocumentenrichmentconfiguration.html", + "Properties": { + "InlineConfigurations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-customdocumentenrichmentconfiguration.html#cfn-kendra-datasource-customdocumentenrichmentconfiguration-inlineconfigurations", + "ItemType": "InlineCustomDocumentEnrichmentConfiguration", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "PostExtractionHookConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-customdocumentenrichmentconfiguration.html#cfn-kendra-datasource-customdocumentenrichmentconfiguration-postextractionhookconfiguration", + "Required": false, + "Type": "HookConfiguration", + "UpdateType": "Mutable" + }, + "PreExtractionHookConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-customdocumentenrichmentconfiguration.html#cfn-kendra-datasource-customdocumentenrichmentconfiguration-preextractionhookconfiguration", + "Required": false, + "Type": "HookConfiguration", + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-customdocumentenrichmentconfiguration.html#cfn-kendra-datasource-customdocumentenrichmentconfiguration-rolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Kendra::DataSource.DataSourceConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourceconfiguration.html", "Properties": { @@ -482,6 +512,82 @@ } } }, + "AWS::Kendra::DataSource.DocumentAttributeCondition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-documentattributecondition.html", + "Properties": { + "ConditionDocumentAttributeKey": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-documentattributecondition.html#cfn-kendra-datasource-documentattributecondition-conditiondocumentattributekey", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ConditionOnValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-documentattributecondition.html#cfn-kendra-datasource-documentattributecondition-conditiononvalue", + "Required": false, + "Type": "DocumentAttributeValue", + "UpdateType": "Mutable" + }, + "Operator": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-documentattributecondition.html#cfn-kendra-datasource-documentattributecondition-operator", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.DocumentAttributeTarget": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-documentattributetarget.html", + "Properties": { + "TargetDocumentAttributeKey": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-documentattributetarget.html#cfn-kendra-datasource-documentattributetarget-targetdocumentattributekey", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "TargetDocumentAttributeValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-documentattributetarget.html#cfn-kendra-datasource-documentattributetarget-targetdocumentattributevalue", + "Required": false, + "Type": "DocumentAttributeValue", + "UpdateType": "Mutable" + }, + "TargetDocumentAttributeValueDeletion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-documentattributetarget.html#cfn-kendra-datasource-documentattributetarget-targetdocumentattributevaluedeletion", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.DocumentAttributeValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-documentattributevalue.html", + "Properties": { + "DateValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-documentattributevalue.html#cfn-kendra-datasource-documentattributevalue-datevalue", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LongValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-documentattributevalue.html#cfn-kendra-datasource-documentattributevalue-longvalue", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "StringListValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-documentattributevalue.html#cfn-kendra-datasource-documentattributevalue-stringlistvalue", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "StringValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-documentattributevalue.html#cfn-kendra-datasource-documentattributevalue-stringvalue", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Kendra::DataSource.DocumentsMetadataConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-documentsmetadataconfiguration.html", "Properties": { @@ -546,6 +652,52 @@ } } }, + "AWS::Kendra::DataSource.HookConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-hookconfiguration.html", + "Properties": { + "InvocationCondition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-hookconfiguration.html#cfn-kendra-datasource-hookconfiguration-invocationcondition", + "Required": false, + "Type": "DocumentAttributeCondition", + "UpdateType": "Mutable" + }, + "LambdaArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-hookconfiguration.html#cfn-kendra-datasource-hookconfiguration-lambdaarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "S3Bucket": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-hookconfiguration.html#cfn-kendra-datasource-hookconfiguration-s3bucket", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.InlineCustomDocumentEnrichmentConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-inlinecustomdocumentenrichmentconfiguration.html", + "Properties": { + "Condition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-inlinecustomdocumentenrichmentconfiguration.html#cfn-kendra-datasource-inlinecustomdocumentenrichmentconfiguration-condition", + "Required": false, + "Type": "DocumentAttributeCondition", + "UpdateType": "Mutable" + }, + "DocumentContentDeletion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-inlinecustomdocumentenrichmentconfiguration.html#cfn-kendra-datasource-inlinecustomdocumentenrichmentconfiguration-documentcontentdeletion", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "Target": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-inlinecustomdocumentenrichmentconfiguration.html#cfn-kendra-datasource-inlinecustomdocumentenrichmentconfiguration-target", + "Required": false, + "Type": "DocumentAttributeTarget", + "UpdateType": "Mutable" + } + } + }, "AWS::Kendra::DataSource.OneDriveConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-onedriveconfiguration.html", "Properties": { @@ -1582,6 +1734,12 @@ }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-datasource.html", "Properties": { + "CustomDocumentEnrichmentConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-datasource.html#cfn-kendra-datasource-customdocumentenrichmentconfiguration", + "Required": false, + "Type": "CustomDocumentEnrichmentConfiguration", + "UpdateType": "Mutable" + }, "DataSourceConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-datasource.html#cfn-kendra-datasource-datasourceconfiguration", "Required": false, diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Kinesis.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Kinesis.json index 6e65b670b451d..506527f7e582f 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Kinesis.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Kinesis.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Kinesis::Stream.StreamEncryption": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesis-stream-streamencryption.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KinesisAnalytics.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KinesisAnalytics.json index 542d07b34f3d6..274721e096413 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KinesisAnalytics.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KinesisAnalytics.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::KinesisAnalytics::Application.CSVMappingParameters": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisanalytics-application-csvmappingparameters.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KinesisAnalyticsV2.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KinesisAnalyticsV2.json index 31328aabfd4f6..0f953718f8b0b 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KinesisAnalyticsV2.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KinesisAnalyticsV2.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::KinesisAnalyticsV2::Application.ApplicationCodeConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisanalyticsv2-application-applicationcodeconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KinesisFirehose.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KinesisFirehose.json index 3a8196c4653c5..e834216437405 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KinesisFirehose.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KinesisFirehose.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::KinesisFirehose::DeliveryStream.AmazonopensearchserviceBufferingHints": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicebufferinghints.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KinesisVideo.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KinesisVideo.json index 03800d67919cc..b033fa1c1dce9 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KinesisVideo.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_KinesisVideo.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::KinesisVideo::SignalingChannel": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LakeFormation.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LakeFormation.json index a3aa534ab6c67..97be64ac2ae10 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LakeFormation.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LakeFormation.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::LakeFormation::DataLakeSettings.Admins": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lakeformation-datalakesettings-admins.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Lambda.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Lambda.json index a957467105130..8410ee175283e 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Lambda.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Lambda.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Lambda::Alias.AliasRoutingConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-alias-aliasroutingconfiguration.html", @@ -128,6 +128,30 @@ } } }, + "AWS::Lambda::EventSourceMapping.Filter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-eventsourcemapping-filter.html", + "Properties": { + "Pattern": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-eventsourcemapping-filter.html#cfn-lambda-eventsourcemapping-filter-pattern", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Lambda::EventSourceMapping.FilterCriteria": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-eventsourcemapping-filtercriteria.html", + "Properties": { + "Filters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-eventsourcemapping-filtercriteria.html#cfn-lambda-eventsourcemapping-filtercriteria-filters", + "DuplicatesAllowed": false, + "ItemType": "Filter", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::Lambda::EventSourceMapping.OnFailure": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-eventsourcemapping-onfailure.html", "Properties": { @@ -225,6 +249,17 @@ } } }, + "AWS::Lambda::Function.EphemeralStorage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-ephemeralstorage.html", + "Properties": { + "Size": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-ephemeralstorage.html#cfn-lambda-function-ephemeralstorage-size", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::Lambda::Function.FileSystemConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-filesystemconfig.html", "Properties": { @@ -484,8 +519,8 @@ }, "FilterCriteria": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html#cfn-lambda-eventsourcemapping-filtercriteria", - "PrimitiveType": "Json", "Required": false, + "Type": "FilterCriteria", "UpdateType": "Mutable" }, "FunctionName": { @@ -558,7 +593,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html#cfn-lambda-eventsourcemapping-startingpositiontimestamp", "PrimitiveType": "Double", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "Topics": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html#cfn-lambda-eventsourcemapping-topics", @@ -622,6 +657,12 @@ "Type": "Environment", "UpdateType": "Mutable" }, + "EphemeralStorage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-ephemeralstorage", + "Required": false, + "Type": "EphemeralStorage", + "UpdateType": "Mutable" + }, "FileSystemConfigs": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-filesystemconfigs", "ItemType": "FileSystemConfig", @@ -818,6 +859,12 @@ "Required": true, "UpdateType": "Immutable" }, + "PrincipalOrgID": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-permission.html#cfn-lambda-permission-principalorgid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "SourceAccount": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-permission.html#cfn-lambda-permission-sourceaccount", "PrimitiveType": "String", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Lex.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Lex.json index af2115a7bf139..5b84bddd31d68 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Lex.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Lex.json @@ -1,9 +1,88 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { + "AWS::Lex::Bot.AdvancedRecognitionSetting": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-advancedrecognitionsetting.html", + "Properties": { + "AudioRecognitionStrategy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-advancedrecognitionsetting.html#cfn-lex-bot-advancedrecognitionsetting-audiorecognitionstrategy", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Lex::Bot.AudioLogDestination": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-audiologdestination.html", + "Properties": { + "S3Bucket": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-audiologdestination.html#cfn-lex-bot-audiologdestination-s3bucket", + "Required": true, + "Type": "S3BucketLogDestination", + "UpdateType": "Mutable" + } + } + }, + "AWS::Lex::Bot.AudioLogSetting": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-audiologsetting.html", + "Properties": { + "Destination": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-audiologsetting.html#cfn-lex-bot-audiologsetting-destination", + "Required": true, + "Type": "AudioLogDestination", + "UpdateType": "Mutable" + }, + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-audiologsetting.html#cfn-lex-bot-audiologsetting-enabled", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Lex::Bot.BotAliasLocaleSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-botaliaslocalesettings.html", + "Properties": { + "CodeHookSpecification": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-botaliaslocalesettings.html#cfn-lex-bot-botaliaslocalesettings-codehookspecification", + "Required": false, + "Type": "CodeHookSpecification", + "UpdateType": "Mutable" + }, + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-botaliaslocalesettings.html#cfn-lex-bot-botaliaslocalesettings-enabled", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Lex::Bot.BotAliasLocaleSettingsItem": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-botaliaslocalesettingsitem.html", + "Properties": { + "BotAliasLocaleSetting": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-botaliaslocalesettingsitem.html#cfn-lex-bot-botaliaslocalesettingsitem-botaliaslocalesetting", + "Required": true, + "Type": "BotAliasLocaleSettings", + "UpdateType": "Mutable" + }, + "LocaleId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-botaliaslocalesettingsitem.html#cfn-lex-bot-botaliaslocalesettingsitem-localeid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::Lex::Bot.BotLocale": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-botlocale.html", "Properties": { + "CustomVocabulary": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-botlocale.html#cfn-lex-bot-botlocale-customvocabulary", + "Required": false, + "Type": "CustomVocabulary", + "UpdateType": "Mutable" + }, "Description": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-botlocale.html#cfn-lex-bot-botlocale-description", "PrimitiveType": "String", @@ -63,6 +142,53 @@ } } }, + "AWS::Lex::Bot.CloudWatchLogGroupLogDestination": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-cloudwatchloggrouplogdestination.html", + "Properties": { + "CloudWatchLogGroupArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-cloudwatchloggrouplogdestination.html#cfn-lex-bot-cloudwatchloggrouplogdestination-cloudwatchloggrouparn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "LogPrefix": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-cloudwatchloggrouplogdestination.html#cfn-lex-bot-cloudwatchloggrouplogdestination-logprefix", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Lex::Bot.CodeHookSpecification": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-codehookspecification.html", + "Properties": { + "LambdaCodeHook": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-codehookspecification.html#cfn-lex-bot-codehookspecification-lambdacodehook", + "Required": true, + "Type": "LambdaCodeHook", + "UpdateType": "Mutable" + } + } + }, + "AWS::Lex::Bot.ConversationLogSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-conversationlogsettings.html", + "Properties": { + "AudioLogSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-conversationlogsettings.html#cfn-lex-bot-conversationlogsettings-audiologsettings", + "ItemType": "AudioLogSetting", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "TextLogSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-conversationlogsettings.html#cfn-lex-bot-conversationlogsettings-textlogsettings", + "ItemType": "TextLogSetting", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::Lex::Bot.CustomPayload": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-custompayload.html", "Properties": { @@ -74,6 +200,35 @@ } } }, + "AWS::Lex::Bot.CustomVocabulary": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-customvocabulary.html", + "Properties": { + "CustomVocabularyItems": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-customvocabulary.html#cfn-lex-bot-customvocabulary-customvocabularyitems", + "ItemType": "CustomVocabularyItem", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Lex::Bot.CustomVocabularyItem": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-customvocabularyitem.html", + "Properties": { + "Phrase": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-customvocabularyitem.html#cfn-lex-bot-customvocabularyitem-phrase", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Weight": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-customvocabularyitem.html#cfn-lex-bot-customvocabularyitem-weight", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Lex::Bot.DialogCodeHookSetting": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-dialogcodehooksetting.html", "Properties": { @@ -423,6 +578,23 @@ } } }, + "AWS::Lex::Bot.LambdaCodeHook": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-lambdacodehook.html", + "Properties": { + "CodeHookInterfaceVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-lambdacodehook.html#cfn-lex-bot-lambdacodehook-codehookinterfaceversion", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "LambdaArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-lambdacodehook.html#cfn-lex-bot-lambdacodehook-lambdaarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::Lex::Bot.Message": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-message.html", "Properties": { @@ -591,6 +763,29 @@ } } }, + "AWS::Lex::Bot.S3BucketLogDestination": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-s3bucketlogdestination.html", + "Properties": { + "KmsKeyArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-s3bucketlogdestination.html#cfn-lex-bot-s3bucketlogdestination-kmskeyarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LogPrefix": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-s3bucketlogdestination.html#cfn-lex-bot-s3bucketlogdestination-logprefix", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "S3BucketArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-s3bucketlogdestination.html#cfn-lex-bot-s3bucketlogdestination-s3bucketarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::Lex::Bot.S3Location": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-s3location.html", "Properties": { @@ -838,6 +1033,12 @@ "AWS::Lex::Bot.SlotValueSelectionSetting": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-slotvalueselectionsetting.html", "Properties": { + "AdvancedRecognitionSetting": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-slotvalueselectionsetting.html#cfn-lex-bot-slotvalueselectionsetting-advancedrecognitionsetting", + "Required": false, + "Type": "AdvancedRecognitionSetting", + "UpdateType": "Mutable" + }, "RegexFilter": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-slotvalueselectionsetting.html#cfn-lex-bot-slotvalueselectionsetting-regexfilter", "Required": false, @@ -882,6 +1083,64 @@ } } }, + "AWS::Lex::Bot.TestBotAliasSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-testbotaliassettings.html", + "Properties": { + "BotAliasLocaleSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-testbotaliassettings.html#cfn-lex-bot-testbotaliassettings-botaliaslocalesettings", + "ItemType": "BotAliasLocaleSettingsItem", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "ConversationLogSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-testbotaliassettings.html#cfn-lex-bot-testbotaliassettings-conversationlogsettings", + "Required": false, + "Type": "ConversationLogSettings", + "UpdateType": "Mutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-testbotaliassettings.html#cfn-lex-bot-testbotaliassettings-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SentimentAnalysisSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-testbotaliassettings.html#cfn-lex-bot-testbotaliassettings-sentimentanalysissettings", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Lex::Bot.TextLogDestination": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-textlogdestination.html", + "Properties": { + "CloudWatch": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-textlogdestination.html#cfn-lex-bot-textlogdestination-cloudwatch", + "Required": true, + "Type": "CloudWatchLogGroupLogDestination", + "UpdateType": "Mutable" + } + } + }, + "AWS::Lex::Bot.TextLogSetting": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-textlogsetting.html", + "Properties": { + "Destination": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-textlogsetting.html#cfn-lex-bot-textlogsetting-destination", + "Required": true, + "Type": "TextLogDestination", + "UpdateType": "Mutable" + }, + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-textlogsetting.html#cfn-lex-bot-textlogsetting-enabled", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::Lex::Bot.VoiceSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-voicesettings.html", "Properties": { @@ -927,7 +1186,7 @@ "Properties": { "S3Bucket": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-botalias-audiologdestination.html#cfn-lex-botalias-audiologdestination-s3bucket", - "Required": false, + "Required": true, "Type": "S3BucketLogDestination", "UpdateType": "Mutable" } @@ -1076,7 +1335,7 @@ "Properties": { "CloudWatch": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-botalias-textlogdestination.html#cfn-lex-botalias-textlogdestination-cloudwatch", - "Required": false, + "Required": true, "Type": "CloudWatchLogGroupLogDestination", "UpdateType": "Mutable" } @@ -1087,14 +1346,14 @@ "Properties": { "Destination": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-botalias-textlogsetting.html#cfn-lex-botalias-textlogsetting-destination", - "Required": false, + "Required": true, "Type": "TextLogDestination", "UpdateType": "Mutable" }, "Enabled": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-botalias-textlogsetting.html#cfn-lex-botalias-textlogsetting-enabled", "PrimitiveType": "Boolean", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -1204,6 +1463,12 @@ "Required": true, "UpdateType": "Mutable" }, + "TestBotAliasSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lex-bot.html#cfn-lex-bot-testbotaliassettings", + "Required": false, + "Type": "TestBotAliasSettings", + "UpdateType": "Mutable" + }, "TestBotAliasTags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lex-bot.html#cfn-lex-bot-testbotaliastags", "DuplicatesAllowed": false, diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LicenseManager.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LicenseManager.json index 953b92c44ebb4..c5f86612ba7e2 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LicenseManager.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LicenseManager.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::LicenseManager::License.BorrowConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-licensemanager-license-borrowconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Lightsail.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Lightsail.json index 714ae644f0f7d..b6e74e0dd10a2 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Lightsail.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Lightsail.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Lightsail::Bucket.AccessRules": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-bucket-accessrules.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Location.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Location.json index 39bcc44c1ed92..56282c7b8294d 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Location.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Location.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Location::Map.MapConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-location-map-mapconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Logs.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Logs.json index b0057d38f2707..614b08cff3161 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Logs.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Logs.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Logs::MetricFilter.MetricTransformation": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-logs-metricfilter-metrictransformation.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LookoutEquipment.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LookoutEquipment.json index 3e2d5e39bd733..77cbcd73bea73 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LookoutEquipment.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LookoutEquipment.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::LookoutEquipment::InferenceScheduler": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LookoutMetrics.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LookoutMetrics.json index 1b70074600cac..6b2d6aa000bd2 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LookoutMetrics.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LookoutMetrics.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::LookoutMetrics::Alert.Action": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-alert-action.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LookoutVision.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LookoutVision.json index 8729770a4730a..d654b1a1da791 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LookoutVision.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_LookoutVision.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::LookoutVision::Project": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MSK.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MSK.json index 9340cac825cc5..26816e3dc00d4 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MSK.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MSK.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::MSK::Cluster.BrokerLogs": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-brokerlogs.html", @@ -35,6 +35,7 @@ }, "ClientSubnets": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-brokernodegroupinfo.html#cfn-msk-cluster-brokernodegroupinfo-clientsubnets", + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": true, "Type": "List", @@ -54,6 +55,7 @@ }, "SecurityGroups": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-brokernodegroupinfo.html#cfn-msk-cluster-brokernodegroupinfo-securitygroups", + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": false, "Type": "List", @@ -381,6 +383,7 @@ "Properties": { "CertificateAuthorityArnList": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-tls.html#cfn-msk-cluster-tls-certificateauthorityarnlist", + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": false, "Type": "List", @@ -407,7 +410,30 @@ } }, "ResourceTypes": { + "AWS::MSK::BatchScramSecret": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-batchscramsecret.html", + "Properties": { + "ClusterArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-batchscramsecret.html#cfn-msk-batchscramsecret-clusterarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "SecretArnList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-batchscramsecret.html#cfn-msk-batchscramsecret-secretarnlist", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::MSK::Cluster": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-cluster.html", "Properties": { "BrokerNodeGroupInfo": { @@ -434,6 +460,12 @@ "Type": "ConfigurationInfo", "UpdateType": "Mutable" }, + "CurrentVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-cluster.html#cfn-msk-cluster-currentversion", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "EncryptionInfo": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-cluster.html#cfn-msk-cluster-encryptioninfo", "Required": false, @@ -472,11 +504,47 @@ }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-cluster.html#cfn-msk-cluster-tags", - "PrimitiveType": "Json", + "PrimitiveItemType": "String", "Required": false, + "Type": "Map", "UpdateType": "Immutable" } } + }, + "AWS::MSK::Configuration": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-configuration.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-configuration.html#cfn-msk-configuration-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "KafkaVersionsList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-configuration.html#cfn-msk-configuration-kafkaversionslist", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-configuration.html#cfn-msk-configuration-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "ServerProperties": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-configuration.html#cfn-msk-configuration-serverproperties", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } } } } diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MWAA.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MWAA.json index 5e4657f5533c5..6ad262d484bb8 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MWAA.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MWAA.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::MWAA::Environment.LoggingConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-loggingconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Macie.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Macie.json index 6a1b5a54a191d..7aeab3d3ab71a 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Macie.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Macie.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Macie::FindingsFilter.Criterion": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-macie-findingsfilter-criterion.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ManagedBlockchain.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ManagedBlockchain.json index 0273b3a2ccd14..214c7ce42f797 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ManagedBlockchain.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ManagedBlockchain.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::ManagedBlockchain::Member.ApprovalThresholdPolicy": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-managedblockchain-member-approvalthresholdpolicy.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaConnect.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaConnect.json index 47886120afddc..87e04105a1976 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaConnect.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaConnect.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::MediaConnect::Flow.Encryption": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediaconnect-flow-encryption.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaConvert.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaConvert.json index 5004984704c40..e62127363e018 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaConvert.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaConvert.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::MediaConvert::JobTemplate.AccelerationSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediaconvert-jobtemplate-accelerationsettings.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaLive.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaLive.json index b31f7f53c3caa..432661c85d1e2 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaLive.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaLive.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::MediaLive::Channel.AacSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-aacsettings.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaPackage.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaPackage.json index 78ce8a18ea102..0b7f7dffdca0a 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaPackage.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaPackage.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::MediaPackage::Asset.EgressEndpoint": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediapackage-asset-egressendpoint.html", @@ -219,6 +219,23 @@ } } }, + "AWS::MediaPackage::OriginEndpoint.EncryptionContractConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediapackage-originendpoint-encryptioncontractconfiguration.html", + "Properties": { + "PresetSpeke20Audio": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediapackage-originendpoint-encryptioncontractconfiguration.html#cfn-mediapackage-originendpoint-encryptioncontractconfiguration-presetspeke20audio", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "PresetSpeke20Video": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediapackage-originendpoint-encryptioncontractconfiguration.html#cfn-mediapackage-originendpoint-encryptioncontractconfiguration-presetspeke20video", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::MediaPackage::OriginEndpoint.HlsEncryption": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediapackage-originendpoint-hlsencryption.html", "Properties": { @@ -441,6 +458,12 @@ "Required": false, "UpdateType": "Mutable" }, + "EncryptionContractConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediapackage-originendpoint-spekekeyprovider.html#cfn-mediapackage-originendpoint-spekekeyprovider-encryptioncontractconfiguration", + "Required": false, + "Type": "EncryptionContractConfiguration", + "UpdateType": "Mutable" + }, "ResourceId": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediapackage-originendpoint-spekekeyprovider.html#cfn-mediapackage-originendpoint-spekekeyprovider-resourceid", "PrimitiveType": "String", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaStore.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaStore.json index 409adcf13cc60..359c46a49c958 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaStore.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MediaStore.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::MediaStore::Container.CorsRule": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediastore-container-corsrule.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MemoryDB.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MemoryDB.json index 0ebdc76cc2ae2..16e2ffd19738d 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MemoryDB.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_MemoryDB.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::MemoryDB::Cluster.Endpoint": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-memorydb-cluster-endpoint.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Neptune.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Neptune.json index c5f4d10d48a81..510739261020b 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Neptune.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Neptune.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Neptune::DBCluster.DBClusterRole": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-neptune-dbcluster-dbclusterrole.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_NetworkFirewall.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_NetworkFirewall.json index 2878789bc8a61..6104afc7f7f5b 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_NetworkFirewall.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_NetworkFirewall.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::NetworkFirewall::Firewall.SubnetMapping": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-firewall-subnetmapping.html", @@ -56,7 +56,7 @@ "Properties": { "StatefulDefaultActions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-firewallpolicy-firewallpolicy.html#cfn-networkfirewall-firewallpolicy-firewallpolicy-statefuldefaultactions", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": false, "Type": "List", @@ -70,7 +70,7 @@ }, "StatefulRuleGroupReferences": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-firewallpolicy-firewallpolicy.html#cfn-networkfirewall-firewallpolicy-firewallpolicy-statefulrulegroupreferences", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "ItemType": "StatefulRuleGroupReference", "Required": false, "Type": "List", @@ -78,7 +78,7 @@ }, "StatelessCustomActions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-firewallpolicy-firewallpolicy.html#cfn-networkfirewall-firewallpolicy-firewallpolicy-statelesscustomactions", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "ItemType": "CustomAction", "Required": false, "Type": "List", @@ -86,7 +86,7 @@ }, "StatelessDefaultActions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-firewallpolicy-firewallpolicy.html#cfn-networkfirewall-firewallpolicy-firewallpolicy-statelessdefaultactions", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": true, "Type": "List", @@ -94,7 +94,7 @@ }, "StatelessFragmentDefaultActions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-firewallpolicy-firewallpolicy.html#cfn-networkfirewall-firewallpolicy-firewallpolicy-statelessfragmentdefaultactions", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": true, "Type": "List", @@ -102,7 +102,7 @@ }, "StatelessRuleGroupReferences": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-firewallpolicy-firewallpolicy.html#cfn-networkfirewall-firewallpolicy-firewallpolicy-statelessrulegroupreferences", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "ItemType": "StatelessRuleGroupReference", "Required": false, "Type": "List", @@ -115,7 +115,7 @@ "Properties": { "Dimensions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-firewallpolicy-publishmetricaction.html#cfn-networkfirewall-firewallpolicy-publishmetricaction-dimensions", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "ItemType": "Dimension", "Required": true, "Type": "List", @@ -300,7 +300,7 @@ "Properties": { "Definition": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-ipset.html#cfn-networkfirewall-rulegroup-ipset-definition", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": false, "Type": "List", @@ -313,7 +313,7 @@ "Properties": { "DestinationPorts": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-matchattributes.html#cfn-networkfirewall-rulegroup-matchattributes-destinationports", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "ItemType": "PortRange", "Required": false, "Type": "List", @@ -321,7 +321,7 @@ }, "Destinations": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-matchattributes.html#cfn-networkfirewall-rulegroup-matchattributes-destinations", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "ItemType": "Address", "Required": false, "Type": "List", @@ -329,7 +329,7 @@ }, "Protocols": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-matchattributes.html#cfn-networkfirewall-rulegroup-matchattributes-protocols", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "PrimitiveItemType": "Integer", "Required": false, "Type": "List", @@ -337,7 +337,7 @@ }, "SourcePorts": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-matchattributes.html#cfn-networkfirewall-rulegroup-matchattributes-sourceports", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "ItemType": "PortRange", "Required": false, "Type": "List", @@ -345,7 +345,7 @@ }, "Sources": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-matchattributes.html#cfn-networkfirewall-rulegroup-matchattributes-sources", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "ItemType": "Address", "Required": false, "Type": "List", @@ -353,7 +353,7 @@ }, "TCPFlags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-matchattributes.html#cfn-networkfirewall-rulegroup-matchattributes-tcpflags", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "ItemType": "TCPFlagField", "Required": false, "Type": "List", @@ -383,7 +383,7 @@ "Properties": { "Definition": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-portset.html#cfn-networkfirewall-rulegroup-portset-definition", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": false, "Type": "List", @@ -396,7 +396,7 @@ "Properties": { "Dimensions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-publishmetricaction.html#cfn-networkfirewall-rulegroup-publishmetricaction-dimensions", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "ItemType": "Dimension", "Required": true, "Type": "List", @@ -409,7 +409,7 @@ "Properties": { "Actions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-ruledefinition.html#cfn-networkfirewall-rulegroup-ruledefinition-actions", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": true, "Type": "List", @@ -457,7 +457,7 @@ }, "Settings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-ruleoption.html#cfn-networkfirewall-rulegroup-ruleoption-settings", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": false, "Type": "List", @@ -501,7 +501,7 @@ }, "StatefulRules": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-rulessource.html#cfn-networkfirewall-rulegroup-rulessource-statefulrules", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "ItemType": "StatefulRule", "Required": false, "Type": "List", @@ -526,7 +526,7 @@ }, "TargetTypes": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-rulessourcelist.html#cfn-networkfirewall-rulegroup-rulessourcelist-targettypes", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": true, "Type": "List", @@ -534,7 +534,7 @@ }, "Targets": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-rulessourcelist.html#cfn-networkfirewall-rulegroup-rulessourcelist-targets", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": true, "Type": "List", @@ -559,7 +559,7 @@ }, "RuleOptions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-statefulrule.html#cfn-networkfirewall-rulegroup-statefulrule-ruleoptions", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "ItemType": "RuleOption", "Required": true, "Type": "List", @@ -600,7 +600,7 @@ "Properties": { "CustomActions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-statelessrulesandcustomactions.html#cfn-networkfirewall-rulegroup-statelessrulesandcustomactions-customactions", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "ItemType": "CustomAction", "Required": false, "Type": "List", @@ -608,7 +608,7 @@ }, "StatelessRules": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-statelessrulesandcustomactions.html#cfn-networkfirewall-rulegroup-statelessrulesandcustomactions-statelessrules", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "ItemType": "StatelessRule", "Required": true, "Type": "List", @@ -621,7 +621,7 @@ "Properties": { "Flags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-tcpflagfield.html#cfn-networkfirewall-rulegroup-tcpflagfield-flags", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": true, "Type": "List", @@ -629,7 +629,7 @@ }, "Masks": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-tcpflagfield.html#cfn-networkfirewall-rulegroup-tcpflagfield-masks", - "DuplicatesAllowed": false, + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": false, "Type": "List", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_NetworkManager.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_NetworkManager.json index c74d96bb7b1e5..01fd7e475bca6 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_NetworkManager.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_NetworkManager.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::NetworkManager::Device.Location": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkmanager-device-location.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_NimbleStudio.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_NimbleStudio.json index b09315338b379..c11221c00052d 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_NimbleStudio.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_NimbleStudio.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::NimbleStudio::LaunchProfile.StreamConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-launchprofile-streamconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_OpenSearchService.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_OpenSearchService.json index 61f50dee6e4ad..9b12f921347de 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_OpenSearchService.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_OpenSearchService.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::OpenSearchService::Domain.AdvancedSecurityOptionsInput": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-advancedsecurityoptionsinput.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_OpsWorks.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_OpsWorks.json index 23f54d76ccc67..d78c3537817ba 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_OpsWorks.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_OpsWorks.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::OpsWorks::App.DataSource": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opsworks-app-datasource.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_OpsWorksCM.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_OpsWorksCM.json index bc74f855b6739..86f16e562ee40 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_OpsWorksCM.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_OpsWorksCM.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::OpsWorksCM::Server.EngineAttribute": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opsworkscm-server-engineattribute.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Panorama.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Panorama.json index 4d0c1d8e7ce5c..996210de5e2a8 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Panorama.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Panorama.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Panorama::ApplicationInstance.ManifestOverridesPayload": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-panorama-applicationinstance-manifestoverridespayload.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Personalize.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Personalize.json new file mode 100644 index 0000000000000..7338d9e5c2624 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Personalize.json @@ -0,0 +1,233 @@ +{ + "$version": "62.0.0", + "PropertyTypes": { + "AWS::Personalize::Dataset.DatasetImportJob": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-personalize-dataset-datasetimportjob.html", + "Properties": { + "DataSource": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-personalize-dataset-datasetimportjob.html#cfn-personalize-dataset-datasetimportjob-datasource", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + }, + "DatasetArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-personalize-dataset-datasetimportjob.html#cfn-personalize-dataset-datasetimportjob-datasetarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "DatasetImportJobArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-personalize-dataset-datasetimportjob.html#cfn-personalize-dataset-datasetimportjob-datasetimportjobarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "JobName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-personalize-dataset-datasetimportjob.html#cfn-personalize-dataset-datasetimportjob-jobname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-personalize-dataset-datasetimportjob.html#cfn-personalize-dataset-datasetimportjob-rolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Personalize::Solution.SolutionConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-personalize-solution-solutionconfig.html", + "Properties": { + "AlgorithmHyperParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-personalize-solution-solutionconfig.html#cfn-personalize-solution-solutionconfig-algorithmhyperparameters", + "PrimitiveItemType": "String", + "Required": false, + "Type": "Map", + "UpdateType": "Immutable" + }, + "AutoMLConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-personalize-solution-solutionconfig.html#cfn-personalize-solution-solutionconfig-automlconfig", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Immutable" + }, + "EventValueThreshold": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-personalize-solution-solutionconfig.html#cfn-personalize-solution-solutionconfig-eventvaluethreshold", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "FeatureTransformationParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-personalize-solution-solutionconfig.html#cfn-personalize-solution-solutionconfig-featuretransformationparameters", + "PrimitiveItemType": "String", + "Required": false, + "Type": "Map", + "UpdateType": "Immutable" + }, + "HpoConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-personalize-solution-solutionconfig.html#cfn-personalize-solution-solutionconfig-hpoconfig", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Immutable" + } + } + } + }, + "ResourceTypes": { + "AWS::Personalize::Dataset": { + "Attributes": { + "DatasetArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-dataset.html", + "Properties": { + "DatasetGroupArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-dataset.html#cfn-personalize-dataset-datasetgrouparn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "DatasetImportJob": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-dataset.html#cfn-personalize-dataset-datasetimportjob", + "Required": false, + "Type": "DatasetImportJob", + "UpdateType": "Mutable" + }, + "DatasetType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-dataset.html#cfn-personalize-dataset-datasettype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-dataset.html#cfn-personalize-dataset-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "SchemaArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-dataset.html#cfn-personalize-dataset-schemaarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::Personalize::DatasetGroup": { + "Attributes": { + "DatasetGroupArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-datasetgroup.html", + "Properties": { + "Domain": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-datasetgroup.html#cfn-personalize-datasetgroup-domain", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "KmsKeyArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-datasetgroup.html#cfn-personalize-datasetgroup-kmskeyarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-datasetgroup.html#cfn-personalize-datasetgroup-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-datasetgroup.html#cfn-personalize-datasetgroup-rolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::Personalize::Schema": { + "Attributes": { + "SchemaArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-schema.html", + "Properties": { + "Domain": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-schema.html#cfn-personalize-schema-domain", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-schema.html#cfn-personalize-schema-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Schema": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-schema.html#cfn-personalize-schema-schema", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::Personalize::Solution": { + "Attributes": { + "SolutionArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-solution.html", + "Properties": { + "DatasetGroupArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-solution.html#cfn-personalize-solution-datasetgrouparn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "EventType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-solution.html#cfn-personalize-solution-eventtype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-solution.html#cfn-personalize-solution-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "PerformAutoML": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-solution.html#cfn-personalize-solution-performautoml", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Immutable" + }, + "PerformHPO": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-solution.html#cfn-personalize-solution-performhpo", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Immutable" + }, + "RecipeArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-solution.html#cfn-personalize-solution-recipearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "SolutionConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-solution.html#cfn-personalize-solution-solutionconfig", + "Required": false, + "Type": "SolutionConfig", + "UpdateType": "Immutable" + } + } + } + } +} diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Pinpoint.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Pinpoint.json index b517c723905d8..745a5a954231c 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Pinpoint.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Pinpoint.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Pinpoint::ApplicationSettings.CampaignHook": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-applicationsettings-campaignhook.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_PinpointEmail.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_PinpointEmail.json index 3aad63d2aac94..cc8ec549f6c9d 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_PinpointEmail.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_PinpointEmail.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::PinpointEmail::ConfigurationSet.DeliveryOptions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpointemail-configurationset-deliveryoptions.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_QLDB.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_QLDB.json index 0276e44cc081c..c79dcca718bda 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_QLDB.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_QLDB.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::QLDB::Stream.KinesisConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-qldb-stream-kinesisconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_QuickSight.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_QuickSight.json index dba094b8566c5..27fbc41d6b7c1 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_QuickSight.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_QuickSight.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::QuickSight::Analysis.AnalysisError": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-analysis-analysiserror.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RAM.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RAM.json index b0d2798efa052..a29931bfe0ea7 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RAM.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RAM.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::RAM::ResourceShare": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RDS.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RDS.json index 8769325792641..8c736b53103db 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RDS.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RDS.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::RDS::DBCluster.DBClusterRole": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-dbcluster-dbclusterrole.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RUM.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RUM.json index ec5af259ff333..5bc6f30391434 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RUM.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RUM.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::RUM::AppMonitor.AppMonitorConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rum-appmonitor-appmonitorconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Redshift.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Redshift.json index b426950efd302..3629c5115177b 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Redshift.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Redshift.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Redshift::Cluster.Endpoint": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-cluster-endpoint.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RefactorSpaces.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RefactorSpaces.json index 57f86550c7c6c..244630b2a83fe 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RefactorSpaces.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RefactorSpaces.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::RefactorSpaces::Application.ApiGatewayProxyInput": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-refactorspaces-application-apigatewayproxyinput.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Rekognition.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Rekognition.json index 4b7745bcf3b41..05a2634638b49 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Rekognition.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Rekognition.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::Rekognition::Collection": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ResilienceHub.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ResilienceHub.json index 381e53e4108d5..6d89c6372e982 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ResilienceHub.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ResilienceHub.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::ResilienceHub::App.PhysicalResourceId": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resiliencehub-app-physicalresourceid.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ResourceGroups.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ResourceGroups.json index a77762f9d4914..dce994bb4dbb9 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ResourceGroups.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ResourceGroups.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::ResourceGroups::Group.ConfigurationItem": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-configurationitem.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RoboMaker.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RoboMaker.json index 2b22457c58c07..e9030414622d4 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RoboMaker.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_RoboMaker.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::RoboMaker::RobotApplication.RobotSoftwareSuite": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-robomaker-robotapplication-robotsoftwaresuite.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Route53.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Route53.json index b50286ed16b6a..cab6632eb5ebe 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Route53.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Route53.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Route53::HealthCheck.HealthCheckTag": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthchecktag.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Route53RecoveryControl.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Route53RecoveryControl.json index aa98faf3b1dfe..7fa168c98f3d6 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Route53RecoveryControl.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Route53RecoveryControl.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Route53RecoveryControl::Cluster.ClusterEndpoint": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53recoverycontrol-cluster-clusterendpoint.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Route53RecoveryReadiness.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Route53RecoveryReadiness.json index 141ab284dddb4..cff04ffe1db8e 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Route53RecoveryReadiness.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Route53RecoveryReadiness.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Route53RecoveryReadiness::ResourceSet.DNSTargetResource": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53recoveryreadiness-resourceset-dnstargetresource.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Route53Resolver.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Route53Resolver.json index cce5c402515bb..167e2d7f6a071 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Route53Resolver.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Route53Resolver.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Route53Resolver::FirewallRuleGroup.FirewallRule": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53resolver-firewallrulegroup-firewallrule.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_S3.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_S3.json index b6ba027e15e29..41ba5c107ed6b 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_S3.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_S3.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::S3::AccessPoint.PublicAccessBlockConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-accesspoint-publicaccessblockconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_S3ObjectLambda.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_S3ObjectLambda.json index 84f9abcd11248..5a159d6c3017d 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_S3ObjectLambda.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_S3ObjectLambda.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::S3ObjectLambda::AccessPoint.ObjectLambdaConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3objectlambda-accesspoint-objectlambdaconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_S3Outposts.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_S3Outposts.json index 76b8194798961..606d9937a6fe8 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_S3Outposts.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_S3Outposts.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::S3Outposts::AccessPoint.VpcConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3outposts-accesspoint-vpcconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SDB.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SDB.json index 59c94899631cf..fcca6d6b5c862 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SDB.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SDB.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::SDB::Domain": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SES.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SES.json index 03ece58e2fcbb..65b1f9060108b 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SES.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SES.json @@ -1,11 +1,12 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::SES::ConfigurationSetEventDestination.CloudWatchDestination": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-configurationseteventdestination-cloudwatchdestination.html", "Properties": { "DimensionConfigurations": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-configurationseteventdestination-cloudwatchdestination.html#cfn-ses-configurationseteventdestination-cloudwatchdestination-dimensionconfigurations", + "DuplicatesAllowed": true, "ItemType": "DimensionConfiguration", "Required": false, "Type": "List", @@ -59,6 +60,7 @@ }, "MatchingEventTypes": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-configurationseteventdestination-eventdestination.html#cfn-ses-configurationseteventdestination-eventdestination-matchingeventtypes", + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": true, "Type": "List", @@ -409,7 +411,7 @@ "SubjectPart": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-template-template.html#cfn-ses-template-template-subjectpart", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "TemplateName": { @@ -440,6 +442,11 @@ } }, "AWS::SES::ConfigurationSetEventDestination": { + "Attributes": { + "Id": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ses-configurationseteventdestination.html", "Properties": { "ConfigurationSetName": { @@ -533,6 +540,11 @@ } }, "AWS::SES::Template": { + "Attributes": { + "Id": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ses-template.html", "Properties": { "Template": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SNS.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SNS.json index 516bbb8847ac3..f1be4f95b6d34 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SNS.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SNS.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::SNS::Topic.Subscription": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sns-subscription.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SQS.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SQS.json index fda51e4e831dd..ad4aa5617c916 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SQS.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SQS.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::SQS::Queue": { @@ -9,90 +9,93 @@ }, "QueueName": { "PrimitiveType": "String" + }, + "QueueUrl": { + "PrimitiveType": "String" } }, - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html", "Properties": { "ContentBasedDeduplication": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-contentbaseddeduplication", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-contentbaseddeduplication", "PrimitiveType": "Boolean", "Required": false, "UpdateType": "Mutable" }, "DeduplicationScope": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-deduplicationscope", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-deduplicationscope", "PrimitiveType": "String", "Required": false, "UpdateType": "Mutable" }, "DelaySeconds": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-delayseconds", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-delayseconds", "PrimitiveType": "Integer", "Required": false, "UpdateType": "Mutable" }, "FifoQueue": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-fifoqueue", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-fifoqueue", "PrimitiveType": "Boolean", "Required": false, "UpdateType": "Immutable" }, "FifoThroughputLimit": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-fifothroughputlimit", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-fifothroughputlimit", "PrimitiveType": "String", "Required": false, "UpdateType": "Mutable" }, "KmsDataKeyReusePeriodSeconds": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-kmsdatakeyreuseperiodseconds", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-kmsdatakeyreuseperiodseconds", "PrimitiveType": "Integer", "Required": false, "UpdateType": "Mutable" }, "KmsMasterKeyId": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-kmsmasterkeyid", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-kmsmasterkeyid", "PrimitiveType": "String", "Required": false, "UpdateType": "Mutable" }, "MaximumMessageSize": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-maxmesgsize", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-maximummessagesize", "PrimitiveType": "Integer", "Required": false, "UpdateType": "Mutable" }, "MessageRetentionPeriod": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-msgretentionperiod", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-messageretentionperiod", "PrimitiveType": "Integer", "Required": false, "UpdateType": "Mutable" }, "QueueName": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-name", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-queuename", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" }, "ReceiveMessageWaitTimeSeconds": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-receivemsgwaittime", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-receivemessagewaittimeseconds", "PrimitiveType": "Integer", "Required": false, "UpdateType": "Mutable" }, "RedriveAllowPolicy": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-redriveallowpolicy", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-redriveallowpolicy", "PrimitiveType": "Json", "Required": false, "UpdateType": "Mutable" }, "RedrivePolicy": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-redrive", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-redrivepolicy", "PrimitiveType": "Json", "Required": false, "UpdateType": "Mutable" }, "Tags": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#cfn-sqs-queue-tags", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-tags", "DuplicatesAllowed": true, "ItemType": "Tag", "Required": false, @@ -100,7 +103,7 @@ "UpdateType": "Mutable" }, "VisibilityTimeout": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-visiblitytimeout", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html#cfn-sqs-queue-visibilitytimeout", "PrimitiveType": "Integer", "Required": false, "UpdateType": "Mutable" diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SSM.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SSM.json index 0f09e4a619bc8..52e3472b8283b 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SSM.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SSM.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::SSM::Association.InstanceAssociationOutputLocation": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ssm-association-instanceassociationoutputlocation.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SSMContacts.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SSMContacts.json index 85290d231e8cc..85b57e417440b 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SSMContacts.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SSMContacts.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::SSMContacts::Contact.ChannelTargetInfo": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ssmcontacts-contact-channeltargetinfo.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SSMIncidents.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SSMIncidents.json index a454c9fb8aaeb..ab44592fea2bf 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SSMIncidents.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SSMIncidents.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::SSMIncidents::ReplicationSet.RegionConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ssmincidents-replicationset-regionconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SSO.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SSO.json index 7dce51b9e0298..1d1440ab395a8 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SSO.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SSO.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::SSO::InstanceAccessControlAttributeConfiguration.AccessControlAttribute": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sso-instanceaccesscontrolattributeconfiguration-accesscontrolattribute.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SageMaker.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SageMaker.json index c21f160a3bdaf..56ea6f7cfb860 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SageMaker.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SageMaker.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::SageMaker::App.ResourceSpec": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-app-resourcespec.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SecretsManager.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SecretsManager.json index c202984f7b2b0..f244c0790c684 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SecretsManager.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SecretsManager.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::SecretsManager::RotationSchedule.HostedRotationLambda": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-secretsmanager-rotationschedule-hostedrotationlambda.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SecurityHub.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SecurityHub.json index e539367cc4cfd..0c2b4c4e27e19 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SecurityHub.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_SecurityHub.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::SecurityHub::Hub": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ServiceCatalog.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ServiceCatalog.json index 0689d2f78b384..d8cfd9227d7c6 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ServiceCatalog.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ServiceCatalog.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::ServiceCatalog::CloudFormationProduct.ProvisioningArtifactProperties": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-servicecatalog-cloudformationproduct-provisioningartifactproperties.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ServiceCatalogAppRegistry.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ServiceCatalogAppRegistry.json index 6f6c2518e24e7..27a603fcf7cb9 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ServiceCatalogAppRegistry.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ServiceCatalogAppRegistry.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": {}, "ResourceTypes": { "AWS::ServiceCatalogAppRegistry::Application": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ServiceDiscovery.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ServiceDiscovery.json index 08472d7bd4297..6533cfd0ed89f 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ServiceDiscovery.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ServiceDiscovery.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::ServiceDiscovery::PrivateDnsNamespace.PrivateDnsPropertiesMutable": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-servicediscovery-privatednsnamespace-privatednspropertiesmutable.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Signer.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Signer.json index a430dc9081ac7..ac65819177be2 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Signer.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Signer.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Signer::SigningProfile.SignatureValidityPeriod": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-signer-signingprofile-signaturevalidityperiod.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_StepFunctions.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_StepFunctions.json index 3ddd071498d13..f837189a4079a 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_StepFunctions.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_StepFunctions.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::StepFunctions::Activity.TagsEntry": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stepfunctions-activity-tagsentry.html", @@ -208,7 +208,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-statemachinetype", "PrimitiveType": "String", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tags", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Synthetics.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Synthetics.json index 662e64e261103..8d2f18abd9309 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Synthetics.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Synthetics.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Synthetics::Canary.ArtifactConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-synthetics-canary-artifactconfig.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Timestream.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Timestream.json index a1121fc7900e9..cb18ef5d2fa0d 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Timestream.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Timestream.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Timestream::ScheduledQuery.DimensionMapping": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-timestream-scheduledquery-dimensionmapping.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Transfer.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Transfer.json index 9fe320dca073e..2570ee33a06ce 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Transfer.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Transfer.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Transfer::Server.EndpointDetails": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-transfer-server-endpointdetails.html", @@ -257,6 +257,18 @@ "Required": false, "UpdateType": "Mutable" }, + "PostAuthenticationLoginBanner": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-transfer-server.html#cfn-transfer-server-postauthenticationloginbanner", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PreAuthenticationLoginBanner": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-transfer-server.html#cfn-transfer-server-preauthenticationloginbanner", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "ProtocolDetails": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-transfer-server.html#cfn-transfer-server-protocoldetails", "Required": false, diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_WAF.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_WAF.json index c47d1a070c415..aef9d7abb75ec 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_WAF.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_WAF.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::WAF::ByteMatchSet.ByteMatchTuple": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-waf-bytematchset-bytematchtuples.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_WAFRegional.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_WAFRegional.json index 204877292f328..d6d436cdb9274 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_WAFRegional.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_WAFRegional.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::WAFRegional::ByteMatchSet.ByteMatchTuple": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafregional-bytematchset-bytematchtuple.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_WAFv2.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_WAFv2.json index f14305b590101..cd2524b6eed39 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_WAFv2.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_WAFv2.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::WAFv2::LoggingConfiguration.FieldToMatch": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-loggingconfiguration-fieldtomatch.html", @@ -898,6 +898,17 @@ } } }, + "AWS::WAFv2::WebACL.FieldIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-fieldidentifier.html", + "Properties": { + "Identifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-fieldidentifier.html#cfn-wafv2-webacl-fieldidentifier-identifier", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::WAFv2::WebACL.FieldToMatch": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-fieldtomatch.html", "Properties": { @@ -1106,6 +1117,35 @@ } } }, + "AWS::WAFv2::WebACL.ManagedRuleGroupConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-managedrulegroupconfig.html", + "Properties": { + "LoginPath": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-managedrulegroupconfig.html#cfn-wafv2-webacl-managedrulegroupconfig-loginpath", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PasswordField": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-managedrulegroupconfig.html#cfn-wafv2-webacl-managedrulegroupconfig-passwordfield", + "Required": false, + "Type": "FieldIdentifier", + "UpdateType": "Mutable" + }, + "PayloadType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-managedrulegroupconfig.html#cfn-wafv2-webacl-managedrulegroupconfig-payloadtype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "UsernameField": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-managedrulegroupconfig.html#cfn-wafv2-webacl-managedrulegroupconfig-usernamefield", + "Required": false, + "Type": "FieldIdentifier", + "UpdateType": "Mutable" + } + } + }, "AWS::WAFv2::WebACL.ManagedRuleGroupStatement": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-managedrulegroupstatement.html", "Properties": { @@ -1116,6 +1156,13 @@ "Type": "List", "UpdateType": "Mutable" }, + "ManagedRuleGroupConfigs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-managedrulegroupstatement.html#cfn-wafv2-webacl-managedrulegroupstatement-managedrulegroupconfigs", + "ItemType": "ManagedRuleGroupConfig", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-managedrulegroupstatement.html#cfn-wafv2-webacl-managedrulegroupstatement-name", "PrimitiveType": "String", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Wisdom.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Wisdom.json index 653a3363b8bcd..b100b5ba69b48 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Wisdom.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_Wisdom.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::Wisdom::Assistant.ServerSideEncryptionConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wisdom-assistant-serversideencryptionconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_WorkSpaces.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_WorkSpaces.json index c9cdd9de0e87b..d1d1b380fd109 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_WorkSpaces.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_WorkSpaces.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::WorkSpaces::ConnectionAlias.ConnectionAliasAssociation": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-workspaces-connectionalias-connectionaliasassociation.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_XRay.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_XRay.json index 521323411b34a..cc356a17882c1 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_XRay.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_XRay.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "AWS::XRay::Group.InsightsConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-xray-group-insightsconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_Alexa_ASK.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_Alexa_ASK.json index b136d975add06..c3f50a0424edd 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_Alexa_ASK.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_Alexa_ASK.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "Alexa::ASK::Skill.AuthenticationConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ask-skill-authenticationconfiguration.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_Tag.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_Tag.json index 8e8941795f83c..2218ba7d03d34 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_Tag.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_Tag.json @@ -1,5 +1,5 @@ { - "$version": "55.0.0", + "$version": "62.0.0", "PropertyTypes": { "Tag": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resource-tags.html", diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/001_Version.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/001_Version.json index dfcc1fc789972..0b72c26e9f22e 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/001_Version.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/001_Version.json @@ -1,3 +1,3 @@ { - "ResourceSpecificationVersion": "55.0.0" + "ResourceSpecificationVersion": "62.0.0" } diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/1002_Lex_BotAlias_TextLogDestination_patch.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/1002_Lex_BotAlias_TextLogDestination_patch.json deleted file mode 100644 index a34166be675b3..0000000000000 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/1002_Lex_BotAlias_TextLogDestination_patch.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "PropertyTypes": { - "AWS::Lex::BotAlias.TextLogDestination": { - "patch": { - "description": "Temporarily remove AWS::Lex::BotAlias.TextLogDestination.CloudWatch until cfn specs for it are stable.", - "operations": [ - { - "op": "remove", - "path": "/Properties/CloudWatch" - } - ] - } - } - } -} diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/index.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/index.ts index 50c2dc35a5eab..5fd6eb6ceda07 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/index.ts +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/index.ts @@ -1,3 +1,4 @@ export * from './cloud-assembly'; export * from './assets'; export * from './manifest'; +export * from './integ-tests'; diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/common.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/common.ts new file mode 100644 index 0000000000000..01ab969b63098 --- /dev/null +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/common.ts @@ -0,0 +1,202 @@ +/** + * In what scenarios should the CLI ask for approval + */ +export enum RequireApproval { + /** + * Never ask for approval + */ + NEVER = 'never', + + /** + * Prompt for approval for any type of change to the stack + */ + ANYCHANGE = 'any-change', + + /** + * Only prompt for approval if there are security related changes + */ + BROADENING = 'broadening' +} + +/** + * Default CDK CLI options that apply to all commands + */ +export interface DefaultCdkOptions { + /** + * List of stacks to deploy + * + * Requried if `all` is not set + * + * @default - [] + */ + readonly stacks?: string[]; + + /** + * Deploy all stacks + * + * Requried if `stacks` is not set + * + * @default - false + */ + readonly all?: boolean; + + /** + * command-line for executing your app or a cloud assembly directory + * e.g. "node bin/my-app.js" + * or + * "cdk.out" + * + * @default - read from cdk.json + */ + readonly app?: string; + + + /** + * Role to pass to CloudFormation for deployment + * + * @default - use the bootstrap cfn-exec role + */ + readonly roleArn?: string; + + /** + * Additional context + * + * @default - no additional context + */ + readonly context?: { [name: string]: string }; + + /** + * Print trace for stack warnings + * + * @default false + */ + readonly trace?: boolean; + + /** + * Do not construct stacks with warnings + * + * @default false + */ + readonly strict?: boolean; + + /** + * Perform context lookups. + * + * Synthesis fails if this is disabled and context lookups need + * to be performed + * + * @default true + */ + readonly lookups?: boolean; + + /** + * Ignores synthesis errors, which will likely produce an invalid output + * + * @default false + */ + readonly ignoreErrors?: boolean; + + /** + * Use JSON output instead of YAML when templates are printed + * to STDOUT + * + * @default false + */ + readonly json?: boolean; + + /** + * show debug logs + * + * @default false + */ + readonly verbose?: boolean; + + /** + * enable emission of additional debugging information, such as creation stack + * traces of tokens + * + * @default false + */ + readonly debug?: boolean; + + /** + * Use the indicated AWS profile as the default environment + * + * @default - no profile is used + */ + readonly profile?: string; + + /** + * Use the indicated proxy. Will read from + * HTTPS_PROXY environment if specified + * + * @default - no proxy + */ + readonly proxy?: string; + + /** + * Path to CA certificate to use when validating HTTPS + * requests. + * + * @default - read from AWS_CA_BUNDLE environment variable + */ + readonly caBundlePath?: string; + + /** + * Force trying to fetch EC2 instance credentials + * + * @default - guess EC2 instance status + */ + readonly ec2Creds?: boolean; + + /** + * Include "AWS::CDK::Metadata" resource in synthesized templates + * + * @default true + */ + readonly versionReporting?: boolean; + + /** + * Include "aws:cdk:path" CloudFormation metadata for each resource + * + * @default true + */ + readonly pathMetadata?: boolean; + + /** + * Include "aws:asset:*" CloudFormation metadata for resources that use assets + * + * @default true + */ + readonly assetMetadata?: boolean; + + /** + * Copy assets to the output directory + * + * Needed for local debugging the source files with SAM CLI + * + * @default false + */ + readonly staging?: boolean; + + /** + * Emits the synthesized cloud assembly into a directory + * + * @default cdk.out + */ + readonly output?: string; + + /** + * Show relevant notices + * + * @default true + */ + readonly notices?: boolean; + + /** + * Show colors and other style from console output + * + * @default true + */ + readonly color?: boolean; +} diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/deploy.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/deploy.ts new file mode 100644 index 0000000000000..09a20c610f12d --- /dev/null +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/deploy.ts @@ -0,0 +1,97 @@ +import { DefaultCdkOptions, RequireApproval } from './common'; + +/** + * Options to use with cdk deploy + */ +export interface DeployOptions extends DefaultCdkOptions { + /** + * Only perform action on the given stack + * + * @default false + */ + readonly exclusively?: boolean; + + /** + * Name of the toolkit stack to use/deploy + * + * @default CDKToolkit + */ + readonly toolkitStackName?: string; + + /** + * Reuse the assets with the given asset IDs + * + * @default - do not reuse assets + */ + readonly reuseAssets?: string[]; + + /** + * Optional name to use for the CloudFormation change set. + * If not provided, a name will be generated automatically. + * + * @default - auto generate a name + */ + readonly changeSetName?: string; + + /** + * Always deploy, even if templates are identical. + * @default false + */ + readonly force?: boolean; + + /** + * Rollback failed deployments + * + * @default true + */ + readonly rollback?: boolean; + + /** + * ARNs of SNS topics that CloudFormation will notify with stack related events + * + * @default - no notifications + */ + readonly notificationArns?: string[]; + + /** + * What kind of security changes require approval + * + * @default RequireApproval.Never + */ + readonly requireApproval?: RequireApproval; + + /** + * Whether to execute the ChangeSet + * Not providing `execute` parameter will result in execution of ChangeSet + * @default true + */ + readonly execute?: boolean; + + /** + * Additional parameters for CloudFormation at deploy time + * @default {} + */ + readonly parameters?: { [name: string]: string }; + + /** + * Use previous values for unspecified parameters + * + * If not set, all parameters must be specified for every deployment. + * + * @default true + */ + readonly usePreviousParameters?: boolean; + + /** + * Path to file where stack outputs will be written after a successful deploy as JSON + * @default - Outputs are not written to any file + */ + readonly outputsFile?: string; + + /** + * Whether we are on a CI system + * + * @default false + */ + readonly ci?: boolean; +} diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/destroy.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/destroy.ts new file mode 100644 index 0000000000000..9dfe8f267c6db --- /dev/null +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/destroy.ts @@ -0,0 +1,20 @@ +import { DefaultCdkOptions } from './common'; + +/** + * Options to use with cdk destroy + */ +export interface DestroyOptions extends DefaultCdkOptions { + /** + * Do not ask for permission before destroying stacks + * + * @default false + */ + readonly force?: boolean; + + /** + * Only destroy the given stack + * + * @default false + */ + readonly exclusively?: boolean; +} diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/index.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/index.ts new file mode 100644 index 0000000000000..528980446938b --- /dev/null +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/index.ts @@ -0,0 +1,3 @@ +export * from './common'; +export * from './deploy'; +export * from './destroy'; diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/index.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/index.ts new file mode 100644 index 0000000000000..5a08e62a47958 --- /dev/null +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/index.ts @@ -0,0 +1,3 @@ +export * from './schema'; +export * from './commands'; +export * from './test-case'; diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/schema.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/schema.ts new file mode 100644 index 0000000000000..4eccc8a6422b4 --- /dev/null +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/schema.ts @@ -0,0 +1,26 @@ +import { TestCase } from './test-case'; +/** + * Definitions for the integration testing manifest + */ +export interface IntegManifest { + /** + * Version of the manifest + */ + readonly version: string; + + /** + * Enable lookups for this test. If lookups are enabled + * then `stackUpdateWorkflow` must be set to false. + * Lookups should only be enabled when you are explicitely testing + * lookups. + * + * @default false + */ + readonly enableLookups?: boolean; + + /** + * test cases + */ + readonly testCases: { [testName: string]: TestCase }; +} + diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/test-case.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/test-case.ts new file mode 100644 index 0000000000000..6d3ecc05c626e --- /dev/null +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/test-case.ts @@ -0,0 +1,186 @@ +import { DeployOptions, DestroyOptions } from './commands'; + +/** + * Represents an integration test test case + */ +export interface TestCase { + /** + * Stacks that should be tested as part of this test case + * The stackNames will be passed as args to the cdk commands + * so dependent stacks will be automatically deployed unless + * `exclusively` is passed + */ + readonly stacks: string[]; + + /** + * Run update workflow on this test case + * This should only be set to false to test scenarios + * that are not possible to test as part of the update workflow + * + * @default true + */ + readonly stackUpdateWorkflow?: boolean; + + /** + * Additional options to use for each CDK command + * + * @default - runner default options + */ + readonly cdkCommandOptions?: CdkCommands; + + /** + * Additional commands to run at predefined points in the test workflow + * + * e.g. { postDeploy: ['yarn', 'test'] } + * + * @default - no hooks + */ + readonly hooks?: Hooks; + + /** + * Whether or not to include asset hashes in the diff + * Asset hashes can introduces a lot of unneccessary noise into tests, + * but there are some cases where asset hashes _should_ be included. For example + * any tests involving custom resources or bundling + * + * @default false + */ + readonly diffAssets?: boolean; + + /** + * List of CloudFormation resource types in this stack that can + * be destroyed as part of an update without failing the test. + * + * This list should only include resources that for this specific + * integration test we are sure will not cause errors or an outage if + * destroyed. For example, maybe we know that a new resource will be created + * first before the old resource is destroyed which prevents any outage. + * + * e.g. ['AWS::IAM::Role'] + * + * @default - do not allow destruction of any resources on update + */ + readonly allowDestroy?: string[]; + + /** + * Limit deployment to these regions + * + * @default - can run in any region + */ + readonly regions?: string[]; +} + +/** + * Commands to run at predefined points during the + * integration test workflow + */ +export interface Hooks { + /** + * Commands to run prior to deploying the cdk stacks + * in the integration test + * + * @default - no commands + */ + readonly preDeploy?: string[]; + + /** + * Commands to run prior after deploying the cdk stacks + * in the integration test + * + * @default - no commands + */ + readonly postDeploy?: string[]; + + /** + * Commands to run prior to destroying the cdk stacks + * in the integration test + * + * @default - no commands + */ + readonly preDestroy?: string[]; + + /** + * Commands to run after destroying the cdk stacks + * in the integration test + * + * @default - no commands + */ + readonly postDestroy?: string[]; +} + +/** + * Represents a cdk command + * i.e. `synth`, `deploy`, & `destroy` + */ +export interface CdkCommand { + /** + * Whether or not to run this command as part of the workflow + * This can be used if you only want to test some of the workflow + * for example enable `synth` and disable `deploy` & `destroy` in order + * to limit the test to synthesis + * + * @default true + */ + readonly enabled?: boolean; + + /** + * If the runner should expect this command to fail + * + * @default false + */ + readonly expectError?: boolean; + + /** + * This can be used in combination with `expectedError` + * to validate that a specific message is returned. + * + * @default - do not validate message + */ + readonly expectedMessage?: string; +} + +/** + * Represents a cdk deploy command + */ +export interface DeployCommand extends CdkCommand { + /** + * Additional arguments to pass to the command + * This can be used to test specific CLI functionality + * + * @default - only default args are used + */ + readonly args?: DeployOptions; +} + +/** + * Represents a cdk destroy command + */ +export interface DestroyCommand extends CdkCommand { + /** + * Additional arguments to pass to the command + * This can be used to test specific CLI functionality + * + * @default - only default args are used + */ + readonly args?: DestroyOptions; +} + +/** + * Options for specific cdk commands that are run + * as part of the integration test workflow + */ +export interface CdkCommands { + /** + * Options to for the cdk deploy command + * + * @default - default deploy options + */ + readonly deploy?: DeployCommand; + + /** + * Options to for the cdk destroy command + * + * @default - default destroy options + */ + readonly destroy?: DestroyCommand; +} diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/manifest.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/manifest.ts index 1e3ea7afa62e7..62f7894a54dd3 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/manifest.ts +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/manifest.ts @@ -3,6 +3,7 @@ import * as jsonschema from 'jsonschema'; import * as semver from 'semver'; import * as assets from './assets'; import * as assembly from './cloud-assembly'; +import * as integ from './integ-tests'; /* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-require-imports */ @@ -21,6 +22,34 @@ const ASSEMBLY_SCHEMA = require('../schema/cloud-assembly.schema.json'); */ const SCHEMA_VERSION = require('../schema/cloud-assembly.version.json').version; +const INTEG_SCHEMA = require('../schema/integ.schema.json'); + +/** + * Options for the loadManifest operation + */ +export interface LoadManifestOptions { + /** + * Skip the version check + * + * This means you may read a newer cloud assembly than the CX API is designed + * to support, and your application may not be aware of all features that in use + * in the Cloud Assembly. + * + * @default false + */ + readonly skipVersionCheck?: boolean; + + /** + * Skip enum checks + * + * This means you may read enum values you don't know about yet. Make sure to always + * check the values of enums you encounter in the manifest. + * + * @default false + */ + readonly skipEnumCheck?: boolean; +} + /** * Protocol utility class. */ @@ -40,8 +69,8 @@ export class Manifest { * * @param filePath - path to the manifest file. */ - public static loadAssemblyManifest(filePath: string): assembly.AssemblyManifest { - return Manifest.loadManifest(filePath, ASSEMBLY_SCHEMA, Manifest.patchStackTagsOnRead); + public static loadAssemblyManifest(filePath: string, options?: LoadManifestOptions): assembly.AssemblyManifest { + return Manifest.loadManifest(filePath, ASSEMBLY_SCHEMA, Manifest.patchStackTagsOnRead, options); } /** @@ -63,6 +92,25 @@ export class Manifest { return this.loadManifest(filePath, ASSETS_SCHEMA); } + /** + * Validates and saves the integ manifest to file. + * + * @param manifest - manifest. + * @param filePath - output file path. + */ + public static saveIntegManifest(manifest: integ.IntegManifest, filePath: string) { + Manifest.saveManifest(manifest, filePath, INTEG_SCHEMA); + } + + /** + * Load and validates the integ manifest from file. + * + * @param filePath - path to the manifest file. + */ + public static loadIntegManifest(filePath: string): integ.IntegManifest { + return this.loadManifest(filePath, INTEG_SCHEMA); + } + /** * Fetch the current schema version number. */ @@ -82,8 +130,7 @@ export class Manifest { */ public static load(filePath: string): assembly.AssemblyManifest { return this.loadAssemblyManifest(filePath); } - private static validate(manifest: { version: string }, schema: jsonschema.Schema) { - + private static validate(manifest: { version: string }, schema: jsonschema.Schema, options?: LoadManifestOptions) { function parseVersion(version: string) { const ver = semver.valid(version); if (!ver) { @@ -96,7 +143,7 @@ export class Manifest { const actual = parseVersion(manifest.version); // first validate the version should be accepted. - if (semver.gt(actual, maxSupported)) { + if (semver.gt(actual, maxSupported) && !options?.skipVersionCheck) { // we use a well known error prefix so that the CLI can identify this specific error // and print some more context to the user. throw new Error(`${VERSION_MISMATCH}: Maximum schema version supported is ${maxSupported}, but found ${actual}`); @@ -112,10 +159,16 @@ export class Manifest { allowUnknownAttributes: false, } as any); - if (!result.valid) { - throw new Error(`Invalid assembly manifest:\n${result}`); + + let errors = result.errors; + if (options?.skipEnumCheck) { + // Enum validations aren't useful when + errors = stripEnumErrors(errors); } + if (errors.length > 0) { + throw new Error(`Invalid assembly manifest:\n${errors.map(e => e.stack).join('\n')}`); + } } private static saveManifest(manifest: any, filePath: string, schema: jsonschema.Schema, preprocess?: (obj: any) => any) { @@ -127,12 +180,12 @@ export class Manifest { fs.writeFileSync(filePath, JSON.stringify(withVersion, undefined, 2)); } - private static loadManifest(filePath: string, schema: jsonschema.Schema, preprocess?: (obj: any) => any) { + private static loadManifest(filePath: string, schema: jsonschema.Schema, preprocess?: (obj: any) => any, options?: LoadManifestOptions) { let obj = JSON.parse(fs.readFileSync(filePath, { encoding: 'utf-8' })); if (preprocess) { obj = preprocess(obj); } - Manifest.validate(obj, schema); + Manifest.validate(obj, schema, options); return obj; } @@ -216,4 +269,8 @@ function noUndefined(xs: A): A { } } return ret; -} \ No newline at end of file +} + +function stripEnumErrors(errors: jsonschema.ValidationError[]) { + return errors.filter(e => typeof e.schema ==='string' || !('enum' in e.schema)); +} diff --git a/packages/@aws-cdk/cloud-assembly-schema/package.json b/packages/@aws-cdk/cloud-assembly-schema/package.json index 10f27bc65691d..8ac885479f264 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/package.json +++ b/packages/@aws-cdk/cloud-assembly-schema/package.json @@ -62,10 +62,10 @@ "devDependencies": { "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "@types/mock-fs": "^4.13.1", "@types/semver": "^7.3.9", - "jest": "^27.4.7", + "jest": "^27.5.1", "mock-fs": "^4.14.0", "typescript-json-schema": "^0.53.0" }, diff --git a/packages/@aws-cdk/cloud-assembly-schema/schema/assets.schema.json b/packages/@aws-cdk/cloud-assembly-schema/schema/assets.schema.json index d3e0b91b97875..40134a4e554a5 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/schema/assets.schema.json +++ b/packages/@aws-cdk/cloud-assembly-schema/schema/assets.schema.json @@ -156,7 +156,7 @@ } }, "networkMode": { - "description": "Networking mode for the RUN commands during build. _Requires Docker Engine API v1.25+_. (Default - no networking mode specified)", + "description": "Networking mode for the RUN commands during build. _Requires Docker Engine API v1.25+_.\n\nSpecify this property to build images on a specific networking mode. (Default - no networking mode specified)", "type": "string" } } @@ -193,4 +193,4 @@ } }, "$schema": "http://json-schema.org/draft-07/schema#" -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json index f52022659f86f..19ab465985d24 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json +++ b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json @@ -227,7 +227,7 @@ "type": "string" }, "networkMode": { - "description": "Networking mode for the RUN commands during build. _Requires Docker Engine API v1.25+_. (Default - no networking mode specified)", + "description": "Networking mode for the RUN commands during build. (Default - no networking mode specified)", "type": "string" }, "id": { @@ -874,4 +874,4 @@ } }, "$schema": "http://json-schema.org/draft-07/schema#" -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json index ae7a33e962d0b..90bef2e09ad39 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json +++ b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json @@ -1 +1 @@ -{"version":"16.0.0"} +{"version":"17.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/cloud-assembly-schema/schema/integ.schema.json b/packages/@aws-cdk/cloud-assembly-schema/schema/integ.schema.json new file mode 100644 index 0000000000000..676c1bdab91dd --- /dev/null +++ b/packages/@aws-cdk/cloud-assembly-schema/schema/integ.schema.json @@ -0,0 +1,474 @@ +{ + "$ref": "#/definitions/IntegManifest", + "definitions": { + "IntegManifest": { + "description": "Definitions for the integration testing manifest", + "type": "object", + "properties": { + "version": { + "description": "Version of the manifest", + "type": "string" + }, + "enableLookups": { + "description": "Enable lookups for this test. If lookups are enabled\nthen `stackUpdateWorkflow` must be set to false.\nLookups should only be enabled when you are explicitely testing\nlookups.", + "default": false, + "type": "boolean" + }, + "testCases": { + "description": "test cases", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/TestCase" + } + } + }, + "required": [ + "testCases", + "version" + ] + }, + "TestCase": { + "description": "Represents an integration test test case", + "type": "object", + "properties": { + "stacks": { + "description": "Stacks that should be tested as part of this test case\nThe stackNames will be passed as args to the cdk commands\nso dependent stacks will be automatically deployed unless\n`exclusively` is passed", + "type": "array", + "items": { + "type": "string" + } + }, + "stackUpdateWorkflow": { + "description": "Run update workflow on this test case\nThis should only be set to false to test scenarios\nthat are not possible to test as part of the update workflow (Default true)", + "type": "boolean" + }, + "cdkCommandOptions": { + "description": "Additional options to use for each CDK command (Default - runner default options)", + "$ref": "#/definitions/CdkCommands" + }, + "hooks": { + "description": "Additional commands to run at predefined points in the test workflow\n\ne.g. { postDeploy: ['yarn', 'test'] } (Default - no hooks)", + "$ref": "#/definitions/Hooks" + }, + "diffAssets": { + "description": "Whether or not to include asset hashes in the diff\nAsset hashes can introduces a lot of unneccessary noise into tests,\nbut there are some cases where asset hashes _should_ be included. For example\nany tests involving custom resources or bundling", + "default": false, + "type": "boolean" + }, + "allowDestroy": { + "description": "List of CloudFormation resource types in this stack that can\nbe destroyed as part of an update without failing the test.\n\nThis list should only include resources that for this specific\nintegration test we are sure will not cause errors or an outage if\ndestroyed. For example, maybe we know that a new resource will be created\nfirst before the old resource is destroyed which prevents any outage.\n\ne.g. ['AWS::IAM::Role'] (Default - do not allow destruction of any resources on update)", + "type": "array", + "items": { + "type": "string" + } + }, + "regions": { + "description": "Limit deployment to these regions (Default - can run in any region)", + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "stacks" + ] + }, + "CdkCommands": { + "description": "Options for specific cdk commands that are run\nas part of the integration test workflow", + "type": "object", + "properties": { + "deploy": { + "description": "Options to for the cdk deploy command (Default - default deploy options)", + "$ref": "#/definitions/DeployCommand" + }, + "destroy": { + "description": "Options to for the cdk destroy command (Default - default destroy options)", + "$ref": "#/definitions/DestroyCommand" + } + } + }, + "DeployCommand": { + "description": "Represents a cdk deploy command", + "type": "object", + "properties": { + "args": { + "description": "Additional arguments to pass to the command\nThis can be used to test specific CLI functionality (Default - only default args are used)", + "$ref": "#/definitions/DeployOptions" + }, + "enabled": { + "description": "Whether or not to run this command as part of the workflow\nThis can be used if you only want to test some of the workflow\nfor example enable `synth` and disable `deploy` & `destroy` in order\nto limit the test to synthesis (Default true)", + "type": "boolean" + }, + "expectError": { + "description": "If the runner should expect this command to fail", + "default": false, + "type": "boolean" + }, + "expectedMessage": { + "description": "This can be used in combination with `expectedError`\nto validate that a specific message is returned. (Default - do not validate message)", + "type": "string" + } + } + }, + "DeployOptions": { + "description": "Options to use with cdk deploy", + "type": "object", + "properties": { + "exclusively": { + "description": "Only perform action on the given stack", + "default": false, + "type": "boolean" + }, + "toolkitStackName": { + "description": "Name of the toolkit stack to use/deploy (Default CDKToolkit)", + "type": "string" + }, + "reuseAssets": { + "description": "Reuse the assets with the given asset IDs (Default - do not reuse assets)", + "type": "array", + "items": { + "type": "string" + } + }, + "changeSetName": { + "description": "Optional name to use for the CloudFormation change set.\nIf not provided, a name will be generated automatically. (Default - auto generate a name)", + "type": "string" + }, + "force": { + "description": "Always deploy, even if templates are identical.", + "default": false, + "type": "boolean" + }, + "rollback": { + "description": "Rollback failed deployments (Default true)", + "type": "boolean" + }, + "notificationArns": { + "description": "ARNs of SNS topics that CloudFormation will notify with stack related events (Default - no notifications)", + "type": "array", + "items": { + "type": "string" + } + }, + "requireApproval": { + "description": "What kind of security changes require approval (Default RequireApproval.Never)", + "enum": [ + "any-change", + "broadening", + "never" + ], + "type": "string" + }, + "execute": { + "description": "Whether to execute the ChangeSet\nNot providing `execute` parameter will result in execution of ChangeSet (Default true)", + "type": "boolean" + }, + "parameters": { + "description": "Additional parameters for CloudFormation at deploy time (Default [object Object])", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "usePreviousParameters": { + "description": "Use previous values for unspecified parameters\n\nIf not set, all parameters must be specified for every deployment. (Default true)", + "type": "boolean" + }, + "outputsFile": { + "description": "Path to file where stack outputs will be written after a successful deploy as JSON (Default - Outputs are not written to any file)", + "type": "string" + }, + "ci": { + "description": "Whether we are on a CI system", + "default": false, + "type": "boolean" + }, + "stacks": { + "description": "List of stacks to deploy\n\nRequried if `all` is not set (Default - [])", + "type": "array", + "items": { + "type": "string" + } + }, + "all": { + "description": "Deploy all stacks\n\nRequried if `stacks` is not set (Default - false)", + "type": "boolean" + }, + "app": { + "description": "command-line for executing your app or a cloud assembly directory\ne.g. \"node bin/my-app.js\"\nor\n\"cdk.out\" (Default - read from cdk.json)", + "type": "string" + }, + "roleArn": { + "description": "Role to pass to CloudFormation for deployment (Default - use the bootstrap cfn-exec role)", + "type": "string" + }, + "context": { + "description": "Additional context (Default - no additional context)", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "trace": { + "description": "Print trace for stack warnings", + "default": false, + "type": "boolean" + }, + "strict": { + "description": "Do not construct stacks with warnings", + "default": false, + "type": "boolean" + }, + "lookups": { + "description": "Perform context lookups.\n\nSynthesis fails if this is disabled and context lookups need\nto be performed (Default true)", + "type": "boolean" + }, + "ignoreErrors": { + "description": "Ignores synthesis errors, which will likely produce an invalid output", + "default": false, + "type": "boolean" + }, + "json": { + "description": "Use JSON output instead of YAML when templates are printed\nto STDOUT", + "default": false, + "type": "boolean" + }, + "verbose": { + "description": "show debug logs", + "default": false, + "type": "boolean" + }, + "debug": { + "description": "enable emission of additional debugging information, such as creation stack\ntraces of tokens", + "default": false, + "type": "boolean" + }, + "profile": { + "description": "Use the indicated AWS profile as the default environment (Default - no profile is used)", + "type": "string" + }, + "proxy": { + "description": "Use the indicated proxy. Will read from\nHTTPS_PROXY environment if specified (Default - no proxy)", + "type": "string" + }, + "caBundlePath": { + "description": "Path to CA certificate to use when validating HTTPS\nrequests. (Default - read from AWS_CA_BUNDLE environment variable)", + "type": "string" + }, + "ec2Creds": { + "description": "Force trying to fetch EC2 instance credentials (Default - guess EC2 instance status)", + "type": "boolean" + }, + "versionReporting": { + "description": "Include \"AWS::CDK::Metadata\" resource in synthesized templates (Default true)", + "type": "boolean" + }, + "pathMetadata": { + "description": "Include \"aws:cdk:path\" CloudFormation metadata for each resource (Default true)", + "type": "boolean" + }, + "assetMetadata": { + "description": "Include \"aws:asset:*\" CloudFormation metadata for resources that use assets (Default true)", + "type": "boolean" + }, + "staging": { + "description": "Copy assets to the output directory\n\nNeeded for local debugging the source files with SAM CLI", + "default": false, + "type": "boolean" + }, + "output": { + "description": "Emits the synthesized cloud assembly into a directory (Default cdk.out)", + "type": "string" + }, + "notices": { + "description": "Show relevant notices (Default true)", + "type": "boolean" + }, + "color": { + "description": "Show colors and other style from console output (Default true)", + "type": "boolean" + } + } + }, + "DestroyCommand": { + "description": "Represents a cdk destroy command", + "type": "object", + "properties": { + "args": { + "description": "Additional arguments to pass to the command\nThis can be used to test specific CLI functionality (Default - only default args are used)", + "$ref": "#/definitions/DestroyOptions" + }, + "enabled": { + "description": "Whether or not to run this command as part of the workflow\nThis can be used if you only want to test some of the workflow\nfor example enable `synth` and disable `deploy` & `destroy` in order\nto limit the test to synthesis (Default true)", + "type": "boolean" + }, + "expectError": { + "description": "If the runner should expect this command to fail", + "default": false, + "type": "boolean" + }, + "expectedMessage": { + "description": "This can be used in combination with `expectedError`\nto validate that a specific message is returned. (Default - do not validate message)", + "type": "string" + } + } + }, + "DestroyOptions": { + "description": "Options to use with cdk destroy", + "type": "object", + "properties": { + "force": { + "description": "Do not ask for permission before destroying stacks", + "default": false, + "type": "boolean" + }, + "exclusively": { + "description": "Only destroy the given stack", + "default": false, + "type": "boolean" + }, + "stacks": { + "description": "List of stacks to deploy\n\nRequried if `all` is not set (Default - [])", + "type": "array", + "items": { + "type": "string" + } + }, + "all": { + "description": "Deploy all stacks\n\nRequried if `stacks` is not set (Default - false)", + "type": "boolean" + }, + "app": { + "description": "command-line for executing your app or a cloud assembly directory\ne.g. \"node bin/my-app.js\"\nor\n\"cdk.out\" (Default - read from cdk.json)", + "type": "string" + }, + "roleArn": { + "description": "Role to pass to CloudFormation for deployment (Default - use the bootstrap cfn-exec role)", + "type": "string" + }, + "context": { + "description": "Additional context (Default - no additional context)", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "trace": { + "description": "Print trace for stack warnings", + "default": false, + "type": "boolean" + }, + "strict": { + "description": "Do not construct stacks with warnings", + "default": false, + "type": "boolean" + }, + "lookups": { + "description": "Perform context lookups.\n\nSynthesis fails if this is disabled and context lookups need\nto be performed (Default true)", + "type": "boolean" + }, + "ignoreErrors": { + "description": "Ignores synthesis errors, which will likely produce an invalid output", + "default": false, + "type": "boolean" + }, + "json": { + "description": "Use JSON output instead of YAML when templates are printed\nto STDOUT", + "default": false, + "type": "boolean" + }, + "verbose": { + "description": "show debug logs", + "default": false, + "type": "boolean" + }, + "debug": { + "description": "enable emission of additional debugging information, such as creation stack\ntraces of tokens", + "default": false, + "type": "boolean" + }, + "profile": { + "description": "Use the indicated AWS profile as the default environment (Default - no profile is used)", + "type": "string" + }, + "proxy": { + "description": "Use the indicated proxy. Will read from\nHTTPS_PROXY environment if specified (Default - no proxy)", + "type": "string" + }, + "caBundlePath": { + "description": "Path to CA certificate to use when validating HTTPS\nrequests. (Default - read from AWS_CA_BUNDLE environment variable)", + "type": "string" + }, + "ec2Creds": { + "description": "Force trying to fetch EC2 instance credentials (Default - guess EC2 instance status)", + "type": "boolean" + }, + "versionReporting": { + "description": "Include \"AWS::CDK::Metadata\" resource in synthesized templates (Default true)", + "type": "boolean" + }, + "pathMetadata": { + "description": "Include \"aws:cdk:path\" CloudFormation metadata for each resource (Default true)", + "type": "boolean" + }, + "assetMetadata": { + "description": "Include \"aws:asset:*\" CloudFormation metadata for resources that use assets (Default true)", + "type": "boolean" + }, + "staging": { + "description": "Copy assets to the output directory\n\nNeeded for local debugging the source files with SAM CLI", + "default": false, + "type": "boolean" + }, + "output": { + "description": "Emits the synthesized cloud assembly into a directory (Default cdk.out)", + "type": "string" + }, + "notices": { + "description": "Show relevant notices (Default true)", + "type": "boolean" + }, + "color": { + "description": "Show colors and other style from console output (Default true)", + "type": "boolean" + } + } + }, + "Hooks": { + "description": "Commands to run at predefined points during the\nintegration test workflow", + "type": "object", + "properties": { + "preDeploy": { + "description": "Commands to run prior to deploying the cdk stacks\nin the integration test (Default - no commands)", + "type": "array", + "items": { + "type": "string" + } + }, + "postDeploy": { + "description": "Commands to run prior after deploying the cdk stacks\nin the integration test (Default - no commands)", + "type": "array", + "items": { + "type": "string" + } + }, + "preDestroy": { + "description": "Commands to run prior to destroying the cdk stacks\nin the integration test (Default - no commands)", + "type": "array", + "items": { + "type": "string" + } + }, + "postDestroy": { + "description": "Commands to run after destroying the cdk stacks\nin the integration test (Default - no commands)", + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/@aws-cdk/cloud-assembly-schema/scripts/update-schema.ts b/packages/@aws-cdk/cloud-assembly-schema/scripts/update-schema.ts index e92083d34b0a6..13a410cd4a36f 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/scripts/update-schema.ts +++ b/packages/@aws-cdk/cloud-assembly-schema/scripts/update-schema.ts @@ -17,6 +17,7 @@ const SCHEMA_DIR = path.resolve(__dirname, '../schema'); const SCHEMA_DEFINITIONS: { [schemaName: string]: { rootTypeName: string } } = { 'assets': { rootTypeName: 'AssetManifest' }, 'cloud-assembly': { rootTypeName: 'AssemblyManifest' }, + 'integ': { rootTypeName: 'IntegManifest' }, }; export const SCHEMAS = Object.keys(SCHEMA_DEFINITIONS); diff --git a/packages/@aws-cdk/cloud-assembly-schema/test/integ-tests.test.ts b/packages/@aws-cdk/cloud-assembly-schema/test/integ-tests.test.ts new file mode 100644 index 0000000000000..3baefc89d750f --- /dev/null +++ b/packages/@aws-cdk/cloud-assembly-schema/test/integ-tests.test.ts @@ -0,0 +1,137 @@ +import * as fs from 'fs'; +import * as os from 'os'; +import * as path from 'path'; +import { Manifest } from '../lib'; + +describe('Integration test', () => { + test('valid input', () => { + expect(() => { + validate({ + version: Manifest.version(), + testCases: { + testCase1: { + stacks: ['stack1', 'stack2'], + stackUpdateWorkflow: true, + cdkCommandOptions: { + deploy: { + enabled: true, + expectError: false, + expectedMessage: 'some message', + args: { + exclusively: true, + toolkitStackName: 'Stack', + reuseAssets: ['asset1', 'asset2'], + changeSetName: 'changeset', + force: true, + rollback: false, + notificationArns: ['arn1', 'arn2'], + execute: true, + parameters: { + 'MYPARAM': 'Value', + 'Stack1:OtherParam': 'OtherValue', + }, + usePreviousParameters: true, + outputsFile: 'outputs.json', + ci: true, + requireApproval: 'never', + app: 'node bin/my-app.js', + roleArn: 'roleArn', + context: { + KEY: 'value', + }, + trace: true, + strict: true, + lookups: true, + ignoreErrors: true, + json: true, + verbose: true, + debug: true, + profile: 'profile', + proxy: 'https://proxy', + caBundlePath: 'path/to/bundle', + ec2Creds: true, + versionReporting: false, + pathMetadata: false, + assetMetadata: true, + staging: false, + output: true, + notices: true, + color: false, + }, + }, + synth: { + enabled: true, + expectError: false, + expectedMessage: 'some message', + args: { + quiet: true, + exclusively: true, + validation: true, + }, + }, + destroy: { + enabled: true, + expectError: false, + expectedMessage: 'some message', + args: { + force: true, + exclusively: true, + }, + }, + }, + hooks: { + preDeploy: ['yarn test'], + postDeploy: ['some other command'], + preDestroy: ['command1', 'command2'], + postDestroy: ['command3', 'command4'], + }, + diffAssets: true, + allowDestroy: ['AWS::IAM::Role'], + region: ['us-east-1', 'us-east-2'], + }, + }, + }); + }); + }); + + test('invalid input', () => { + expect(() => { + validate({ + version: Manifest.version(), + testCases: { + stacks: true, + }, + }); + }).toThrow(/instance\.testCases\.stacks is not of a type\(s\) object/); + }); + + test('without command options', () => { + expect(() => { + validate({ + version: Manifest.version(), + testCases: { + testCase1: { + stacks: ['stack1', 'stack2'], + stackUpdateWorkflow: true, + hooks: { + preDeploy: ['yarn test'], + }, + diffAssets: true, + }, + }, + }); + }); + }); +}); + +function validate(manifest: any) { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'integ.test.')); + const filePath = path.join(dir, 'manifest.json'); + fs.writeFileSync(filePath, JSON.stringify(manifest, undefined, 2)); + try { + Manifest.loadIntegManifest(filePath); + } finally { + fs.unlinkSync(filePath); + fs.rmdirSync(dir); + } +} diff --git a/packages/@aws-cdk/cloud-assembly-schema/test/manifest.test.ts b/packages/@aws-cdk/cloud-assembly-schema/test/manifest.test.ts index c8e5554662164..a8f1311a2dcc9 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/test/manifest.test.ts +++ b/packages/@aws-cdk/cloud-assembly-schema/test/manifest.test.ts @@ -71,6 +71,31 @@ test('manifest load fails on higher minor version', () => { } }); +test('manifest load doesnt fail if version checking is disabled, and unknown properties are added', () => { + const outdir = fs.mkdtempSync(path.join(os.tmpdir(), 'schema-tests')); + const manifestFile = path.join(outdir, 'manifest.json'); + const newVersion = semver.inc(Manifest.version(), 'major'); + expect(newVersion).toBeTruthy(); + + const assemblyManifest: AssemblyManifest = { + version: newVersion!, + artifacts: { + SomeArtifact: { + type: 'aws:cloudformation:stack', + thisPropertyWillNeverBeInTheManifest: 'i_hope', + } as any, + UnknownArtifact: { + type: 'unknown-artifact-type', + } as any, + }, + }; + + // can't use saveAssemblyManifest because it will force the correct version + fs.writeFileSync(manifestFile, JSON.stringify(assemblyManifest)); + + Manifest.loadAssemblyManifest(manifestFile, { skipVersionCheck: true, skipEnumCheck: true }); +}); + // once we start introducing patch version bumps that are considered // non breaking, this test can be removed. test('manifest load fails on higher patch version', () => { diff --git a/packages/@aws-cdk/cloudformation-diff/lib/format-table.ts b/packages/@aws-cdk/cloudformation-diff/lib/format-table.ts index 193223725c9f2..7e7afb98cfa53 100644 --- a/packages/@aws-cdk/cloudformation-diff/lib/format-table.ts +++ b/packages/@aws-cdk/cloudformation-diff/lib/format-table.ts @@ -1,5 +1,5 @@ import * as chalk from 'chalk'; -import * as stringWidth from 'string-width'; +import stringWidth from 'string-width'; import * as table from 'table'; /** diff --git a/packages/@aws-cdk/cloudformation-diff/lib/iam/statement.ts b/packages/@aws-cdk/cloudformation-diff/lib/iam/statement.ts index ea89ad4e597ee..7f83a5561bc76 100644 --- a/packages/@aws-cdk/cloudformation-diff/lib/iam/statement.ts +++ b/packages/@aws-cdk/cloudformation-diff/lib/iam/statement.ts @@ -1,6 +1,9 @@ -import * as deepEqual from 'fast-deep-equal'; import { deepRemoveUndefined } from '../util'; +// namespace object imports won't work in the bundle for function exports +// eslint-disable-next-line @typescript-eslint/no-require-imports +const deepEqual = require('fast-deep-equal'); + export class Statement { /** * Statement ID diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index 0db6702ef67f0..270fb182e3b1b 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -34,11 +34,11 @@ "devDependencies": { "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "@types/string-width": "^4.0.1", - "fast-check": "^2.21.0", - "jest": "^27.4.7", - "ts-jest": "^27.1.3" + "fast-check": "^2.23.2", + "jest": "^27.5.1", + "ts-jest": "^27.1.4" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", diff --git a/packages/@aws-cdk/cloudformation-include/package.json b/packages/@aws-cdk/cloudformation-include/package.json index 00a6e48fb8e95..9ea7741368e29 100644 --- a/packages/@aws-cdk/cloudformation-include/package.json +++ b/packages/@aws-cdk/cloudformation-include/package.json @@ -97,6 +97,7 @@ "@aws-cdk/aws-autoscalingplans": "0.0.0", "@aws-cdk/aws-backup": "0.0.0", "@aws-cdk/aws-batch": "0.0.0", + "@aws-cdk/aws-billingconductor": "0.0.0", "@aws-cdk/aws-budgets": "0.0.0", "@aws-cdk/aws-cassandra": "0.0.0", "@aws-cdk/aws-ce": "0.0.0", @@ -211,6 +212,7 @@ "@aws-cdk/aws-opsworks": "0.0.0", "@aws-cdk/aws-opsworkscm": "0.0.0", "@aws-cdk/aws-panorama": "0.0.0", + "@aws-cdk/aws-personalize": "0.0.0", "@aws-cdk/aws-pinpoint": "0.0.0", "@aws-cdk/aws-pinpointemail": "0.0.0", "@aws-cdk/aws-qldb": "0.0.0", @@ -286,6 +288,7 @@ "@aws-cdk/aws-autoscalingplans": "0.0.0", "@aws-cdk/aws-backup": "0.0.0", "@aws-cdk/aws-batch": "0.0.0", + "@aws-cdk/aws-billingconductor": "0.0.0", "@aws-cdk/aws-budgets": "0.0.0", "@aws-cdk/aws-cassandra": "0.0.0", "@aws-cdk/aws-ce": "0.0.0", @@ -400,6 +403,7 @@ "@aws-cdk/aws-opsworks": "0.0.0", "@aws-cdk/aws-opsworkscm": "0.0.0", "@aws-cdk/aws-panorama": "0.0.0", + "@aws-cdk/aws-personalize": "0.0.0", "@aws-cdk/aws-pinpoint": "0.0.0", "@aws-cdk/aws-pinpointemail": "0.0.0", "@aws-cdk/aws-qldb": "0.0.0", @@ -454,9 +458,9 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7", - "ts-jest": "^27.1.3" + "@types/jest": "^27.4.1", + "jest": "^27.5.1", + "ts-jest": "^27.1.4" }, "bundledDependencies": [ "yaml" diff --git a/packages/@aws-cdk/core/README.md b/packages/@aws-cdk/core/README.md index d2b1e2c5e5222..041eccef39873 100644 --- a/packages/@aws-cdk/core/README.md +++ b/packages/@aws-cdk/core/README.md @@ -57,6 +57,45 @@ organize their deployments with. If you want to vend a reusable construct, define it as a subclasses of `Construct`: the consumers of your construct will decide where to place it in their own stacks. +## Stack Synthesizers + +Each Stack has a *synthesizer*, an object that determines how and where +the Stack should be synthesized and deployed. The synthesizer controls +aspects like: + +- How does the stack reference assets? (Either through CloudFormation + parameters the CLI supplies, or because the Stack knows a predefined + location where assets will be uploaded). +- What roles are used to deploy the stack? These can be bootstrapped + roles, roles created in some other way, or just the CLI's current + credentials. + +The following synthesizers are available: + +- `DefaultStackSynthesizer`: recommended. Uses predefined asset locations and + roles created by the modern bootstrap template. Access control is done by + controlling who can assume the deploy role. This is the default stack + synthesizer in CDKv2. +- `LegacyStackSynthesizer`: Uses CloudFormation parameters to communicate + asset locations, and the CLI's current permissions to deploy stacks. The + is the default stack synthesizer in CDKv1. +- `CliCredentialsStackSynthesizer`: Uses predefined asset locations, and the + CLI's current permissions. + +Each of these synthesizers takes configuration arguments. To configure +a stack with a synthesizer, pass it as one of its properties: + +```ts +new MyStack(app, 'MyStack', { + synthesizer: new DefaultStackSynthesizer({ + fileAssetsBucketName: 'my-orgs-asset-bucket', + }), +}); +``` + +For more information on bootstrapping accounts and customizing synthesis, +see [Bootstrapping in the CDK Developer Guide](https://docs.aws.amazon.com/cdk/latest/guide/bootstrapping.html). + ## Nested Stacks [Nested stacks](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-nested-stacks.html) are stacks created as part of other stacks. You create a nested stack within another stack by using the `NestedStack` construct. diff --git a/packages/@aws-cdk/core/lib/arn.ts b/packages/@aws-cdk/core/lib/arn.ts index a04f03baf466f..2f6cb68e2dc95 100644 --- a/packages/@aws-cdk/core/lib/arn.ts +++ b/packages/@aws-cdk/core/lib/arn.ts @@ -417,8 +417,6 @@ function parseArnShape(arn: string): 'token' | string[] { // Tokens won't contain ":", so this won't break them. const components = arn.split(':'); - // const [/* arn */, partition, service, /* region */ , /* account */ , resource] = components; - const partition = components.length > 1 ? components[1] : undefined; if (!partition) { throw new Error('The `partition` component (2nd component) of an ARN is required: ' + arn); diff --git a/packages/@aws-cdk/core/lib/aspect.ts b/packages/@aws-cdk/core/lib/aspect.ts index bde33e6724e9e..98a8cd977aaeb 100644 --- a/packages/@aws-cdk/core/lib/aspect.ts +++ b/packages/@aws-cdk/core/lib/aspect.ts @@ -1,6 +1,6 @@ import { IConstruct } from './construct-compat'; -const ASPECTS_SYMBOL = Symbol('cdk-aspects'); +const ASPECTS_SYMBOL = Symbol.for('cdk-aspects'); /** * Represents an Aspect diff --git a/packages/@aws-cdk/core/lib/asset-staging.ts b/packages/@aws-cdk/core/lib/asset-staging.ts index 5ecafd9d3da56..ee1f2bafc6a04 100644 --- a/packages/@aws-cdk/core/lib/asset-staging.ts +++ b/packages/@aws-cdk/core/lib/asset-staging.ts @@ -4,7 +4,6 @@ import * as path from 'path'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import * as fs from 'fs-extra'; -import * as minimatch from 'minimatch'; import { AssetHashType, AssetOptions, FileAssetPackaging } from './assets'; import { BundlingOptions, BundlingOutput } from './bundling'; import { FileSystem, FingerprintOptions } from './fs'; @@ -188,9 +187,7 @@ export class AssetStaging extends CoreConstruct { let skip = false; if (props.bundling) { // Check if we actually have to bundle for this stack - const bundlingStacks: string[] = this.node.tryGetContext(cxapi.BUNDLING_STACKS) ?? ['*']; - // bundlingStacks is of the form `Stage/Stack`, convert it to `Stage-Stack` before comparing to stack name - skip = !bundlingStacks.find(pattern => minimatch(Stack.of(this).stackName, pattern.replace('/', '-'))); + skip = !Stack.of(this).bundlingRequired; const bundling = props.bundling; stageThisAsset = () => this.stageByBundling(bundling, skip); } else { diff --git a/packages/@aws-cdk/core/lib/assets.ts b/packages/@aws-cdk/core/lib/assets.ts index e0f48ea73e9e5..7466ded8e6d60 100644 --- a/packages/@aws-cdk/core/lib/assets.ts +++ b/packages/@aws-cdk/core/lib/assets.ts @@ -256,6 +256,9 @@ export interface FileAssetLocation { /** * The HTTP URL of this asset on Amazon S3. * + * This value suitable for inclusion in a CloudFormation template, and + * may be an encoded token. + * * Example value: `https://s3-us-east-1.amazonaws.com/mybucket/myobject` */ readonly httpUrl: string; @@ -263,6 +266,9 @@ export interface FileAssetLocation { /** * The S3 URL of this asset on Amazon S3. * + * This value suitable for inclusion in a CloudFormation template, and + * may be an encoded token. + * * Example value: `s3://mybucket/myobject` */ readonly s3ObjectUrl: string; @@ -285,6 +291,16 @@ export interface FileAssetLocation { * key via the bucket and no additional parameters have to be granted anymore. */ readonly kmsKeyArn?: string; + + /** + * Like `s3ObjectUrl`, but not suitable for CloudFormation consumption + * + * If there are placeholders in the S3 URL, they will be returned unreplaced + * and un-evaluated. + * + * @default - This feature cannot be used + */ + readonly s3ObjectUrlWithPlaceholders?: string; } /** diff --git a/packages/@aws-cdk/core/lib/cfn-mapping.ts b/packages/@aws-cdk/core/lib/cfn-mapping.ts index 18b670a4ff927..d8a5f6a972f5d 100644 --- a/packages/@aws-cdk/core/lib/cfn-mapping.ts +++ b/packages/@aws-cdk/core/lib/cfn-mapping.ts @@ -43,7 +43,7 @@ export class CfnMapping extends CfnRefElement { constructor(scope: Construct, id: string, props: CfnMappingProps = {}) { super(scope, id); - this.mapping = props.mapping ?? { }; + this.mapping = props.mapping ? this.validateMapping(props.mapping) : {}; this.lazy = props.lazy; } @@ -51,6 +51,8 @@ export class CfnMapping extends CfnRefElement { * Sets a value in the map based on the two keys. */ public setValue(key1: string, key2: string, value: any) { + this.validateAlphanumeric(key2); + if (!(key1 in this.mapping)) { this.mapping[key1] = { }; } @@ -108,4 +110,16 @@ export class CfnMapping extends CfnRefElement { } this.lazyInformed = true; } + + private validateMapping(mapping: Mapping): Mapping { + Object.keys(mapping).forEach((m) => Object.keys(mapping[m]).forEach(this.validateAlphanumeric)); + return mapping; + } + + private validateAlphanumeric(value: any) { + // https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/mappings-section-structure.html + if (value.match(/[^a-zA-Z0-9]/g)) { + throw new Error(`Attribute name '${value}' must contain only alphanumeric characters.`); + } + } } diff --git a/packages/@aws-cdk/core/lib/feature-flags.ts b/packages/@aws-cdk/core/lib/feature-flags.ts index 926a60168732f..2da5397b8ec23 100644 --- a/packages/@aws-cdk/core/lib/feature-flags.ts +++ b/packages/@aws-cdk/core/lib/feature-flags.ts @@ -1,5 +1,5 @@ import * as cxapi from '@aws-cdk/cx-api'; -import { Construct } from '../lib/construct-compat'; +import { IConstruct, Node } from 'constructs'; /** * Features that are implemented behind a flag in order to preserve backwards @@ -12,11 +12,11 @@ export class FeatureFlags { /** * Inspect feature flags on the construct node's context. */ - public static of(scope: Construct) { + public static of(scope: IConstruct) { return new FeatureFlags(scope); } - private constructor(private readonly construct: Construct) {} + private constructor(private readonly construct: IConstruct) {} /** * Check whether a feature flag is enabled. If configured, the flag is present in @@ -24,7 +24,7 @@ export class FeatureFlags { * module. */ public isEnabled(featureFlag: string): boolean | undefined { - const context = this.construct.node.tryGetContext(featureFlag); + const context = Node.of(this.construct).tryGetContext(featureFlag); if (cxapi.FUTURE_FLAGS_EXPIRED.includes(featureFlag)) { if (context !== undefined) { throw new Error(`Unsupported feature flag '${featureFlag}'. This flag existed on CDKv1 but has been removed in CDKv2.` diff --git a/packages/@aws-cdk/core/lib/nested-stack.ts b/packages/@aws-cdk/core/lib/nested-stack.ts index 39cc59ebd366f..e1248d69888aa 100644 --- a/packages/@aws-cdk/core/lib/nested-stack.ts +++ b/packages/@aws-cdk/core/lib/nested-stack.ts @@ -205,6 +205,16 @@ export class NestedStack extends Stack { return false; } + // When adding tags to nested stack, the tags need to be added to all the resources in + // in nested stack, which is handled by the `tags` property, But to tag the + // tags have to be added in the parent stack CfnStack resource. The CfnStack resource created + // by this class dont share the same TagManager as that of the one exposed by the `tag` property of the + // class, all the tags need to be copied to the CfnStack resource before synthesizing the resource. + // See https://github.com/aws/aws-cdk/pull/19128 + Object.entries(this.tags.tagValues()).forEach(([key, value]) => { + this.resource.tags.setTag(key, value); + }); + const cfn = JSON.stringify(this._toCloudFormation()); const templateHash = crypto.createHash('sha256').update(cfn).digest('hex'); diff --git a/packages/@aws-cdk/core/lib/private/region-lookup.ts b/packages/@aws-cdk/core/lib/private/region-lookup.ts index 208ff7eee30be..226df28d7f444 100644 --- a/packages/@aws-cdk/core/lib/private/region-lookup.ts +++ b/packages/@aws-cdk/core/lib/private/region-lookup.ts @@ -31,7 +31,7 @@ export function deployTimeLookup(stack: Stack, factName: string, lookupMap: Reco : [factName, 'value'] as const; const mapId = `${ucfirst(factClass)}Map`; - const factKey = factParam.replace(/[^a-zA-Z0-9]/g, '_'); + const factKey = factParam.replace(/[^a-zA-Z0-9]/g, 'x'); let mapping = stack.node.tryFindChild(mapId) as CfnMapping | undefined; if (!mapping) { diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/_asset-manifest-builder.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/_asset-manifest-builder.ts new file mode 100644 index 0000000000000..b1e121399cf4a --- /dev/null +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/_asset-manifest-builder.ts @@ -0,0 +1,219 @@ +import * as fs from 'fs'; +import * as path from 'path'; + +import * as cxschema from '@aws-cdk/cloud-assembly-schema'; +import { FileAssetSource, FileAssetLocation, FileAssetPackaging, DockerImageAssetSource, DockerImageAssetLocation } from '../assets'; +import { Fn } from '../cfn-fn'; +import { ISynthesisSession } from '../construct-compat'; +import { Stack } from '../stack'; +import { resolvedOr } from './_shared'; + +/** + * Build an manifest from assets added to a stack synthesizer + */ +export class AssetManifestBuilder { + private readonly files: NonNullable = {}; + private readonly dockerImages: NonNullable = {}; + + public addFileAssetDefault( + asset: FileAssetSource, + stack: Stack, + bucketName: string, + bucketPrefix: string, + role?: RoleOptions, + ): FileAssetLocation { + validateFileAssetSource(asset); + + const extension = + asset.fileName != undefined ? path.extname(asset.fileName) : ''; + const objectKey = + bucketPrefix + + asset.sourceHash + + (asset.packaging === FileAssetPackaging.ZIP_DIRECTORY + ? '.zip' + : extension); + + // Add to manifest + this.files[asset.sourceHash] = { + source: { + path: asset.fileName, + executable: asset.executable, + packaging: asset.packaging, + }, + destinations: { + [this.manifestEnvName(stack)]: { + bucketName: bucketName, + objectKey, + region: resolvedOr(stack.region, undefined), + assumeRoleArn: role?.assumeRoleArn, + assumeRoleExternalId: role?.assumeRoleExternalId, + }, + }, + }; + + const { region, urlSuffix } = stackLocationOrInstrinsics(stack); + const httpUrl = cfnify( + `https://s3.${region}.${urlSuffix}/${bucketName}/${objectKey}`, + ); + const s3ObjectUrlWithPlaceholders = `s3://${bucketName}/${objectKey}`; + + // Return CFN expression + // + // 's3ObjectUrlWithPlaceholders' is intended for the CLI. The CLI ultimately needs a + // 'https://s3.REGION.amazonaws.com[.cn]/name/hash' URL to give to CloudFormation. + // However, there's no way for us to actually know the URL_SUFFIX in the framework, so + // we can't construct that URL. Instead, we record the 's3://.../...' form, and the CLI + // transforms it to the correct 'https://.../' URL before calling CloudFormation. + return { + bucketName: cfnify(bucketName), + objectKey, + httpUrl, + s3ObjectUrl: cfnify(s3ObjectUrlWithPlaceholders), + s3ObjectUrlWithPlaceholders, + s3Url: httpUrl, + }; + } + + public addDockerImageAssetDefault( + asset: DockerImageAssetSource, + stack: Stack, + repositoryName: string, + dockerTagPrefix: string, + role?: RoleOptions, + ): DockerImageAssetLocation { + validateDockerImageAssetSource(asset); + const imageTag = dockerTagPrefix + asset.sourceHash; + + // Add to manifest + this.dockerImages[asset.sourceHash] = { + source: { + executable: asset.executable, + directory: asset.directoryName, + dockerBuildArgs: asset.dockerBuildArgs, + dockerBuildTarget: asset.dockerBuildTarget, + dockerFile: asset.dockerFile, + networkMode: asset.networkMode, + }, + destinations: { + [this.manifestEnvName(stack)]: { + repositoryName: repositoryName, + imageTag, + region: resolvedOr(stack.region, undefined), + assumeRoleArn: role?.assumeRoleArn, + assumeRoleExternalId: role?.assumeRoleExternalId, + }, + }, + }; + + const { account, region, urlSuffix } = stackLocationOrInstrinsics(stack); + + // Return CFN expression + return { + repositoryName: cfnify(repositoryName), + imageUri: cfnify( + `${account}.dkr.ecr.${region}.${urlSuffix}/${repositoryName}:${imageTag}`, + ), + }; + } + + /** + * Write the manifest to disk, and add it to the synthesis session + * + * Reutrn the artifact Id + */ + public writeManifest( + stack: Stack, + session: ISynthesisSession, + additionalProps: Partial = {}, + ): string { + const artifactId = `${stack.artifactId}.assets`; + const manifestFile = `${artifactId}.json`; + const outPath = path.join(session.assembly.outdir, manifestFile); + + const manifest: cxschema.AssetManifest = { + version: cxschema.Manifest.version(), + files: this.files, + dockerImages: this.dockerImages, + }; + + fs.writeFileSync(outPath, JSON.stringify(manifest, undefined, 2)); + + session.assembly.addArtifact(artifactId, { + type: cxschema.ArtifactType.ASSET_MANIFEST, + properties: { + file: manifestFile, + ...additionalProps, + }, + }); + + return artifactId; + } + + private manifestEnvName(stack: Stack): string { + return [ + resolvedOr(stack.account, 'current_account'), + resolvedOr(stack.region, 'current_region'), + ].join('-'); + } +} + +export interface RoleOptions { + readonly assumeRoleArn?: string; + readonly assumeRoleExternalId?: string; +} + +function validateFileAssetSource(asset: FileAssetSource) { + if (!!asset.executable === !!asset.fileName) { + throw new Error(`Exactly one of 'fileName' or 'executable' is required, got: ${JSON.stringify(asset)}`); + } + + if (!!asset.packaging !== !!asset.fileName) { + throw new Error(`'packaging' is expected in combination with 'fileName', got: ${JSON.stringify(asset)}`); + } +} + +function validateDockerImageAssetSource(asset: DockerImageAssetSource) { + if (!!asset.executable === !!asset.directoryName) { + throw new Error(`Exactly one of 'directoryName' or 'executable' is required, got: ${JSON.stringify(asset)}`); + } + + check('dockerBuildArgs'); + check('dockerBuildTarget'); + check('dockerFile'); + + function check(key: K) { + if (asset[key] && !asset.directoryName) { + throw new Error(`'${key}' is only allowed in combination with 'directoryName', got: ${JSON.stringify(asset)}`); + } + } +} + +/** + * Return the stack locations if they're concrete, or the original CFN intrisics otherwise + * + * We need to return these instead of the tokenized versions of the strings, + * since we must accept those same ${AWS::AccountId}/${AWS::Region} placeholders + * in bucket names and role names (in order to allow environment-agnostic stacks). + * + * We'll wrap a single {Fn::Sub} around the final string in order to replace everything, + * but we can't have the token system render part of the string to {Fn::Join} because + * the CFN specification doesn't allow the {Fn::Sub} template string to be an arbitrary + * expression--it must be a string literal. + */ +function stackLocationOrInstrinsics(stack: Stack) { + return { + account: resolvedOr(stack.account, '${AWS::AccountId}'), + region: resolvedOr(stack.region, '${AWS::Region}'), + urlSuffix: resolvedOr(stack.urlSuffix, '${AWS::URLSuffix}'), + }; +} + +/** + * If the string still contains placeholders, wrap it in a Fn::Sub so they will be substituted at CFN deployment time + * + * (This happens to work because the placeholders we picked map directly onto CFN + * placeholders. If they didn't we'd have to do a transformation here). + */ +function cfnify(s: string): string { + return s.indexOf('${') > -1 ? Fn.sub(s) : s; +} \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts index a9b9e0d7acb5d..f0cc2d548fd81 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts @@ -1,7 +1,12 @@ import * as crypto from 'crypto'; +import * as fs from 'fs'; +import * as path from 'path'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; +import * as cxapi from '@aws-cdk/cx-api'; +import { FileAssetSource, FileAssetPackaging } from '../assets'; import { ConstructNode, IConstruct, ISynthesisSession } from '../construct-compat'; import { Stack } from '../stack'; +import { Token } from '../token'; /** * Shared logic of writing stack artifact to the Cloud Assembly @@ -90,7 +95,7 @@ function collectStackMetadata(stack: Stack) { } function findParentStack(node: IConstruct): Stack | undefined { - if (node instanceof Stack && node.nestedStackParent === undefined) { + if (Stack.isStack(node) && node.nestedStackParent === undefined) { return node; } @@ -122,4 +127,60 @@ export function assertBound(x: A | undefined): asserts x is NonNullable { function nonEmptyDict(xs: Record) { return Object.keys(xs).length > 0 ? xs : undefined; -} \ No newline at end of file +} + +/** + * A "replace-all" function that doesn't require us escaping a literal string to a regex + */ +function replaceAll(s: string, search: string, replace: string) { + return s.split(search).join(replace); +} + +export class StringSpecializer { + constructor(private readonly stack: Stack, private readonly qualifier: string) { + } + + /** + * Function to replace placeholders in the input string as much as possible + * + * We replace: + * - ${Qualifier}: always + * - ${AWS::AccountId}, ${AWS::Region}: only if we have the actual values available + * - ${AWS::Partition}: never, since we never have the actual partition value. + */ + public specialize(s: string): string { + s = replaceAll(s, '${Qualifier}', this.qualifier); + return cxapi.EnvironmentPlaceholders.replace(s, { + region: resolvedOr(this.stack.region, cxapi.EnvironmentPlaceholders.CURRENT_REGION), + accountId: resolvedOr(this.stack.account, cxapi.EnvironmentPlaceholders.CURRENT_ACCOUNT), + partition: cxapi.EnvironmentPlaceholders.CURRENT_PARTITION, + }); + } + + /** + * Specialize only the qualifier + */ + public qualifierOnly(s: string): string { + return replaceAll(s, '${Qualifier}', this.qualifier); + } +} + +/** + * Return the given value if resolved or fall back to a default + */ +export function resolvedOr(x: string, def: A): string | A { + return Token.isUnresolved(x) ? def : x; +} + +export function stackTemplateFileAsset(stack: Stack, session: ISynthesisSession): FileAssetSource { + const templatePath = path.join(session.assembly.outdir, stack.templateFile); + const template = fs.readFileSync(templatePath, { encoding: 'utf-8' }); + + const sourceHash = contentHash(template); + + return { + fileName: stack.templateFile, + packaging: FileAssetPackaging.FILE, + sourceHash, + }; +} diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/bootstrapless-synthesizer.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/bootstrapless-synthesizer.ts index 1a9a2ab8ee0cc..d1526edb79891 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/bootstrapless-synthesizer.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/bootstrapless-synthesizer.ts @@ -24,11 +24,19 @@ export interface BootstraplessSynthesizerProps { } /** - * A special synthesizer that behaves similarly to DefaultStackSynthesizer, - * but doesn't require bootstrapping the environment it operates in. - * Because of that, stacks using it cannot have assets inside of them. + * Synthesizer that reuses bootstrap roles from a different region + * + * A special synthesizer that behaves similarly to `DefaultStackSynthesizer`, + * but doesn't require bootstrapping the environment it operates in. Instead, + * it will re-use the Roles that were created for a different region (which + * is possible because IAM is a global service). + * + * However, it will not assume asset buckets or repositories have been created, + * and therefore does not support assets. + * * Used by the CodePipeline construct for the support stacks needed for - * cross-region replication S3 buckets. + * cross-region replication S3 buckets. App builders do not need to use this + * synthesizer directly. */ export class BootstraplessSynthesizer extends DefaultStackSynthesizer { constructor(props: BootstraplessSynthesizerProps) { diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/cli-credentials-synthesizer.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/cli-credentials-synthesizer.ts new file mode 100644 index 0000000000000..0f268297999b3 --- /dev/null +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/cli-credentials-synthesizer.ts @@ -0,0 +1,174 @@ +import * as cxapi from '@aws-cdk/cx-api'; +import { DockerImageAssetLocation, DockerImageAssetSource, FileAssetLocation, FileAssetSource } from '../assets'; +import { ISynthesisSession } from '../construct-compat'; +import { Stack } from '../stack'; +import { Token } from '../token'; +import { AssetManifestBuilder } from './_asset-manifest-builder'; +import { assertBound, StringSpecializer, stackTemplateFileAsset } from './_shared'; +import { BOOTSTRAP_QUALIFIER_CONTEXT, DefaultStackSynthesizer } from './default-synthesizer'; +import { StackSynthesizer } from './stack-synthesizer'; + +/** + * Properties for the CliCredentialsStackSynthesizer + */ +export interface CliCredentialsStackSynthesizerProps { + /** + * Name of the S3 bucket to hold file assets + * + * You must supply this if you have given a non-standard name to the staging bucket. + * + * The placeholders `${Qualifier}`, `${AWS::AccountId}` and `${AWS::Region}` will + * be replaced with the values of qualifier and the stack's account and region, + * respectively. + * + * @default DefaultStackSynthesizer.DEFAULT_FILE_ASSETS_BUCKET_NAME + */ + readonly fileAssetsBucketName?: string; + + /** + * Name of the ECR repository to hold Docker Image assets + * + * You must supply this if you have given a non-standard name to the ECR repository. + * + * The placeholders `${Qualifier}`, `${AWS::AccountId}` and `${AWS::Region}` will + * be replaced with the values of qualifier and the stack's account and region, + * respectively. + * + * @default DefaultStackSynthesizer.DEFAULT_IMAGE_ASSETS_REPOSITORY_NAME + */ + readonly imageAssetsRepositoryName?: string; + + /** + * Qualifier to disambiguate multiple environments in the same account + * + * You can use this and leave the other naming properties empty if you have deployed + * the bootstrap environment with standard names but only differnet qualifiers. + * + * @default - Value of context key '@aws-cdk/core:bootstrapQualifier' if set, otherwise `DefaultStackSynthesizer.DEFAULT_QUALIFIER` + */ + readonly qualifier?: string; + + /** + * bucketPrefix to use while storing S3 Assets + * + * @default - DefaultStackSynthesizer.DEFAULT_FILE_ASSET_PREFIX + */ + readonly bucketPrefix?: string; + + /** + * A prefix to use while tagging and uploading Docker images to ECR. + * + * This does not add any separators - the source hash will be appended to + * this string directly. + * + * @default - DefaultStackSynthesizer.DEFAULT_DOCKER_ASSET_PREFIX + */ + readonly dockerTagPrefix?: string; +} + +/** + * A synthesizer that uses conventional asset locations, but not conventional deployment roles + * + * Instead of assuming the bootstrapped deployment roles, all stack operations will be performed + * using the CLI's current credentials. + * + * - This synthesizer does not support deploying to accounts to which the CLI does not have + * credentials. It also does not support deploying using **CDK Pipelines**. For either of those + * features, use `DefaultStackSynthesizer`. + * - This synthesizer requires an S3 bucket and ECR repository with well-known names. To + * not depend on those, use `LegacyStackSynthesizer`. + * + * Be aware that your CLI credentials must be valid for the duration of the + * entire deployment. If you are using session credentials, make sure the + * session lifetime is long enough. + * + * By default, expects the environment to have been bootstrapped with just the staging resources + * of the Bootstrap Stack V2 (also known as "modern bootstrap stack"). You can override + * the default names using the synthesizer's construction properties. + */ +export class CliCredentialsStackSynthesizer extends StackSynthesizer { + private stack?: Stack; + private qualifier?: string; + private bucketName?: string; + private repositoryName?: string; + private bucketPrefix?: string; + private dockerTagPrefix?: string; + + private readonly assetManifest = new AssetManifestBuilder(); + + constructor(private readonly props: CliCredentialsStackSynthesizerProps = {}) { + super(); + + for (const key in props) { + if (props.hasOwnProperty(key)) { + validateNoToken(key as keyof CliCredentialsStackSynthesizerProps); + } + } + + function validateNoToken(key: A) { + const prop = props[key]; + if (typeof prop === 'string' && Token.isUnresolved(prop)) { + throw new Error(`DefaultSynthesizer property '${key}' cannot contain tokens; only the following placeholder strings are allowed: ` + [ + '${Qualifier}', + cxapi.EnvironmentPlaceholders.CURRENT_REGION, + cxapi.EnvironmentPlaceholders.CURRENT_ACCOUNT, + cxapi.EnvironmentPlaceholders.CURRENT_PARTITION, + ].join(', ')); + } + } + } + + public bind(stack: Stack): void { + if (this.stack !== undefined) { + throw new Error('A StackSynthesizer can only be used for one Stack: create a new instance to use with a different Stack'); + } + + this.stack = stack; + + const qualifier = this.props.qualifier ?? stack.node.tryGetContext(BOOTSTRAP_QUALIFIER_CONTEXT) ?? DefaultStackSynthesizer.DEFAULT_QUALIFIER; + this.qualifier = qualifier; + + const spec = new StringSpecializer(stack, qualifier); + + /* eslint-disable max-len */ + this.bucketName = spec.specialize(this.props.fileAssetsBucketName ?? DefaultStackSynthesizer.DEFAULT_FILE_ASSETS_BUCKET_NAME); + this.repositoryName = spec.specialize(this.props.imageAssetsRepositoryName ?? DefaultStackSynthesizer.DEFAULT_IMAGE_ASSETS_REPOSITORY_NAME); + this.bucketPrefix = spec.specialize(this.props.bucketPrefix ?? DefaultStackSynthesizer.DEFAULT_FILE_ASSET_PREFIX); + this.dockerTagPrefix = spec.specialize(this.props.dockerTagPrefix ?? DefaultStackSynthesizer.DEFAULT_DOCKER_ASSET_PREFIX); + /* eslint-enable max-len */ + } + + public addFileAsset(asset: FileAssetSource): FileAssetLocation { + assertBound(this.stack); + assertBound(this.bucketName); + assertBound(this.bucketPrefix); + + return this.assetManifest.addFileAssetDefault(asset, this.stack, this.bucketName, this.bucketPrefix); + } + + public addDockerImageAsset(asset: DockerImageAssetSource): DockerImageAssetLocation { + assertBound(this.stack); + assertBound(this.repositoryName); + assertBound(this.dockerTagPrefix); + + return this.assetManifest.addDockerImageAssetDefault(asset, this.stack, this.repositoryName, this.dockerTagPrefix); + } + + /** + * Synthesize the associated stack to the session + */ + public synthesize(session: ISynthesisSession): void { + assertBound(this.stack); + assertBound(this.qualifier); + + this.synthesizeStackTemplate(this.stack, session); + + const templateAsset = this.addFileAsset(stackTemplateFileAsset(this.stack, session)); + const assetManifestId = this.assetManifest.writeManifest(this.stack, session); + + this.emitStackArtifact(this.stack, session, { + stackTemplateAssetObjectUrl: templateAsset.s3ObjectUrlWithPlaceholders, + additionalDependencies: [assetManifestId], + }); + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts index 70b30a375dd37..8f8e79ac467b9 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts @@ -1,15 +1,13 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import * as cxapi from '@aws-cdk/cx-api'; -import { DockerImageAssetLocation, DockerImageAssetSource, FileAssetLocation, FileAssetPackaging, FileAssetSource } from '../assets'; +import { DockerImageAssetLocation, DockerImageAssetSource, FileAssetLocation, FileAssetSource } from '../assets'; import { Fn } from '../cfn-fn'; import { CfnParameter } from '../cfn-parameter'; import { CfnRule } from '../cfn-rule'; import { ISynthesisSession } from '../construct-compat'; import { Stack } from '../stack'; import { Token } from '../token'; -import { assertBound, contentHash } from './_shared'; +import { AssetManifestBuilder } from './_asset-manifest-builder'; +import { assertBound, StringSpecializer, stackTemplateFileAsset } from './_shared'; import { StackSynthesizer } from './stack-synthesizer'; export const BOOTSTRAP_QUALIFIER_CONTEXT = '@aws-cdk/core:bootstrapQualifier'; @@ -218,13 +216,19 @@ export interface DefaultStackSynthesizerProps { } /** - * Uses conventionally named roles and reify asset storage locations + * Uses conventionally named roles and asset storage locations * - * This synthesizer is the only StackSynthesizer that generates - * an asset manifest, and is required to deploy CDK applications using the - * `@aws-cdk/app-delivery` CI/CD library. + * This synthesizer: * - * Requires the environment to have been bootstrapped with Bootstrap Stack V2. + * - Supports cross-account deployments (the CLI can have credentials to one + * account, and you can still deploy to another account by assuming roles with + * well-known names in the other account). + * - Supports the **CDK Pipelines** library. + * + * Requires the environment to have been bootstrapped with Bootstrap Stack V2 + * (also known as "modern bootstrap stack"). The synthesizer adds a version + * check to the template, to make sure the bootstrap stack is recent enough + * to support all features expected by this synthesizer. */ export class DefaultStackSynthesizer extends StackSynthesizer { /** @@ -300,8 +304,7 @@ export class DefaultStackSynthesizer extends StackSynthesizer { private dockerTagPrefix?: string; private bootstrapStackVersionSsmParameter?: string; - private readonly files: NonNullable = {}; - private readonly dockerImages: NonNullable = {}; + private assetManifest = new AssetManifestBuilder(); constructor(private readonly props: DefaultStackSynthesizerProps = {}) { super(); @@ -336,117 +339,45 @@ export class DefaultStackSynthesizer extends StackSynthesizer { const qualifier = this.props.qualifier ?? stack.node.tryGetContext(BOOTSTRAP_QUALIFIER_CONTEXT) ?? DefaultStackSynthesizer.DEFAULT_QUALIFIER; this.qualifier = qualifier; - // Function to replace placeholders in the input string as much as possible - // - // We replace: - // - ${Qualifier}: always - // - ${AWS::AccountId}, ${AWS::Region}: only if we have the actual values available - // - ${AWS::Partition}: never, since we never have the actual partition value. - const specialize = (s: string) => { - s = replaceAll(s, '${Qualifier}', qualifier); - return cxapi.EnvironmentPlaceholders.replace(s, { - region: resolvedOr(stack.region, cxapi.EnvironmentPlaceholders.CURRENT_REGION), - accountId: resolvedOr(stack.account, cxapi.EnvironmentPlaceholders.CURRENT_ACCOUNT), - partition: cxapi.EnvironmentPlaceholders.CURRENT_PARTITION, - }); - }; + const spec = new StringSpecializer(stack, qualifier); /* eslint-disable max-len */ - this.bucketName = specialize(this.props.fileAssetsBucketName ?? DefaultStackSynthesizer.DEFAULT_FILE_ASSETS_BUCKET_NAME); - this.repositoryName = specialize(this.props.imageAssetsRepositoryName ?? DefaultStackSynthesizer.DEFAULT_IMAGE_ASSETS_REPOSITORY_NAME); - this._deployRoleArn = specialize(this.props.deployRoleArn ?? DefaultStackSynthesizer.DEFAULT_DEPLOY_ROLE_ARN); - this._cloudFormationExecutionRoleArn = specialize(this.props.cloudFormationExecutionRole ?? DefaultStackSynthesizer.DEFAULT_CLOUDFORMATION_ROLE_ARN); - this.fileAssetPublishingRoleArn = specialize(this.props.fileAssetPublishingRoleArn ?? DefaultStackSynthesizer.DEFAULT_FILE_ASSET_PUBLISHING_ROLE_ARN); - this.imageAssetPublishingRoleArn = specialize(this.props.imageAssetPublishingRoleArn ?? DefaultStackSynthesizer.DEFAULT_IMAGE_ASSET_PUBLISHING_ROLE_ARN); - this.lookupRoleArn = specialize(this.props.lookupRoleArn ?? DefaultStackSynthesizer.DEFAULT_LOOKUP_ROLE_ARN); - this.bucketPrefix = specialize(this.props.bucketPrefix ?? DefaultStackSynthesizer.DEFAULT_FILE_ASSET_PREFIX); - this.dockerTagPrefix = specialize(this.props.dockerTagPrefix ?? DefaultStackSynthesizer.DEFAULT_DOCKER_ASSET_PREFIX); - this.bootstrapStackVersionSsmParameter = replaceAll( - this.props.bootstrapStackVersionSsmParameter ?? DefaultStackSynthesizer.DEFAULT_BOOTSTRAP_STACK_VERSION_SSM_PARAMETER, - '${Qualifier}', - qualifier, - ); + this.bucketName = spec.specialize(this.props.fileAssetsBucketName ?? DefaultStackSynthesizer.DEFAULT_FILE_ASSETS_BUCKET_NAME); + this.repositoryName = spec.specialize(this.props.imageAssetsRepositoryName ?? DefaultStackSynthesizer.DEFAULT_IMAGE_ASSETS_REPOSITORY_NAME); + this._deployRoleArn = spec.specialize(this.props.deployRoleArn ?? DefaultStackSynthesizer.DEFAULT_DEPLOY_ROLE_ARN); + this._cloudFormationExecutionRoleArn = spec.specialize(this.props.cloudFormationExecutionRole ?? DefaultStackSynthesizer.DEFAULT_CLOUDFORMATION_ROLE_ARN); + this.fileAssetPublishingRoleArn = spec.specialize(this.props.fileAssetPublishingRoleArn ?? DefaultStackSynthesizer.DEFAULT_FILE_ASSET_PUBLISHING_ROLE_ARN); + this.imageAssetPublishingRoleArn = spec.specialize(this.props.imageAssetPublishingRoleArn ?? DefaultStackSynthesizer.DEFAULT_IMAGE_ASSET_PUBLISHING_ROLE_ARN); + this.lookupRoleArn = spec.specialize(this.props.lookupRoleArn ?? DefaultStackSynthesizer.DEFAULT_LOOKUP_ROLE_ARN); + this.bucketPrefix = spec.specialize(this.props.bucketPrefix ?? DefaultStackSynthesizer.DEFAULT_FILE_ASSET_PREFIX); + this.dockerTagPrefix = spec.specialize(this.props.dockerTagPrefix ?? DefaultStackSynthesizer.DEFAULT_DOCKER_ASSET_PREFIX); + this.bootstrapStackVersionSsmParameter = spec.qualifierOnly(this.props.bootstrapStackVersionSsmParameter ?? DefaultStackSynthesizer.DEFAULT_BOOTSTRAP_STACK_VERSION_SSM_PARAMETER); /* eslint-enable max-len */ } public addFileAsset(asset: FileAssetSource): FileAssetLocation { assertBound(this.stack); assertBound(this.bucketName); - validateFileAssetSource(asset); - - const extension = asset.fileName != undefined ? path.extname(asset.fileName) : ''; - const objectKey = this.bucketPrefix + asset.sourceHash + (asset.packaging === FileAssetPackaging.ZIP_DIRECTORY ? '.zip' : extension); + assertBound(this.bucketPrefix); - // Add to manifest - this.files[asset.sourceHash] = { - source: { - path: asset.fileName, - executable: asset.executable, - packaging: asset.packaging, - }, - destinations: { - [this.manifestEnvName]: { - bucketName: this.bucketName, - objectKey, - region: resolvedOr(this.stack.region, undefined), - assumeRoleArn: this.fileAssetPublishingRoleArn, - assumeRoleExternalId: this.props.fileAssetPublishingExternalId, - }, - }, - }; - - const { region, urlSuffix } = stackLocationOrInstrinsics(this.stack); - const httpUrl = cfnify(`https://s3.${region}.${urlSuffix}/${this.bucketName}/${objectKey}`); - const s3ObjectUrl = cfnify(`s3://${this.bucketName}/${objectKey}`); - - // Return CFN expression - return { - bucketName: cfnify(this.bucketName), - objectKey, - httpUrl, - s3ObjectUrl, - s3Url: httpUrl, - }; + return this.assetManifest.addFileAssetDefault(asset, this.stack, this.bucketName, this.bucketPrefix, { + assumeRoleArn: this.fileAssetPublishingRoleArn, + assumeRoleExternalId: this.props.fileAssetPublishingExternalId, + }); } public addDockerImageAsset(asset: DockerImageAssetSource): DockerImageAssetLocation { assertBound(this.stack); assertBound(this.repositoryName); - validateDockerImageAssetSource(asset); - - const imageTag = this.dockerTagPrefix + asset.sourceHash; - - // Add to manifest - this.dockerImages[asset.sourceHash] = { - source: { - executable: asset.executable, - directory: asset.directoryName, - dockerBuildArgs: asset.dockerBuildArgs, - dockerBuildTarget: asset.dockerBuildTarget, - dockerFile: asset.dockerFile, - networkMode: asset.networkMode, - }, - destinations: { - [this.manifestEnvName]: { - repositoryName: this.repositoryName, - imageTag, - region: resolvedOr(this.stack.region, undefined), - assumeRoleArn: this.imageAssetPublishingRoleArn, - assumeRoleExternalId: this.props.imageAssetPublishingExternalId, - }, - }, - }; + assertBound(this.dockerTagPrefix); - const { account, region, urlSuffix } = stackLocationOrInstrinsics(this.stack); - - // Return CFN expression - return { - repositoryName: cfnify(this.repositoryName), - imageUri: cfnify(`${account}.dkr.ecr.${region}.${urlSuffix}/${this.repositoryName}:${imageTag}`), - }; + return this.assetManifest.addDockerImageAssetDefault(asset, this.stack, this.repositoryName, this.dockerTagPrefix, { + assumeRoleArn: this.imageAssetPublishingRoleArn, + assumeRoleExternalId: this.props.imageAssetPublishingExternalId, + }); } - protected synthesizeStackTemplate(stack: Stack, session: ISynthesisSession): void { + protected synthesizeStackTemplate(stack: Stack, session: ISynthesisSession) { stack._synthesizeTemplate(session, this.lookupRoleArn); } @@ -468,19 +399,21 @@ export class DefaultStackSynthesizer extends StackSynthesizer { this.synthesizeStackTemplate(this.stack, session); - // Add the stack's template to the artifact manifest - const templateManifestUrl = this.addStackTemplateToAssetManifest(session); + const templateAsset = this.addFileAsset(stackTemplateFileAsset(this.stack, session)); - const artifactId = this.writeAssetManifest(session); + const assetManifestId = this.assetManifest.writeManifest(this.stack, session, { + requiresBootstrapStackVersion: MIN_BOOTSTRAP_STACK_VERSION, + bootstrapStackVersionSsmParameter: this.bootstrapStackVersionSsmParameter, + }); this.emitStackArtifact(this.stack, session, { assumeRoleExternalId: this.props.deployRoleExternalId, assumeRoleArn: this._deployRoleArn, cloudFormationExecutionRoleArn: this._cloudFormationExecutionRoleArn, - stackTemplateAssetObjectUrl: templateManifestUrl, + stackTemplateAssetObjectUrl: templateAsset.s3ObjectUrlWithPlaceholders, requiresBootstrapStackVersion: MIN_BOOTSTRAP_STACK_VERSION, bootstrapStackVersionSsmParameter: this.bootstrapStackVersionSsmParameter, - additionalDependencies: [artifactId], + additionalDependencies: [assetManifestId], lookupRole: this.useLookupRoleForStackOperations && this.lookupRoleArn ? { arn: this.lookupRoleArn, assumeRoleExternalId: this.props.lookupRoleExternalId, @@ -513,126 +446,6 @@ export class DefaultStackSynthesizer extends StackSynthesizer { protected get stack(): Stack | undefined { return this._stack; } - - /** - * Add the stack's template as one of the manifest assets - * - * This will make it get uploaded to S3 automatically by S3-assets. Return - * the manifest URL. - * - * (We can't return the location returned from `addFileAsset`, as that - * contains CloudFormation intrinsics which can't go into the manifest). - */ - private addStackTemplateToAssetManifest(session: ISynthesisSession) { - assertBound(this.stack); - - const templatePath = path.join(session.assembly.outdir, this.stack.templateFile); - const template = fs.readFileSync(templatePath, { encoding: 'utf-8' }); - - const sourceHash = contentHash(template); - - this.addFileAsset({ - fileName: this.stack.templateFile, - packaging: FileAssetPackaging.FILE, - sourceHash, - }); - - // We should technically return an 'https://s3.REGION.amazonaws.com[.cn]/name/hash' URL here, - // because that is what CloudFormation expects to see. - // - // However, there's no way for us to actually know the UrlSuffix a priori, so we can't construct it here. - // - // Instead, we'll have a protocol with the CLI that we put an 's3://.../...' URL here, and the CLI - // is going to resolve it to the correct 'https://.../' URL before it gives it to CloudFormation. - // - // ALSO: it would be great to reuse the return value of `addFileAsset()` here, except those contain - // CloudFormation REFERENCES to locations, not actual locations (can contain `{ Ref: AWS::Region }` and - // `{ Ref: SomeParameter }` etc). We therefore have to duplicate some logic here :(. - const extension = path.extname(this.stack.templateFile); - return `s3://${this.bucketName}/${this.bucketPrefix}${sourceHash}${extension}`; - } - - /** - * Write an asset manifest to the Cloud Assembly, return the artifact IDs written - */ - private writeAssetManifest(session: ISynthesisSession): string { - assertBound(this.stack); - - const artifactId = `${this.stack.artifactId}.assets`; - const manifestFile = `${artifactId}.json`; - const outPath = path.join(session.assembly.outdir, manifestFile); - - const manifest: cxschema.AssetManifest = { - version: cxschema.Manifest.version(), - files: this.files, - dockerImages: this.dockerImages, - }; - - fs.writeFileSync(outPath, JSON.stringify(manifest, undefined, 2)); - session.assembly.addArtifact(artifactId, { - type: cxschema.ArtifactType.ASSET_MANIFEST, - properties: { - file: manifestFile, - requiresBootstrapStackVersion: MIN_BOOTSTRAP_STACK_VERSION, - bootstrapStackVersionSsmParameter: this.bootstrapStackVersionSsmParameter, - }, - }); - - return artifactId; - } - - private get manifestEnvName(): string { - assertBound(this.stack); - - return [ - resolvedOr(this.stack.account, 'current_account'), - resolvedOr(this.stack.region, 'current_region'), - ].join('-'); - } -} - -/** - * Return the given value if resolved or fall back to a default - */ -function resolvedOr(x: string, def: A): string | A { - return Token.isUnresolved(x) ? def : x; -} - -/** - * A "replace-all" function that doesn't require us escaping a literal string to a regex - */ -function replaceAll(s: string, search: string, replace: string) { - return s.split(search).join(replace); -} - -/** - * If the string still contains placeholders, wrap it in a Fn::Sub so they will be substituted at CFN deployment time - * - * (This happens to work because the placeholders we picked map directly onto CFN - * placeholders. If they didn't we'd have to do a transformation here). - */ -function cfnify(s: string): string { - return s.indexOf('${') > -1 ? Fn.sub(s) : s; -} - -/** - * Return the stack locations if they're concrete, or the original CFN intrisics otherwise - * - * We need to return these instead of the tokenized versions of the strings, - * since we must accept those same ${AWS::AccountId}/${AWS::Region} placeholders - * in bucket names and role names (in order to allow environment-agnostic stacks). - * - * We'll wrap a single {Fn::Sub} around the final string in order to replace everything, - * but we can't have the token system render part of the string to {Fn::Join} because - * the CFN specification doesn't allow the {Fn::Sub} template string to be an arbitrary - * expression--it must be a string literal. - */ -function stackLocationOrInstrinsics(stack: Stack) { - return { - account: resolvedOr(stack.account, '${AWS::AccountId}'), - region: resolvedOr(stack.region, '${AWS::Region}'), - urlSuffix: resolvedOr(stack.urlSuffix, '${AWS::URLSuffix}'), - }; } /** @@ -675,29 +488,3 @@ function range(startIncl: number, endExcl: number) { return ret; } - -function validateFileAssetSource(asset: FileAssetSource) { - if (!!asset.executable === !!asset.fileName) { - throw new Error(`Exactly one of 'fileName' or 'executable' is required, got: ${JSON.stringify(asset)}`); - } - - if (!!asset.packaging !== !!asset.fileName) { - throw new Error(`'packaging' is expected in combination with 'fileName', got: ${JSON.stringify(asset)}`); - } -} - -function validateDockerImageAssetSource(asset: DockerImageAssetSource) { - if (!!asset.executable === !!asset.directoryName) { - throw new Error(`Exactly one of 'directoryName' or 'executable' is required, got: ${JSON.stringify(asset)}`); - } - - check('dockerBuildArgs'); - check('dockerBuildTarget'); - check('dockerFile'); - - function check(key: K) { - if (asset[key] && !asset.directoryName) { - throw new Error(`'${key}' is only allowed in combination with 'directoryName', got: ${JSON.stringify(asset)}`); - } - } -} diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/index.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/index.ts index db5f8e4d3f656..2a7a4060dcf53 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/index.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/index.ts @@ -4,3 +4,4 @@ export * from './legacy'; export * from './bootstrapless-synthesizer'; export * from './nested'; export * from './stack-synthesizer'; +export * from './cli-credentials-synthesizer'; diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/legacy.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/legacy.ts index 185dd9730e9d2..204f3b8ba6827 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/legacy.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/legacy.ts @@ -24,10 +24,22 @@ const ASSETS_ECR_REPOSITORY_NAME = 'aws-cdk/assets'; const ASSETS_ECR_REPOSITORY_NAME_OVERRIDE_CONTEXT_KEY = 'assets-ecr-repository-name'; /** - * Use the original deployment environment + * Use the CDK classic way of referencing assets * - * This deployment environment is restricted in cross-environment deployments, - * CI/CD deployments, and will use up CloudFormation parameters in your template. + * This synthesizer will generate CloudFormation parameters for every referenced + * asset, and use the CLI's current credentials to deploy the stack. + * + * - It does not support cross-account deployment (the CLI must have credentials + * to the account you are trying to deploy to). + * - It cannot be used with **CDK Pipelines**. To deploy using CDK Pipelines, + * you must use the `DefaultStackSynthesizer`. + * - Each asset will take up a CloudFormation Parameter in your template. Keep in + * mind that there is a maximum of 200 parameters in a CloudFormation template. + * To use determinstic asset locations instead, use `CliCredentialsStackSynthesizer`. + * + * Be aware that your CLI credentials must be valid for the duration of the + * entire deployment. If you are using session credentials, make sure the + * session lifetime is long enough. * * This is the only StackSynthesizer that supports customizing asset behavior * by overriding `Stack.addFileAsset()` and `Stack.addDockerImageAsset()`. diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/nested.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/nested.ts index 8eb05d34cba9e..ff5f1def0652f 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/nested.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/nested.ts @@ -6,9 +6,12 @@ import { StackSynthesizer } from './stack-synthesizer'; import { IStackSynthesizer } from './types'; /** - * Deployment environment for a nested stack + * Synthesizer for a nested stack * - * Interoperates with the StackSynthesizer of the parent stack. + * Forwards all calls to the parent stack's synthesizer. + * + * This synthesizer is automatically used for `NestedStack` constructs. + * App builder do not need to use this class directly. */ export class NestedStackSynthesizer extends StackSynthesizer { private stack?: Stack; diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/stack-synthesizer.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/stack-synthesizer.ts index ea7c7745f2419..75e4b46bf015f 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/stack-synthesizer.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/stack-synthesizer.ts @@ -47,7 +47,6 @@ export abstract class StackSynthesizer implements IStackSynthesizer { stack._synthesizeTemplate(session); } - /** * Write the stack artifact to the session * diff --git a/packages/@aws-cdk/core/lib/stack.ts b/packages/@aws-cdk/core/lib/stack.ts index 0efd45fc14b3f..d6278d05834e3 100644 --- a/packages/@aws-cdk/core/lib/stack.ts +++ b/packages/@aws-cdk/core/lib/stack.ts @@ -3,6 +3,7 @@ import * as path from 'path'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import * as cxapi from '@aws-cdk/cx-api'; import { IConstruct, Construct, Node } from 'constructs'; +import * as minimatch from 'minimatch'; import { Annotations } from './annotations'; import { App } from './app'; import { Arn, ArnComponents, ArnFormat } from './arn'; @@ -1153,6 +1154,19 @@ export class Stack extends CoreConstruct implements ITaggable { return makeStackName(ids); } + + /** + * Indicates whether the stack requires bundling or not + */ + public get bundlingRequired() { + const bundlingStacks: string[] = this.node.tryGetContext(cxapi.BUNDLING_STACKS) ?? ['*']; + + // bundlingStacks is of the form `Stage/Stack`, convert it to `Stage-Stack` before comparing to stack name + return bundlingStacks.some(pattern => minimatch( + this.stackName, + pattern.replace('/', '-'), + )); + } } function merge(template: any, fragment: any): void { diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index aa2ee18ee84f0..35cdfcc8d0d46 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -178,15 +178,15 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.92", + "@types/aws-lambda": "^8.10.93", "@types/fs-extra": "^8.1.2", - "@types/jest": "^27.4.0", - "@types/lodash": "^4.14.178", + "@types/jest": "^27.4.1", + "@types/lodash": "^4.14.181", "@types/minimatch": "^3.0.5", "@types/node": "^10.17.60", "@types/sinon": "^9.0.11", - "fast-check": "^2.21.0", - "jest": "^27.4.7", + "fast-check": "^2.23.2", + "jest": "^27.5.1", "lodash": "^4.17.21", "sinon": "^9.2.4", "ts-mock-imports": "^1.3.8" @@ -199,7 +199,7 @@ "constructs": "^3.3.69", "fs-extra": "^9.1.0", "ignore": "^5.2.0", - "minimatch": "^3.0.4" + "minimatch": "^3.1.2" }, "bundledDependencies": [ "fs-extra", diff --git a/packages/@aws-cdk/core/rosetta/default.ts-fixture b/packages/@aws-cdk/core/rosetta/default.ts-fixture index 26a25736acb17..e0da717734235 100644 --- a/packages/@aws-cdk/core/rosetta/default.ts-fixture +++ b/packages/@aws-cdk/core/rosetta/default.ts-fixture @@ -23,6 +23,7 @@ import { CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, + DefaultStackSynthesizer, DependableTrait, Duration, Fn, diff --git a/packages/@aws-cdk/core/test/feature-flags.test.ts b/packages/@aws-cdk/core/test/feature-flags.test.ts index 09b79b7c26123..cdffe64e04d2f 100644 --- a/packages/@aws-cdk/core/test/feature-flags.test.ts +++ b/packages/@aws-cdk/core/test/feature-flags.test.ts @@ -23,7 +23,7 @@ describe('feature flags', () => { test('invalid flag', () => { const stack = new Stack(); - expect(FeatureFlags.of(stack).isEnabled('non-existent-flag')).toEqual(undefined); + expect(FeatureFlags.of(stack).isEnabled('non-existent-flag')).toEqual(false); }); }); diff --git a/packages/@aws-cdk/core/test/mappings.test.ts b/packages/@aws-cdk/core/test/mappings.test.ts index 7d1964f60bfe8..5d67aa0163e68 100644 --- a/packages/@aws-cdk/core/test/mappings.test.ts +++ b/packages/@aws-cdk/core/test/mappings.test.ts @@ -58,8 +58,6 @@ describe('mappings', () => { }, }, }); - - }); test('allow using unresolved tokens in find-in-map', () => { @@ -67,26 +65,25 @@ describe('mappings', () => { const mapping = new CfnMapping(stack, 'mapping', { mapping: { - instanceCount: { - 'us-east-1': 12, + 'us-east-1': { + instanceCount: 12, }, }, }); - const v1 = mapping.findInMap('instanceCount', Aws.REGION); - const v2 = Fn.findInMap(mapping.logicalId, 'instanceCount', Aws.REGION); + const v1 = mapping.findInMap(Aws.REGION, 'instanceCount'); + const v2 = Fn.findInMap(mapping.logicalId, Aws.REGION, 'instanceCount'); - const expected = { 'Fn::FindInMap': ['mapping', 'instanceCount', { Ref: 'AWS::Region' }] }; + const expected = { 'Fn::FindInMap': ['mapping', { Ref: 'AWS::Region' }, 'instanceCount'] }; expect(stack.resolve(v1)).toEqual(expected); expect(stack.resolve(v2)).toEqual(expected); expect(toCloudFormation(stack).Mappings).toEqual({ mapping: { - instanceCount: { - 'us-east-1': 12, + 'us-east-1': { + instanceCount: 12, }, }, }); - }); test('no validation if first key is token and second is a static string', () => { @@ -114,7 +111,6 @@ describe('mappings', () => { }, }, }); - }); test('validate first key if it is a string and second is a token', () => { @@ -122,26 +118,36 @@ describe('mappings', () => { const stack = new Stack(); const mapping = new CfnMapping(stack, 'mapping', { mapping: { - size: { - 'us-east-1': 12, + 'us-east-1': { + size: 12, }, }, }); // WHEN - const v = mapping.findInMap('size', Aws.REGION); + const v = mapping.findInMap(Aws.REGION, 'size'); // THEN - expect(() => mapping.findInMap('not-found', Aws.REGION)).toThrow(/Mapping doesn't contain top-level key 'not-found'/); - expect(stack.resolve(v)).toEqual({ 'Fn::FindInMap': ['mapping', 'size', { Ref: 'AWS::Region' }] }); + expect(() => mapping.findInMap('not-found', 'size')).toThrow(/Mapping doesn't contain top-level key 'not-found'/); + expect(stack.resolve(v)).toEqual({ 'Fn::FindInMap': ['mapping', { Ref: 'AWS::Region' }, 'size'] }); expect(toCloudFormation(stack).Mappings).toEqual({ mapping: { - size: { - 'us-east-1': 12, + 'us-east-1': { + size: 12, }, }, }); + }); + test('throws if mapping attribute name not alphanumeric', () => { + const stack = new Stack(); + expect(() => new CfnMapping(stack, 'mapping', { + mapping: { + size: { + 'us-east-1': 12, + }, + }, + })).toThrowError(/Attribute name 'us-east-1' must contain only alphanumeric characters./); }); }); diff --git a/packages/@aws-cdk/core/test/stack-synthesis/clicreds-synthesis.test.ts b/packages/@aws-cdk/core/test/stack-synthesis/clicreds-synthesis.test.ts new file mode 100644 index 0000000000000..3fab5ef7e0b5f --- /dev/null +++ b/packages/@aws-cdk/core/test/stack-synthesis/clicreds-synthesis.test.ts @@ -0,0 +1,257 @@ +import * as fs from 'fs'; +import * as cxschema from '@aws-cdk/cloud-assembly-schema'; +import * as cxapi from '@aws-cdk/cx-api'; +import { App, Aws, CfnResource, CliCredentialsStackSynthesizer, FileAssetPackaging, Stack } from '../../lib'; +import { evaluateCFN } from '../evaluate-cfn'; + +const CFN_CONTEXT = { + 'AWS::Region': 'the_region', + 'AWS::AccountId': 'the_account', + 'AWS::URLSuffix': 'domain.aws', +}; + +let app: App; +let stack: Stack; +describe('CLI creds synthesis', () => { + beforeEach(() => { + app = new App(); + stack = new Stack(app, 'Stack', { + synthesizer: new CliCredentialsStackSynthesizer(), + }); + }); + + test('stack template is in asset manifest', () => { + // GIVEN + new CfnResource(stack, 'Resource', { + type: 'Some::Resource', + }); + + // WHEN + const asm = app.synth(); + + // THEN -- the S3 url is advertised on the stack artifact + const stackArtifact = asm.getStackArtifact('Stack'); + + const templateObjectKey = last(stackArtifact.stackTemplateAssetObjectUrl?.split('/')); + + expect(stackArtifact.stackTemplateAssetObjectUrl).toEqual(`s3://cdk-hnb659fds-assets-\${AWS::AccountId}-\${AWS::Region}/${templateObjectKey}`); + + // THEN - the template is in the asset manifest + const manifestArtifact = asm.artifacts.filter(isAssetManifest)[0]; + expect(manifestArtifact).toBeDefined(); + const manifest: cxschema.AssetManifest = JSON.parse(fs.readFileSync(manifestArtifact.file, { encoding: 'utf-8' })); + + const firstFile = (manifest.files ? manifest.files[Object.keys(manifest.files)[0]] : undefined) ?? {}; + + expect(firstFile).toEqual({ + source: { path: 'Stack.template.json', packaging: 'file' }, + destinations: { + 'current_account-current_region': { + bucketName: 'cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}', + objectKey: templateObjectKey, + }, + }, + }); + }); + + test('add file asset', () => { + // WHEN + const location = stack.synthesizer.addFileAsset({ + fileName: __filename, + packaging: FileAssetPackaging.FILE, + sourceHash: 'abcdef', + }); + + // THEN - we have a fixed asset location with region placeholders + expect(evalCFN(location.bucketName)).toEqual('cdk-hnb659fds-assets-the_account-the_region'); + expect(evalCFN(location.s3Url)).toEqual('https://s3.the_region.domain.aws/cdk-hnb659fds-assets-the_account-the_region/abcdef.js'); + + // THEN - object key contains source hash somewhere + expect(location.objectKey.indexOf('abcdef')).toBeGreaterThan(-1); + }); + + test('add docker image asset', () => { + // WHEN + const location = stack.synthesizer.addDockerImageAsset({ + directoryName: '.', + sourceHash: 'abcdef', + }); + + // THEN - we have a fixed asset location with region placeholders + expect(evalCFN(location.repositoryName)).toEqual('cdk-hnb659fds-container-assets-the_account-the_region'); + expect(evalCFN(location.imageUri)).toEqual('the_account.dkr.ecr.the_region.domain.aws/cdk-hnb659fds-container-assets-the_account-the_region:abcdef'); + + + }); + + test('synthesis', () => { + // GIVEN + stack.synthesizer.addFileAsset({ + fileName: __filename, + packaging: FileAssetPackaging.FILE, + sourceHash: 'abcdef', + }); + stack.synthesizer.addDockerImageAsset({ + directoryName: '.', + sourceHash: 'abcdef', + }); + + // WHEN + const asm = app.synth(); + + // THEN - we have an asset manifest with both assets and the stack template in there + const manifestArtifact = getAssetManifest(asm); + const manifest = readAssetManifest(manifestArtifact); + + expect(Object.keys(manifest.files || {}).length).toEqual(2); + expect(Object.keys(manifest.dockerImages || {}).length).toEqual(1); + }); + + test('customize publishing resources', () => { + // GIVEN + const myapp = new App(); + + // WHEN + const mystack = new Stack(myapp, 'mystack', { + synthesizer: new CliCredentialsStackSynthesizer({ + fileAssetsBucketName: 'file-asset-bucket', + imageAssetsRepositoryName: 'image-ecr-repository', + }), + }); + + mystack.synthesizer.addFileAsset({ + fileName: __filename, + packaging: FileAssetPackaging.FILE, + sourceHash: 'file-asset-hash', + }); + + mystack.synthesizer.addDockerImageAsset({ + directoryName: '.', + sourceHash: 'docker-asset-hash', + }); + + // THEN + const asm = myapp.synth(); + const manifest = readAssetManifest(getAssetManifest(asm)); + + expect(manifest.files?.['file-asset-hash']?.destinations?.['current_account-current_region']).toEqual({ + bucketName: 'file-asset-bucket', + objectKey: 'file-asset-hash.js', + }); + + expect(manifest.dockerImages?.['docker-asset-hash']?.destinations?.['current_account-current_region']).toEqual({ + repositoryName: 'image-ecr-repository', + imageTag: 'docker-asset-hash', + }); + }); + + test('synthesis with bucketPrefix', () => { + // GIVEN + const myapp = new App(); + + // WHEN + const mystack = new Stack(myapp, 'mystack-bucketPrefix', { + synthesizer: new CliCredentialsStackSynthesizer({ + fileAssetsBucketName: 'file-asset-bucket', + bucketPrefix: '000000000000/', + }), + }); + + mystack.synthesizer.addFileAsset({ + fileName: __filename, + packaging: FileAssetPackaging.FILE, + sourceHash: 'file-asset-hash-with-prefix', + }); + + // WHEN + const asm = myapp.synth(); + + // THEN -- the S3 url is advertised on the stack artifact + const stackArtifact = asm.getStackArtifact('mystack-bucketPrefix'); + + // THEN - we have an asset manifest with both assets and the stack template in there + const manifest = readAssetManifest(getAssetManifest(asm)); + + // THEN + expect(manifest.files?.['file-asset-hash-with-prefix']?.destinations?.['current_account-current_region']).toEqual({ + bucketName: 'file-asset-bucket', + objectKey: '000000000000/file-asset-hash-with-prefix.js', + }); + + const templateHash = last(stackArtifact.stackTemplateAssetObjectUrl?.split('/')); + + expect(stackArtifact.stackTemplateAssetObjectUrl).toEqual(`s3://file-asset-bucket/000000000000/${templateHash}`); + }); + + test('synthesis with dockerPrefix', () => { + // GIVEN + const myapp = new App(); + + // WHEN + const mystack = new Stack(myapp, 'mystack-dockerPrefix', { + synthesizer: new CliCredentialsStackSynthesizer({ + dockerTagPrefix: 'test-prefix-', + }), + }); + + mystack.synthesizer.addDockerImageAsset({ + directoryName: 'some-folder', + sourceHash: 'docker-asset-hash', + }); + + const asm = myapp.synth(); + + // THEN + const manifest = readAssetManifest(getAssetManifest(asm)); + const imageTag = manifest.dockerImages?.['docker-asset-hash']?.destinations?.['current_account-current_region'].imageTag; + expect(imageTag).toEqual('test-prefix-docker-asset-hash'); + }); + + test('cannot use same synthesizer for multiple stacks', () => { + // GIVEN + const synthesizer = new CliCredentialsStackSynthesizer(); + + // WHEN + new Stack(app, 'Stack2', { synthesizer }); + expect(() => { + new Stack(app, 'Stack3', { synthesizer }); + }).toThrow(/A StackSynthesizer can only be used for one Stack/); + + }); +}); + +test('get an exception when using tokens for parameters', () => { + expect(() => { + // GIVEN + new CliCredentialsStackSynthesizer({ + fileAssetsBucketName: `my-bucket-${Aws.REGION}`, + }); + }).toThrow(/cannot contain tokens/); +}); + +/** + * Evaluate a possibly string-containing value the same way CFN would do + * + * (Be invariant to the specific Fn::Sub or Fn::Join we would output) + */ +function evalCFN(value: any) { + return evaluateCFN(stack.resolve(value), CFN_CONTEXT); +} + +function isAssetManifest(x: cxapi.CloudArtifact): x is cxapi.AssetManifestArtifact { + return x instanceof cxapi.AssetManifestArtifact; +} + +function getAssetManifest(asm: cxapi.CloudAssembly): cxapi.AssetManifestArtifact { + const manifestArtifact = asm.artifacts.filter(isAssetManifest)[0]; + if (!manifestArtifact) { throw new Error('no asset manifest in assembly'); } + return manifestArtifact; +} + +function readAssetManifest(manifestArtifact: cxapi.AssetManifestArtifact): cxschema.AssetManifest { + return JSON.parse(fs.readFileSync(manifestArtifact.file, { encoding: 'utf-8' })); +} + +function last(xs?: A[]): A | undefined { + return xs ? xs[xs.length - 1] : undefined; +} diff --git a/packages/@aws-cdk/core/test/stack.test.ts b/packages/@aws-cdk/core/test/stack.test.ts index b344dbbbff0be..e41796bccb624 100644 --- a/packages/@aws-cdk/core/test/stack.test.ts +++ b/packages/@aws-cdk/core/test/stack.test.ts @@ -1191,6 +1191,38 @@ describe('stack', () => { expect(new Stack(app, 'Stack', { analyticsReporting: true })._versionReportingEnabled).toBeDefined(); }); + + test('requires bundling when wildcard is specified in BUNDLING_STACKS', () => { + const app = new App(); + const stack = new Stack(app, 'Stack'); + stack.node.setContext(cxapi.BUNDLING_STACKS, ['*']); + expect(stack.bundlingRequired).toBe(true); + + }); + + test('requires bundling when stackName has an exact match in BUNDLING_STACKS', () => { + const app = new App(); + const stack = new Stack(app, 'Stack'); + stack.node.setContext(cxapi.BUNDLING_STACKS, ['Stack']); + expect(stack.bundlingRequired).toBe(true); + + }); + + test('does not require bundling when no item from BUILDING_STACKS matches stackName', () => { + const app = new App(); + const stack = new Stack(app, 'Stack'); + stack.node.setContext(cxapi.BUNDLING_STACKS, ['Stac']); + expect(stack.bundlingRequired).toBe(false); + + }); + + test('does not require bundling when BUNDLING_STACKS is empty', () => { + const app = new App(); + const stack = new Stack(app, 'Stack'); + stack.node.setContext(cxapi.BUNDLING_STACKS, []); + expect(stack.bundlingRequired).toBe(false); + + }); }); describe('regionalFact', () => { diff --git a/packages/@aws-cdk/custom-resources/README.md b/packages/@aws-cdk/custom-resources/README.md index cb30aada65d7f..8bfcd02d5a411 100644 --- a/packages/@aws-cdk/custom-resources/README.md +++ b/packages/@aws-cdk/custom-resources/README.md @@ -354,7 +354,7 @@ This sample demonstrates the following concepts: ### Customizing Provider Function name -In multi-account environments or when the custom resource may be re-utilized across several +In multi-account environments or when the custom resource may be re-utilized across several stacks it may be useful to manually set a name for the Provider Function Lambda and therefore have a predefined service token ARN. @@ -401,9 +401,19 @@ the `installLatestAwsSdk` prop to `false`. You must provide the `policy` property defining the IAM Policy that will be applied to the API calls. The library provides two factory methods to quickly configure this: -* **`AwsCustomResourcePolicy.fromSdkCalls`** - Use this to auto-generate IAM Policy statements based on the configured SDK calls. -Note that you will have to either provide specific ARN's, or explicitly use `AwsCustomResourcePolicy.ANY_RESOURCE` to allow access to any resource. -* **`AwsCustomResourcePolicy.fromStatements`** - Use this to specify your own custom statements. +* **`AwsCustomResourcePolicy.fromSdkCalls`** - Use this to auto-generate IAM + Policy statements based on the configured SDK calls. Keep two things in mind + when using this policy: + * This policy variant assumes the IAM policy name has the same name as the API + call. This is true in 99% of cases, but there are exceptions (for example, + S3's `PutBucketLifecycleConfiguration` requires + `s3:PutLifecycleConfiguration` permissions, Lambda's `Invoke` requires + `lambda:InvokeFunction` permissions). Use `fromStatements` if you want to + do a call that requires different IAM action names. + * You will have to either provide specific ARNs, or explicitly use + `AwsCustomResourcePolicy.ANY_RESOURCE` to allow access to any resource. +* **`AwsCustomResourcePolicy.fromStatements`** - Use this to specify your own + custom statements. The custom resource also implements `iam.IGrantable`, making it possible to use the `grantXxx()` methods. diff --git a/packages/@aws-cdk/custom-resources/lib/aws-custom-resource/aws-custom-resource.ts b/packages/@aws-cdk/custom-resources/lib/aws-custom-resource/aws-custom-resource.ts index 9d9c938f3f894..ccac23249940a 100644 --- a/packages/@aws-cdk/custom-resources/lib/aws-custom-resource/aws-custom-resource.ts +++ b/packages/@aws-cdk/custom-resources/lib/aws-custom-resource/aws-custom-resource.ts @@ -199,6 +199,13 @@ export class AwsCustomResourcePolicy { * * Each SDK call with be translated to an IAM Policy Statement in the form of: `call.service:call.action` (e.g `s3:PutObject`). * + * This policy generator assumes the IAM policy name has the same name as the API + * call. This is true in 99% of cases, but there are exceptions (for example, + * S3's `PutBucketLifecycleConfiguration` requires + * `s3:PutLifecycleConfiguration` permissions, Lambda's `Invoke` requires + * `lambda:InvokeFunction` permissions). Use `fromStatements` if you want to + * do a call that requires different IAM action names. + * * @param options options for the policy generation */ public static fromSdkCalls(options: SdkCallsPolicyOptions) { @@ -263,7 +270,7 @@ export interface AwsCustomResourceProps { readonly policy: AwsCustomResourcePolicy; /** - * The execution role for the Lambda function implementing this custom + * The execution role for the singleton Lambda function implementing this custom * resource provider. This role will apply to all `AwsCustomResource` * instances in the stack. The role must be assumable by the * `lambda.amazonaws.com` service principal. @@ -273,14 +280,14 @@ export interface AwsCustomResourceProps { readonly role?: iam.IRole; /** - * The timeout for the Lambda function implementing this custom resource. + * The timeout for the singleton Lambda function implementing this custom resource. * * @default Duration.minutes(2) */ readonly timeout?: cdk.Duration /** - * The number of days log events of the Lambda function implementing + * The number of days log events of the singleton Lambda function implementing * this custom resource are kept in CloudWatch Logs. * * @default logs.RetentionDays.INFINITE @@ -298,7 +305,8 @@ export interface AwsCustomResourceProps { readonly installLatestAwsSdk?: boolean; /** - * A name for the Lambda function implementing this custom resource. + * A name for the singleton Lambda function implementing this custom resource. + * The function name will remain the same after the first AwsCustomResource is created in a stack. * * @default - AWS CloudFormation generates a unique physical ID and uses that * ID for the function's name. For more information, see Name Type. @@ -307,7 +315,8 @@ export interface AwsCustomResourceProps { } /** - * Defines a custom resource that is materialized using specific AWS API calls. + * Defines a custom resource that is materialized using specific AWS API calls. These calls are created using + * a singleton Lambda function. * * Use this to bridge any gap that might exist in the CloudFormation Coverage. * You can specify exactly which calls are invoked for the 'CREATE', 'UPDATE' and 'DELETE' life cycle events. diff --git a/packages/@aws-cdk/custom-resources/lib/provider-framework/runtime/framework.ts b/packages/@aws-cdk/custom-resources/lib/provider-framework/runtime/framework.ts index 181968611d354..9c2d8a4bfc0fc 100644 --- a/packages/@aws-cdk/custom-resources/lib/provider-framework/runtime/framework.ts +++ b/packages/@aws-cdk/custom-resources/lib/provider-framework/runtime/framework.ts @@ -73,6 +73,7 @@ async function isComplete(event: AWSCDKAsyncCustomResource.IsCompleteRequest) { const response = { ...event, + ...isCompleteResult, Data: { ...event.Data, ...isCompleteResult.Data, diff --git a/packages/@aws-cdk/custom-resources/lib/provider-framework/types.d.ts b/packages/@aws-cdk/custom-resources/lib/provider-framework/types.d.ts index 9a9536eac078b..288dc217c7f82 100644 --- a/packages/@aws-cdk/custom-resources/lib/provider-framework/types.d.ts +++ b/packages/@aws-cdk/custom-resources/lib/provider-framework/types.d.ts @@ -4,7 +4,7 @@ /** * these types can be accessed without needing to `import` the module. * e.g. `AWSCDKAsyncCustomResource.OnEventRequest` - */ + */ export as namespace AWSCDKAsyncCustomResource; /** @@ -105,6 +105,11 @@ export interface IsCompleteResponse { */ readonly IsComplete: boolean; + /** + * If present, overrides the PhysicalResourceId of OnEventResponse with the PhysicalResourceId of IsCompleteResponse. + */ + readonly PhysicalResourceId?: string; + /** * Additional/changes to resource attributes. This hash will be merged with the one returned from `OnEventResponse`. */ diff --git a/packages/@aws-cdk/custom-resources/lib/provider-framework/waiter-state-machine.ts b/packages/@aws-cdk/custom-resources/lib/provider-framework/waiter-state-machine.ts index 6799fb3178123..b6bc6116c328c 100644 --- a/packages/@aws-cdk/custom-resources/lib/provider-framework/waiter-state-machine.ts +++ b/packages/@aws-cdk/custom-resources/lib/provider-framework/waiter-state-machine.ts @@ -1,4 +1,4 @@ -import { Grant, IGrantable, PolicyStatement, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; +import { Grant, IGrantable, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import { IFunction } from '@aws-cdk/aws-lambda'; import { CfnResource, Duration, Stack } from '@aws-cdk/core'; @@ -49,14 +49,8 @@ export class WaiterStateMachine extends Construct { const role = new Role(this, 'Role', { assumedBy: new ServicePrincipal('states.amazonaws.com'), }); - role.addToPolicy(new PolicyStatement({ - actions: ['lambda:InvokeFunction'], - resources: [props.isCompleteHandler.functionArn], - })); - role.addToPolicy(new PolicyStatement({ - actions: ['lambda:InvokeFunction'], - resources: [props.timeoutHandler.functionArn], - })); + props.isCompleteHandler.grantInvoke(role); + props.timeoutHandler.grantInvoke(role); const definition = Stack.of(this).toJsonString({ StartAt: 'framework-isComplete-task', diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index 5ee0eb2d5e71e..4a1359916223c 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -87,9 +87,9 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.92", + "@types/aws-lambda": "^8.10.93", "@types/fs-extra": "^8.1.2", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", "aws-sdk-mock": "5.6.0", diff --git a/packages/@aws-cdk/custom-resources/test/aws-custom-resource/integ.aws-custom-resource.expected.json b/packages/@aws-cdk/custom-resources/test/aws-custom-resource/integ.aws-custom-resource.expected.json index 2cad60974266d..38a11e5519402 100644 --- a/packages/@aws-cdk/custom-resources/test/aws-custom-resource/integ.aws-custom-resource.expected.json +++ b/packages/@aws-cdk/custom-resources/test/aws-custom-resource/integ.aws-custom-resource.expected.json @@ -109,7 +109,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersbd060cb930079c194320bc9a045d159066215c3a4858c45bdb12a79ef9a1edbaS3BucketACF45CC2" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16" }, "S3Key": { "Fn::Join": [ @@ -122,7 +122,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersbd060cb930079c194320bc9a045d159066215c3a4858c45bdb12a79ef9a1edbaS3VersionKeyBCA0A3F3" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -135,7 +135,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersbd060cb930079c194320bc9a045d159066215c3a4858c45bdb12a79ef9a1edbaS3VersionKeyBCA0A3F3" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -274,17 +274,17 @@ } }, "Parameters": { - "AssetParametersbd060cb930079c194320bc9a045d159066215c3a4858c45bdb12a79ef9a1edbaS3BucketACF45CC2": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16": { "Type": "String", - "Description": "S3 bucket for asset \"bd060cb930079c194320bc9a045d159066215c3a4858c45bdb12a79ef9a1edba\"" + "Description": "S3 bucket for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParametersbd060cb930079c194320bc9a045d159066215c3a4858c45bdb12a79ef9a1edbaS3VersionKeyBCA0A3F3": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B": { "Type": "String", - "Description": "S3 key for asset version \"bd060cb930079c194320bc9a045d159066215c3a4858c45bdb12a79ef9a1edba\"" + "Description": "S3 key for asset version \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParametersbd060cb930079c194320bc9a045d159066215c3a4858c45bdb12a79ef9a1edbaArtifactHashF3AE56EF": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87ArtifactHash40DDF5EE": { "Type": "String", - "Description": "Artifact hash for asset \"bd060cb930079c194320bc9a045d159066215c3a4858c45bdb12a79ef9a1edba\"" + "Description": "Artifact hash for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.expected.json b/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.expected.json index aa0407ca5b164..646f935ff4ea6 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.expected.json +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.expected.json @@ -18,8 +18,7 @@ "Ref": "MyBucketF68F3FF0" }, "Contents": "Hello, world, 1980!", - "ObjectKey": "second.txt", - "PublicRead": true + "ObjectKey": "second.txt" }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" @@ -62,12 +61,12 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", - "s3:PutObject*", - "s3:Abort*" + "s3:PutObject*" ], "Effect": "Allow", "Resource": "*" @@ -131,7 +130,7 @@ ] }, "Handler": "index.onEvent", - "Runtime": "nodejs10.x" + "Runtime": "nodejs12.x" }, "DependsOn": [ "comamazonawscdkcustomresourcess3fileproviders3fileoneventServiceRoleDefaultPolicy10D24725", @@ -177,12 +176,28 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "comamazonawscdkcustomresourcess3fileproviders3fileonevent48293DE8", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3fileproviders3fileonevent48293DE8", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3fileproviders3fileonevent48293DE8", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -200,7 +215,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, "S3Key": { "Fn::Join": [ @@ -213,7 +228,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -226,7 +241,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -428,8 +443,8 @@ "Statement": [ { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -540,22 +555,48 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "comamazonawscdkcustomresourcess3assertproviders3assertoneventF1EEF783", - "Arn" - ] - } - }, - { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "comamazonawscdkcustomresourcess3assertproviders3assertiscomplete6AC08EF9", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3assertproviders3assertiscomplete6AC08EF9", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3assertproviders3assertoneventF1EEF783", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3assertproviders3assertiscomplete6AC08EF9", + "Arn" + ] + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3assertproviders3assertoneventF1EEF783", + "Arn" + ] + }, + ":*" + ] + ] + } + ] }, { "Action": "states:StartExecution", @@ -580,7 +621,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, "S3Key": { "Fn::Join": [ @@ -593,7 +634,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -606,7 +647,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -690,22 +731,48 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "comamazonawscdkcustomresourcess3assertproviders3assertoneventF1EEF783", - "Arn" - ] - } - }, - { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "comamazonawscdkcustomresourcess3assertproviders3assertiscomplete6AC08EF9", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3assertproviders3assertiscomplete6AC08EF9", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3assertproviders3assertoneventF1EEF783", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3assertproviders3assertiscomplete6AC08EF9", + "Arn" + ] + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3assertproviders3assertoneventF1EEF783", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -723,7 +790,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, "S3Key": { "Fn::Join": [ @@ -736,7 +803,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -749,7 +816,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -830,22 +897,48 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "comamazonawscdkcustomresourcess3assertproviders3assertoneventF1EEF783", - "Arn" - ] - } - }, - { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "comamazonawscdkcustomresourcess3assertproviders3assertiscomplete6AC08EF9", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3assertproviders3assertiscomplete6AC08EF9", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3assertproviders3assertoneventF1EEF783", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3assertproviders3assertiscomplete6AC08EF9", + "Arn" + ] + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3assertproviders3assertoneventF1EEF783", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -863,7 +956,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, "S3Key": { "Fn::Join": [ @@ -876,7 +969,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -889,7 +982,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -967,22 +1060,48 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "comamazonawscdkcustomresourcess3assertproviderframeworkisComplete63829575", - "Arn" - ] - } - }, - { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "comamazonawscdkcustomresourcess3assertproviderframeworkonTimeoutA1E1E5DC", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3assertproviderframeworkisComplete63829575", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3assertproviderframeworkonTimeoutA1E1E5DC", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3assertproviderframeworkisComplete63829575", + "Arn" + ] + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "comamazonawscdkcustomresourcess3assertproviderframeworkonTimeoutA1E1E5DC", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -1046,17 +1165,17 @@ "Type": "String", "Description": "Artifact hash for asset \"192597c3e09c72bcb5fca6899fca0b42745cb003a702e275a7f96123a9baf590\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { "Type": "String", - "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { "Type": "String", - "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { "Type": "String", - "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, "AssetParameters4bafad8d010ba693e235b77d2c6decfc2ac79a8208d4477cbb36d31caf7189e8S3Bucket0DB889DF": { "Type": "String", diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.ts index 64ec2bbb33987..282395b1b9096 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.ts @@ -16,7 +16,6 @@ class TestStack extends Stack { bucket, objectKey: 'second.txt', contents: 'Hello, world, 1980!', - public: true, }); const file2 = new S3File(this, 'file2', { diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-file.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-file.ts index d70759be12b79..7b37e16fee6b1 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-file.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-file.ts @@ -82,7 +82,7 @@ class S3FileProvider extends CoreConstruct { this.provider = new cr.Provider(this, 's3file-provider', { onEventHandler: new lambda.Function(this, 's3file-on-event', { code: lambda.Code.fromAsset(path.join(__dirname, 's3-file-handler')), - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.onEvent', initialPolicy: [ new iam.PolicyStatement({ diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/runtime.test.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/runtime.test.ts index d2af0a4fafd2d..751e33e6408e0 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/runtime.test.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/runtime.test.ts @@ -169,6 +169,23 @@ describe('PhysicalResourceId', () => { }); }); + test('UPDATE: can override the physical ID with the actual on isComplete', async () => { + // GIVEN + mocks.onEventImplMock = async () => ({ PhysicalResourceId: 'TemporaryPhysicalId' }); + mocks.isCompleteImplMock = async () => ({ IsComplete: true, PhysicalResourceId: 'NewPhysicalId' }); + + // WHEN + await simulateEvent({ + RequestType: 'Update', + PhysicalResourceId: 'CurrentPhysicalId', + }); + + // THEN + expectCloudFormationSuccess({ + PhysicalResourceId: 'NewPhysicalId', + }); + }); + test('DELETE: cannot change the physical resource ID during a delete', async () => { // GIVEN mocks.onEventImplMock = async () => ({ PhysicalResourceId: 'NewPhysicalId' }); diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/waiter-state-machine.test.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/waiter-state-machine.test.ts index 7548f4e151041..514c1af72391b 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/waiter-state-machine.test.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/waiter-state-machine.test.ts @@ -83,12 +83,12 @@ describe('state machine', () => { { Action: 'lambda:InvokeFunction', Effect: 'Allow', - Resource: stack.resolve(isCompleteHandler.functionArn), + Resource: stack.resolve(isCompleteHandler.resourceArnsForGrantInvoke), }, { Action: 'lambda:InvokeFunction', Effect: 'Allow', - Resource: stack.resolve(timeoutHandler.functionArn), + Resource: stack.resolve(timeoutHandler.resourceArnsForGrantInvoke), }, ], Version: '2012-10-17', diff --git a/packages/@aws-cdk/cx-api/lib/artifacts/asset-manifest-artifact.ts b/packages/@aws-cdk/cx-api/lib/artifacts/asset-manifest-artifact.ts index 3c8c102f2c5ab..10ddea69b624e 100644 --- a/packages/@aws-cdk/cx-api/lib/artifacts/asset-manifest-artifact.ts +++ b/packages/@aws-cdk/cx-api/lib/artifacts/asset-manifest-artifact.ts @@ -3,10 +3,33 @@ import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { CloudArtifact } from '../cloud-artifact'; import { CloudAssembly } from '../cloud-assembly'; +const ASSET_MANIFEST_ARTIFACT_SYM = Symbol.for('@aws-cdk/cx-api.AssetManifestArtifact'); + /** * Asset manifest is a description of a set of assets which need to be built and published */ export class AssetManifestArtifact extends CloudArtifact { + /** + * Checks if `art` is an instance of this class. + * + * Use this method instead of `instanceof` to properly detect `AssetManifestArtifact` + * instances, even when the construct library is symlinked. + * + * Explanation: in JavaScript, multiple copies of the `cx-api` library on + * disk are seen as independent, completely different libraries. As a + * consequence, the class `AssetManifestArtifact` in each copy of the `cx-api` library + * is seen as a different class, and an instance of one class will not test as + * `instanceof` the other class. `npm install` will not create installations + * like this, but users may manually symlink construct libraries together or + * use a monorepo tool: in those cases, multiple copies of the `cx-api` + * library can be accidentally installed, and `instanceof` will behave + * unpredictably. It is safest to avoid using `instanceof`, and using + * this type-testing method instead. + */ + public static isAssetManifestArtifact(art: any): art is AssetManifestArtifact { + return art && typeof art === 'object' && art[ASSET_MANIFEST_ARTIFACT_SYM]; + } + /** * The file name of the asset manifest */ @@ -36,3 +59,15 @@ export class AssetManifestArtifact extends CloudArtifact { this.bootstrapStackVersionSsmParameter = properties.bootstrapStackVersionSsmParameter; } } + +/** + * Mark all instances of 'AssetManifestArtifact' + * + * Why not put this in the constructor? Because this is a class property, + * not an instance property. It applies to all instances of the class. + */ +Object.defineProperty(AssetManifestArtifact.prototype, ASSET_MANIFEST_ARTIFACT_SYM, { + value: true, + enumerable: false, + writable: false, +}); diff --git a/packages/@aws-cdk/cx-api/lib/artifacts/cloudformation-artifact.ts b/packages/@aws-cdk/cx-api/lib/artifacts/cloudformation-artifact.ts index 3e6f395b5c99d..f601131d9f532 100644 --- a/packages/@aws-cdk/cx-api/lib/artifacts/cloudformation-artifact.ts +++ b/packages/@aws-cdk/cx-api/lib/artifacts/cloudformation-artifact.ts @@ -37,9 +37,10 @@ export class CloudFormationStackArtifact extends CloudArtifact { public readonly stackName: string; /** - * A string that represents this stack. Should only be used in user interfaces. - * If the stackName and artifactId are the same, it will just return that. Otherwise, - * it will return something like " ()" + * A string that represents this stack. Should only be used in user + * interfaces. If the stackName has not been set explicitly, or has been set + * to artifactId, it will return the hierarchicalId of the stack. Otherwise, + * it will return something like " ()" */ public readonly displayName: string; @@ -148,8 +149,8 @@ export class CloudFormationStackArtifact extends CloudArtifact { this.assets = this.findMetadataByType(cxschema.ArtifactMetadataEntryType.ASSET).map(e => e.data as cxschema.AssetMetadataEntry); this.displayName = this.stackName === artifactId - ? this.stackName - : `${artifactId} (${this.stackName})`; + ? this.hierarchicalId + : `${this.hierarchicalId} (${this.stackName})`; this.name = this.stackName; // backwards compat this.originalName = this.stackName; diff --git a/packages/@aws-cdk/cx-api/lib/cloud-assembly.ts b/packages/@aws-cdk/cx-api/lib/cloud-assembly.ts index 400981cea7054..70f4ecc850f36 100644 --- a/packages/@aws-cdk/cx-api/lib/cloud-assembly.ts +++ b/packages/@aws-cdk/cx-api/lib/cloud-assembly.ts @@ -2,6 +2,7 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; +import { LoadManifestOptions } from '@aws-cdk/cloud-assembly-schema'; import { CloudFormationStackArtifact } from './artifacts/cloudformation-artifact'; import { NestedCloudAssemblyArtifact } from './artifacts/nested-cloud-assembly-artifact'; import { TreeCloudArtifact } from './artifacts/tree-cloud-artifact'; @@ -46,10 +47,10 @@ export class CloudAssembly { * Reads a cloud assembly from the specified directory. * @param directory The root directory of the assembly. */ - constructor(directory: string) { + constructor(directory: string, loadOptions?: LoadManifestOptions) { this.directory = directory; - this.manifest = cxschema.Manifest.loadAssemblyManifest(path.join(directory, MANIFEST_FILE)); + this.manifest = cxschema.Manifest.loadAssemblyManifest(path.join(directory, MANIFEST_FILE), loadOptions); this.version = this.manifest.version; this.artifacts = this.renderArtifacts(); this.runtime = this.manifest.runtime || { libraries: { } }; diff --git a/packages/@aws-cdk/cx-api/lib/features.ts b/packages/@aws-cdk/cx-api/lib/features.ts index f4ced76f60d3a..9b5dc4e872892 100644 --- a/packages/@aws-cdk/cx-api/lib/features.ts +++ b/packages/@aws-cdk/cx-api/lib/features.ts @@ -3,8 +3,18 @@ // implemented behind a flag in order to preserve backwards compatibility for // existing apps. When a new app is initialized through `cdk init`, the CLI will // automatically add enable these features by adding them to the generated -// `cdk.json` file. In the next major release of the CDK, these feature flags -// will be removed and will become the default behavior. +// `cdk.json` file. +// +// Some of these flags only affect the behavior of the construct library -- +// these will be removed in the next major release and the behavior they are +// gating will become the only behavior. +// +// Other flags also affect the generated CloudFormation templates, in a way +// that prevents seamless upgrading. In the next major version, their +// behavior will become the default, but the flag still exists so users can +// switch it *off* in order to revert to the old behavior. These flags +// are marked with with the [PERMANENT] tag below. +// // See https://github.com/aws/aws-cdk-rfcs/blob/master/text/0055-feature-flags.md // -------------------------------------------------------------------------------- @@ -31,6 +41,8 @@ export const ENABLE_DIFF_NO_FAIL = ENABLE_DIFF_NO_FAIL_CONTEXT; /** * Switch to new stack synthesis method which enable CI/CD + * + * [PERMANENT] */ export const NEW_STYLE_STACK_SYNTHESIS_CONTEXT = '@aws-cdk/core:newStyleStackSynthesis'; @@ -41,6 +53,8 @@ export const NEW_STYLE_STACK_SYNTHESIS_CONTEXT = '@aws-cdk/core:newStyleStackSyn * ensure uniqueness, and makes the export names robust against refactoring * the location of the stack in the construct tree (specifically, moving the Stack * into a Stage). + * + * [PERMANENT] */ export const STACK_RELATIVE_EXPORTS_CONTEXT = '@aws-cdk/core:stackRelativeExports'; @@ -116,6 +130,8 @@ export const ECS_REMOVE_DEFAULT_DESIRED_COUNT = '@aws-cdk/aws-ecs-patterns:remov * * This feature flag make correct the ServerlessCluster.clusterArn when * clusterIdentifier contains a Upper case letters. + * + * [PERMANENT] */ export const RDS_LOWERCASE_DB_IDENTIFIER = '@aws-cdk/aws-rds:lowercaseDbIdentifier'; @@ -132,6 +148,8 @@ export const RDS_LOWERCASE_DB_IDENTIFIER = '@aws-cdk/aws-rds:lowercaseDbIdentifi * * In effect, there is no way to get out of this mess in a backwards compatible way, while supporting existing stacks. * This flag changes the logical id layout of UsagePlanKey to not be sensitive to order. + * + * [PERMANENT] */ export const APIGATEWAY_USAGEPLANKEY_ORDERINSENSITIVE_ID = '@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId'; @@ -150,6 +168,8 @@ export const EFS_DEFAULT_ENCRYPTION_AT_REST = '@aws-cdk/aws-efs:defaultEncryptio * not constitute creating a new Version. * * See 'currentVersion' section in the aws-lambda module's README for more details. + * + * [PERMANENT] */ export const LAMBDA_RECOGNIZE_VERSION_PROPS = '@aws-cdk/aws-lambda:recognizeVersionProps'; @@ -157,6 +177,8 @@ export const LAMBDA_RECOGNIZE_VERSION_PROPS = '@aws-cdk/aws-lambda:recognizeVers * Enable this feature flag to have cloudfront distributions use the security policy TLSv1.2_2021 by default. * * The security policy can also be configured explicitly using the `minimumProtocolVersion` property. + * + * [PERMANENT] */ export const CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021 = '@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021'; @@ -167,6 +189,8 @@ export const CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021 = '@aws-cdk/aws-cl * of unnecessary regions included in stacks without a known region. * * The type of this value should be a list of strings. + * + * [PERMANENT] */ export const TARGET_PARTITIONS = '@aws-cdk/core:target-partitions'; @@ -175,6 +199,8 @@ export const TARGET_PARTITIONS = '@aws-cdk/core:target-partitions'; * `awslogs` log driver for the application container of the service to send the container logs to CloudWatch Logs. * * This is a feature flag as the new behavior provides a better default experience for the users. + * + * [PERMANENT] */ export const ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER = '@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver'; @@ -190,15 +216,20 @@ export const ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER = '@aws-cdk-contai export const EC2_UNIQUE_IMDSV2_LAUNCH_TEMPLATE_NAME = '@aws-cdk/aws-ec2:uniqueImdsv2TemplateName'; /** - * This map includes context keys and values for feature flags that enable - * capabilities "from the future", which we could not introduce as the default - * behavior due to backwards compatibility for existing projects. + * Minimize IAM policies by combining Principals, Actions and Resources of two + * Statements in the policies, as long as it doesn't change the meaning of the + * policy. * - * New projects generated through `cdk init` will include these flags in their - * generated `cdk.json` file. + * [PERMANENT] + */ +export const IAM_MINIMIZE_POLICIES = '@aws-cdk/aws-iam:minimizePolicies'; + +/** + * Flag values that should apply for new projects * - * When we release the next major version of the CDK, we will flip the logic of - * these features and clean up the `cdk.json` generated by `cdk init`. + * Add a flag in here (typically with the value `true`), to enable + * backwards-breaking behavior changes only for new projects. New projects + * generated through `cdk init` will include these flags in their generated * * Tests must cover the default (disabled) case and the future (enabled) case. */ @@ -218,9 +249,7 @@ export const FUTURE_FLAGS: { [key: string]: boolean } = { [CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021]: true, [ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER]: true, [EC2_UNIQUE_IMDSV2_LAUNCH_TEMPLATE_NAME]: true, - - // We will advertise this flag when the feature is complete - // [NEW_STYLE_STACK_SYNTHESIS_CONTEXT]: 'true', + [IAM_MINIMIZE_POLICIES]: true, }; /** @@ -238,28 +267,17 @@ export const FUTURE_FLAGS_EXPIRED: string[] = [ ]; /** - * The set of defaults that should be applied if the feature flag is not - * explicitly configured. + * The default values of each of these flags. + * + * This is the effective value of the flag, unless it's overriden via + * context. + * + * Adding new flags here is only allowed during the pre-release period of a new + * major version! */ const FUTURE_FLAGS_DEFAULTS: { [key: string]: boolean } = { - [APIGATEWAY_USAGEPLANKEY_ORDERINSENSITIVE_ID]: false, - [ENABLE_STACK_NAME_DUPLICATES_CONTEXT]: false, - [ENABLE_DIFF_NO_FAIL_CONTEXT]: false, - [STACK_RELATIVE_EXPORTS_CONTEXT]: false, - [NEW_STYLE_STACK_SYNTHESIS_CONTEXT]: false, - [DOCKER_IGNORE_SUPPORT]: false, - [SECRETS_MANAGER_PARSE_OWNED_SECRET_NAME]: false, - [KMS_DEFAULT_KEY_POLICIES]: false, - [S3_GRANT_WRITE_WITHOUT_ACL]: false, - [ECS_REMOVE_DEFAULT_DESIRED_COUNT]: false, - [RDS_LOWERCASE_DB_IDENTIFIER]: false, - [EFS_DEFAULT_ENCRYPTION_AT_REST]: false, - [LAMBDA_RECOGNIZE_VERSION_PROPS]: false, - [CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021]: false, - [ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER]: false, - [EC2_UNIQUE_IMDSV2_LAUNCH_TEMPLATE_NAME]: false, }; -export function futureFlagDefault(flag: string): boolean | undefined { - return FUTURE_FLAGS_DEFAULTS[flag]; +export function futureFlagDefault(flag: string): boolean { + return FUTURE_FLAGS_DEFAULTS[flag] ?? false; } diff --git a/packages/@aws-cdk/cx-api/package.json b/packages/@aws-cdk/cx-api/package.json index a775754011d4d..90941529df1f3 100644 --- a/packages/@aws-cdk/cx-api/package.json +++ b/packages/@aws-cdk/cx-api/package.json @@ -68,10 +68,10 @@ "devDependencies": { "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "@types/mock-fs": "^4.13.1", "@types/semver": "^7.3.9", - "jest": "^27.4.7", + "jest": "^27.5.1", "madge": "^5.0.1", "mock-fs": "^4.14.0" }, diff --git a/packages/@aws-cdk/cx-api/test/cloud-assembly.test.ts b/packages/@aws-cdk/cx-api/test/cloud-assembly.test.ts index 2151e2345620c..804d1e43e16b6 100644 --- a/packages/@aws-cdk/cx-api/test/cloud-assembly.test.ts +++ b/packages/@aws-cdk/cx-api/test/cloud-assembly.test.ts @@ -132,7 +132,22 @@ test('getStackArtifact retrieves a stack by artifact id', () => { expect(assembly.getStackArtifact('stack1').id).toEqual('stack1'); }); -test('displayName shows both artifact ID and stack name if needed', () => { +test('displayName shows hierarchical ID for nested stack without explicit stackName', () => { + const assembly = new CloudAssembly(path.join(FIXTURES, 'nested-stacks')); + const stackArtifact = assembly.getStackArtifact('topLevelStackNestedStackDAC87084'); + expect(stackArtifact.hierarchicalId).toStrictEqual('topLevelStack/nestedStack'); + expect(stackArtifact.displayName).toStrictEqual('topLevelStack/nestedStack'); +}); + +test('displayName shows hierarchical ID and stackName for nested stack with explicit stackName', () => { + const assembly = new CloudAssembly(path.join(FIXTURES, 'nested-stacks')); + const nestedStack = assembly.getStackArtifact('topLevelStackNestedStackWithStackName6D28EAEF'); + expect(nestedStack.hierarchicalId).toStrictEqual('topLevelStack/nestedStackWithStackName'); + expect(nestedStack.stackName).toStrictEqual('explicitStackName'); + expect(nestedStack.displayName).toStrictEqual('topLevelStack/nestedStackWithStackName (explicitStackName)'); +}); + +test('displayName shows both hierarchical ID and stack name if needed', () => { const a1 = new CloudAssembly(path.join(FIXTURES, 'multiple-stacks-same-name')); expect(a1.getStackArtifact('stack1').displayName).toStrictEqual('stack1 (the-physical-name-of-the-stack)'); expect(a1.getStackArtifact('stack2').displayName).toStrictEqual('stack2 (the-physical-name-of-the-stack)'); diff --git a/packages/@aws-cdk/cx-api/test/features.test.ts b/packages/@aws-cdk/cx-api/test/features.test.ts index afc9c0838d7da..b71927bfeeffd 100644 --- a/packages/@aws-cdk/cx-api/test/features.test.ts +++ b/packages/@aws-cdk/cx-api/test/features.test.ts @@ -7,8 +7,8 @@ test('all future flags have defaults configured', () => { }); }); -test('futureFlagDefault returns undefined if non existent flag was given', () => { - expect(feats.futureFlagDefault('non-existent-flag')).toEqual(undefined); +test('futureFlagDefault returns false if non existent flag was given', () => { + expect(feats.futureFlagDefault('non-existent-flag')).toEqual(false); }); testLegacyBehavior('FUTURE_FLAGS_EXPIRED must be empty in CDKv1', Object, () => { diff --git a/packages/@aws-cdk/cx-api/test/fixtures/nested-stacks/manifest.json b/packages/@aws-cdk/cx-api/test/fixtures/nested-stacks/manifest.json new file mode 100644 index 0000000000000..8d732d2105e2d --- /dev/null +++ b/packages/@aws-cdk/cx-api/test/fixtures/nested-stacks/manifest.json @@ -0,0 +1,30 @@ +{ + "version": "0.0.0", + "artifacts": { + "topLevelStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://111111111111/us-east-1", + "properties": { + "templateFile": "topLevelStack.template.json" + }, + "displayName": "topLevelStack" + }, + "topLevelStackNestedStackDAC87084": { + "type": "aws:cloudformation:stack", + "environment": "aws://111111111111/us-east-1", + "properties": { + "templateFile": "nestedStack.template.json" + }, + "displayName": "topLevelStack/nestedStack" + }, + "topLevelStackNestedStackWithStackName6D28EAEF": { + "type": "aws:cloudformation:stack", + "environment": "aws://111111111111/us-east-1", + "properties": { + "templateFile": "nestedStackWithStackName.template.json", + "stackName": "explicitStackName" + }, + "displayName": "topLevelStack/nestedStackWithStackName" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/cx-api/test/fixtures/nested-stacks/nestedStack.template.json b/packages/@aws-cdk/cx-api/test/fixtures/nested-stacks/nestedStack.template.json new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/@aws-cdk/cx-api/test/fixtures/nested-stacks/nestedStackWithStackName.template.json b/packages/@aws-cdk/cx-api/test/fixtures/nested-stacks/nestedStackWithStackName.template.json new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/@aws-cdk/cx-api/test/fixtures/nested-stacks/topLevelStack.template.json b/packages/@aws-cdk/cx-api/test/fixtures/nested-stacks/topLevelStack.template.json new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/@aws-cdk/example-construct-library/package.json b/packages/@aws-cdk/example-construct-library/package.json index f37f388b24062..afc6831a83f5f 100644 --- a/packages/@aws-cdk/example-construct-library/package.json +++ b/packages/@aws-cdk/example-construct-library/package.json @@ -77,8 +77,8 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -111,8 +111,5 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } - }, - "ubergen": { - "exclude": true } } diff --git a/packages/@aws-cdk/example-construct-library/rosetta/default.ts-fixture b/packages/@aws-cdk/example-construct-library/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..e8deb6060d76d --- /dev/null +++ b/packages/@aws-cdk/example-construct-library/rosetta/default.ts-fixture @@ -0,0 +1,11 @@ +// Fixture with packages imported, but nothing else +import { Construct } from 'constructs'; +import { Stack } from '@aws-cdk/core'; + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + /// here + } +} diff --git a/packages/@aws-cdk/integ-runner/.eslintrc.js b/packages/@aws-cdk/integ-runner/.eslintrc.js new file mode 100644 index 0000000000000..2658ee8727166 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; diff --git a/packages/@aws-cdk/integ-runner/.gitignore b/packages/@aws-cdk/integ-runner/.gitignore new file mode 100644 index 0000000000000..d24092a6feda2 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/.gitignore @@ -0,0 +1,28 @@ +*.js +*.js.map +*.d.ts +!lib/init-templates/**/javascript/**/* +node_modules +dist + +# Generated by generate.sh +build-info.json + +.LAST_BUILD +.nyc_output +coverage +nyc.config.js +.LAST_PACKAGE +*.snk + +!test/integ/run-wrappers/dist +!test/integ/cli/**/* +assets.json +npm-shrinkwrap.json +!.eslintrc.js +!jest.config.js + +junit.xml + +# Ignore this symlink, we recreate it at test time +test/test-archive-follow/data/linked diff --git a/packages/@aws-cdk/integ-runner/.npmignore b/packages/@aws-cdk/integ-runner/.npmignore new file mode 100644 index 0000000000000..45b8808bdd7ac --- /dev/null +++ b/packages/@aws-cdk/integ-runner/.npmignore @@ -0,0 +1,30 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.template.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +*.snk + +!lib/init-templates/*/*/tsconfig.json +!test/integ/cli/**/*.js +!test/integ/run-wrappers/dist + +*.tsbuildinfo + +tsconfig.json + +# init templates include default tsconfig.json files which we need +!lib/init-templates/**/tsconfig.json +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml +test/ \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/LICENSE b/packages/@aws-cdk/integ-runner/LICENSE new file mode 100644 index 0000000000000..82ad00bb02d0b --- /dev/null +++ b/packages/@aws-cdk/integ-runner/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/integ-runner/NOTICE b/packages/@aws-cdk/integ-runner/NOTICE new file mode 100644 index 0000000000000..1b7adbb891265 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/integ-runner/README.md b/packages/@aws-cdk/integ-runner/README.md new file mode 100644 index 0000000000000..e67a64282a42b --- /dev/null +++ b/packages/@aws-cdk/integ-runner/README.md @@ -0,0 +1,161 @@ +# integ-runner + + + +--- + +![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) + +> The APIs of higher level constructs in this module are experimental and under active development. +> They are subject to non-backward compatible changes or removal in any future version. These are +> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be +> announced in the release notes. This means that while you may use them, you may need to update +> your source code when upgrading to a newer version of this package. + +--- + + + + +## Overview + + +## Usage + +- Run all integration tests in `test` directory + +```bash +integ-runner [ARGS] [TEST...] +``` + +This will look for all files that match the naming convention of `/integ.*.ts$/`. Each of these files will be expected +to be a self contained CDK app. The runner will execute the following for each file (app): + +1. Check if a snapshot file exists (i.e. `/integ.*.expected.snapshot$/`) +2. If the snapshot does not exist + 2a. Synth the integ app which will produce the `integ.json` file +3. Read the `integ.json` file which contains instructions on what the runner should do. +4. Execute instructions + +### Options + +- `--update-on-failed` (default=false) + Rerun integration tests if snapshot fails +- `--clean` (default=`true`) + Destroy stacks after deploy (use `--no-clean` for debugging) +- `--verbose` (default=`false`) + verbose logging +- `--parallel` (default=`false`) + Run tests in parallel across default regions +- `--parallel-regions` + List of regions to run tests in. If this is provided then all tests will + be run in parallel across these regions +- `--directory` (default=`test`) + Search for integration tests recursively from this starting directory +- `--force` (default=`false`) + Rerun integration test even if the test passes +- `--file` + Read the list of tests from this file + +Example: + +```bash +integ-runner --update --parallel --parallel-regions us-east-1 --parallel-regions us-east-2 --parallel-regions us-west-2 --directory ./ +``` + +This will search for integration tests recursively from the current directory and then execute them in parallel across `us-east-1`, `us-east-2`, & `us-west-2`. + +### integ.json schema + +See [@aws-cdk/cloud-assembly-schema/lib/integ-tests/schema.ts](../cloud-assembly-schema/lib/integ-tests/schema.ts) + +### defining an integration test + +In most cases an integration test will be an instance of a stack + +```ts +import { Function, FunctionOptions } from '../lib'; + +interface MyIntegTestProps extends StackOptions { + functionProps?: FunctionOptions; +} +class MyIntegTest extends Stack { + constructor(scope: Construct, id: string, props: MyIntegTestProps) { + super(scope, id, props); + + new Function(this, 'Handler', { + runtime: Runtime.NODEJS_12_X, + handler: 'index.handler', + code: Code.fromAsset(path.join(__dirname, 'lambda-handler')), + ...props.functionProps, + }); + } +} +``` + +You would then use the `IntegTest` construct to create your test cases + +```ts +new IntegTeset(app, 'ArmTest', { + stacks: [ + new MyIntegTest(app, 'Stack1', { + functionProps: { + architecture: lambda.Architecture.ARM_64, + }, + }), + ], + diffAssets: true, + update: true, + cdkCommandOptions: { + deploy: { + args: { + requireApproval: RequireApproval.NEVER, + json: true, + }, + }, + destroy: { + args: { + force: true, + }, + }, + }, +}); + +new IntegTeset(app, 'AmdTest', { + stacks: [ + new MyIntegTest(app, 'Stack2', { + functionProps: { + architecture: lambda.Architecture.X86_64, + }, + }), + ], +}); +``` + +This will synthesize an `integ.json` file with the following contents + +```json +{ + "ArmTest": { + "stacks": ["Stack1"], + "diffAssets": true, + "update": true, + "cdkCommands": { + "deploy": { + "args": { + "requireApproval": "never", + "json": true + } + }, + "destroy": { + "args": { + "force": true + } + } + } + }, + "AmdTest": { + "stacks": ["Stack2"] + } +} +``` diff --git a/packages/@aws-cdk/integ-runner/bin/integ-runner b/packages/@aws-cdk/integ-runner/bin/integ-runner new file mode 100755 index 0000000000000..20ace56b80449 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/bin/integ-runner @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('./integ-runner.js'); diff --git a/packages/@aws-cdk/integ-runner/bin/integ-runner.ts b/packages/@aws-cdk/integ-runner/bin/integ-runner.ts new file mode 100644 index 0000000000000..ca343920f91cb --- /dev/null +++ b/packages/@aws-cdk/integ-runner/bin/integ-runner.ts @@ -0,0 +1,169 @@ +#!/usr/bin/env node +// Exercise all integ stacks and if they deploy, update the expected synth files +import * as os from 'os'; +import * as path from 'path'; +import * as chalk from 'chalk'; +import * as workerpool from 'workerpool'; +import * as yargs from 'yargs'; +import { IntegrationTests, IntegTestConfig } from '../lib/runner/integ-tests'; +import * as logger from '../lib/runner/private/logger'; +import { IntegBatchResponse, printResults } from '../lib/workers/common'; +import { SnapshotBatchRequest } from '../lib/workers/extract_worker'; +import { runIntegrationTestsInParallel, IntegTestRunOptions } from '../lib/workers/integ-test-worker'; + + +/** + * Split a list of snapshot tests into batches that can be run using a workerpool. + */ +function batchTests(tests: IntegTestConfig[]): SnapshotBatchRequest[] { + let batchSize = 3; + const ret: SnapshotBatchRequest[] = []; + for (let i = 0; i < tests.length; i += batchSize) { + ret.push({ + tests: tests.slice(i, i + batchSize), + }); + } + return ret; +} + +export function printSummary(total: number, failed: number): void { + if (failed > 0) { + logger.print('%s: %s %s, %s total', chalk.bold('Tests'), chalk.red(failed), chalk.red('failed'), total); + } else { + logger.print('%s: %s %s, %s total', chalk.bold('Tests'), chalk.green(total), chalk.green('passed'), total); + } +} + +/** + * Run Integration tests. + */ +async function runIntegrationTests(options: IntegTestRunOptions): Promise { + logger.highlight('\nRunning integration tests for failed tests...\n'); + logger.print('Running in parallel across: %s', options.regions.join(', ')); + const totalTests = options.tests.length; + const failedTests: IntegTestConfig[] = []; + + const responses = await runIntegrationTestsInParallel(options); + for (const response of responses) { + failedTests.push(...response.failedTests); + } + logger.highlight('\nTest Results: \n'); + printSummary(totalTests, failedTests.length); +} + +/** + * Run Snapshot tests + * First batch up the tests. By default there will be 3 tests per batch. + * Use a workerpool to run the batches in parallel. + */ +async function runSnapshotTests(pool: workerpool.WorkerPool, tests: IntegTestConfig[]): Promise { + const testsToRun: IntegTestConfig[] = []; + const requests = batchTests(tests); + logger.highlight('\nVerifying integration test snapshots...\n'); + const responses: IntegBatchResponse[] = await Promise.all( + requests.map((request) => pool.exec('snapshotTestBatch', [request], { + on: printResults, + })), + ); + for (const response of responses) { + testsToRun.push(...response.failedTests); + } + + logger.highlight('\nSnapshot Results: \n'); + printSummary(tests.length, testsToRun.length); + return testsToRun; +} + +async function main() { + const argv = yargs + .usage('Usage: integ-runner [TEST...]') + .option('list', { type: 'boolean', default: false, desc: 'List tests instead of running them' }) + .option('clean', { type: 'boolean', default: true, desc: 'Skips stack clean up after test is completed (use --no-clean to negate)' }) + .option('verbose', { type: 'boolean', default: false, alias: 'v', desc: 'Verbose logs' }) + .option('dry-run', { type: 'boolean', default: false, desc: 'do not actually deploy the stack. just update the snapshot (not recommended!)' }) + .option('update-on-failed', { type: 'boolean', default: false, desc: 'rerun integration tests and update snapshots for failed tests.' }) + .option('force', { type: 'boolean', default: false, desc: 'Rerun all integration tests even if tests are passing' }) + .option('parallel', { type: 'boolean', default: false, desc: 'run integration tests in parallel' }) + .option('parallel-regions', { type: 'array', desc: 'if --parallel is used then these regions are used to run tests in parallel', nargs: 1, default: [] }) + .options('directory', { type: 'string', default: 'test', desc: 'starting directory to discover integration tests' }) + .argv; + + // Cap to a reasonable top-level limit to prevent thrash on machines with many, many cores. + const maxWorkers = parseInt(process.env.CDK_INTEG_MAX_WORKER_COUNT ?? '16'); + const N = Math.min(maxWorkers, Math.max(1, Math.ceil(os.cpus().length / 2))); + const pool = workerpool.pool(path.join(__dirname, '../lib/workers/extract_worker.js'), { + maxWorkers: N, + }); + + // list of integration tests that will be executed + const testsToRun: IntegTestConfig[] = []; + const testsFromArgs: IntegTestConfig[] = []; + const parallelRegions = arrayFromYargs(argv['parallel-regions']); + const testRegions: string[] = parallelRegions ?? ['us-east-1', 'us-east-2', 'us-west-2']; + const runUpdateOnFailed = argv['update-on-failed'] ?? false; + + + try { + if (argv.list) { + const tests = await new IntegrationTests(argv.directory).fromCliArgs(); + process.stdout.write(tests.map(t => t.fileName).join('\n') + '\n'); + return; + } + + if (argv._.length === 0) { + testsFromArgs.push(...(await new IntegrationTests(argv.directory).fromCliArgs())); + } else { + testsFromArgs.push(...(await new IntegrationTests(argv.directory).fromCliArgs(argv._.map(x => x.toString())))); + } + + // If `--force` is not used then first validate the snapshots and gather + // the failed snapshot tests. If `--force` is used then we will skip snapshot + // tests and run integration tests for all tests + if (!argv.force) { + const failedSnapshots = await runSnapshotTests(pool, testsFromArgs); + testsToRun.push(...failedSnapshots); + } else { + testsToRun.push(...testsFromArgs); + } + + + // run integration tests if `--update-on-failed` OR `--force` is used + if (runUpdateOnFailed || argv.force) { + await runIntegrationTests({ + pool, + tests: testsToRun, + regions: testRegions, + clean: argv.clean, + dryRun: argv['dry-run'], + verbose: argv.verbose, + }); + + if (argv.clean === false) { + logger.warning('Not cleaning up stacks since "--no-clean" was used'); + } + } + + } finally { + void pool.terminate(); + } +} + +/** + * Translate a Yargs input array to something that makes more sense in a programming language + * model (telling the difference between absence and an empty array) + * + * - An empty array is the default case, meaning the user didn't pass any arguments. We return + * undefined. + * - If the user passed a single empty string, they did something like `--array=`, which we'll + * take to mean they passed an empty array. + */ +function arrayFromYargs(xs: string[]): string[] | undefined { + if (xs.length === 0) { return undefined; } + return xs.filter(x => x !== ''); +} + +main().catch(e => { + // eslint-disable-next-line no-console + console.error(e); + process.exit(1); +}); diff --git a/packages/@aws-cdk/integ-runner/jest.config.js b/packages/@aws-cdk/integ-runner/jest.config.js new file mode 100644 index 0000000000000..d052cbb29f05d --- /dev/null +++ b/packages/@aws-cdk/integ-runner/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + ...baseConfig.coverageThreshold.global, + branches: 60, + }, + }, +}; diff --git a/packages/@aws-cdk/integ-runner/lib/runner/integ-tests.ts b/packages/@aws-cdk/integ-runner/lib/runner/integ-tests.ts new file mode 100644 index 0000000000000..0fd648c31c5d1 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/runner/integ-tests.ts @@ -0,0 +1,76 @@ +import * as path from 'path'; +import * as fs from 'fs-extra'; + +/** + * Represents a single integration test + */ +export interface IntegTestConfig { + readonly directory: string; + readonly fileName: string; +} + +/** + * Discover integration tests + */ +export class IntegrationTests { + constructor(private readonly directory: string) { + } + + /** + * Takes an optional list of tests to look for, otherwise + * it will look for all tests from the directory + */ + public async fromCliArgs(tests?: string[]): Promise { + let allTests = await this.discover(); + const all = allTests.map(x => x.fileName); + let foundAll = true; + + if (tests && tests.length > 0) { + // Pare down found tests to filter + allTests = allTests.filter(t => { + const parts = path.parse(t.fileName); + return (tests.includes(t.fileName) || tests.includes(parts.base)); + }); + + const selectedNames = allTests.map(t => path.parse(t.fileName).base); + for (const unmatched of tests.filter(t => !selectedNames.includes(t))) { + process.stderr.write(`No such integ test: ${unmatched}\n`); + foundAll = false; + } + } + + if (!foundAll) { + process.stderr.write(`Available tests: ${all.join(' ')}\n`); + return []; + } + + return allTests; + } + + private async discover(): Promise { + const files = await this.readTree(); + const integs = files.filter(fileName => path.basename(fileName).startsWith('integ.') && path.basename(fileName).endsWith('.js')); + return this.request(integs); + } + + private request(files: string[]): IntegTestConfig[] { + return files.map(fileName => { return { directory: this.directory, fileName }; }); + } + + private async readTree(): Promise { + const ret = new Array(); + + async function recurse(dir: string) { + const files = await fs.readdir(dir); + for (const file of files) { + const fullPath = path.join(dir, file); + const statf = await fs.stat(fullPath); + if (statf.isFile()) { ret.push(fullPath); } + if (statf.isDirectory()) { await recurse(path.join(fullPath)); } + } + } + + await recurse(this.directory); + return ret; + } +} diff --git a/packages/@aws-cdk/integ-runner/lib/runner/private/canonicalize-assets.ts b/packages/@aws-cdk/integ-runner/lib/runner/private/canonicalize-assets.ts new file mode 100644 index 0000000000000..9cee3d4742b3c --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/runner/private/canonicalize-assets.ts @@ -0,0 +1,71 @@ +/** + * Reduce template to a normal form where asset references have been normalized + * + * This makes it possible to compare templates if all that's different between + * them is the hashes of the asset values. + * + * Currently only handles parameterized assets, but can (and should) + * be adapted to handle convention-mode assets as well when we start using + * more of those. + */ +export function canonicalizeTemplate(template: any): any { + // For the weird case where we have an array of templates... + if (Array.isArray(template)) { + return template.map(canonicalizeTemplate); + } + + // Find assets via parameters + const stringSubstitutions = new Array<[RegExp, string]>(); + const paramRe = /^AssetParameters([a-zA-Z0-9]{64})(S3Bucket|S3VersionKey|ArtifactHash)([a-zA-Z0-9]{8})$/; + + const assetsSeen = new Set(); + for (const paramName of Object.keys(template?.Parameters || {})) { + const m = paramRe.exec(paramName); + if (!m) { continue; } + if (assetsSeen.has(m[1])) { continue; } + + assetsSeen.add(m[1]); + const ix = assetsSeen.size; + + // Full parameter reference + stringSubstitutions.push([ + new RegExp(`AssetParameters${m[1]}(S3Bucket|S3VersionKey|ArtifactHash)([a-zA-Z0-9]{8})`), + `Asset${ix}$1`, + ]); + // Substring asset hash reference + stringSubstitutions.push([ + new RegExp(`${m[1]}`), + `Asset${ix}Hash`, + ]); + } + + // Substitute them out + return substitute(template); + + function substitute(what: any): any { + if (Array.isArray(what)) { + return what.map(substitute); + } + + if (typeof what === 'object' && what !== null) { + const ret: any = {}; + for (const [k, v] of Object.entries(what)) { + ret[stringSub(k)] = substitute(v); + } + return ret; + } + + if (typeof what === 'string') { + return stringSub(what); + } + + return what; + } + + function stringSub(x: string) { + for (const [re, replacement] of stringSubstitutions) { + x = x.replace(re, replacement); + } + return x; + } +} diff --git a/packages/@aws-cdk/integ-runner/lib/runner/private/cloud-assembly.ts b/packages/@aws-cdk/integ-runner/lib/runner/private/cloud-assembly.ts new file mode 100644 index 0000000000000..99626ea53bdb2 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/runner/private/cloud-assembly.ts @@ -0,0 +1,66 @@ +import * as path from 'path'; +import { AssemblyManifest, Manifest, ArtifactType, AwsCloudFormationStackProperties } from '@aws-cdk/cloud-assembly-schema'; +import * as fs from 'fs-extra'; + +/** + * Reads a Cloud Assembly manifest + */ +export class AssemblyManifestReader { + public static readonly DEFAULT_FILENAME = 'manifest.json'; + + /** + * Reads a Cloud Assembly manifest from a file + */ + public static fromFile(fileName: string): AssemblyManifestReader { + try { + const obj = Manifest.loadAssemblyManifest(fileName); + return new AssemblyManifestReader(path.dirname(fileName), obj); + + } catch (e) { + throw new Error(`Cannot read integ manifest '${fileName}': ${e.message}`); + } + } + + /** + * Reads a Cloud Assembly manifest from a file or a directory + * If the given filePath is a directory then it will look for + * a file within the directory with the DEFAULT_FILENAME + */ + public static fromPath(filePath: string): AssemblyManifestReader { + let st; + try { + st = fs.statSync(filePath); + } catch (e) { + throw new Error(`Cannot read integ manifest at '${filePath}': ${e.message}`); + } + if (st.isDirectory()) { + return AssemblyManifestReader.fromFile(path.join(filePath, AssemblyManifestReader.DEFAULT_FILENAME)); + } + return AssemblyManifestReader.fromFile(filePath); + } + + /** + * The directory where the manifest was found + */ + public readonly directory: string; + + constructor(directory: string, private readonly manifest: AssemblyManifest) { + this.directory = directory; + } + + /** + * Get the stacks from the manifest + * returns a map of artifactId to CloudFormation template + */ + public get stacks(): Record { + const stacks: Record = {}; + for (const [artifactId, artifact] of Object.entries(this.manifest.artifacts ?? {})) { + if (artifact.type !== ArtifactType.AWS_CLOUDFORMATION_STACK) { continue; } + const props = artifact.properties as AwsCloudFormationStackProperties; + + const template = fs.readJSONSync(path.resolve(this.directory, props.templateFile)); + stacks[artifactId] = template; + } + return stacks; + } +} diff --git a/packages/@aws-cdk/integ-runner/lib/runner/private/integ-manifest.ts b/packages/@aws-cdk/integ-runner/lib/runner/private/integ-manifest.ts new file mode 100644 index 0000000000000..80b567dbb69ce --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/runner/private/integ-manifest.ts @@ -0,0 +1,76 @@ +import * as path from 'path'; +import { IntegManifest, Manifest, TestCase } from '@aws-cdk/cloud-assembly-schema'; +import * as fs from 'fs-extra'; + +/** + * Test case configuration read from the integ manifest + */ +export interface IntegTestConfig { + /** + * Test cases contained in this integration test + */ + readonly testCases: { [testCaseName: string]: TestCase }; + + /** + * Whether to enable lookups for this test + * + * @default false + */ + readonly enableLookups: boolean; +} + +/** + * Reads an integration tests manifest + */ +export class IntegManifestReader { + public static readonly DEFAULT_FILENAME = 'integ.json'; + + /** + * Reads an integration test manifest from the specified file + */ + public static fromFile(fileName: string): IntegManifestReader { + try { + const obj = Manifest.loadIntegManifest(fileName); + return new IntegManifestReader(path.dirname(fileName), obj); + + } catch (e) { + throw new Error(`Cannot read integ manifest '${fileName}': ${e.message}`); + } + } + + /** + * Reads a Integration test manifest from a file or a directory + * If the given filePath is a directory then it will look for + * a file within the directory with the DEFAULT_FILENAME + */ + public static fromPath(filePath: string): IntegManifestReader { + let st; + try { + st = fs.statSync(filePath); + } catch (e) { + throw new Error(`Cannot read integ manifest at '${filePath}': ${e.message}`); + } + if (st.isDirectory()) { + return IntegManifestReader.fromFile(path.join(filePath, IntegManifestReader.DEFAULT_FILENAME)); + } + return IntegManifestReader.fromFile(filePath); + } + + /** + * The directory where the manifest was found + */ + public readonly directory: string; + constructor(directory: string, private readonly manifest: IntegManifest) { + this.directory = directory; + } + + /** + * List of integration tests in the manifest + */ + public get tests(): IntegTestConfig { + return { + testCases: this.manifest.testCases, + enableLookups: this.manifest.enableLookups ?? false, + }; + } +} diff --git a/packages/@aws-cdk/integ-runner/lib/runner/private/logger.ts b/packages/@aws-cdk/integ-runner/lib/runner/private/logger.ts new file mode 100644 index 0000000000000..55c7f80b24365 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/runner/private/logger.ts @@ -0,0 +1,20 @@ +import { Writable } from 'stream'; +import * as util from 'util'; +import * as chalk from 'chalk'; + +type StyleFn = (str: string) => string; +const { stderr } = process; + +const logger = (stream: Writable, styles?: StyleFn[]) => (fmt: string, ...args: any[]) => { + let str = util.format(fmt, ...args); + if (styles && styles.length) { + str = styles.reduce((a, style) => style(a), str); + } + stream.write(str + '\n'); +}; + +export const print = logger(stderr); +export const error = logger(stderr, [chalk.red]); +export const warning = logger(stderr, [chalk.yellow]); +export const success = logger(stderr, [chalk.green]); +export const highlight = logger(stderr, [chalk.bold]); diff --git a/packages/@aws-cdk/integ-runner/lib/runner/runners.ts b/packages/@aws-cdk/integ-runner/lib/runner/runners.ts new file mode 100644 index 0000000000000..747d240c8f04d --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/runner/runners.ts @@ -0,0 +1,606 @@ +import * as path from 'path'; +import { Writable, WritableOptions } from 'stream'; +import { StringDecoder, NodeStringDecoder } from 'string_decoder'; +import { TestCase, RequireApproval, DefaultCdkOptions } from '@aws-cdk/cloud-assembly-schema'; +import { diffTemplate, formatDifferences } from '@aws-cdk/cloudformation-diff'; +import { AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY, FUTURE_FLAGS, TARGET_PARTITIONS } from '@aws-cdk/cx-api'; +import { CdkCliWrapper, ICdk } from 'cdk-cli-wrapper'; +import * as fs from 'fs-extra'; +import { Diagnostic, DiagnosticReason } from '../workers/common'; +import { canonicalizeTemplate } from './private/canonicalize-assets'; +import { AssemblyManifestReader } from './private/cloud-assembly'; +import { IntegManifestReader } from './private/integ-manifest'; + +const CDK_OUTDIR_PREFIX = 'cdk-integ.out'; +const CDK_INTEG_STACK_PRAGMA = '/// !cdk-integ'; +const PRAGMA_PREFIX = 'pragma:'; +const SET_CONTEXT_PRAGMA_PREFIX = 'pragma:set-context:'; +const VERIFY_ASSET_HASHES = 'pragma:include-assets-hashes'; +const ENABLE_LOOKUPS_PRAGMA = 'pragma:enable-lookups'; + +/** + * Options for creating an integration test runner + */ +export interface IntegRunnerOptions { + /** + * The name of the file that contains the integration test + * This should be a JavaScript file + */ + readonly fileName: string, + + /** + * Additional environment variables that will be available + * to the CDK CLI + * + * @default - no additional environment variables + */ + readonly env?: { [name: string]: string }, + + /** + * tmp cdk.out directory + * + * @default - directory will be `cdk-integ.out.${testName}` + */ + readonly integOutDir?: string, + + /** + * Instance of the CDK CLI to use + * + * @default - CdkCliWrapper + */ + readonly cdk?: ICdk; +} + +/** + * Represents an Integration test runner + */ +export abstract class IntegRunner { + /** + * The directory where the snapshot will be stored + */ + public readonly snapshotDir: string; + + /** + * An instance of the CDK CLI + */ + public readonly cdk: ICdk; + + /** + * Pretty name of the test + */ + public readonly testName: string; + + /** + * The path to the integration test file + */ + protected readonly sourceFilePath: string; + + /** + * The value used in the '--app' CLI parameter + */ + protected readonly cdkApp: string; + + /** + * The path where the `cdk.context.json` file + * will be created + */ + protected readonly cdkContextPath: string; + + /** + * The relative path from the cwd to the snapshot directory + */ + protected readonly relativeSnapshotDir: string; + + /** + * The integration tests that this runner will execute + */ + protected _tests?: { [testName: string]: TestCase }; + + /** + * The working directory that the integration tests will be + * executed from + */ + protected readonly directory: string; + + /** + * Default options to pass to the CDK CLI + */ + protected readonly defaultArgs: DefaultCdkOptions = { + pathMetadata: false, + assetMetadata: false, + versionReporting: false, + } + + private _enableLookups?: boolean; + + /** + * The directory where the CDK will be synthed to + */ + protected readonly cdkOutDir: string; + + constructor(options: IntegRunnerOptions) { + const parsed = path.parse(options.fileName); + this.directory = parsed.dir; + this.testName = parsed.name.slice(6); + this.snapshotDir = path.join(this.directory, `${this.testName}.integ.snapshot`); + this.relativeSnapshotDir = `${this.testName}.integ.snapshot`; + this.sourceFilePath = path.join(this.directory, parsed.base); + this.cdkContextPath = path.join(this.directory, 'cdk.context.json'); + this.cdk = options.cdk ?? new CdkCliWrapper({ + directory: this.directory, + env: options.env, + }); + this.cdkOutDir = options.integOutDir ?? `${CDK_OUTDIR_PREFIX}.${this.testName}`; + this.cdkApp = `node ${parsed.base}`; + if (this.hasSnapshot()) { + this.loadManifest(); + } + } + + /** + * Whether or not lookups are enabled for a given test case + */ + protected get enableLookups(): boolean { + return this._enableLookups ?? false; + } + + /** + * Return this list of test cases for this integration test + */ + public get tests(): { [testName: string]: TestCase } | undefined { + return this._tests; + } + + /** + * Returns true if a snapshot already exists for this test + */ + public hasSnapshot(): boolean { + if (fs.existsSync(this.snapshotDir)) { + return true; + } else { + return false; + } + } + + protected loadManifest(dir?: string): void { + try { + const reader = IntegManifestReader.fromPath(dir ?? this.snapshotDir); + this._tests = reader.tests.testCases; + this._enableLookups = reader.tests.enableLookups; + } catch (e) { + this._tests = this.renderTestCasesForLegacyTests(); + this._enableLookups = this.pragmas().includes(ENABLE_LOOKUPS_PRAGMA); + } + } + + protected cleanup(): void { + const cdkOutPath = path.join(this.directory, this.cdkOutDir); + if (fs.existsSync(cdkOutPath)) { + fs.removeSync(cdkOutPath); + } + } + + protected createSnapshot(): void { + if (fs.existsSync(this.snapshotDir)) { + fs.removeSync(this.snapshotDir); + } + + // if lookups are enabled then we need to synth again + // using dummy context and save that as the snapshot + if (this.enableLookups) { + this.writeContext(); + this.cdk.synth({ + ...this.defaultArgs, + all: true, + app: this.cdkApp, + output: this.relativeSnapshotDir, + // TODO: figure out if we need this... + // env: { + // ...DEFAULT_SYNTH_OPTIONS.env, + // }, + }); + this.cleanupContextFile(); + } else { + fs.moveSync(path.join(this.directory, this.cdkOutDir), this.snapshotDir, { overwrite: true }); + } + } + + /** + * Returns the single test stack to use. + * + * If the test has a single stack, it will be chosen. Otherwise a pragma is expected within the + * test file the name of the stack: + * + * @example + * + * /// !cdk-integ + * + */ + private renderTestCasesForLegacyTests(): { [testName: string]: TestCase } { + const tests: TestCase = { + stacks: [], + }; + const pragma = this.readStackPragma(); + if (pragma.length > 0) { + tests.stacks.push(...pragma); + } else { + const stacks = (this.cdk.list({ + ...this.defaultArgs, + all: true, + app: this.cdkApp, + output: this.cdkOutDir, + })).split('\n'); + if (stacks.length !== 1) { + throw new Error('"cdk-integ" can only operate on apps with a single stack.\n\n' + + ' If your app has multiple stacks, specify which stack to select by adding this to your test source:\n\n' + + ` ${CDK_INTEG_STACK_PRAGMA} STACK ...\n\n` + + ` Available stacks: ${stacks.join(' ')} (wildcards are also supported)\n`); + } + tests.stacks.push(...stacks); + } + + return { + [this.testName]: tests, + }; + } + + /** + * Reads stack names from the "!cdk-integ" pragma. + * + * Every word that's NOT prefixed by "pragma:" is considered a stack name. + * + * @example + * + * /// !cdk-integ + */ + private readStackPragma(): string[] { + return (this.readIntegPragma()).filter(p => !p.startsWith(PRAGMA_PREFIX)); + } + + /** + * Read arbitrary cdk-integ pragma directives + * + * Reads the test source file and looks for the "!cdk-integ" pragma. If it exists, returns it's + * contents. This allows integ tests to supply custom command line arguments to "cdk deploy" and "cdk synth". + * + * @example + * + * /// !cdk-integ [...] + */ + private readIntegPragma(): string[] { + const source = fs.readFileSync(this.sourceFilePath, { encoding: 'utf-8' }); + const pragmaLine = source.split('\n').find(x => x.startsWith(CDK_INTEG_STACK_PRAGMA + ' ')); + if (!pragmaLine) { + return []; + } + + const args = pragmaLine.substring(CDK_INTEG_STACK_PRAGMA.length).trim().split(' '); + if (args.length === 0) { + throw new Error(`Invalid syntax for cdk-integ pragma. Usage: "${CDK_INTEG_STACK_PRAGMA} [STACK] [pragma:PRAGMA] [...]"`); + } + return args; + } + + /** + * Return the non-stack pragmas + * + * These are all pragmas that start with "pragma:". + * + * For backwards compatibility reasons, all pragmas that DON'T start with this + * string are considered to be stack names. + */ + protected pragmas(): string[] { + return (this.readIntegPragma()).filter(p => p.startsWith(PRAGMA_PREFIX)); + } + + /** + * There is not currently a way to pass structured context to the CLI + * so to workaround this we write the context to a file + */ + protected writeContext(additionalContext?: Record): void { + const ctxPragmaContext: Record = {}; + + // apply context from set-context pragma + // usage: pragma:set-context:key=value + const ctxPragmas = (this.pragmas()).filter(p => p.startsWith(SET_CONTEXT_PRAGMA_PREFIX)); + for (const p of ctxPragmas) { + const instruction = p.substring(SET_CONTEXT_PRAGMA_PREFIX.length); + const [key, value] = instruction.split('='); + if (key == null || value == null) { + throw new Error(`invalid "set-context" pragma syntax. example: "pragma:set-context:@aws-cdk/core:newStyleStackSynthesis=true" got: ${p}`); + } + + ctxPragmaContext[key] = value; + } + const context: Record = { + ...DEFAULT_SYNTH_OPTIONS.context, + ...ctxPragmaContext, + ...additionalContext, + }; + fs.writeFileSync(this.cdkContextPath, JSON.stringify(context, undefined, 2), { encoding: 'utf-8' }); + } + + protected cleanupContextFile() { + if (fs.existsSync(this.cdkContextPath)) { + fs.unlinkSync(this.cdkContextPath); + } + } +} + +/** + * Options for the integration test runner + */ +export interface IntegTestRunOptions { + /** + * The test case to execute + */ + readonly testCase: TestCase; + + /** + * Whether or not to run `cdk destroy` and cleanup the + * integration test stacks. + * + * Set this to false if you need to perform any validation + * or troubleshooting after deployment. + * + * @default true + */ + readonly clean?: boolean; + + /** + * If set to true, the integration test will not deploy + * anything and will simply update the snapshot. + * + * You should NOT use this method since you are essentially + * bypassing the integration test. + * + * @default false + */ + readonly dryRun?: boolean; +} + +/** + * An integration test runner that orchestrates executing + * integration tests + */ +export class IntegTestRunner extends IntegRunner { + constructor(options: IntegRunnerOptions) { + super(options); + } + + /** + * Orchestrates running integration tests. Currently this includes + * + * 1. Deploying the integration test stacks + * 2. Saving the snapshot + * 3. Destroying the integration test stacks + */ + public runIntegTestCase(options: IntegTestRunOptions): void { + const clean = options.clean ?? true; + try { + if (!options.dryRun) { + this.cdk.deploy({ + ...this.defaultArgs, + stacks: options.testCase.stacks, + requireApproval: RequireApproval.NEVER, + output: this.cdkOutDir, + app: this.cdkApp, + lookups: this.enableLookups, + }); + } else { + this.cdk.synth({ + ...this.defaultArgs, + stacks: options.testCase.stacks, + output: this.cdkOutDir, + app: this.cdkApp, + lookups: this.enableLookups, + }); + } + this.createSnapshot(); + } catch (e) { + throw e; + } finally { + if (!options.dryRun) { + if (clean) { + this.cdk.destroy({ + ...this.defaultArgs, + stacks: options.testCase.stacks, + force: true, + app: this.cdkApp, + output: this.cdkOutDir, + }); + } + } + this.cleanup(); + } + } + + /** + * Generate a snapshot if one does not exist + * This will synth and then load the integration test manifest + */ + public generateSnapshot(): void { + if (this.hasSnapshot()) { + throw new Error(`${this.testName} already has a snapshot: ${this.snapshotDir}`); + } + + this.cdk.synth({ + ...this.defaultArgs, + all: true, + app: this.cdkApp, + output: this.cdkOutDir, + }); + this.loadManifest(this.cdkOutDir); + } +} + +/** + * Runner for snapshot tests. This handles orchestrating + * the validation of the integration test snapshots + */ +export class IntegSnapshotRunner extends IntegRunner { + constructor(options: IntegRunnerOptions) { + super(options); + } + + /** + * Synth the integration tests and compare the templates + * to the existing snapshot. + */ + public testSnapshot(): Diagnostic[] { + try { + // read the existing snapshot + const expectedStacks = this.readAssembly(this.snapshotDir); + + // if lookups are enabled then write the dummy context file + if (this.enableLookups) { + this.writeContext(); + } + // synth the integration test + this.cdk.synth({ + ...this.defaultArgs, + all: true, + app: this.cdkApp, + output: this.cdkOutDir, + lookups: this.enableLookups, + }); + const actualStacks = this.readAssembly(path.join(this.directory, this.cdkOutDir)); + + // diff the existing snapshot (expected) with the integration test (actual) + const diagnostics = this.diffAssembly(expectedStacks, actualStacks); + return diagnostics; + } catch (e) { + throw e; + } finally { + this.cleanupContextFile(); + this.cleanup(); + } + } + + private diffAssembly(existing: Record, actual: Record): Diagnostic[] { + const verifyHashes = this.pragmas().includes(VERIFY_ASSET_HASHES); + const failures: Diagnostic[] = []; + for (const templateId of Object.keys(existing)) { + if (!actual.hasOwnProperty(templateId)) { + failures.push({ + testName: this.testName, + reason: DiagnosticReason.SNAPSHOT_FAILED, + message: `${templateId} exists in snapshot, but not in actual`, + }); + } + } + + for (const templateId of Object.keys(actual)) { + if (!existing.hasOwnProperty(templateId)) { + failures.push({ + testName: this.testName, + reason: DiagnosticReason.SNAPSHOT_FAILED, + message: `${templateId} does not exist in snapshot, but does in actual`, + }); + } else { + let actualTemplate = actual[templateId]; + let expectedTemplate = existing[templateId]; + + if (!verifyHashes) { + actualTemplate = canonicalizeTemplate(actualTemplate); + expectedTemplate = canonicalizeTemplate(expectedTemplate); + } + const diff = diffTemplate(expectedTemplate, actualTemplate); + if (!diff.isEmpty) { + const writable = new StringWritable({}); + formatDifferences(writable, diff); + failures.push({ + reason: DiagnosticReason.SNAPSHOT_FAILED, + message: writable.data, + testName: this.testName, + }); + } + } + } + + return failures; + } + + private readAssembly(dir: string): Record { + const assembly = AssemblyManifestReader.fromPath(dir); + const stacks = assembly.stacks; + + return stacks; + } +} + +class StringWritable extends Writable { + public data: string; + private _decoder: NodeStringDecoder; + constructor(options: WritableOptions) { + super(options); + this._decoder = new StringDecoder(); + this.data = ''; + } + + _write(chunk: any, encoding: string, callback: (error?: Error | null) => void): void { + if (encoding === 'buffer') { + chunk = this._decoder.write(chunk); + } + + this.data += chunk; + callback(); + } + + _final(callback: (error?: Error | null) => void): void { + this.data += this._decoder.end(); + callback(); + } +} + +// Default context we run all integ tests with, so they don't depend on the +// account of the exercising user. +const DEFAULT_SYNTH_OPTIONS = { + context: { + [AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY]: ['test-region-1a', 'test-region-1b', 'test-region-1c'], + 'availability-zones:account=12345678:region=test-region': ['test-region-1a', 'test-region-1b', 'test-region-1c'], + 'ssm:account=12345678:parameterName=/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2:region=test-region': 'ami-1234', + 'ssm:account=12345678:parameterName=/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2:region=test-region': 'ami-1234', + 'ssm:account=12345678:parameterName=/aws/service/ecs/optimized-ami/amazon-linux/recommended:region=test-region': '{"image_id": "ami-1234"}', + // eslint-disable-next-line max-len + 'ami:account=12345678:filters.image-type.0=machine:filters.name.0=amzn-ami-vpc-nat-*:filters.state.0=available:owners.0=amazon:region=test-region': 'ami-1234', + 'vpc-provider:account=12345678:filter.isDefault=true:region=test-region:returnAsymmetricSubnets=true': { + vpcId: 'vpc-60900905', + subnetGroups: [ + { + type: 'Public', + name: 'Public', + subnets: [ + { + subnetId: 'subnet-e19455ca', + availabilityZone: 'us-east-1a', + routeTableId: 'rtb-e19455ca', + }, + { + subnetId: 'subnet-e0c24797', + availabilityZone: 'us-east-1b', + routeTableId: 'rtb-e0c24797', + }, + { + subnetId: 'subnet-ccd77395', + availabilityZone: 'us-east-1c', + routeTableId: 'rtb-ccd77395', + }, + ], + }, + ], + }, + // Enable feature flags for all integ tests + ...FUTURE_FLAGS, + + // Restricting to these target partitions makes most service principals synthesize to + // `service.${URL_SUFFIX}`, which is technically *incorrect* (it's only `amazonaws.com` + // or `amazonaws.com.cn`, never UrlSuffix for any of the restricted regions) but it's what + // most existing integ tests contain, and we want to disturb as few as possible. + [TARGET_PARTITIONS]: ['aws', 'aws-cn'], + }, + env: { + CDK_INTEG_ACCOUNT: '12345678', + CDK_INTEG_REGION: 'test-region', + }, +}; diff --git a/packages/@aws-cdk/integ-runner/lib/workers/common.ts b/packages/@aws-cdk/integ-runner/lib/workers/common.ts new file mode 100644 index 0000000000000..db196cc809937 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/workers/common.ts @@ -0,0 +1,119 @@ +import { IntegTestConfig } from '../runner/integ-tests'; +import * as logger from '../runner/private/logger'; + +/** + * Integration test results + */ +export interface IntegBatchResponse { + failedTests: IntegTestConfig[]; +} + +/** + * Common options for running integration tests + */ +export interface IntegTestOptions { + /** + * A list of integration tests to run + * in this batch + */ + readonly tests: IntegTestConfig[]; + + /** + * Whether or not to destroy the stacks at the + * end of the test + * + * @default true + */ + readonly clean?: boolean; + + /** + * When this is set to `true` the snapshot will + * be created _without_ running the integration test + * The resulting snapshot SHOULD NOT be checked in + * + * @default false + */ + readonly dryRun?: boolean; + + /** + * Whether to enable verbose logging + * + * @default false + */ + readonly verbose?: boolean; +} + +/** + * Represents possible reasons for a diagnostic + */ +export enum DiagnosticReason { + /** + * The integration test failed because there + * is not existing snapshot + */ + NO_SNAPSHOT = 'NO_SNAPSHOT', + + /** + * The integration test failed + */ + TEST_FAILED = 'TEST_FAILED', + + /** + * The snapshot test failed because the actual + * snapshot was different than the expected snapshot + */ + SNAPSHOT_FAILED = 'SNAPSHOT_FAILED', + + /** + * The snapshot test succeeded + */ + SNAPSHOT_SUCCESS = 'SNAPSHOT_SUCCESS', + + /** + * The integration test succeeded + */ + TEST_SUCCESS = 'TEST_SUCCESS', +} + +/** + * Integration test diagnostics + * This is used to report back the status of each test + */ +export interface Diagnostic { + /** + * The name of the test + */ + readonly testName: string; + + /** + * The diagnostic message + */ + readonly message: string; + + /** + * The reason for the diagnostic + */ + readonly reason: DiagnosticReason; +} + +/** + * Print out the results from tests + */ +export function printResults(diagnostic: Diagnostic): void { + switch (diagnostic.reason) { + case DiagnosticReason.SNAPSHOT_SUCCESS: + logger.success(' %s No Change!', diagnostic.testName); + break; + case DiagnosticReason.TEST_SUCCESS: + logger.success(' %s Test Succeeded!', diagnostic.testName); + break; + case DiagnosticReason.NO_SNAPSHOT: + logger.error(' %s - No Snapshot!', diagnostic.testName); + break; + case DiagnosticReason.SNAPSHOT_FAILED: + logger.error(' %s - Snapshot changed!\n%s', diagnostic.testName, diagnostic.message); + break; + case DiagnosticReason.TEST_FAILED: + logger.error(' %s - Failed!\n%s', diagnostic.testName, diagnostic.message); + } +} diff --git a/packages/@aws-cdk/integ-runner/lib/workers/extract_worker.ts b/packages/@aws-cdk/integ-runner/lib/workers/extract_worker.ts new file mode 100644 index 0000000000000..42b0e63b1f9af --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/workers/extract_worker.ts @@ -0,0 +1,35 @@ +import * as workerpool from 'workerpool'; +import { IntegTestConfig } from '../runner/integ-tests'; +import { Diagnostic, IntegBatchResponse } from './common'; +import { singleThreadedSnapshotRunner } from './integ-snapshot-worker'; +import { singleThreadedTestRunner, IntegTestBatchRequest } from './integ-test-worker'; + +/** + * Options for running snapshot tests + */ +export interface SnapshotBatchRequest { + readonly tests: IntegTestConfig[]; +} + +/** + * Snapshot test results + */ +export interface SnapshotBatchResponse { + diagnostics: Diagnostic[]; + failedTests: IntegTestConfig[]; +} + +function integTestBatch(request: IntegTestBatchRequest): IntegBatchResponse { + const result = singleThreadedTestRunner(request); + return result; +} + +function snapshotTestBatch(request: SnapshotBatchRequest): IntegBatchResponse { + const result = singleThreadedSnapshotRunner(request.tests); + return result; +} + +workerpool.worker({ + snapshotTestBatch, + integTestBatch, +}); diff --git a/packages/@aws-cdk/integ-runner/lib/workers/integ-snapshot-worker.ts b/packages/@aws-cdk/integ-runner/lib/workers/integ-snapshot-worker.ts new file mode 100644 index 0000000000000..f92efe543746a --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/workers/integ-snapshot-worker.ts @@ -0,0 +1,51 @@ +import * as workerpool from 'workerpool'; +import { IntegTestConfig } from '../runner/integ-tests'; +import { IntegSnapshotRunner } from '../runner/runners'; +import { DiagnosticReason, IntegBatchResponse } from './common'; + +/** + * Runs a single snapshot test batch request. + * For each integration test this will check to see + * if there is an existing snapshot, and if there is will + * check if there are any changes + */ +export function singleThreadedSnapshotRunner(tests: IntegTestConfig[]): IntegBatchResponse { + const failedTests = new Array(); + for (const test of tests) { + const runner = new IntegSnapshotRunner({ fileName: test.fileName }); + try { + if (!runner.hasSnapshot()) { + workerpool.workerEmit({ + reason: DiagnosticReason.NO_SNAPSHOT, + testName: runner.testName, + message: 'No Snapshot', + }); + failedTests.push(test); + } else { + const snapshotDiagnostics = runner.testSnapshot(); + if (snapshotDiagnostics.length > 0) { + snapshotDiagnostics.forEach(diagnostic => workerpool.workerEmit(diagnostic)); + failedTests.push(test); + } else { + workerpool.workerEmit({ + reason: DiagnosticReason.SNAPSHOT_SUCCESS, + testName: runner.testName, + message: 'Success', + }); + } + } + } catch (e) { + failedTests.push(test); + workerpool.workerEmit({ + message: e.message, + testName: runner.testName, + reason: DiagnosticReason.SNAPSHOT_FAILED, + }); + } + } + + return { + failedTests, + }; +} + diff --git a/packages/@aws-cdk/integ-runner/lib/workers/integ-test-worker.ts b/packages/@aws-cdk/integ-runner/lib/workers/integ-test-worker.ts new file mode 100644 index 0000000000000..def9915d91c35 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/workers/integ-test-worker.ts @@ -0,0 +1,124 @@ +import * as workerpool from 'workerpool'; +import { IntegTestConfig } from '../runner/integ-tests'; +import * as logger from '../runner/private/logger'; +import { IntegTestRunner } from '../runner/runners'; +import { printResults, IntegBatchResponse, IntegTestOptions, DiagnosticReason } from './common'; + +/** + * Options for an integration test batch + */ +export interface IntegTestBatchRequest extends IntegTestOptions { + /** + * The AWS region to run this batch in + */ + readonly region: string; +} + +/** + * Options for running all integration tests + */ +export interface IntegTestRunOptions extends IntegTestOptions { + /** + * The regions to run the integration tests across. + * This allows the runner to run integration tests in parallel + */ + readonly regions: string[]; + + /** + * The workerpool to use + */ + readonly pool: workerpool.WorkerPool; +} + + +/** + * Runs a set of integration tests in parallel across a list of AWS regions. + * Only a single test can be run at a time in a given region. Once a region + * is done running a test, the next test will be pulled from the queue + */ +export async function runIntegrationTestsInParallel( + options: IntegTestRunOptions, +): Promise { + + const queue = options.tests; + const results: IntegBatchResponse[] = []; + + async function runTest(region: string): Promise { + do { + const test = queue.pop(); + if (!test) break; + logger.highlight(`Running test ${test.fileName} in ${region}`); + const response: IntegBatchResponse = await options.pool.exec('integTestBatch', [{ + region, + tests: [test], + clean: options.clean, + dryRun: options.dryRun, + verbose: options.verbose, + }], { + on: printResults, + }); + + results.push(response); + } while (queue.length > 0); + } + + const workers = options.regions.map((region) => runTest(region)); + await Promise.all(workers); + return results; +} + +/** + * Runs a single integration test batch request. + * If the test does not have an existing snapshot, + * this will first generate a snapshot and then execute + * the integration tests. + * + * If the tests succeed it will then save the snapshot + */ +export function singleThreadedTestRunner(request: IntegTestBatchRequest): IntegBatchResponse { + const failures: IntegTestConfig[] = []; + for (const test of request.tests) { + const runner = new IntegTestRunner({ + fileName: test.fileName, + env: { + AWS_REGION: request.region, + }, + }); + try { + if (!runner.hasSnapshot()) { + runner.generateSnapshot(); + } + + if (!runner.tests) { + throw new Error(`No tests defined for ${runner.testName}`); + } + for (const [testName, testCase] of Object.entries(runner.tests)) { + try { + runner.runIntegTestCase({ + testCase: testCase, + clean: request.clean, + dryRun: request.dryRun, + }); + workerpool.workerEmit({ + reason: DiagnosticReason.TEST_SUCCESS, + testName: testName, + message: 'Success', + }); + } catch (e) { + failures.push(test); + workerpool.workerEmit({ + reason: DiagnosticReason.TEST_FAILED, + testName: testName, + message: `Integration test failed: ${e}`, + }); + } + } + } catch (e) { + logger.error(`Errors running test cases: ${e}`); + } + } + + return { + failedTests: failures, + }; +} diff --git a/packages/@aws-cdk/integ-runner/package.json b/packages/@aws-cdk/integ-runner/package.json new file mode 100644 index 0000000000000..af90b78aef132 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/package.json @@ -0,0 +1,79 @@ +{ + "name": "@aws-cdk/integ-runner", + "description": "CDK Integration Testing Tool", + "version": "0.0.0", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "bin": { + "integ-runner": "bin/integ-runner" + }, + "scripts": { + "build": "cdk-build", + "lint": "cdk-lint", + "package": "cdk-package", + "awslint": "cdk-awslint", + "pkglint": "pkglint -f", + "test": "cdk-test", + "watch": "cdk-watch", + "build+test": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "build+extract": "yarn build", + "build+test+extract": "yarn build+test" + }, + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/fs-extra": "^8.1.2", + "@types/jest": "^27.4.1", + "@types/node": "^10.17.60", + "@types/workerpool": "^6.1.0", + "@types/yargs": "^15.0.14", + "jest": "^27.5.1" + }, + "dependencies": { + "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/cloudformation-diff": "0.0.0", + "@aws-cdk/cx-api": "0.0.0", + "aws-cdk": "0.0.0", + "cdk-cli-wrapper": "0.0.0", + "chalk": "^4", + "fs-extra": "^9.1.0", + "workerpool": "^6.2.0", + "yargs": "^16.2.0" + }, + "repository": { + "url": "https://github.com/aws/aws-cdk.git", + "type": "git", + "directory": "packages/@aws-cdk/integ-runner" + }, + "keywords": [ + "aws", + "cdk" + ], + "homepage": "https://github.com/aws/aws-cdk", + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "cdk-package": { + "shrinkWrap": true + }, + "nozem": { + "ostools": [ + "unzip", + "diff", + "rm" + ] + }, + "stability": "experimental", + "maturity": "experimental", + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/integ-runner/test/runner/integration-tests.test.ts b/packages/@aws-cdk/integ-runner/test/runner/integration-tests.test.ts new file mode 100644 index 0000000000000..878f5bf5d2489 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/runner/integration-tests.test.ts @@ -0,0 +1,15 @@ +import * as path from 'path'; +import { IntegrationTests } from '../../lib/runner/integ-tests'; + +const directory = path.join(__dirname, '../test-data'); + +describe('IntegrationTests', () => { + test('from cli args', async () => { + const tests = new IntegrationTests(directory); + + const integTests = await tests.fromCliArgs(['integ.integ-test1.js']); + + expect(integTests.length).toEqual(1); + expect(integTests[0].fileName).toEqual(expect.stringMatching(/integ.integ-test1.js$/)); + }); +}); diff --git a/packages/@aws-cdk/integ-runner/test/runner/runners.test.ts b/packages/@aws-cdk/integ-runner/test/runner/runners.test.ts new file mode 100644 index 0000000000000..8894f5ba92843 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/runner/runners.test.ts @@ -0,0 +1,324 @@ +import * as path from 'path'; +import * as fs from 'fs-extra'; +import { IntegTestRunner, IntegSnapshotRunner } from '../../lib/runner/runners'; +import { DiagnosticReason } from '../../lib/workers/common'; + +describe('IntegTest runSnapshotTests', () => { + let synthMock: jest.SpyInstance; + beforeEach(() => { + jest.spyOn(process.stderr, 'write').mockImplementation(() => { return true; }); + jest.spyOn(process.stdout, 'write').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'moveSync').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'removeSync').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'writeFileSync').mockImplementation(() => { return true; }); + }); + afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + jest.restoreAllMocks(); + }); + test('with defaults no diff', () => { + // WHEN + const integTest = new IntegSnapshotRunner({ + fileName: path.join(__dirname, '../test-data/integ.test-with-snapshot.js'), + integOutDir: 'test-with-snapshot.integ.snapshot', + }); + synthMock = jest.spyOn(integTest.cdk, 'synth').mockImplementation(); + integTest.testSnapshot(); + + // THEN + expect(synthMock).toHaveBeenCalledTimes(1); + expect(synthMock.mock.calls[0][0]).toEqual({ + all: true, + app: 'node integ.test-with-snapshot.js', + output: 'test-with-snapshot.integ.snapshot', + pathMetadata: false, + assetMetadata: false, + versionReporting: false, + lookups: false, + }); + }); + + test('with defaults and diff', () => { + // WHEN + const integTest = new IntegSnapshotRunner({ + fileName: path.join(__dirname, '../test-data/integ.test-with-snapshot.js'), + integOutDir: 'test-with-snapshot-diff.integ.snapshot', + }); + synthMock = jest.spyOn(integTest.cdk, 'synth').mockImplementation(); + const diagnostics = integTest.testSnapshot(); + + // THEN + expect(synthMock).toHaveBeenCalledTimes(1); + expect(synthMock.mock.calls[0][0]).toEqual({ + all: true, + app: 'node integ.test-with-snapshot.js', + output: 'test-with-snapshot-diff.integ.snapshot', + pathMetadata: false, + assetMetadata: false, + versionReporting: false, + lookups: false, + }); + expect(diagnostics).toEqual(expect.arrayContaining([expect.objectContaining({ + reason: DiagnosticReason.SNAPSHOT_FAILED, + testName: integTest.testName, + message: expect.stringContaining('foobar'), + })])); + }); + + test('dont diff asset hashes', () => { + // WHEN + const integTest = new IntegSnapshotRunner({ + fileName: path.join(__dirname, '../test-data/integ.test-with-snapshot-assets-diff.js'), + integOutDir: 'test-with-snapshot-assets.integ.snapshot', + }); + synthMock = jest.spyOn(integTest.cdk, 'synth').mockImplementation(); + expect(() => { + integTest.testSnapshot(); + }).not.toThrow(); + + // THEN + expect(synthMock).toHaveBeenCalledTimes(1); + expect(synthMock.mock.calls[0][0]).toEqual({ + all: true, + app: 'node integ.test-with-snapshot-assets-diff.js', + output: 'test-with-snapshot-assets.integ.snapshot', + pathMetadata: false, + assetMetadata: false, + versionReporting: false, + lookups: true, + }); + }); + + test('diff asset hashes', () => { + // WHEN + const integTest = new IntegSnapshotRunner({ + fileName: path.join(__dirname, '../test-data/integ.test-with-snapshot-assets.js'), + integOutDir: 'test-with-snapshot-assets-diff.integ.snapshot', + }); + synthMock = jest.spyOn(integTest.cdk, 'synth').mockImplementation(); + const diagnostics = integTest.testSnapshot(); + + // THEN + expect(synthMock).toHaveBeenCalledTimes(1); + expect(synthMock.mock.calls[0][0]).toEqual({ + all: true, + app: 'node integ.test-with-snapshot-assets.js', + output: 'test-with-snapshot-assets-diff.integ.snapshot', + pathMetadata: false, + assetMetadata: false, + versionReporting: false, + lookups: false, + }); + expect(diagnostics).toEqual(expect.arrayContaining([expect.objectContaining({ + reason: DiagnosticReason.SNAPSHOT_FAILED, + testName: integTest.testName, + message: expect.stringContaining('Parameters'), + })])); + }); +}); + +describe('IntegTest runIntegTests', () => { + let integTest: IntegTestRunner; + let deployMock: jest.SpyInstance; + let destroyMock: jest.SpyInstance; + let synthMock: jest.SpyInstance; + let listMock: jest.SpyInstance; + // let stderrMock: jest.SpyInstance; + beforeEach(() => { + integTest = new IntegTestRunner({ fileName: path.join(__dirname, '../test-data/integ.integ-test1.js') }); + deployMock = jest.spyOn(integTest.cdk, 'deploy').mockImplementation(); + destroyMock = jest.spyOn(integTest.cdk, 'destroy').mockImplementation(); + synthMock = jest.spyOn(integTest.cdk, 'synth').mockImplementation(); + listMock = jest.spyOn(integTest.cdk, 'list').mockImplementation(); + jest.spyOn(process.stderr, 'write').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'moveSync').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'removeSync').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'writeFileSync').mockImplementation(() => { return true; }); + }); + afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + jest.restoreAllMocks(); + }); + test('with defaults', () => { + // WHEN + integTest.runIntegTestCase({ + testCase: { + stacks: ['stack1'], + }, + }); + + // THEN + expect(deployMock).toHaveBeenCalledTimes(1); + expect(destroyMock).toHaveBeenCalledTimes(1); + expect(synthMock).toHaveBeenCalledTimes(0); + expect(deployMock.mock.calls[0][0]).toEqual({ + app: 'node integ.integ-test1.js', + requireApproval: 'never', + pathMetadata: false, + assetMetadata: false, + versionReporting: false, + lookups: false, + stacks: ['stack1'], + output: 'cdk-integ.out.integ-test1', + }); + expect(destroyMock.mock.calls[0][0]).toEqual({ + app: 'node integ.integ-test1.js', + pathMetadata: false, + assetMetadata: false, + versionReporting: false, + force: true, + stacks: ['stack1'], + output: 'cdk-integ.out.integ-test1', + }); + }); + + test('with lookups', () => { + // WHEN + integTest = new IntegTestRunner({ fileName: path.join(__dirname, '../test-data/integ.test-with-snapshot-assets-diff.js') }); + deployMock = jest.spyOn(integTest.cdk, 'deploy').mockImplementation(); + destroyMock = jest.spyOn(integTest.cdk, 'destroy').mockImplementation(); + synthMock = jest.spyOn(integTest.cdk, 'synth').mockImplementation(); + listMock = jest.spyOn(integTest.cdk, 'list').mockImplementation(); + integTest.runIntegTestCase({ + testCase: { + stacks: ['test-stack'], + }, + }); + + // THEN + expect(deployMock).toHaveBeenCalledTimes(1); + expect(destroyMock).toHaveBeenCalledTimes(1); + expect(synthMock).toHaveBeenCalledTimes(1); + expect(deployMock.mock.calls[0][0]).toEqual({ + app: 'node integ.test-with-snapshot-assets-diff.js', + requireApproval: 'never', + pathMetadata: false, + assetMetadata: false, + versionReporting: false, + lookups: true, + stacks: ['test-stack'], + output: 'cdk-integ.out.test-with-snapshot-assets-diff', + }); + expect(synthMock.mock.calls[0][0]).toEqual({ + app: 'node integ.test-with-snapshot-assets-diff.js', + pathMetadata: false, + assetMetadata: false, + versionReporting: false, + all: true, + output: 'test-with-snapshot-assets-diff.integ.snapshot', + }); + expect(destroyMock.mock.calls[0][0]).toEqual({ + app: 'node integ.test-with-snapshot-assets-diff.js', + pathMetadata: false, + assetMetadata: false, + versionReporting: false, + force: true, + stacks: ['test-stack'], + output: 'cdk-integ.out.test-with-snapshot-assets-diff', + }); + }); + + test('no clean', () => { + // WHEN + integTest.runIntegTestCase({ + clean: false, + testCase: { + stacks: ['stack1'], + }, + }); + + // THEN + expect(deployMock).toHaveBeenCalledTimes(1); + expect(destroyMock).toHaveBeenCalledTimes(0); + expect(synthMock).toHaveBeenCalledTimes(0); + }); + + test('dryrun', () => { + // WHEN + integTest.runIntegTestCase({ + dryRun: true, + testCase: { + stacks: ['stack1'], + }, + }); + + // THEN + expect(deployMock).toHaveBeenCalledTimes(0); + expect(destroyMock).toHaveBeenCalledTimes(0); + expect(synthMock).toHaveBeenCalledTimes(1); + }); + + test('determine test stack via pragma', () => { + // WHEN + integTest.generateSnapshot(); + + // THEN + expect(integTest.tests).toEqual(expect.objectContaining({ + 'integ-test1': { + stacks: ['stack1'], + }, + })); + expect(listMock).toHaveBeenCalledTimes(0); + }); + + test('generate snapshot', () => { + // WHEN + integTest.generateSnapshot(); + + // THEN + expect(synthMock).toHaveBeenCalledTimes(1); + expect(synthMock.mock.calls[0][0]).toEqual({ + all: true, + pathMetadata: false, + assetMetadata: false, + versionReporting: false, + app: 'node integ.integ-test1.js', + output: 'cdk-integ.out.integ-test1', + }); + }); +}); + +describe('IntegTest no pragma', () => { + let integTest: IntegTestRunner; + let synthMock: jest.SpyInstance; + beforeEach(() => { + integTest = new IntegTestRunner({ fileName: path.join(__dirname, '../test-data/integ.integ-test2.js') }); + jest.spyOn(integTest.cdk, 'deploy').mockImplementation(); + jest.spyOn(integTest.cdk, 'destroy').mockImplementation(); + synthMock = jest.spyOn(integTest.cdk, 'synth').mockImplementation(); + jest.spyOn(integTest.cdk, 'list').mockImplementation(() => { + return 'stackabc'; + }); + jest.spyOn(process.stderr, 'write').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'moveSync').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'removeSync').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'writeFileSync').mockImplementation(() => { return true; }); + }); + afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + jest.restoreAllMocks(); + }); + test('get stacks from list', async () => { + // WHEN + integTest.generateSnapshot(); + + // THEN + expect(integTest.tests).toEqual(expect.objectContaining({ + 'integ-test2': { + stacks: ['stackabc'], + }, + })); + expect(synthMock).toHaveBeenCalledTimes(1); + expect(synthMock.mock.calls[0][0]).toEqual({ + app: 'node integ.integ-test2.js', + all: true, + pathMetadata: false, + assetMetadata: false, + versionReporting: false, + output: 'cdk-integ.out.integ-test2', + }); + }); +}); diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/cdk.out new file mode 100644 index 0000000000000..2efc89439fab8 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/cdk.out @@ -0,0 +1 @@ +{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/manifest.json new file mode 100644 index 0000000000000..c0da3afe14484 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/manifest.json @@ -0,0 +1,57 @@ +{ + "version": "17.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B", + "trace": [ + "new Role (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-iam/lib/role.js:50:22)", + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:82:35)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ], + "/test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E", + "trace": [ + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:154:26)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ] + }, + "displayName": "test-stack" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/test-stack.template.json new file mode 100644 index 0000000000000..40f4c8238c04f --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/test-stack.template.json @@ -0,0 +1,54 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "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" + ] + ] + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/tree.json new file mode 100644 index 0000000000000..b664bec74b37c --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/tree.json @@ -0,0 +1,114 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "@aws-cdk/core.Construct", + "version": "0.0.0" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction1": { + "id": "MyFunction1", + "path": "test-stack/MyFunction1", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction1/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "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" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/cdk.out new file mode 100644 index 0000000000000..2efc89439fab8 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/cdk.out @@ -0,0 +1 @@ +{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/manifest.json new file mode 100644 index 0000000000000..c0da3afe14484 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/manifest.json @@ -0,0 +1,57 @@ +{ + "version": "17.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B", + "trace": [ + "new Role (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-iam/lib/role.js:50:22)", + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:82:35)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ], + "/test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E", + "trace": [ + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:154:26)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ] + }, + "displayName": "test-stack" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/test-stack.template.json new file mode 100644 index 0000000000000..40f4c8238c04f --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/test-stack.template.json @@ -0,0 +1,54 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "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" + ] + ] + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/tree.json new file mode 100644 index 0000000000000..b664bec74b37c --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/tree.json @@ -0,0 +1,114 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "@aws-cdk/core.Construct", + "version": "0.0.0" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction1": { + "id": "MyFunction1", + "path": "test-stack/MyFunction1", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction1/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "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" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/cdk.out new file mode 100644 index 0000000000000..2efc89439fab8 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/manifest.json new file mode 100644 index 0000000000000..c0da3afe14484 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/manifest.json @@ -0,0 +1,57 @@ +{ + "version": "17.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B", + "trace": [ + "new Role (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-iam/lib/role.js:50:22)", + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:82:35)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ], + "/test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E", + "trace": [ + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:154:26)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ] + }, + "displayName": "test-stack" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/test-stack.template.json new file mode 100644 index 0000000000000..40f4c8238c04f --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/test-stack.template.json @@ -0,0 +1,54 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "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" + ] + ] + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/tree.json new file mode 100644 index 0000000000000..b664bec74b37c --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/tree.json @@ -0,0 +1,114 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "@aws-cdk/core.Construct", + "version": "0.0.0" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction1": { + "id": "MyFunction1", + "path": "test-stack/MyFunction1", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction1/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "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" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/integ.integ-test1.ts b/packages/@aws-cdk/integ-runner/test/test-data/integ.integ-test1.ts new file mode 100644 index 0000000000000..26679b49d93bc --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/integ.integ-test1.ts @@ -0,0 +1,2 @@ +/// !cdk-integ stack1 pragma:ignore-assets +/// !cdk-integ pragma:ignore-assets diff --git a/packages/@aws-cdk/integ-runner/test/test-data/integ.integ-test2.ts b/packages/@aws-cdk/integ-runner/test/test-data/integ.integ-test2.ts new file mode 100644 index 0000000000000..bb0eb24f2756d --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/integ.integ-test2.ts @@ -0,0 +1 @@ +/// !cdk-integ pragma:enable-lookups diff --git a/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot-assets-diff.ts b/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot-assets-diff.ts new file mode 100644 index 0000000000000..bcdc92fbcdcf2 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot-assets-diff.ts @@ -0,0 +1 @@ +/// !cdk-integ test-stack pragma:enable-lookups diff --git a/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot-assets.ts b/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot-assets.ts new file mode 100644 index 0000000000000..ff230f9f7e58e --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot-assets.ts @@ -0,0 +1 @@ +/// !cdk-integ test-stack pragma:include-assets-hashes diff --git a/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot.ts b/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot.ts new file mode 100644 index 0000000000000..c3548a8acffcc --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot.ts @@ -0,0 +1,2 @@ +/// !cdk-integ test-stack pragma:ignore-assets +/// !cdk-integ pragma:ignore-assets diff --git a/packages/@aws-cdk/integ-runner/test/test-data/not.integ-test.ts b/packages/@aws-cdk/integ-runner/test/test-data/not.integ-test.ts new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/cdk.out new file mode 100644 index 0000000000000..2efc89439fab8 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/manifest.json new file mode 100644 index 0000000000000..c0da3afe14484 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/manifest.json @@ -0,0 +1,57 @@ +{ + "version": "17.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B", + "trace": [ + "new Role (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-iam/lib/role.js:50:22)", + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:82:35)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ], + "/test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E", + "trace": [ + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:154:26)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ] + }, + "displayName": "test-stack" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/test-stack.template.json new file mode 100644 index 0000000000000..969780cdf33e5 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/test-stack.template.json @@ -0,0 +1,68 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "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" + ] + ] + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + } + }, + "Parameters": { + "AssetParametersDec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3BucketBF50F97C": { + "Type": "String", + "Description": "S3 bucket for asset \"Dec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" + }, + "AssetParametersDec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3VersionKeyF21AC8C1": { + "Type": "String", + "Description": "S3 key for asset version \"Dec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" + }, + "AssetParametersDec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509ArtifactHash5D8C129B": { + "Type": "String", + "Description": "Artifact hash for asset \"Dec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/tree.json new file mode 100644 index 0000000000000..b664bec74b37c --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/tree.json @@ -0,0 +1,114 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "@aws-cdk/core.Construct", + "version": "0.0.0" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction1": { + "id": "MyFunction1", + "path": "test-stack/MyFunction1", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction1/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "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" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/cdk.out new file mode 100644 index 0000000000000..2efc89439fab8 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/manifest.json new file mode 100644 index 0000000000000..c0da3afe14484 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/manifest.json @@ -0,0 +1,57 @@ +{ + "version": "17.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B", + "trace": [ + "new Role (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-iam/lib/role.js:50:22)", + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:82:35)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ], + "/test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E", + "trace": [ + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:154:26)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ] + }, + "displayName": "test-stack" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/test-stack.template.json new file mode 100644 index 0000000000000..ed2a09b94be23 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/test-stack.template.json @@ -0,0 +1,68 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "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" + ] + ] + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + } + }, + "Parameters": { + "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3BucketBF50F97C": { + "Type": "String", + "Description": "S3 bucket for asset \"fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" + }, + "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3VersionKeyF21AC8C1": { + "Type": "String", + "Description": "S3 key for asset version \"fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" + }, + "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509ArtifactHash5D8C129B": { + "Type": "String", + "Description": "Artifact hash for asset \"fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/tree.json new file mode 100644 index 0000000000000..b664bec74b37c --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/tree.json @@ -0,0 +1,114 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "@aws-cdk/core.Construct", + "version": "0.0.0" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction1": { + "id": "MyFunction1", + "path": "test-stack/MyFunction1", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction1/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "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" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/cdk.out new file mode 100644 index 0000000000000..2efc89439fab8 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/manifest.json new file mode 100644 index 0000000000000..c0da3afe14484 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/manifest.json @@ -0,0 +1,57 @@ +{ + "version": "17.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B", + "trace": [ + "new Role (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-iam/lib/role.js:50:22)", + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:82:35)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ], + "/test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E", + "trace": [ + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:154:26)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ] + }, + "displayName": "test-stack" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/test-stack.template.json new file mode 100644 index 0000000000000..3d62830b46139 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/test-stack.template.json @@ -0,0 +1,54 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "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" + ] + ] + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foobar" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/tree.json new file mode 100644 index 0000000000000..b664bec74b37c --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/tree.json @@ -0,0 +1,114 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "@aws-cdk/core.Construct", + "version": "0.0.0" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction1": { + "id": "MyFunction1", + "path": "test-stack/MyFunction1", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction1/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "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" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/cdk.out new file mode 100644 index 0000000000000..2efc89439fab8 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/manifest.json new file mode 100644 index 0000000000000..c0da3afe14484 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/manifest.json @@ -0,0 +1,57 @@ +{ + "version": "17.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B", + "trace": [ + "new Role (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-iam/lib/role.js:50:22)", + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:82:35)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ], + "/test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E", + "trace": [ + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:154:26)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ] + }, + "displayName": "test-stack" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/test-stack.template.json new file mode 100644 index 0000000000000..40f4c8238c04f --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/test-stack.template.json @@ -0,0 +1,54 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "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" + ] + ] + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/tree.json new file mode 100644 index 0000000000000..b664bec74b37c --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/tree.json @@ -0,0 +1,114 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "@aws-cdk/core.Construct", + "version": "0.0.0" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction1": { + "id": "MyFunction1", + "path": "test-stack/MyFunction1", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction1/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "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" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/workers/mock-extract_worker.ts b/packages/@aws-cdk/integ-runner/test/workers/mock-extract_worker.ts new file mode 100644 index 0000000000000..7479d229302b8 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/workers/mock-extract_worker.ts @@ -0,0 +1,15 @@ +import * as workerpool from 'workerpool'; +import { IntegBatchResponse } from '../../lib/workers/common'; +import { IntegTestBatchRequest } from '../../lib/workers/integ-test-worker'; + + +function integTestBatch(request: IntegTestBatchRequest): IntegBatchResponse { + return { + failedTests: request.tests, + }; +} + +workerpool.worker({ + integTestBatch, +}); + diff --git a/packages/@aws-cdk/integ-runner/test/workers/workers.test.ts b/packages/@aws-cdk/integ-runner/test/workers/workers.test.ts new file mode 100644 index 0000000000000..cc0be1ec8a9b0 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/workers/workers.test.ts @@ -0,0 +1,266 @@ +import * as child_process from 'child_process'; +import * as path from 'path'; +import * as fs from 'fs-extra'; +import * as workerpool from 'workerpool'; +import { singleThreadedSnapshotRunner } from '../../lib/workers/integ-snapshot-worker'; +import { singleThreadedTestRunner, runIntegrationTestsInParallel } from '../../lib/workers/integ-test-worker'; + +const directory = path.join(__dirname, '../test-data'); +describe('Snapshot tests', () => { + beforeEach(() => { + jest.spyOn(process.stderr, 'write').mockImplementation(() => { return true; }); + jest.spyOn(process.stdout, 'write').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'moveSync').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'removeSync').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'writeFileSync').mockImplementation(() => { return true; }); + }); + afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + jest.restoreAllMocks(); + }); + test('no snapshot', () => { + // WHEN + const test = { + fileName: path.join(directory, 'integ.integ-test1.js'), + directory: directory, + }; + const result = singleThreadedSnapshotRunner([test]); + + // THEN + expect(result.failedTests.length).toEqual(1); + expect(result.failedTests[0]).toEqual(test); + }); + + test('has snapshot', () => { + // WHEN + jest.spyOn(child_process, 'spawnSync').mockResolvedValue; + const test = { + fileName: path.join(directory, 'integ.test-with-snapshot.js'), + directory: directory, + }; + const result = singleThreadedSnapshotRunner([test]); + + // THEN + expect(result.failedTests.length).toEqual(0); + }); + + test('failed snapshot', () => { + // WHEN + jest.spyOn(child_process, 'spawnSync').mockRejectedValue; + const test = { + fileName: path.join(directory, 'integ.test-with-snapshot-assets.js'), + directory: directory, + }; + const result = singleThreadedSnapshotRunner([test]); + + // THEN + expect(result.failedTests.length).toEqual(1); + expect(result.failedTests[0]).toEqual(test); + }); +}); + +describe('test runner', () => { + beforeEach(() => { + jest.spyOn(process.stderr, 'write').mockImplementation(() => { return true; }); + jest.spyOn(process.stdout, 'write').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'moveSync').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'removeSync').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'writeFileSync').mockImplementation(() => { return true; }); + }); + afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + jest.restoreAllMocks(); + }); + + test('no snapshot', () => { + // WHEN + const test = { + fileName: path.join(directory, 'integ.integ-test1.js'), + directory: directory, + }; + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockImplementation(); + singleThreadedTestRunner({ + tests: [test], + region: 'us-east-1', + }); + + expect(spawnSyncMock).toHaveBeenCalledWith( + expect.stringMatching(/cdk/), + ['synth', '--app', 'node integ.integ-test1.js', '--no-version-reporting', '--no-path-metadata', '--no-asset-metadata', '--output', 'cdk-integ.out.integ-test1', '--all'], + expect.anything(), + ); + }); +}); + +describe('parallel worker', () => { + let pool: workerpool.WorkerPool; + let stderrMock: jest.SpyInstance; + beforeEach(() => { + pool = workerpool.pool(path.join(__dirname, './mock-extract_worker.js')); + stderrMock = jest.spyOn(process.stderr, 'write').mockImplementation(() => { return true; }); + jest.spyOn(process.stdout, 'write').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'moveSync').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'removeSync').mockImplementation(() => { return true; }); + jest.spyOn(fs, 'writeFileSync').mockImplementation(() => { return true; }); + }); + afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + jest.restoreAllMocks(); + void pool.terminate(); + }); + test('run tests', async () => { + const tests = [{ + fileName: 'integ.test-with-snapshot.js', + directory, + }]; + const results = await runIntegrationTestsInParallel({ + tests, + pool, + regions: ['us-east-1'], + }); + + expect(stderrMock.mock.calls[0][0]).toContain( + 'Running test integ.test-with-snapshot.js in us-east-1', + ); + expect(results).toEqual([ + { + failedTests: [{ + fileName: 'integ.test-with-snapshot.js', + directory, + }], + }, + ]); + }); + + test('run multiple tests', async () => { + const tests = [ + { + fileName: 'integ.test-with-snapshot.js', + directory, + }, + { + fileName: 'integ.another-test-with-snapshot.js', + directory, + }, + ]; + const results = await runIntegrationTestsInParallel({ + tests, + pool, + regions: ['us-east-1', 'us-east-2'], + }); + + expect(stderrMock.mock.calls[1][0]).toContain( + 'Running test integ.test-with-snapshot.js in us-east-2', + ); + expect(stderrMock.mock.calls[0][0]).toContain( + 'Running test integ.another-test-with-snapshot.js in us-east-1', + ); + expect(results).toEqual(expect.arrayContaining([ + { + failedTests: [ + { + fileName: 'integ.test-with-snapshot.js', + directory, + }, + ], + }, + { + failedTests: [ + { + fileName: 'integ.another-test-with-snapshot.js', + directory, + }, + ], + }, + ])); + }); + + test('more tests than regions', async () => { + const tests = [ + { + fileName: 'integ.test-with-snapshot.js', + directory, + }, + { + fileName: 'integ.another-test-with-snapshot.js', + directory, + }, + ]; + const results = await runIntegrationTestsInParallel({ + tests, + pool, + regions: ['us-east-1'], + }); + + expect(stderrMock.mock.calls[1][0]).toContain( + 'Running test integ.test-with-snapshot.js in us-east-1', + ); + expect(stderrMock.mock.calls[0][0]).toContain( + 'Running test integ.another-test-with-snapshot.js in us-east-1', + ); + expect(results).toEqual([ + { + failedTests: [ + { + fileName: 'integ.another-test-with-snapshot.js', + directory, + }, + ], + }, + { + failedTests: [ + { + fileName: 'integ.test-with-snapshot.js', + directory, + }, + ], + }, + ]); + }); + + test('more regions than tests', async () => { + const tests = [ + { + fileName: 'integ.test-with-snapshot.js', + directory, + }, + { + fileName: 'integ.another-test-with-snapshot.js', + directory, + }, + ]; + const results = await runIntegrationTestsInParallel({ + tests, + pool, + regions: ['us-east-1', 'us-east-2', 'us-west-2'], + }); + + expect(stderrMock.mock.calls[1][0]).toContain( + 'Running test integ.test-with-snapshot.js in us-east-2', + ); + expect(stderrMock.mock.calls[0][0]).toContain( + 'Running test integ.another-test-with-snapshot.js in us-east-1', + ); + expect(results).toEqual(expect.arrayContaining([ + { + failedTests: [ + { + fileName: 'integ.another-test-with-snapshot.js', + directory, + }, + ], + }, + { + failedTests: [ + { + fileName: 'integ.test-with-snapshot.js', + directory, + }, + ], + }, + ])); + }); +}); diff --git a/packages/@aws-cdk/integ-runner/tsconfig.json b/packages/@aws-cdk/integ-runner/tsconfig.json new file mode 100644 index 0000000000000..04e0404f04442 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "ES2018", + "module": "commonjs", + "lib": ["es2018", "dom"], + "strict": true, + "alwaysStrict": true, + "declaration": true, + "inlineSourceMap": true, + "inlineSources": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "resolveJsonModule": true, + "composite": true, + "incremental": true + }, + "include": [ + "**/*.ts", + "**/*.d.ts", + "lib/init-templates/*/*/add-project.hook.ts" + ], + "exclude": [ + "lib/init-templates/*/typescript/**/*.ts" + ] +} + diff --git a/packages/@aws-cdk/lambda-layer-awscli/layer/requirements.txt b/packages/@aws-cdk/lambda-layer-awscli/layer/requirements.txt index ef2306f3b53b4..1137fa10c7c4b 100644 --- a/packages/@aws-cdk/lambda-layer-awscli/layer/requirements.txt +++ b/packages/@aws-cdk/lambda-layer-awscli/layer/requirements.txt @@ -1 +1 @@ -awscli==1.22.49 +awscli==1.22.82 diff --git a/packages/@aws-cdk/lambda-layer-awscli/package.json b/packages/@aws-cdk/lambda-layer-awscli/package.json index 72e500cd130b2..7daf454a10df1 100644 --- a/packages/@aws-cdk/lambda-layer-awscli/package.json +++ b/packages/@aws-cdk/lambda-layer-awscli/package.json @@ -78,8 +78,8 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", diff --git a/packages/@aws-cdk/lambda-layer-awscli/test/integ.awscli-layer.expected.json b/packages/@aws-cdk/lambda-layer-awscli/test/integ.awscli-layer.expected.json index d37e67106e0cf..d9411d0b44b0d 100644 --- a/packages/@aws-cdk/lambda-layer-awscli/test/integ.awscli-layer.expected.json +++ b/packages/@aws-cdk/lambda-layer-awscli/test/integ.awscli-layer.expected.json @@ -5,7 +5,7 @@ "Properties": { "Content": { "S3Bucket": { - "Ref": "AssetParametersba23ea22aa357b771a4ebc95be163f8848dafee07daf2333380d3b890472d1f3S3BucketD774C319" + "Ref": "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3Bucket940CB35D" }, "S3Key": { "Fn::Join": [ @@ -18,7 +18,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersba23ea22aa357b771a4ebc95be163f8848dafee07daf2333380d3b890472d1f3S3VersionKey9C5C53B3" + "Ref": "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3VersionKey248C9936" } ] } @@ -31,7 +31,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersba23ea22aa357b771a4ebc95be163f8848dafee07daf2333380d3b890472d1f3S3VersionKey9C5C53B3" + "Ref": "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3VersionKey248C9936" } ] } @@ -175,12 +175,28 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "Lambdapython36B64E8A5D", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "Lambdapython36B64E8A5D", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Lambdapython36B64E8A5D", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -198,7 +214,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters733a1180c316ce99003dfcfd7bd70d8039134b3fbac69643f144aceea90d6b8cS3BucketBA45D90E" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, "S3Key": { "Fn::Join": [ @@ -211,7 +227,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters733a1180c316ce99003dfcfd7bd70d8039134b3fbac69643f144aceea90d6b8cS3VersionKey1021C50F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -224,7 +240,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters733a1180c316ce99003dfcfd7bd70d8039134b3fbac69643f144aceea90d6b8cS3VersionKey1021C50F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -404,12 +420,28 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "Lambdapython3780349E0A", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "Lambdapython3780349E0A", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Lambdapython3780349E0A", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -427,7 +459,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters733a1180c316ce99003dfcfd7bd70d8039134b3fbac69643f144aceea90d6b8cS3BucketBA45D90E" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, "S3Key": { "Fn::Join": [ @@ -440,7 +472,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters733a1180c316ce99003dfcfd7bd70d8039134b3fbac69643f144aceea90d6b8cS3VersionKey1021C50F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -453,7 +485,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters733a1180c316ce99003dfcfd7bd70d8039134b3fbac69643f144aceea90d6b8cS3VersionKey1021C50F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -633,12 +665,28 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "Lambdapython39426A0480", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "Lambdapython39426A0480", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Lambdapython39426A0480", + "Arn" + ] + }, + ":*" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -656,7 +704,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters733a1180c316ce99003dfcfd7bd70d8039134b3fbac69643f144aceea90d6b8cS3BucketBA45D90E" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A" }, "S3Key": { "Fn::Join": [ @@ -669,7 +717,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters733a1180c316ce99003dfcfd7bd70d8039134b3fbac69643f144aceea90d6b8cS3VersionKey1021C50F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -682,7 +730,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters733a1180c316ce99003dfcfd7bd70d8039134b3fbac69643f144aceea90d6b8cS3VersionKey1021C50F" + "Ref": "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6" } ] } @@ -733,17 +781,17 @@ } }, "Parameters": { - "AssetParametersba23ea22aa357b771a4ebc95be163f8848dafee07daf2333380d3b890472d1f3S3BucketD774C319": { + "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3Bucket940CB35D": { "Type": "String", - "Description": "S3 bucket for asset \"ba23ea22aa357b771a4ebc95be163f8848dafee07daf2333380d3b890472d1f3\"" + "Description": "S3 bucket for asset \"d78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27\"" }, - "AssetParametersba23ea22aa357b771a4ebc95be163f8848dafee07daf2333380d3b890472d1f3S3VersionKey9C5C53B3": { + "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27S3VersionKey248C9936": { "Type": "String", - "Description": "S3 key for asset version \"ba23ea22aa357b771a4ebc95be163f8848dafee07daf2333380d3b890472d1f3\"" + "Description": "S3 key for asset version \"d78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27\"" }, - "AssetParametersba23ea22aa357b771a4ebc95be163f8848dafee07daf2333380d3b890472d1f3ArtifactHash4F540915": { + "AssetParametersd78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27ArtifactHash934284DB": { "Type": "String", - "Description": "Artifact hash for asset \"ba23ea22aa357b771a4ebc95be163f8848dafee07daf2333380d3b890472d1f3\"" + "Description": "Artifact hash for asset \"d78148e12051f01bfd7332d83ccd5c159c8106d3b878d178f7eb093fabafab27\"" }, "AssetParameters5dff6208ccd5fb196bb0354fd6e47faa8431a789e6125d20386586fef761ed48S3Bucket1DD21439": { "Type": "String", @@ -757,17 +805,17 @@ "Type": "String", "Description": "Artifact hash for asset \"5dff6208ccd5fb196bb0354fd6e47faa8431a789e6125d20386586fef761ed48\"" }, - "AssetParameters733a1180c316ce99003dfcfd7bd70d8039134b3fbac69643f144aceea90d6b8cS3BucketBA45D90E": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3BucketB4102E9A": { "Type": "String", - "Description": "S3 bucket for asset \"733a1180c316ce99003dfcfd7bd70d8039134b3fbac69643f144aceea90d6b8c\"" + "Description": "S3 bucket for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParameters733a1180c316ce99003dfcfd7bd70d8039134b3fbac69643f144aceea90d6b8cS3VersionKey1021C50F": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391S3VersionKeyC1EC3ED6": { "Type": "String", - "Description": "S3 key for asset version \"733a1180c316ce99003dfcfd7bd70d8039134b3fbac69643f144aceea90d6b8c\"" + "Description": "S3 key for asset version \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" }, - "AssetParameters733a1180c316ce99003dfcfd7bd70d8039134b3fbac69643f144aceea90d6b8cArtifactHash371618FE": { + "AssetParameters5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391ArtifactHashA391D940": { "Type": "String", - "Description": "Artifact hash for asset \"733a1180c316ce99003dfcfd7bd70d8039134b3fbac69643f144aceea90d6b8c\"" + "Description": "Artifact hash for asset \"5b47c8e4cbbce7e4a8085f1aa83ed9c4691b7f65927ba092d6620bbba925f391\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/lambda-layer-kubectl/package.json b/packages/@aws-cdk/lambda-layer-kubectl/package.json index 88b6a6748cd6f..2a2223166c3ee 100644 --- a/packages/@aws-cdk/lambda-layer-kubectl/package.json +++ b/packages/@aws-cdk/lambda-layer-kubectl/package.json @@ -77,8 +77,8 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "pkglint": { "attribution": [ diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/.no-packagejson-validator b/packages/@aws-cdk/lambda-layer-node-proxy-agent/.no-packagejson-validator new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/README.md b/packages/@aws-cdk/lambda-layer-node-proxy-agent/README.md index f27c51013b3fc..da6471a4950da 100644 --- a/packages/@aws-cdk/lambda-layer-node-proxy-agent/README.md +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/README.md @@ -23,4 +23,4 @@ declare const fn: lambda.Function; fn.addLayers(new NodeProxyAgentLayer(this, 'NodeProxyAgentLayer')); ``` -[`proxy-agent`](https://www.npmjs.com/package/proxy-agent) will be installed under `/opt/nodejs/node_modules`. +[`proxy-agent`](https://www.npmjs.com/package/proxy-agent) will be installed under `/nodejs/node_modules`. diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/Dockerfile b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/Dockerfile index 2e3f644258652..0166da75f4651 100644 --- a/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/Dockerfile +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/Dockerfile @@ -1,8 +1,6 @@ # base lambda image FROM public.ecr.aws/lambda/nodejs:latest -ARG PROXY_AGENT_VERSION=5.0.0 - USER root RUN mkdir -p /opt WORKDIR /tmp @@ -19,7 +17,8 @@ RUN yum update -y \ # RUN mkdir -p /opt/nodejs -RUN cd /opt/nodejs && npm install proxy-agent@${PROXY_AGENT_VERSION} +COPY package*.json /opt/nodejs/ +RUN cd /opt/nodejs && npm ci && rm package*.json # # create the bundle diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/build.sh b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/build.sh index 6a84896b9d991..d45f9d47a77d7 100755 --- a/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/build.sh +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/build.sh @@ -3,7 +3,7 @@ set -euo pipefail cd $(dirname $0) -echo ">> Building AWS Lambda layer inside a docker image..." +echo ">> Building AWS Lambda layer inside a docker image for Proxy Agent..." TAG='aws-lambda-node-proxy-agent' diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/package-lock.json b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/package-lock.json new file mode 100644 index 0000000000000..19220af66d40b --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/package-lock.json @@ -0,0 +1,1137 @@ +{ + "name": "proxy-agent-layer", + "version": "0.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "proxy-agent-layer", + "version": "0.0.0", + "license": "ISC", + "devDependencies": { + "proxy-agent": "^5.0.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/bytes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", + "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/data-uri-to-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", + "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/degenerator": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.1.tgz", + "integrity": "sha512-LFsIFEeLPlKvAKXu7j3ssIG6RT0TbI7/GhsqrI0DnHASEQjXQ0LUSYcjJteGgRGmZbl1TnMSxpNQIAiJ7Du5TQ==", + "dev": true, + "dependencies": { + "ast-types": "^0.13.2", + "escodegen": "^1.8.1", + "esprima": "^4.0.0", + "vm2": "^3.9.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/file-uri-to-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", + "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", + "dev": true, + "dependencies": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/get-uri": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", + "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "data-uri-to-buffer": "3", + "debug": "4", + "file-uri-to-path": "2", + "fs-extra": "^8.1.0", + "ftp": "^0.3.10" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "dev": true + }, + "node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pac-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", + "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4", + "get-uri": "3", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "5", + "pac-resolver": "^5.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "5" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/pac-resolver": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.0.tgz", + "integrity": "sha512-H+/A6KitiHNNW+bxBKREk2MCGSxljfqRX76NjummWEYIat7ldVXRU3dhRIE3iXZ0nvGBk6smv3nntxKkzRL8NA==", + "dev": true, + "dependencies": { + "degenerator": "^3.0.1", + "ip": "^1.1.5", + "netmask": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", + "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.0", + "debug": "4", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "lru-cache": "^5.1.1", + "pac-proxy-agent": "^5.0.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^5.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/raw-body": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", + "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", + "dev": true, + "dependencies": { + "bytes": "3.1.1", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.1.tgz", + "integrity": "sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA==", + "dev": true, + "dependencies": { + "ip": "^1.1.5", + "smart-buffer": "^4.1.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", + "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vm2": { + "version": "3.9.8", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.8.tgz", + "integrity": "sha512-/1PYg/BwdKzMPo8maOZ0heT7DLI0DAFTm7YQaz/Lim9oIaFZsJs3EdtalvXuBfZwczNwsYhju75NW4d6E+4q+w==", + "dev": true, + "dependencies": { + "acorn": "^8.7.0", + "acorn-walk": "^8.2.0" + }, + "bin": { + "vm2": "bin/vm2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/xregexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + }, + "dependencies": { + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "requires": { + "tslib": "^2.0.1" + } + }, + "bytes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", + "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==", + "dev": true + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "data-uri-to-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", + "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", + "dev": true + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "degenerator": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.1.tgz", + "integrity": "sha512-LFsIFEeLPlKvAKXu7j3ssIG6RT0TbI7/GhsqrI0DnHASEQjXQ0LUSYcjJteGgRGmZbl1TnMSxpNQIAiJ7Du5TQ==", + "dev": true, + "requires": { + "ast-types": "^0.13.2", + "escodegen": "^1.8.1", + "esprima": "^4.0.0", + "vm2": "^3.9.3" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "file-uri-to-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", + "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", + "dev": true, + "requires": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + } + }, + "get-uri": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", + "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "data-uri-to-buffer": "3", + "debug": "4", + "file-uri-to-path": "2", + "fs-extra": "^8.1.0", + "ftp": "^0.3.10" + } + }, + "graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "dev": true + }, + "http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + } + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "pac-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", + "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4", + "get-uri": "3", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "5", + "pac-resolver": "^5.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "5" + } + }, + "pac-resolver": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.0.tgz", + "integrity": "sha512-H+/A6KitiHNNW+bxBKREk2MCGSxljfqRX76NjummWEYIat7ldVXRU3dhRIE3iXZ0nvGBk6smv3nntxKkzRL8NA==", + "dev": true, + "requires": { + "degenerator": "^3.0.1", + "ip": "^1.1.5", + "netmask": "^2.0.1" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", + "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", + "dev": true, + "requires": { + "agent-base": "^6.0.0", + "debug": "4", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "lru-cache": "^5.1.1", + "pac-proxy-agent": "^5.0.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^5.0.0" + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "raw-body": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", + "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", + "dev": true, + "requires": { + "bytes": "3.1.1", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, + "socks": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.1.tgz", + "integrity": "sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA==", + "dev": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.1.0" + } + }, + "socks-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", + "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "vm2": { + "version": "3.9.8", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.8.tgz", + "integrity": "sha512-/1PYg/BwdKzMPo8maOZ0heT7DLI0DAFTm7YQaz/Lim9oIaFZsJs3EdtalvXuBfZwczNwsYhju75NW4d6E+4q+w==", + "dev": true, + "requires": { + "acorn": "^8.7.0", + "acorn-walk": "^8.2.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "xregexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } +} diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/package.json b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/package.json new file mode 100644 index 0000000000000..d6e8118c9b4df --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/package.json @@ -0,0 +1,12 @@ +{ + "name": "proxy-agent-layer", + "private": true, + "version": "0.0.0", + "description": "", + "devDependencies": { + "proxy-agent": "^5.0.0" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json b/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json index 1753c1057db84..8f0dfffef911b 100644 --- a/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json @@ -77,8 +77,8 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", - "jest": "^27.4.7" + "@types/jest": "^27.4.1", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", diff --git a/packages/@aws-cdk/pipelines/README.md b/packages/@aws-cdk/pipelines/README.md index b6477e465a80a..3711f5e11110f 100644 --- a/packages/@aws-cdk/pipelines/README.md +++ b/packages/@aws-cdk/pipelines/README.md @@ -49,9 +49,10 @@ them. You can deploy to the same account and Region, or to a different one, with the same amount of code. The *CDK Pipelines* library takes care of the details. -CDK Pipelines supports multiple *deployment engines* (see below), and comes with -a deployment engine that deploys CDK apps using AWS CodePipeline. To use the -CodePipeline engine, define a `CodePipeline` construct. The following +CDK Pipelines supports multiple *deployment engines* (see +[Using a different deployment engine](#using-a-different-deployment-engine)), +and comes with a deployment engine that deploys CDK apps using AWS CodePipeline. +To use the CodePipeline engine, define a `CodePipeline` construct. The following example creates a CodePipeline that deploys an application from GitHub: ```ts @@ -149,21 +150,9 @@ pipeline will automatically reconfigure itself to deploy those new stages and stacks. (Note that have to *bootstrap* all environments before the above code -will work, see the section **CDK Environment Bootstrapping** below). - -## CDK Versioning - -This library uses prerelease features of the CDK framework, which can be enabled -by adding the following to `cdk.json`: - -```js -{ - // ... - "context": { - "@aws-cdk/core:newStyleStackSynthesis": true - } -} -``` +will work, and switch on "Modern synthesis" if you are using +CDKv1. See the section **CDK Environment Bootstrapping** below for +more information). ## Provisioning the pipeline @@ -225,9 +214,10 @@ const originalPipeline = new pipelines.CdkPipeline(this, 'Pipeline', { ## Definining the pipeline -This section of the documentation describes the AWS CodePipeline engine, which -comes with this library. If you want to use a different deployment engine, read -the section *Using a different deployment engine* below. +This section of the documentation describes the AWS CodePipeline engine, +which comes with this library. If you want to use a different deployment +engine, read the section +[Using a different deployment engine](#using-a-different-deployment-engine)below. ### Synth and sources @@ -348,6 +338,40 @@ const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { You can adapt these examples to your own situation. +#### Migrating from buildspec.yml files + +You may currently have the build instructions for your CodeBuild Projects in a +`buildspec.yml` file in your source repository. In addition to your build +commands, the CodeBuild Project's buildspec also controls some information that +CDK Pipelines manages for you, like artifact identifiers, input artifact +locations, Docker authorization, and exported variables. + +Since there is no way in general for CDK Pipelines to modify the file in your +resource repository, CDK Pipelines configures the BuildSpec directly on the +CodeBuild Project, instead of loading it from the `buildspec.yml` file. +This requires a pipeline self-mutation to update. + +To avoid this, put your build instructions in a separate script, for example +`build.sh`, and call that script from the build `commands` array: + +```ts +declare const source: pipelines.IFileSetProducer; + +const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { + synth: new pipelines.ShellStep('Synth', { + input: source, + commands: [ + // Abstract over doing the build + './build.sh', + ], + }) +}); +``` + +Doing so keeps your exact build instructions in sync with your source code in +the source repository where it belongs, and provides a convenient build script +for developers at the same time. + #### CodePipeline Sources In CodePipeline, *Sources* define where the source of your application lives. @@ -402,6 +426,16 @@ const bucket = s3.Bucket.fromBucketName(this, 'Bucket', 'my-bucket'); pipelines.CodePipelineSource.s3(bucket, 'my/source.zip'); ``` +##### ECR + +You can use a Docker image in ECR as the source of the pipeline. The pipeline will be +triggered every time an image is pushed to ECR: + +```ts +const repository = new ecr.Repository(this, 'Repository'); +pipelines.CodePipelineSource.ecr(repository); +``` + #### Additional inputs `ShellStep` allows passing in more than one input: additional @@ -766,6 +800,13 @@ class MyJenkinsStep extends pipelines.Step implements pipelines.ICodePipelineAct private readonly input: pipelines.FileSet, ) { super('MyJenkinsStep'); + + // This is necessary if your step accepts parametres, like environment variables, + // that may contain outputs from other steps. It doesn't matter what the + // structure is, as long as it contains the values that may contain outputs. + this.discoverReferencedOutputs({ + env: { /* ... */ } + }); } public produceAction(stage: codepipeline.IStage, options: pipelines.ProduceActionOptions): pipelines.CodePipelineActionFactoryResult { @@ -944,22 +985,30 @@ or future deployments to this environment will fail. If you want to upgrade the bootstrap stack to a newer version, do that by updating it in-place. > This library requires the *modern* bootstrapping stack which has -> been updated specifically to support cross-account continuous delivery. Starting, -> in CDK v2 this new bootstrapping stack will become the default, but for now it is still -> opt-in. +> been updated specifically to support cross-account continuous delivery. > -> The commands below assume you are running `cdk bootstrap` in a directory -> where `cdk.json` contains the `"@aws-cdk/core:newStyleStackSynthesis": true` -> setting in its context, which will switch to the new bootstrapping stack -> automatically. +> If you are using CDKv2, you do not need to do anything else. Modern +> bootstrapping and modern stack synthesis (also known as "default stack +> synthesis") is the default. > -> If run from another directory, be sure to run the bootstrap command with -> the environment variable `CDK_NEW_BOOTSTRAP=1` set. +> If you are using CDKv1, you need to opt in to modern bootstrapping and +> modern stack synthesis using a feature flag. Make sure `cdk.json` includes: +> +> ```json +> { +> "context": { +> "@aws-cdk/core:newStyleStackSynthesis": true +> } +> } +> ``` +> +> And be sure to run `cdk bootstrap` in the same directory as the `cdk.json` +> file. To bootstrap an environment for provisioning the pipeline: ```console -$ env CDK_NEW_BOOTSTRAP=1 npx cdk bootstrap \ +$ npx cdk bootstrap \ [--profile admin-profile-1] \ --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess \ aws://111111111111/us-east-1 @@ -969,7 +1018,7 @@ To bootstrap a different environment for deploying CDK applications into using a pipeline in account `111111111111`: ```console -$ env CDK_NEW_BOOTSTRAP=1 npx cdk bootstrap \ +$ npx cdk bootstrap \ [--profile admin-profile-2] \ --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess \ --trust 11111111111 \ @@ -980,7 +1029,7 @@ If you only want to trust an account to do lookups (e.g, when your CDK applicati `Vpc.fromLookup()` call), use the option `--trust-for-lookup`: ```console -$ env CDK_NEW_BOOTSTRAP=1 npx cdk bootstrap \ +$ npx cdk bootstrap \ [--profile admin-profile-2] \ --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess \ --trust-for-lookup 11111111111 \ @@ -1203,6 +1252,17 @@ pipeline.addStage(stage, { **Note**: Manual Approvals notifications only apply when an application has security check enabled. +## Using a different deployment engine + +CDK Pipelines supports multiple *deployment engines*, but this module vends a +construct for only one such engine: AWS CodePipeline. It is also possible to +use CDK Pipelines to build pipelines backed by other deployment engines. + +Here is a list of CDK Libraries that integrate CDK Pipelines with +alternative deployment engines: + +* GitHub Workflows: [`cdk-pipelines-github`](https://github.com/cdklabs/cdk-pipelines-github) + ## Troubleshooting Here are some common errors you may encounter while using this library. diff --git a/packages/@aws-cdk/pipelines/lib/blueprint/manual-approval.ts b/packages/@aws-cdk/pipelines/lib/blueprint/manual-approval.ts index 859c279533fa3..31b93f5b9cf87 100644 --- a/packages/@aws-cdk/pipelines/lib/blueprint/manual-approval.ts +++ b/packages/@aws-cdk/pipelines/lib/blueprint/manual-approval.ts @@ -33,5 +33,7 @@ export class ManualApprovalStep extends Step { super(id); this.comment = props.comment; + + this.discoverReferencedOutputs(props.comment); } } \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/lib/blueprint/shell-step.ts b/packages/@aws-cdk/pipelines/lib/blueprint/shell-step.ts index 1f03105c78ee9..fa01624e9635a 100644 --- a/packages/@aws-cdk/pipelines/lib/blueprint/shell-step.ts +++ b/packages/@aws-cdk/pipelines/lib/blueprint/shell-step.ts @@ -87,11 +87,11 @@ export interface ShellStepProps { * @default - No primary output */ readonly primaryOutputDirectory?: string; - } /** - * Run shell script commands in the pipeline + * Run shell script commands in the pipeline. This is a generic step designed + * to be deployment engine agnostic. */ export class ShellStep extends Step { /** @@ -151,6 +151,11 @@ export class ShellStep extends Step { this.env = props.env ?? {}; this.envFromCfnOutputs = mapValues(props.envFromCfnOutputs ?? {}, StackOutputReference.fromCfnOutput); + // 'env' is the only thing that can contain outputs + this.discoverReferencedOutputs({ + env: this.env, + }); + // Inputs if (props.input) { const fileSet = props.input.primaryOutput; diff --git a/packages/@aws-cdk/pipelines/lib/blueprint/step.ts b/packages/@aws-cdk/pipelines/lib/blueprint/step.ts index 65f4636b2ecbc..ffdb3ea359a1c 100644 --- a/packages/@aws-cdk/pipelines/lib/blueprint/step.ts +++ b/packages/@aws-cdk/pipelines/lib/blueprint/step.ts @@ -1,4 +1,5 @@ import { Stack, Token } from '@aws-cdk/core'; +import { StepOutput } from '../helpers-internal/step-output'; import { FileSet, IFileSetProducer } from './file-set'; /** @@ -39,7 +40,7 @@ export abstract class Step implements IFileSetProducer { private _primaryOutput?: FileSet; - private _dependencies: Step[] = []; + private _dependencies = new Set(); constructor( /** Identifier for this step */ @@ -54,7 +55,10 @@ export abstract class Step implements IFileSetProducer { * Return the steps this step depends on, based on the FileSets it requires */ public get dependencies(): Step[] { - return this.dependencyFileSets.map(f => f.producer).concat(this._dependencies); + return Array.from(new Set([ + ...this.dependencyFileSets.map(f => f.producer), + ...this._dependencies, + ])); } /** @@ -79,7 +83,7 @@ export abstract class Step implements IFileSetProducer { * Add a dependency on another step. */ public addStepDependency(step: Step) { - this._dependencies.push(step); + this._dependencies.add(step); } /** @@ -97,6 +101,21 @@ export abstract class Step implements IFileSetProducer { protected configurePrimaryOutput(fs: FileSet) { this._primaryOutput = fs; } + + /** + * Crawl the given structure for references to StepOutputs and add dependencies on all steps found + * + * Should be called in the constructor of subclasses based on what the user + * passes in as construction properties. The format of the structure passed in + * here does not have to correspond exactly to what gets rendered into the + * engine, it just needs to contain the same data. + */ + protected discoverReferencedOutputs(structure: any) { + for (const output of StepOutput.findAll(structure)) { + this._dependencies.add(output.step); + StepOutput.recordProducer(output); + } + } } /** @@ -128,5 +147,4 @@ export interface StackSteps { * @default - no additional steps */ readonly post?: Step[]; - } \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts index f835e261aba3d..43519fdda97bf 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts @@ -1,8 +1,10 @@ -import { Duration } from '@aws-cdk/core'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; +import { Duration } from '@aws-cdk/core'; import { ShellStep, ShellStepProps } from '../blueprint'; +import { mergeBuildSpecs } from './private/buildspecs'; +import { makeCodePipelineOutput } from './private/outputs'; /** * Construction props for a CodeBuildStep @@ -96,6 +98,17 @@ export interface CodeBuildStepProps extends ShellStepProps { /** * Run a script as a CodeBuild Project + * + * The BuildSpec must be available inline--it cannot reference a file + * on disk. If your current build instructions are in a file like + * `buildspec.yml` in your repository, extract them to a script + * (say, `build.sh`) and invoke that script as part of the build: + * + * ```ts + * new pipelines.CodeBuildStep('Synth', { + * commands: ['./build.sh'], + * }); + * ``` */ export class CodeBuildStep extends ShellStep { /** @@ -105,13 +118,6 @@ export class CodeBuildStep extends ShellStep { */ public readonly projectName?: string; - /** - * Additional configuration that can only be configured via BuildSpec - * - * @default - No value specified at construction time, use defaults - */ - public readonly partialBuildSpec?: codebuild.BuildSpec; - /** * The VPC where to execute the SimpleSynth. * @@ -164,13 +170,16 @@ export class CodeBuildStep extends ShellStep { readonly timeout?: Duration; private _project?: codebuild.IProject; + private _partialBuildSpec?: codebuild.BuildSpec; + private readonly exportedVariables = new Set(); + private exportedVarsRendered = false; constructor(id: string, props: CodeBuildStepProps) { super(id, props); this.projectName = props.projectName; this.buildEnvironment = props.buildEnvironment; - this.partialBuildSpec = props.partialBuildSpec; + this._partialBuildSpec = props.partialBuildSpec; this.vpc = props.vpc; this.subnetSelection = props.subnetSelection; this.role = props.role; @@ -198,6 +207,58 @@ export class CodeBuildStep extends ShellStep { return this.project.grantPrincipal; } + /** + * Additional configuration that can only be configured via BuildSpec + * + * Contains exported variables + * + * @default - Contains the exported variables + */ + public get partialBuildSpec(): codebuild.BuildSpec | undefined { + this.exportedVarsRendered = true; + + const varsBuildSpec = this.exportedVariables.size > 0 ? codebuild.BuildSpec.fromObject({ + version: '0.2', + env: { + 'exported-variables': Array.from(this.exportedVariables), + }, + }) : undefined; + + return mergeBuildSpecs(varsBuildSpec, this._partialBuildSpec); + } + + /** + * Reference a CodePipeline variable defined by the CodeBuildStep. + * + * The variable must be set in the shell of the CodeBuild step when + * it finishes its `post_build` phase. + * + * @param variableName the name of the variable for reference. + * @example + * // Access the output of one CodeBuildStep in another CodeBuildStep + * declare const pipeline: pipelines.CodePipeline; + * + * const step1 = new pipelines.CodeBuildStep('Step1', { + * commands: ['export MY_VAR=hello'], + * }); + * + * const step2 = new pipelines.CodeBuildStep('Step2', { + * env: { + * IMPORTED_VAR: step1.exportedVariable('MY_VAR'), + * }, + * commands: ['echo $IMPORTED_VAR'], + * }); + */ + public exportedVariable(variableName: string): string { + if (this.exportedVarsRendered && !this.exportedVariables.has(variableName)) { + throw new Error('exportVariable(): Pipeline has already been produced, cannot call this function anymore'); + } + + this.exportedVariables.add(variableName); + + return makeCodePipelineOutput(this, variableName); + } + /** * Set the internal project value * diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-action-factory.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-action-factory.ts index 62c9fa86d025b..734c2fefa0128 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-action-factory.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-action-factory.ts @@ -23,6 +23,15 @@ export interface ProduceActionOptions { */ readonly runOrder: number; + /** + * If this step is producing outputs, the variables namespace assigned to it + * + * Pass this on to the Action you are creating. + * + * @default - Step doesn't produce any outputs + */ + readonly variablesNamespace?: string; + /** * Helper object to translate FileSets to CodePipeline Artifacts */ @@ -87,6 +96,8 @@ export interface ICodePipelineActionFactory { export interface CodePipelineActionFactoryResult { /** * How many RunOrders were consumed + * + * If you add 1 action, return the value 1 here. */ readonly runOrdersConsumed: number; diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-source.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-source.ts index dd40d0d6cf0e7..ef5f7479c66b5 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-source.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-source.ts @@ -3,12 +3,14 @@ import * as cp from '@aws-cdk/aws-codepipeline'; import { Artifact } from '@aws-cdk/aws-codepipeline'; import * as cp_actions from '@aws-cdk/aws-codepipeline-actions'; import { Action, CodeCommitTrigger, GitHubTrigger, S3Trigger } from '@aws-cdk/aws-codepipeline-actions'; +import { IRepository } from '@aws-cdk/aws-ecr'; import * as iam from '@aws-cdk/aws-iam'; import { IBucket } from '@aws-cdk/aws-s3'; -import { SecretValue, Token } from '@aws-cdk/core'; +import { Fn, SecretValue, Token } from '@aws-cdk/core'; import { Node } from 'constructs'; import { FileSet, Step } from '../blueprint'; import { CodePipelineActionFactoryResult, ProduceActionOptions, ICodePipelineActionFactory } from './codepipeline-action-factory'; +import { makeCodePipelineOutput } from './private/outputs'; /** * Factory for CodePipeline source steps @@ -56,6 +58,22 @@ export abstract class CodePipelineSource extends Step implements ICodePipelineAc return new S3Source(bucket, objectKey, props); } + /** + * Returns an ECR source. + * + * @param repository The repository that will be watched for changes. + * @param props The options, which include the image tag to be checked for changes. + * + * @example + * declare const repository: ecr.IRepository; + * pipelines.CodePipelineSource.ecr(repository, { + * imageTag: 'latest', + * }); + */ + public static ecr(repository: IRepository, props: ECRSourceOptions = {}): CodePipelineSource { + return new ECRSource(repository, props); + } + /** * Returns a CodeStar connection source. A CodeStar connection allows AWS CodePipeline to * access external resources, such as repositories in GitHub, GitHub Enterprise or @@ -104,12 +122,67 @@ export abstract class CodePipelineSource extends Step implements ICodePipelineAc public produceAction(stage: cp.IStage, options: ProduceActionOptions): CodePipelineActionFactoryResult { const output = options.artifacts.toCodePipeline(this.primaryOutput!); - const action = this.getAction(output, options.actionName, options.runOrder); + + const action = this.getAction(output, options.actionName, options.runOrder, options.variablesNamespace); stage.addAction(action); return { runOrdersConsumed: 1 }; } - protected abstract getAction(output: Artifact, actionName: string, runOrder: number): Action; + protected abstract getAction(output: Artifact, actionName: string, runOrder: number, variablesNamespace?: string): Action; + + /** + * Return an attribute of the current source revision + * + * These values can be passed into the environment variables of pipeline steps, + * so your steps can access information about the source revision. + * + * Pipeline synth step has some source attributes predefined in the environment. + * If these suffice, you don't need to use this method for the synth step. + * @see https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html + * + * What attributes are available depends on the type of source. These attributes + * are supported: + * + * - GitHub, CodeCommit, and CodeStarSourceConnection + * - `AuthorDate` + * - `BranchName` + * - `CommitId` + * - `CommitMessage` + * - GitHub, CodeCommit and ECR + * - `RepositoryName` + * - GitHub and CodeCommit + * - `CommitterDate` + * - GitHub + * - `CommitUrl` + * - CodeStarSourceConnection + * - `FullRepositoryName` + * - S3 + * - `ETag` + * - `VersionId` + * - ECR + * - `ImageDigest` + * - `ImageTag` + * - `ImageURI` + * - `RegistryId` + * + * @see https://docs.aws.amazon.com/codepipeline/latest/userguide/reference-variables.html#reference-variables-list + * @example + * // Access the CommitId of a GitHub source in the synth + * const source = pipelines.CodePipelineSource.gitHub('owner/repo', 'main'); + * + * const pipeline = new pipelines.CodePipeline(scope, 'MyPipeline', { + * synth: new pipelines.ShellStep('Synth', { + * input: source, + * commands: [], + * env: { + * 'COMMIT_ID': source.sourceAttribute('CommitId'), + * } + * }) + * }); + */ + public sourceAttribute(name: string): string { + return makeCodePipelineOutput(this, name); + } } /** @@ -173,7 +246,7 @@ class GitHubSource extends CodePipelineSource { this.configurePrimaryOutput(new FileSet('Source', this)); } - protected getAction(output: Artifact, actionName: string, runOrder: number) { + protected getAction(output: Artifact, actionName: string, runOrder: number, variablesNamespace?: string) { return new cp_actions.GitHubSourceAction({ output, actionName, @@ -183,6 +256,7 @@ class GitHubSource extends CodePipelineSource { repo: this.repo, branch: this.branch, trigger: this.props.trigger, + variablesNamespace, }); } } @@ -216,7 +290,7 @@ class S3Source extends CodePipelineSource { this.configurePrimaryOutput(new FileSet('Source', this)); } - protected getAction(output: Artifact, _actionName: string, runOrder: number) { + protected getAction(output: Artifact, _actionName: string, runOrder: number, variablesNamespace?: string) { return new cp_actions.S3SourceAction({ output, // Bucket names are guaranteed to conform to ActionName restrictions @@ -225,6 +299,47 @@ class S3Source extends CodePipelineSource { bucketKey: this.objectKey, trigger: this.props.trigger, bucket: this.bucket, + variablesNamespace, + }); + } +} + +/** + * Options for ECR sources + */ +export interface ECRSourceOptions { + /** + * The image tag that will be checked for changes. + * + * @default latest + */ + readonly imageTag?: string; + + /** + * The action name used for this source in the CodePipeline + * + * @default - The repository name + */ + readonly actionName?: string; +} + +class ECRSource extends CodePipelineSource { + constructor(readonly repository: IRepository, readonly props: ECRSourceOptions) { + super(Node.of(repository).addr); + + this.configurePrimaryOutput(new FileSet('Source', this)); + } + + protected getAction(output: Artifact, _actionName: string, runOrder: number, variablesNamespace: string) { + // RepositoryName can contain '/' that is not a valid ActionName character, use '_' instead + const formattedRepositoryName = Fn.join('_', Fn.split('/', this.repository.repositoryName)); + return new cp_actions.EcrSourceAction({ + output, + actionName: this.props.actionName ?? formattedRepositoryName, + runOrder, + repository: this.repository, + imageTag: this.props.imageTag, + variablesNamespace, }); } } @@ -284,7 +399,7 @@ class CodeStarConnectionSource extends CodePipelineSource { this.configurePrimaryOutput(new FileSet('Source', this)); } - protected getAction(output: Artifact, actionName: string, runOrder: number) { + protected getAction(output: Artifact, actionName: string, runOrder: number, variablesNamespace?: string) { return new cp_actions.CodeStarConnectionsSourceAction({ output, actionName, @@ -295,6 +410,7 @@ class CodeStarConnectionSource extends CodePipelineSource { branch: this.branch, codeBuildCloneOutput: this.props.codeBuildCloneOutput, triggerOnPush: this.props.triggerOnPush, + variablesNamespace, }); } } @@ -341,7 +457,7 @@ class CodeCommitSource extends CodePipelineSource { this.configurePrimaryOutput(new FileSet('Source', this)); } - protected getAction(output: Artifact, _actionName: string, runOrder: number) { + protected getAction(output: Artifact, _actionName: string, runOrder: number, variablesNamespace?: string) { return new cp_actions.CodeCommitSourceAction({ output, // Guaranteed to be okay as action name @@ -352,6 +468,7 @@ class CodeCommitSource extends CodePipelineSource { repository: this.repository, eventRole: this.props.eventRole, codeBuildCloneOutput: this.props.codeBuildCloneOutput, + variablesNamespace, }); } } diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts index 0beae3ea56fa1..84562b07aec8b 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts @@ -18,10 +18,11 @@ import { toPosixPath } from '../private/fs'; import { actionName, stackVariableNamespace } from '../private/identifiers'; import { enumerate, flatten, maybeSuffix, noUndefined } from '../private/javascript'; import { writeTemplateConfiguration } from '../private/template-configuration'; -import { CodeBuildFactory, mergeCodeBuildOptions } from './_codebuild-factory'; import { ArtifactMap } from './artifact-map'; import { CodeBuildStep } from './codebuild-step'; import { CodePipelineActionFactoryResult, ICodePipelineActionFactory } from './codepipeline-action-factory'; +import { CodeBuildFactory, mergeCodeBuildOptions } from './private/codebuild-factory'; +import { namespaceStepOutputs } from './private/outputs'; /** @@ -418,9 +419,14 @@ export class CodePipeline extends PipelineBase { const factory = this.actionFromNode(node); const nodeType = this.nodeTypeFromNode(node); + const name = actionName(node, sharedParent); + + const variablesNamespace = node.data?.type === 'step' + ? namespaceStepOutputs(node.data.step, pipelineStage, name) + : undefined; const result = factory.produceAction(pipelineStage, { - actionName: actionName(node, sharedParent), + actionName: name, runOrder, artifacts: this.artifacts, scope: obtainScope(this.pipeline, stageName), @@ -429,6 +435,7 @@ export class CodePipeline extends PipelineBase { // If this step happens to produce a CodeBuild job, set the default options codeBuildDefaults: nodeType ? this.codeBuildDefaultsFor(nodeType) : undefined, beforeSelfMutation, + variablesNamespace, }); if (node.data?.type === 'self-update') { diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/private/buildspecs.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/private/buildspecs.ts new file mode 100644 index 0000000000000..f904d7c174629 --- /dev/null +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/private/buildspecs.ts @@ -0,0 +1,10 @@ +import * as codebuild from '@aws-cdk/aws-codebuild'; + +export function mergeBuildSpecs(a: codebuild.BuildSpec, b?: codebuild.BuildSpec): codebuild.BuildSpec; +export function mergeBuildSpecs(a: codebuild.BuildSpec | undefined, b: codebuild.BuildSpec): codebuild.BuildSpec; +export function mergeBuildSpecs(a?: codebuild.BuildSpec, b?: codebuild.BuildSpec): codebuild.BuildSpec | undefined; +export function mergeBuildSpecs(a?: codebuild.BuildSpec, b?: codebuild.BuildSpec) { + if (!a || !b) { return a ?? b; } + return codebuild.mergeBuildSpecs(a, b); +} + diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/_codebuild-factory.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts similarity index 94% rename from packages/@aws-cdk/pipelines/lib/codepipeline/_codebuild-factory.ts rename to packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts index 3414554cd5197..84a0cf934a4ca 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/_codebuild-factory.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts @@ -7,15 +7,17 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import { IDependable, Stack, Token } from '@aws-cdk/core'; import { Construct, Node } from 'constructs'; -import { FileSetLocation, ShellStep, StackOutputReference } from '../blueprint'; -import { PipelineQueries } from '../helpers-internal/pipeline-queries'; -import { cloudAssemblyBuildSpecDir, obtainScope } from '../private/construct-internals'; -import { hash, stackVariableNamespace } from '../private/identifiers'; -import { mapValues, mkdict, noEmptyObject, noUndefined, partition } from '../private/javascript'; -import { ArtifactMap } from './artifact-map'; -import { CodeBuildStep } from './codebuild-step'; -import { CodeBuildOptions } from './codepipeline'; -import { ICodePipelineActionFactory, ProduceActionOptions, CodePipelineActionFactoryResult } from './codepipeline-action-factory'; +import { FileSetLocation, ShellStep, StackOutputReference } from '../../blueprint'; +import { PipelineQueries } from '../../helpers-internal/pipeline-queries'; +import { StepOutput } from '../../helpers-internal/step-output'; +import { cloudAssemblyBuildSpecDir, obtainScope } from '../../private/construct-internals'; +import { hash, stackVariableNamespace } from '../../private/identifiers'; +import { mapValues, mkdict, noEmptyObject, noUndefined, partition } from '../../private/javascript'; +import { ArtifactMap } from '../artifact-map'; +import { CodeBuildStep } from '../codebuild-step'; +import { CodeBuildOptions } from '../codepipeline'; +import { ICodePipelineActionFactory, ProduceActionOptions, CodePipelineActionFactoryResult } from '../codepipeline-action-factory'; +import { mergeBuildSpecs } from './buildspecs'; export interface CodeBuildFactoryProps { /** @@ -110,6 +112,11 @@ export interface CodeBuildFactoryProps { * @default false */ readonly isSynth?: boolean; + + /** + * StepOutputs produced by this CodeBuild step + */ + readonly producedStepOutputs?: StepOutput[]; } /** @@ -129,6 +136,7 @@ export class CodeBuildFactory implements ICodePipelineActionFactory { outputs: shellStep.outputs, stepId: shellStep.id, installCommands: shellStep.installCommands, + producedStepOutputs: StepOutput.producedStepOutputs(shellStep), ...additional, }); } @@ -314,6 +322,7 @@ export class CodeBuildFactory implements ICodePipelineActionFactory { outputs: outputArtifacts, project, runOrder: options.runOrder, + variablesNamespace: options.variablesNamespace, // Inclusion of the hash here will lead to the pipeline structure for any changes // made the config of the underlying CodeBuild Project. @@ -421,14 +430,6 @@ function mergeBuildEnvironments(a?: codebuild.BuildEnvironment, b?: codebuild.Bu }; } -export function mergeBuildSpecs(a: codebuild.BuildSpec, b?: codebuild.BuildSpec): codebuild.BuildSpec; -export function mergeBuildSpecs(a: codebuild.BuildSpec | undefined, b: codebuild.BuildSpec): codebuild.BuildSpec; -export function mergeBuildSpecs(a?: codebuild.BuildSpec, b?: codebuild.BuildSpec): codebuild.BuildSpec | undefined; -export function mergeBuildSpecs(a?: codebuild.BuildSpec, b?: codebuild.BuildSpec) { - if (!a || !b) { return a ?? b; } - return codebuild.mergeBuildSpecs(a, b); -} - function isDefined(x: A | undefined): x is NonNullable { return x !== undefined; } @@ -452,7 +453,7 @@ function serializeBuildEnvironment(env: codebuild.BuildEnvironment) { * Whether the given string contains a reference to a CodePipeline variable */ function containsPipelineVariable(s: string) { - return !!s.match(/#\{[^}]+\}/); + return !!s.match(/#\{[^}]+\}/) || StepOutput.findAll(s).length > 0; } /** @@ -507,4 +508,4 @@ function filterBuildSpecCommands(buildSpec: codebuild.BuildSpec, osType: ec2.Ope } return [undefined, x]; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/private/outputs.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/private/outputs.ts new file mode 100644 index 0000000000000..f721cb3e5212e --- /dev/null +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/private/outputs.ts @@ -0,0 +1,38 @@ +import * as cp from '@aws-cdk/aws-codepipeline'; +import { Step } from '../../blueprint/step'; +import { StepOutput } from '../../helpers-internal'; + +const CODEPIPELINE_ENGINE_NAME = 'codepipeline'; + +export function makeCodePipelineOutput(step: Step, variableName: string) { + return new StepOutput(step, CODEPIPELINE_ENGINE_NAME, variableName).toString(); +} + +/** + * If the step is producing outputs, determine a variableNamespace for it, and configure that on the outputs + */ +export function namespaceStepOutputs(step: Step, stage: cp.IStage, name: string): string | undefined { + let ret: string | undefined; + for (const output of StepOutput.producedStepOutputs(step)) { + ret = namespaceName(stage, name); + if (output.engineName !== CODEPIPELINE_ENGINE_NAME) { + throw new Error(`Found unrecognized output type: ${output.engineName}`); + } + + if (typeof output.engineSpecificInformation !== 'string') { + throw new Error(`CodePipeline requires that 'engineSpecificInformation' is a string, got: ${JSON.stringify(output.engineSpecificInformation)}`); + } + output.defineResolution(`#{${ret}.${output.engineSpecificInformation}}`); + } + return ret; +} + +/** + * Generate a variable namespace from stage and action names + * + * Variable namespaces cannot have '.', but they can have '@'. Other than that, + * action names are more limited so they translate easily. + */ +export function namespaceName(stage: cp.IStage, name: string) { + return `${stage.stageName}/${name}`.replace(/[^a-zA-Z0-9@_-]/g, '@'); +} \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/lib/helpers-internal/index.ts b/packages/@aws-cdk/pipelines/lib/helpers-internal/index.ts index 6709f7c84488f..8f081e10d88d8 100644 --- a/packages/@aws-cdk/pipelines/lib/helpers-internal/index.ts +++ b/packages/@aws-cdk/pipelines/lib/helpers-internal/index.ts @@ -1,2 +1,3 @@ export * from './pipeline-graph'; -export * from './graph'; \ No newline at end of file +export * from './graph'; +export * from './step-output'; \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/lib/helpers-internal/step-output.ts b/packages/@aws-cdk/pipelines/lib/helpers-internal/step-output.ts new file mode 100644 index 0000000000000..1ac53575acafe --- /dev/null +++ b/packages/@aws-cdk/pipelines/lib/helpers-internal/step-output.ts @@ -0,0 +1,160 @@ +import { IResolvable, IResolveContext, Token, Tokenization } from '@aws-cdk/core'; +import { Step } from '../blueprint/step'; + + +const STEP_OUTPUT_SYM = Symbol.for('@aws-cdk/pipelines.StepOutput'); + +const PRODUCED_OUTPUTS_SYM = Symbol.for('@aws-cdk/pipelines.outputs'); + + +/** + * A symbolic reference to a value produced by another step + * + * Generating and consuming outputs is engine-specific. Many engines will be + * able to support a feature like "outputs", but it's not guaranteed that + * all of them will. + * + * Outputs can only be generated by engine-specific steps (CodeBuildStep instead + * of ShellStep, etc), but can (currently) be consumed anywhere(*). When + * an engine-specific step generates an Output, it should put a well-known + * string and arbitrary data that is useful to the engine into the engine-specific + * fields on the StepOutput. + * + * The graph blueprint will take care of dependencies and ordering, the engine + * is responsible interpreting and rendering StepOutputs. The engine should call + * `defineResolution()` on all outputs. + * + * StepOutputs currently purposely aren't part of the public API because users + * shouldn't see the innards poking out. So, instead of keeping state on `Step`, + * we keep side-state here in a WeakMap which can be accessed via static members + * on `StepOutput`. + * + * (*) If we need to restrict this, we add the checking and erroring in the engine. + */ +export class StepOutput implements IResolvable { + /** + * Return true if the given IResolvable is a StepOutput + */ + public static isStepOutput(resolvable: IResolvable): resolvable is StepOutput { + return !!(resolvable as any)[STEP_OUTPUT_SYM]; + } + + /** + * Find all StepOutputs referenced in the given structure + */ + public static findAll(structure: any): StepOutput[] { + return findAllStepOutputs(structure); + } + + /** + * Return the produced outputs for the given step + */ + public static producedStepOutputs(step: Step): StepOutput[] { + return (step as any)[PRODUCED_OUTPUTS_SYM] ?? []; + } + + /** + * Add produced outputs for the given step + */ + public static recordProducer(...outputs: StepOutput[]) { + for (const output of outputs) { + const step = output.step; + let list = (step as any)[PRODUCED_OUTPUTS_SYM]; + if (!list) { + list = []; + (step as any)[PRODUCED_OUTPUTS_SYM] = list; + } + list.push(...outputs); + } + } + + /** + * The step that produces this output + */ + public readonly step: Step; + + /** + * Name of the engine for which this output is intended + */ + public readonly engineName: string; + + /** + * Additional data on the output, to be interpreted by the engine + */ + public readonly engineSpecificInformation: any; + + public readonly creationStack: string[] = []; + private resolution: any = undefined; + + constructor(step: Step, engineName: string, engineSpecificInformation: any) { + this.step = step; + this.engineName = engineName; + this.engineSpecificInformation = engineSpecificInformation; + Object.defineProperty(this, STEP_OUTPUT_SYM, { value: true }); + } + + /** + * Define the resolved value for this StepOutput. + * + * Should be called by the engine. + */ + public defineResolution(value: any) { + this.resolution = value; + } + + public resolve(_context: IResolveContext) { + if (this.resolution === undefined) { + throw new Error(`Output for step ${this.step} not configured. Either the step is not in the pipeline, the step implementation did not call 'this.discoverReferencedOutputs()', or this engine does not support Outputs for this step.`); + } + return this.resolution; + } + + public toString(): string { + return Token.asString(this); + } +} + +function findAllStepOutputs(structure: any): StepOutput[] { + const ret = new Set(); + recurse(structure); + return Array.from(ret); + + function checkToken(x?: IResolvable) { + if (x && StepOutput.isStepOutput(x)) { + ret.add(x); + return true; + } + + // Return false if it wasn't a Token in the first place (in which case we recurse) + return x !== undefined; + } + + function recurse(x: any): void { + if (!x) { return; } + + if (Tokenization.isResolvable(x)) { + checkToken(x); + return; + } + if (Array.isArray(x)) { + if (!checkToken(Tokenization.reverseList(x))) { + x.forEach(recurse); + } + return; + } + if (typeof x === 'number') { + checkToken(Tokenization.reverseNumber(x)); + return; + } + if (typeof x === 'string') { + Tokenization.reverseString(x).tokens.forEach(checkToken); + return; + } + if (typeof x === 'object') { + for (const [k, v] of Object.entries(x)) { + recurse(k); + recurse(v); + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/package.json b/packages/@aws-cdk/pipelines/package.json index 1249fa706977b..53fd337d2df98 100644 --- a/packages/@aws-cdk/pipelines/package.json +++ b/packages/@aws-cdk/pipelines/package.json @@ -48,7 +48,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "aws-sdk": "^2.848.0" }, "peerDependencies": { diff --git a/packages/@aws-cdk/pipelines/test/codepipeline/codebuild-step.test.ts b/packages/@aws-cdk/pipelines/test/codepipeline/codebuild-step.test.ts index 393f1ffb965ba..5b9538a5a4d00 100644 --- a/packages/@aws-cdk/pipelines/test/codepipeline/codebuild-step.test.ts +++ b/packages/@aws-cdk/pipelines/test/codepipeline/codebuild-step.test.ts @@ -141,4 +141,70 @@ test('envFromOutputs works even with very long stage and stack names', () => { }); // THEN - did not throw an error about identifier lengths +}); + +test('exportedVariables', () => { + const pipeline = new ModernTestGitHubNpmPipeline(pipelineStack, 'Cdk'); + + // GIVEN + const producer = new cdkp.CodeBuildStep('Produce', { + commands: ['export MY_VAR=hello'], + }); + + const consumer = new cdkp.CodeBuildStep('Consume', { + env: { + THE_VAR: producer.exportedVariable('MY_VAR'), + }, + commands: [ + 'echo "The variable was: $THE_VAR"', + ], + }); + + // WHEN + pipeline.addWave('MyWave', { + post: [consumer, producer], + }); + + // THEN + const template = Template.fromStack(pipelineStack); + template.hasResourceProperties('AWS::CodePipeline::Pipeline', { + Stages: [ + { Name: 'Source' }, + { Name: 'Build' }, + { Name: 'UpdatePipeline' }, + { + Name: 'MyWave', + Actions: [ + Match.objectLike({ + Name: 'Produce', + Namespace: 'MyWave@Produce', + RunOrder: 1, + }), + Match.objectLike({ + Name: 'Consume', + RunOrder: 2, + Configuration: Match.objectLike({ + EnvironmentVariables: Match.serializedJson(Match.arrayWith([ + { + name: 'THE_VAR', + type: 'PLAINTEXT', + value: '#{MyWave@Produce.MY_VAR}', + }, + ])), + }), + }), + ], + }, + ], + }); + + template.hasResourceProperties('AWS::CodeBuild::Project', { + Source: { + BuildSpec: Match.serializedJson(Match.objectLike({ + env: { + 'exported-variables': ['MY_VAR'], + }, + })), + }, + }); }); \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/test/codepipeline/codepipeline-sources.test.ts b/packages/@aws-cdk/pipelines/test/codepipeline/codepipeline-sources.test.ts index 46fb468c37623..93284d031d11c 100644 --- a/packages/@aws-cdk/pipelines/test/codepipeline/codepipeline-sources.test.ts +++ b/packages/@aws-cdk/pipelines/test/codepipeline/codepipeline-sources.test.ts @@ -1,6 +1,7 @@ import { Capture, Match, Template } from '@aws-cdk/assertions'; import * as ccommit from '@aws-cdk/aws-codecommit'; import { CodeCommitTrigger, GitHubTrigger } from '@aws-cdk/aws-codepipeline-actions'; +import * as ecr from '@aws-cdk/aws-ecr'; import { AnyPrincipal, Role } from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import { SecretValue, Stack, Token } from '@aws-cdk/core'; @@ -75,9 +76,9 @@ test('CodeCommit source honors all valid properties', () => { }); test('S3 source handles tokenized names correctly', () => { - const buckit = new s3.Bucket(pipelineStack, 'Buckit'); + const bucket = new s3.Bucket(pipelineStack, 'Bucket'); new ModernTestGitHubNpmPipeline(pipelineStack, 'Pipeline', { - input: cdkp.CodePipelineSource.s3(buckit, 'thefile.zip'), + input: cdkp.CodePipelineSource.s3(bucket, 'thefile.zip'), }); Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', { @@ -96,6 +97,40 @@ test('S3 source handles tokenized names correctly', () => { }); }); +test('ECR source handles tokenized and namespaced names correctly', () => { + const repository = new ecr.Repository(pipelineStack, 'Repository', { repositoryName: 'namespace/repo' }); + new ModernTestGitHubNpmPipeline(pipelineStack, 'Pipeline', { + input: cdkp.CodePipelineSource.ecr(repository), + }); + + const template = Template.fromStack(pipelineStack); + template.hasResourceProperties('AWS::CodePipeline::Pipeline', { + Stages: Match.arrayWith([{ + Name: 'Source', + Actions: [ + Match.objectLike({ + Configuration: Match.objectLike({ + RepositoryName: { Ref: Match.anyValue() }, + }), + Name: Match.objectLike({ + 'Fn::Join': [ + '_', + { + 'Fn::Split': [ + '/', + { + Ref: Match.anyValue(), + }, + ], + }, + ], + }), + }), + ], + }]), + }); +}); + test('GitHub source honors all valid properties', () => { new ModernTestGitHubNpmPipeline(pipelineStack, 'Pipeline', { input: cdkp.CodePipelineSource.gitHub('owner/repo', 'main', { @@ -178,4 +213,45 @@ test('artifact names are never longer than 128 characters', () => { }); expect(artifactId.asString().length).toBeLessThanOrEqual(128); +}); + +test('can use source attributes in pipeline', () => { + const gitHub = cdkp.CodePipelineSource.gitHub('owner/my-repo', 'main'); + + // WHEN + new ModernTestGitHubNpmPipeline(pipelineStack, 'Pipeline', { + input: gitHub, + synth: new cdkp.ShellStep('Synth', { + env: { + GITHUB_URL: gitHub.sourceAttribute('CommitUrl'), + }, + commands: [ + 'echo "Click here: $GITHUB_URL"', + ], + }), + selfMutation: false, + }); + + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', { + Stages: [ + { Name: 'Source' }, + { + Name: 'Build', + Actions: [ + { + Name: 'Synth', + Configuration: Match.objectLike({ + EnvironmentVariables: Match.serializedJson([ + { + name: 'GITHUB_URL', + type: 'PLAINTEXT', + value: '#{Source@owner_my-repo.CommitUrl}', + }, + ]), + }), + }, + ], + }, + ], + }); }); \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/test/compliance/security-check.test.ts b/packages/@aws-cdk/pipelines/test/compliance/security-check.test.ts index d2ea77f45ff7d..f8c53a40e3e37 100644 --- a/packages/@aws-cdk/pipelines/test/compliance/security-check.test.ts +++ b/packages/@aws-cdk/pipelines/test/compliance/security-check.test.ts @@ -165,12 +165,28 @@ behavior('pipeline created with auto approve tags and lambda/codebuild w/ valid { Action: 'lambda:InvokeFunction', Effect: 'Allow', - Resource: { - 'Fn::GetAtt': [ - stringLike('*AutoApprove*'), - 'Arn', - ], - }, + Resource: [ + { + 'Fn::GetAtt': [ + stringLike('*AutoApprove*'), + 'Arn', + ], + }, + { + 'Fn::Join': [ + '', + [ + { + 'Fn::GetAtt': [ + stringLike('*AutoApprove*'), + 'Arn', + ], + }, + ':*', + ], + ], + }, + ], }, ]), }, diff --git a/packages/@aws-cdk/pipelines/test/integ.newpipeline-with-vpc.expected.json b/packages/@aws-cdk/pipelines/test/integ.newpipeline-with-vpc.expected.json index 4bd2e638afb4c..1f0deaf6dc981 100644 --- a/packages/@aws-cdk/pipelines/test/integ.newpipeline-with-vpc.expected.json +++ b/packages/@aws-cdk/pipelines/test/integ.newpipeline-with-vpc.expected.json @@ -580,8 +580,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -662,16 +662,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -700,69 +700,55 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineBuildSynthCodePipelineActionRole4E7A6C97", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineUpdatePipelineSelfMutateCodePipelineActionRoleD6D4E5CF", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineAssetsFileAsset1CodePipelineActionRoleC0EC649A", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineAssetsFileAsset2CodePipelineActionRole06965A59", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::", - { - "Ref": "AWS::AccountId" - }, - ":role/cdk-hnb659fds-deploy-role-", - { - "Ref": "AWS::AccountId" - }, - "-", - { - "Ref": "AWS::Region" - } + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineAssetsFileAsset1CodePipelineActionRoleC0EC649A", + "Arn" ] - ] - } + }, + { + "Fn::GetAtt": [ + "PipelineAssetsFileAsset2CodePipelineActionRole06965A59", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineBuildSynthCodePipelineActionRole4E7A6C97", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineUpdatePipelineSelfMutateCodePipelineActionRoleD6D4E5CF", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-", + { + "Ref": "AWS::Region" + } + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -1225,7 +1211,8 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" - } + }, + ":*" ] ] }, @@ -1240,8 +1227,7 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" - }, - ":*" + } ] ] } @@ -1249,11 +1235,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -1275,16 +1261,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -1402,11 +1388,11 @@ { "Action": [ "ec2:CreateNetworkInterface", - "ec2:DescribeNetworkInterfaces", "ec2:DeleteNetworkInterface", - "ec2:DescribeSubnets", - "ec2:DescribeSecurityGroups", "ec2:DescribeDhcpOptions", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", "ec2:DescribeVpcs" ], "Effect": "Allow", @@ -1796,7 +1782,8 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" - } + }, + ":*" ] ] }, @@ -1811,8 +1798,7 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" - }, - ":*" + } ] ] } @@ -1820,11 +1806,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -1859,19 +1845,17 @@ "Resource": "arn:*:iam::12345678:role/*" }, { - "Action": "cloudformation:DescribeStacks", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "s3:ListBucket", + "Action": [ + "cloudformation:DescribeStacks", + "s3:ListBucket" + ], "Effect": "Allow", "Resource": "*" }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -1990,11 +1974,11 @@ { "Action": [ "ec2:CreateNetworkInterface", - "ec2:DescribeNetworkInterfaces", "ec2:DeleteNetworkInterface", - "ec2:DescribeSubnets", - "ec2:DescribeSecurityGroups", "ec2:DescribeDhcpOptions", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", "ec2:DescribeVpcs" ], "Effect": "Allow", @@ -2016,13 +2000,6 @@ "Properties": { "AssumeRolePolicyDocument": { "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "codebuild.amazonaws.com" - } - }, { "Action": "sts:AssumeRole", "Effect": "Allow", @@ -2038,7 +2015,8 @@ ":iam::12345678:root" ] ] - } + }, + "Service": "codebuild.amazonaws.com" } } ], @@ -2073,11 +2051,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -2105,11 +2083,9 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": [ - { - "Fn::Sub": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" - } - ] + "Resource": { + "Fn::Sub": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } }, { "Action": "ec2:CreateNetworkInterfacePermission", @@ -2213,8 +2189,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -2333,11 +2309,11 @@ { "Action": [ "ec2:CreateNetworkInterface", - "ec2:DescribeNetworkInterfaces", "ec2:DeleteNetworkInterface", - "ec2:DescribeSubnets", - "ec2:DescribeSecurityGroups", "ec2:DescribeDhcpOptions", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", "ec2:DescribeVpcs" ], "Effect": "Allow", diff --git a/packages/@aws-cdk/pipelines/test/integ.newpipeline.expected.json b/packages/@aws-cdk/pipelines/test/integ.newpipeline.expected.json index 37cd5d99fd7f8..7914350f39b6f 100644 --- a/packages/@aws-cdk/pipelines/test/integ.newpipeline.expected.json +++ b/packages/@aws-cdk/pipelines/test/integ.newpipeline.expected.json @@ -66,8 +66,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -148,16 +148,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -186,49 +186,43 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineBuildSynthCodePipelineActionRole4E7A6C97", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineUpdatePipelineSelfMutateCodePipelineActionRoleD6D4E5CF", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::", - { - "Ref": "AWS::AccountId" - }, - ":role/cdk-hnb659fds-deploy-role-", - { - "Ref": "AWS::AccountId" - }, - "-", - { - "Ref": "AWS::Region" - } + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineBuildSynthCodePipelineActionRole4E7A6C97", + "Arn" ] - ] - } + }, + { + "Fn::GetAtt": [ + "PipelineUpdatePipelineSelfMutateCodePipelineActionRoleD6D4E5CF", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-", + { + "Ref": "AWS::Region" + } + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -1922,7 +1916,8 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" - } + }, + ":*" ] ] }, @@ -1937,8 +1932,7 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" - }, - ":*" + } ] ] } @@ -1946,11 +1940,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -1972,16 +1966,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -2205,7 +2199,8 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" - } + }, + ":*" ] ] }, @@ -2220,8 +2215,7 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" - }, - ":*" + } ] ] } @@ -2229,11 +2223,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -2268,19 +2262,17 @@ "Resource": "arn:*:iam::12345678:role/*" }, { - "Action": "cloudformation:DescribeStacks", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "s3:ListBucket", + "Action": [ + "cloudformation:DescribeStacks", + "s3:ListBucket" + ], "Effect": "Allow", "Resource": "*" }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-security.expected.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-security.expected.json index f9f2ec14d2199..1d9619be9c0c9 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-security.expected.json +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-security.expected.json @@ -139,8 +139,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -210,16 +210,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -250,8 +250,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -264,108 +264,74 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "TestPipelineBuildSynthCodePipelineActionRoleF7BF5926", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "TestPipelineUnattachedStageSingleStageSecurityCheckCodePipelineActionRoleFF6E43E2", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "TestPipelineUnattachedStageSingleStageManualApprovalCodePipelineActionRoleF7A614C8", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "TestPipelinePreProductionPreProductionSecurityCheckCodePipelineActionRole4E54C194", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "TestPipelinePreProductionPreProductionManualApprovalCodePipelineActionRole81B9C4F9", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "TestPipelinePreProductionSafeProductionSecurityCheckCodePipelineActionRole399C68A6", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "TestPipelinePreProductionSafeProductionManualApprovalCodePipelineActionRole4F30C0D9", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "TestPipelineNoSecurityCheckEnableSecurityCheckSecurityCheckCodePipelineActionRole8D10AA6D", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "TestPipelineNoSecurityCheckEnableSecurityCheckManualApprovalCodePipelineActionRole27FC4015", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region" + "Resource": [ + { + "Fn::GetAtt": [ + "TestPipelineBuildSynthCodePipelineActionRoleF7BF5926", + "Arn" ] - ] - } + }, + { + "Fn::GetAtt": [ + "TestPipelineNoSecurityCheckEnableSecurityCheckManualApprovalCodePipelineActionRole27FC4015", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "TestPipelineNoSecurityCheckEnableSecurityCheckSecurityCheckCodePipelineActionRole8D10AA6D", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "TestPipelinePreProductionPreProductionManualApprovalCodePipelineActionRole81B9C4F9", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "TestPipelinePreProductionPreProductionSecurityCheckCodePipelineActionRole4E54C194", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "TestPipelinePreProductionSafeProductionManualApprovalCodePipelineActionRole4F30C0D9", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "TestPipelinePreProductionSafeProductionSecurityCheckCodePipelineActionRole399C68A6", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "TestPipelineUnattachedStageSingleStageManualApprovalCodePipelineActionRoleF7A614C8", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "TestPipelineUnattachedStageSingleStageSecurityCheckCodePipelineActionRoleFF6E43E2", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -1259,7 +1225,8 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "TestPipelineBuildSynthCdkBuildProject755D4B01" - } + }, + ":*" ] ] }, @@ -1274,8 +1241,7 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "TestPipelineBuildSynthCdkBuildProject755D4B01" - }, - ":*" + } ] ] } @@ -1283,11 +1249,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -1309,16 +1275,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -1349,23 +1315,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "TestPipelineArtifactsBucketEncryptionKey13258842", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -1894,7 +1845,8 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "TestPipelinePipelineApplicationSecurityCheckCDKSecurityCheckBEE4547C" - } + }, + ":*" ] ] }, @@ -1909,8 +1861,7 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "TestPipelinePipelineApplicationSecurityCheckCDKSecurityCheckBEE4547C" - }, - ":*" + } ] ] } @@ -1918,11 +1869,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -1957,12 +1908,28 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "TestPipelinePipelineApplicationSecurityCheckCDKPipelinesAutoApprove1EE0AA81", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "TestPipelinePipelineApplicationSecurityCheckCDKPipelinesAutoApprove1EE0AA81", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "TestPipelinePipelineApplicationSecurityCheckCDKPipelinesAutoApprove1EE0AA81", + "Arn" + ] + }, + ":*" + ] + ] + } + ] }, { "Action": "sns:Publish", @@ -1973,8 +1940,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -2004,22 +1971,10 @@ { "Action": [ "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "TestPipelineArtifactsBucketEncryptionKey13258842", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", + "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -2208,7 +2163,8 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "UnattachedStageStageApplicationSecurityCheckCDKSecurityCheckADCE795B" - } + }, + ":*" ] ] }, @@ -2223,8 +2179,7 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "UnattachedStageStageApplicationSecurityCheckCDKSecurityCheckADCE795B" - }, - ":*" + } ] ] } @@ -2232,11 +2187,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -2271,12 +2226,28 @@ { "Action": "lambda:InvokeFunction", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "UnattachedStageStageApplicationSecurityCheckCDKPipelinesAutoApprove249F82F9", - "Arn" - ] - } + "Resource": [ + { + "Fn::GetAtt": [ + "UnattachedStageStageApplicationSecurityCheckCDKPipelinesAutoApprove249F82F9", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "UnattachedStageStageApplicationSecurityCheckCDKPipelinesAutoApprove249F82F9", + "Arn" + ] + }, + ":*" + ] + ] + } + ] }, { "Action": "sns:Publish", @@ -2287,8 +2258,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -2318,22 +2289,10 @@ { "Action": [ "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "TestPipelineArtifactsBucketEncryptionKey13258842", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", + "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets-single-upload.expected.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets-single-upload.expected.json index 26cecb377ee68..cd761893998ed 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets-single-upload.expected.json +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets-single-upload.expected.json @@ -139,8 +139,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -210,16 +210,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -250,8 +250,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -264,58 +264,44 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineBuildSynthCodePipelineActionRole4E7A6C97", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineUpdatePipelineSelfMutateCodePipelineActionRoleD6D4E5CF", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineAssetsFileRole59943A77", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelinePreProdUseSourceCodePipelineActionRoleA2043BDA", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region" + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineAssetsFileRole59943A77", + "Arn" ] - ] - } + }, + { + "Fn::GetAtt": [ + "PipelineBuildSynthCodePipelineActionRole4E7A6C97", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelinePreProdUseSourceCodePipelineActionRoleA2043BDA", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineUpdatePipelineSelfMutateCodePipelineActionRoleD6D4E5CF", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -695,7 +681,8 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" - } + }, + ":*" ] ] }, @@ -710,8 +697,7 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" - }, - ":*" + } ] ] } @@ -719,11 +705,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -745,16 +731,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -785,23 +771,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineArtifactsBucketEncryptionKeyF5BF0670", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -1021,7 +992,8 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelinePreProdUseSourceProject2E711EB4" - } + }, + ":*" ] ] }, @@ -1036,8 +1008,7 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelinePreProdUseSourceProject2E711EB4" - }, - ":*" + } ] ] } @@ -1045,11 +1016,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -1071,8 +1042,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -1102,22 +1073,10 @@ { "Action": [ "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineArtifactsBucketEncryptionKeyF5BF0670", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", + "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -1213,7 +1172,8 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" - } + }, + ":*" ] ] }, @@ -1228,8 +1188,7 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" - }, - ":*" + } ] ] } @@ -1237,11 +1196,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -1276,19 +1235,17 @@ "Resource": "arn:*:iam::12345678:role/*" }, { - "Action": "cloudformation:DescribeStacks", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "s3:ListBucket", + "Action": [ + "cloudformation:DescribeStacks", + "s3:ListBucket" + ], "Effect": "Allow", "Resource": "*" }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -1318,22 +1275,10 @@ { "Action": [ "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineArtifactsBucketEncryptionKeyF5BF0670", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", + "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -1393,13 +1338,6 @@ "Properties": { "AssumeRolePolicyDocument": { "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "codebuild.amazonaws.com" - } - }, { "Action": "sts:AssumeRole", "Effect": "Allow", @@ -1415,7 +1353,8 @@ ":iam::12345678:root" ] ] - } + }, + "Service": "codebuild.amazonaws.com" } } ], @@ -1450,11 +1389,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -1482,16 +1421,14 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": [ - { - "Fn::Sub": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-file-publishing-role-12345678-test-region" - } - ] + "Resource": { + "Fn::Sub": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-file-publishing-role-12345678-test-region" + } }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets.expected.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets.expected.json index c757e3097d633..89fe06e7c3e32 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets.expected.json +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets.expected.json @@ -139,8 +139,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -210,16 +210,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -250,8 +250,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -264,58 +264,44 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineBuildSynthCodePipelineActionRole4E7A6C97", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineUpdatePipelineSelfMutateCodePipelineActionRoleD6D4E5CF", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineAssetsFileRole59943A77", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelinePreProdUseSourceCodePipelineActionRoleA2043BDA", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region" + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineAssetsFileRole59943A77", + "Arn" ] - ] - } + }, + { + "Fn::GetAtt": [ + "PipelineBuildSynthCodePipelineActionRole4E7A6C97", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelinePreProdUseSourceCodePipelineActionRoleA2043BDA", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineUpdatePipelineSelfMutateCodePipelineActionRoleD6D4E5CF", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -722,7 +708,8 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" - } + }, + ":*" ] ] }, @@ -737,8 +724,7 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" - }, - ":*" + } ] ] } @@ -746,11 +732,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -772,16 +758,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -812,23 +798,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineArtifactsBucketEncryptionKeyF5BF0670", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -1048,7 +1019,8 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelinePreProdUseSourceProject2E711EB4" - } + }, + ":*" ] ] }, @@ -1063,8 +1035,7 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelinePreProdUseSourceProject2E711EB4" - }, - ":*" + } ] ] } @@ -1072,11 +1043,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -1098,8 +1069,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -1129,22 +1100,10 @@ { "Action": [ "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineArtifactsBucketEncryptionKeyF5BF0670", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", + "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -1240,7 +1199,8 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" - } + }, + ":*" ] ] }, @@ -1255,8 +1215,7 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" - }, - ":*" + } ] ] } @@ -1264,11 +1223,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -1303,19 +1262,17 @@ "Resource": "arn:*:iam::12345678:role/*" }, { - "Action": "cloudformation:DescribeStacks", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "s3:ListBucket", + "Action": [ + "cloudformation:DescribeStacks", + "s3:ListBucket" + ], "Effect": "Allow", "Resource": "*" }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -1345,22 +1302,10 @@ { "Action": [ "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineArtifactsBucketEncryptionKeyF5BF0670", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", + "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -1420,13 +1365,6 @@ "Properties": { "AssumeRolePolicyDocument": { "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "codebuild.amazonaws.com" - } - }, { "Action": "sts:AssumeRole", "Effect": "Allow", @@ -1442,7 +1380,8 @@ ":iam::12345678:root" ] ] - } + }, + "Service": "codebuild.amazonaws.com" } } ], @@ -1477,11 +1416,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -1509,16 +1448,14 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": [ - { - "Fn::Sub": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-file-publishing-role-12345678-test-region" - } - ] + "Resource": { + "Fn::Sub": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-file-publishing-role-12345678-test-region" + } }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-variables.expected.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-variables.expected.json new file mode 100644 index 0000000000000..49ac746217192 --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-variables.expected.json @@ -0,0 +1,1008 @@ +{ + "Resources": { + "PipelineArtifactsBucketAEA9A052": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "aws:kms" + } + } + ] + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "PipelineArtifactsBucketPolicyF53CCC52": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "PipelineArtifactsBucketAEA9A052" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineRoleB27FAA37": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "codepipeline.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineRoleDefaultPolicy7BDC1ABB": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:Abort*", + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*", + "s3:PutObject", + "s3:PutObjectLegalHold", + "s3:PutObjectRetention", + "s3:PutObjectTagging", + "s3:PutObjectVersionTagging" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineBuildSynthCodePipelineActionRole4E7A6C97", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineMyWaveConsumeCodePipelineActionRole7FAA4EFA", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineMyWaveProduceCodePipelineActionRoleE0DCE9D3", + "Arn" + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineRoleDefaultPolicy7BDC1ABB", + "Roles": [ + { + "Ref": "PipelineRoleB27FAA37" + } + ] + } + }, + "Pipeline9850B417": { + "Type": "AWS::CodePipeline::Pipeline", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "PipelineRoleB27FAA37", + "Arn" + ] + }, + "Stages": [ + { + "Actions": [ + { + "ActionTypeId": { + "Category": "Source", + "Owner": "ThirdParty", + "Provider": "GitHub", + "Version": "1" + }, + "Configuration": { + "Owner": "cdklabs", + "Repo": "construct-hub-probe", + "Branch": "main", + "OAuthToken": "{{resolve:secretsmanager:github-token:SecretString:::}}", + "PollForSourceChanges": true + }, + "Name": "cdklabs_construct-hub-probe", + "OutputArtifacts": [ + { + "Name": "cdklabs_construct_hub_probe_Source" + } + ], + "RunOrder": 1 + } + ], + "Name": "Source" + }, + { + "Actions": [ + { + "ActionTypeId": { + "Category": "Build", + "Owner": "AWS", + "Provider": "CodeBuild", + "Version": "1" + }, + "Configuration": { + "ProjectName": { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + } + }, + "InputArtifacts": [ + { + "Name": "cdklabs_construct_hub_probe_Source" + } + ], + "Name": "Synth", + "OutputArtifacts": [ + { + "Name": "Synth_Output" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "PipelineBuildSynthCodePipelineActionRole4E7A6C97", + "Arn" + ] + }, + "RunOrder": 1 + } + ], + "Name": "Build" + }, + { + "Actions": [ + { + "ActionTypeId": { + "Category": "Build", + "Owner": "AWS", + "Provider": "CodeBuild", + "Version": "1" + }, + "Configuration": { + "ProjectName": { + "Ref": "PipelineMyWaveProduce884410D6" + } + }, + "InputArtifacts": [ + { + "Name": "cdklabs_construct_hub_probe_Source" + } + ], + "Name": "Produce", + "Namespace": "MyWave@Produce", + "RoleArn": { + "Fn::GetAtt": [ + "PipelineMyWaveProduceCodePipelineActionRoleE0DCE9D3", + "Arn" + ] + }, + "RunOrder": 1 + }, + { + "ActionTypeId": { + "Category": "Build", + "Owner": "AWS", + "Provider": "CodeBuild", + "Version": "1" + }, + "Configuration": { + "ProjectName": { + "Ref": "PipelineMyWaveConsumeC5D5CCD7" + }, + "EnvironmentVariables": "[{\"name\":\"THE_VAR\",\"type\":\"PLAINTEXT\",\"value\":\"#{MyWave@Produce.MY_VAR}\"}]" + }, + "InputArtifacts": [ + { + "Name": "cdklabs_construct_hub_probe_Source" + } + ], + "Name": "Consume", + "RoleArn": { + "Fn::GetAtt": [ + "PipelineMyWaveConsumeCodePipelineActionRole7FAA4EFA", + "Arn" + ] + }, + "RunOrder": 2 + } + ], + "Name": "MyWave" + } + ], + "ArtifactStore": { + "Location": { + "Ref": "PipelineArtifactsBucketAEA9A052" + }, + "Type": "S3" + }, + "RestartExecutionOnUpdate": true + }, + "DependsOn": [ + "PipelineRoleDefaultPolicy7BDC1ABB", + "PipelineRoleB27FAA37" + ] + }, + "PipelineBuildSynthCdkBuildProjectRole231EEA2A": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "codebuild.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:test-region:12345678:log-group:/aws/codebuild/", + { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:test-region:12345678:log-group:/aws/codebuild/", + { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + } + ] + ] + } + ] + }, + { + "Action": [ + "codebuild:BatchPutCodeCoverages", + "codebuild:BatchPutTestCases", + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:test-region:12345678:report-group/", + { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + "-*" + ] + ] + } + }, + { + "Action": [ + "s3:Abort*", + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*", + "s3:PutObject", + "s3:PutObjectLegalHold", + "s3:PutObjectRetention", + "s3:PutObjectTagging", + "s3:PutObjectVersionTagging" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C", + "Roles": [ + { + "Ref": "PipelineBuildSynthCdkBuildProjectRole231EEA2A" + } + ] + } + }, + "PipelineBuildSynthCdkBuildProject6BEFA8E6": { + "Type": "AWS::CodeBuild::Project", + "Properties": { + "Artifacts": { + "Type": "CODEPIPELINE" + }, + "Environment": { + "ComputeType": "BUILD_GENERAL1_SMALL", + "Image": "aws/codebuild/standard:5.0", + "ImagePullCredentialsType": "CODEBUILD", + "PrivilegedMode": false, + "Type": "LINUX_CONTAINER" + }, + "ServiceRole": { + "Fn::GetAtt": [ + "PipelineBuildSynthCdkBuildProjectRole231EEA2A", + "Arn" + ] + }, + "Source": { + "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"build\": {\n \"commands\": [\n \"mkdir cdk.out\",\n \"touch cdk.out/dummy\"\n ]\n }\n },\n \"artifacts\": {\n \"base-directory\": \"cdk.out\",\n \"files\": \"**/*\"\n }\n}", + "Type": "CODEPIPELINE" + }, + "Cache": { + "Type": "NO_CACHE" + }, + "Description": "Pipeline step VariablePipelineStack/Pipeline/Build/Synth", + "EncryptionKey": "alias/aws/s3" + } + }, + "PipelineBuildSynthCodePipelineActionRole4E7A6C97": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::12345678:root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineBuildSynthCodePipelineActionRoleDefaultPolicy92C90290": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "codebuild:BatchGetBuilds", + "codebuild:StartBuild", + "codebuild:StopBuild" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineBuildSynthCdkBuildProject6BEFA8E6", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineBuildSynthCodePipelineActionRoleDefaultPolicy92C90290", + "Roles": [ + { + "Ref": "PipelineBuildSynthCodePipelineActionRole4E7A6C97" + } + ] + } + }, + "PipelineMyWaveProduceRole24E3565D": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "codebuild.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineMyWaveProduceRoleDefaultPolicy209239D4": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:test-region:12345678:log-group:/aws/codebuild/", + { + "Ref": "PipelineMyWaveProduce884410D6" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:test-region:12345678:log-group:/aws/codebuild/", + { + "Ref": "PipelineMyWaveProduce884410D6" + } + ] + ] + } + ] + }, + { + "Action": [ + "codebuild:BatchPutCodeCoverages", + "codebuild:BatchPutTestCases", + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:test-region:12345678:report-group/", + { + "Ref": "PipelineMyWaveProduce884410D6" + }, + "-*" + ] + ] + } + }, + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineMyWaveProduceRoleDefaultPolicy209239D4", + "Roles": [ + { + "Ref": "PipelineMyWaveProduceRole24E3565D" + } + ] + } + }, + "PipelineMyWaveProduce884410D6": { + "Type": "AWS::CodeBuild::Project", + "Properties": { + "Artifacts": { + "Type": "CODEPIPELINE" + }, + "Environment": { + "ComputeType": "BUILD_GENERAL1_SMALL", + "Image": "aws/codebuild/standard:5.0", + "ImagePullCredentialsType": "CODEBUILD", + "PrivilegedMode": false, + "Type": "LINUX_CONTAINER" + }, + "ServiceRole": { + "Fn::GetAtt": [ + "PipelineMyWaveProduceRole24E3565D", + "Arn" + ] + }, + "Source": { + "BuildSpec": "{\n \"version\": \"0.2\",\n \"env\": {\n \"exported-variables\": [\n \"MY_VAR\"\n ]\n },\n \"phases\": {\n \"build\": {\n \"commands\": [\n \"export MY_VAR=hello\"\n ]\n }\n }\n}", + "Type": "CODEPIPELINE" + }, + "Cache": { + "Type": "NO_CACHE" + }, + "Description": "Pipeline step VariablePipelineStack/Pipeline/MyWave/Produce", + "EncryptionKey": "alias/aws/s3" + } + }, + "PipelineMyWaveProduceCodePipelineActionRoleE0DCE9D3": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::12345678:root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineMyWaveProduceCodePipelineActionRoleDefaultPolicy34DCB79A": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "codebuild:BatchGetBuilds", + "codebuild:StartBuild", + "codebuild:StopBuild" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineMyWaveProduce884410D6", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineMyWaveProduceCodePipelineActionRoleDefaultPolicy34DCB79A", + "Roles": [ + { + "Ref": "PipelineMyWaveProduceCodePipelineActionRoleE0DCE9D3" + } + ] + } + }, + "PipelineMyWaveConsumeRole2A96FF33": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "codebuild.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineMyWaveConsumeRoleDefaultPolicyC80F0194": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:test-region:12345678:log-group:/aws/codebuild/", + { + "Ref": "PipelineMyWaveConsumeC5D5CCD7" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:test-region:12345678:log-group:/aws/codebuild/", + { + "Ref": "PipelineMyWaveConsumeC5D5CCD7" + } + ] + ] + } + ] + }, + { + "Action": [ + "codebuild:BatchPutCodeCoverages", + "codebuild:BatchPutTestCases", + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:test-region:12345678:report-group/", + { + "Ref": "PipelineMyWaveConsumeC5D5CCD7" + }, + "-*" + ] + ] + } + }, + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineMyWaveConsumeRoleDefaultPolicyC80F0194", + "Roles": [ + { + "Ref": "PipelineMyWaveConsumeRole2A96FF33" + } + ] + } + }, + "PipelineMyWaveConsumeC5D5CCD7": { + "Type": "AWS::CodeBuild::Project", + "Properties": { + "Artifacts": { + "Type": "CODEPIPELINE" + }, + "Environment": { + "ComputeType": "BUILD_GENERAL1_SMALL", + "Image": "aws/codebuild/standard:5.0", + "ImagePullCredentialsType": "CODEBUILD", + "PrivilegedMode": false, + "Type": "LINUX_CONTAINER" + }, + "ServiceRole": { + "Fn::GetAtt": [ + "PipelineMyWaveConsumeRole2A96FF33", + "Arn" + ] + }, + "Source": { + "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"build\": {\n \"commands\": [\n \"echo \\\"The variable was: $THE_VAR\\\"\"\n ]\n }\n }\n}", + "Type": "CODEPIPELINE" + }, + "Cache": { + "Type": "NO_CACHE" + }, + "Description": "Pipeline step VariablePipelineStack/Pipeline/MyWave/Consume", + "EncryptionKey": "alias/aws/s3" + } + }, + "PipelineMyWaveConsumeCodePipelineActionRole7FAA4EFA": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::12345678:root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineMyWaveConsumeCodePipelineActionRoleDefaultPolicy3666898A": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "codebuild:BatchGetBuilds", + "codebuild:StartBuild", + "codebuild:StopBuild" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineMyWaveConsumeC5D5CCD7", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineMyWaveConsumeCodePipelineActionRoleDefaultPolicy3666898A", + "Roles": [ + { + "Ref": "PipelineMyWaveConsumeCodePipelineActionRole7FAA4EFA" + } + ] + } + } + }, + "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/pipelines/test/integ.pipeline-with-variables.ts b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-variables.ts new file mode 100644 index 0000000000000..2a2351375ef62 --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-variables.ts @@ -0,0 +1,52 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +/// !cdk-integ VariablePipelineStack pragma:set-context:@aws-cdk/core:newStyleStackSynthesis=true +import { GitHubTrigger } from '@aws-cdk/aws-codepipeline-actions'; +import { App, Stack, StackProps } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import * as pipelines from '../lib'; + +class PipelineStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { + synth: new pipelines.ShellStep('Synth', { + input: pipelines.CodePipelineSource.gitHub('cdklabs/construct-hub-probe', 'main', { + trigger: GitHubTrigger.POLL, + }), + commands: ['mkdir cdk.out', 'touch cdk.out/dummy'], + }), + selfMutation: false, + }); + + const producer = new pipelines.CodeBuildStep('Produce', { + commands: ['export MY_VAR=hello'], + }); + + const consumer = new pipelines.CodeBuildStep('Consume', { + env: { + THE_VAR: producer.exportedVariable('MY_VAR'), + }, + commands: [ + 'echo "The variable was: $THE_VAR"', + ], + }); + + // WHEN + pipeline.addWave('MyWave', { + post: [consumer, producer], + }); + } +} + +const app = new App({ + context: { + '@aws-cdk/core:newStyleStackSynthesis': '1', + }, +}); + +new PipelineStack(app, 'VariablePipelineStack', { + env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION }, +}); + +app.synth(); \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline.expected.json b/packages/@aws-cdk/pipelines/test/integ.pipeline.expected.json index ab3e7cbede27a..4674a0e8891fa 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline.expected.json +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline.expected.json @@ -139,8 +139,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -210,16 +210,16 @@ "Statement": [ { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -250,8 +250,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -264,48 +264,38 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineBuildSynthCodePipelineActionRole4E7A6C97", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineUpdatePipelineSelfMutateCodePipelineActionRoleD6D4E5CF", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelinePreProdUseSourceCodePipelineActionRoleA2043BDA", - "Arn" - ] - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region" + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineBuildSynthCodePipelineActionRole4E7A6C97", + "Arn" ] - ] - } + }, + { + "Fn::GetAtt": [ + "PipelinePreProdUseSourceCodePipelineActionRoleA2043BDA", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineUpdatePipelineSelfMutateCodePipelineActionRoleD6D4E5CF", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region" + ] + ] + } + ] } ], "Version": "2012-10-17" @@ -653,7 +643,8 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" - } + }, + ":*" ] ] }, @@ -668,8 +659,7 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" - }, - ":*" + } ] ] } @@ -677,11 +667,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -703,16 +693,16 @@ }, { "Action": [ - "s3:GetObject*", + "s3:Abort*", + "s3:DeleteObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*", - "s3:DeleteObject*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*" + "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ @@ -743,23 +733,8 @@ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineArtifactsBucketEncryptionKeyF5BF0670", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -979,7 +954,8 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelinePreProdUseSourceProject2E711EB4" - } + }, + ":*" ] ] }, @@ -994,8 +970,7 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelinePreProdUseSourceProject2E711EB4" - }, - ":*" + } ] ] } @@ -1003,11 +978,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -1029,8 +1004,8 @@ }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -1060,22 +1035,10 @@ { "Action": [ "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineArtifactsBucketEncryptionKeyF5BF0670", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", + "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { @@ -1171,7 +1134,8 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" - } + }, + ":*" ] ] }, @@ -1186,8 +1150,7 @@ ":logs:test-region:12345678:log-group:/aws/codebuild/", { "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" - }, - ":*" + } ] ] } @@ -1195,11 +1158,11 @@ }, { "Action": [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", + "codebuild:BatchPutCodeCoverages", "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages" + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" ], "Effect": "Allow", "Resource": { @@ -1234,19 +1197,17 @@ "Resource": "arn:*:iam::12345678:role/*" }, { - "Action": "cloudformation:DescribeStacks", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "s3:ListBucket", + "Action": [ + "cloudformation:DescribeStacks", + "s3:ListBucket" + ], "Effect": "Allow", "Resource": "*" }, { "Action": [ - "s3:GetObject*", "s3:GetBucket*", + "s3:GetObject*", "s3:List*" ], "Effect": "Allow", @@ -1276,22 +1237,10 @@ { "Action": [ "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "PipelineArtifactsBucketEncryptionKeyF5BF0670", - "Arn" - ] - } - }, - { - "Action": [ - "kms:Decrypt", + "kms:DescribeKey", "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:GenerateDataKey*", + "kms:ReEncrypt*" ], "Effect": "Allow", "Resource": { diff --git a/packages/@aws-cdk/region-info/package.json b/packages/@aws-cdk/region-info/package.json index f3400ed30b3e4..701e87c62a2c7 100644 --- a/packages/@aws-cdk/region-info/package.json +++ b/packages/@aws-cdk/region-info/package.json @@ -63,7 +63,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/fs-extra": "^8.1.2", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "fs-extra": "^9.1.0" }, "repository": { diff --git a/packages/@aws-cdk/triggers/.eslintrc.js b/packages/@aws-cdk/triggers/.eslintrc.js new file mode 100644 index 0000000000000..2658ee8727166 --- /dev/null +++ b/packages/@aws-cdk/triggers/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; diff --git a/packages/@aws-cdk/triggers/.gitignore b/packages/@aws-cdk/triggers/.gitignore new file mode 100644 index 0000000000000..d8a8561d50885 --- /dev/null +++ b/packages/@aws-cdk/triggers/.gitignore @@ -0,0 +1,19 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +nyc.config.js +.LAST_PACKAGE +*.snk +!.eslintrc.js +!jest.config.js + +junit.xml \ No newline at end of file diff --git a/packages/@aws-cdk/triggers/.npmignore b/packages/@aws-cdk/triggers/.npmignore new file mode 100644 index 0000000000000..6077c04a3e8a3 --- /dev/null +++ b/packages/@aws-cdk/triggers/.npmignore @@ -0,0 +1,28 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml +!*.lit.ts +test/ \ No newline at end of file diff --git a/packages/@aws-cdk/triggers/LICENSE b/packages/@aws-cdk/triggers/LICENSE new file mode 100644 index 0000000000000..82ad00bb02d0b --- /dev/null +++ b/packages/@aws-cdk/triggers/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/triggers/NOTICE b/packages/@aws-cdk/triggers/NOTICE new file mode 100644 index 0000000000000..1b7adbb891265 --- /dev/null +++ b/packages/@aws-cdk/triggers/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/triggers/README.md b/packages/@aws-cdk/triggers/README.md new file mode 100644 index 0000000000000..4ed41ce05ca0a --- /dev/null +++ b/packages/@aws-cdk/triggers/README.md @@ -0,0 +1,94 @@ +# Triggers + + +--- + +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) + +--- + + + +Triggers allows you to execute code during deployments. This can be used for a +variety of use cases such as: + +* Self tests: validate something after a resource/construct been provisioned +* Data priming: add initial data to resources after they are created +* Preconditions: check things such as account limits or external dependencies + before deployment. + +## Usage + +The `TriggerFunction` construct will define an AWS Lambda function which is +triggered *during* deployment: + +```ts +import * as lambda from '@aws-cdk/aws-lambda'; +import * as triggers from '@aws-cdk/triggers'; +import { Stack } from '@aws-cdk/core'; + +declare const stack: Stack; + +new triggers.TriggerFunction(stack, 'MyTrigger', { + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(__dirname + '/my-trigger'), +}); +``` + +In the above example, the AWS Lambda function defined in `myLambdaFunction` will +be invoked when the stack is deployed. + +## Trigger Failures + +If the trigger handler fails (e.g. an exception is raised), the CloudFormation +deployment will fail, as if a resource failed to provision. This makes it easy +to implement "self tests" via triggers by simply making a set of assertions on +some provisioned infrastructure. + +## Order of Execution + +By default, a trigger will be executed by CloudFormation after the associated +handler is provisioned. This means that if the handler takes an implicit +dependency on other resources (e.g. via environment variables), those resources +will be provisioned *before* the trigger is executed. + +In most cases, implicit ordering should be sufficient, but you can also use +`executeAfter` and `executeBefore` to control the order of execution. + +The following example defines the following order: `(hello, world) => myTrigger => goodbye`. +The resources under `hello` and `world` will be provisioned in +parallel, and then the trigger `myTrigger` will be executed. Only then the +resources under `goodbye` will be provisioned: + +```ts +import { Construct, Node } from 'constructs'; +import * as triggers from '@aws-cdk/triggers'; + +declare const myTrigger: triggers.Trigger; +declare const hello: Construct; +declare const world: Construct; +declare const goodbye: Construct; + +myTrigger.executeAfter(hello, world); +myTrigger.executeBefore(goodbye); +``` + +Note that `hello` and `world` are construct *scopes*. This means that they can +be specific resources (such as an `s3.Bucket` object) or groups of resources +composed together into constructs. + +## Re-execution of Triggers + +By default, `executeOnHandlerChange` is enabled. This implies that the trigger +is re-executed every time the handler function code or configuration changes. If +this option is disabled, the trigger will be executed only once upon first +deployment. + +In the future we will consider adding support for additional re-execution modes: + +* `executeOnEveryDeployment: boolean` - re-executes every time the stack is + deployed (add random "salt" during synthesis). +* `executeOnResourceChange: Construct[]` - re-executes when one of the resources + under the specified scopes has changed (add the hash the CloudFormation + resource specs). diff --git a/packages/@aws-cdk/triggers/jest.config.js b/packages/@aws-cdk/triggers/jest.config.js new file mode 100644 index 0000000000000..3a2fd93a1228a --- /dev/null +++ b/packages/@aws-cdk/triggers/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/triggers/lib/index.ts b/packages/@aws-cdk/triggers/lib/index.ts new file mode 100644 index 0000000000000..1e2bf5e2dab37 --- /dev/null +++ b/packages/@aws-cdk/triggers/lib/index.ts @@ -0,0 +1,2 @@ +export * from './trigger'; +export * from './trigger-function'; \ No newline at end of file diff --git a/packages/@aws-cdk/triggers/lib/lambda/.gitignore b/packages/@aws-cdk/triggers/lib/lambda/.gitignore new file mode 100644 index 0000000000000..eef5e8dd7e177 --- /dev/null +++ b/packages/@aws-cdk/triggers/lib/lambda/.gitignore @@ -0,0 +1 @@ +__entrypoint__.js diff --git a/packages/@aws-cdk/triggers/lib/lambda/index.ts b/packages/@aws-cdk/triggers/lib/lambda/index.ts new file mode 100644 index 0000000000000..7975ac5b56bc0 --- /dev/null +++ b/packages/@aws-cdk/triggers/lib/lambda/index.ts @@ -0,0 +1,56 @@ +/* eslint-disable no-console */ + +// eslint-disable-next-line import/no-extraneous-dependencies +import * as AWS from 'aws-sdk'; + +export type InvokeFunction = (functionName: string) => Promise; + +export const invoke: InvokeFunction = async functionName => { + const lambda = new AWS.Lambda(); + const invokeRequest = { FunctionName: functionName }; + console.log({ invokeRequest }); + const invokeResponse = await lambda.invoke(invokeRequest).promise(); + console.log({ invokeResponse }); + return invokeResponse; +}; + +export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent) { + console.log({ event }); + + if (event.RequestType === 'Delete') { + console.log('not calling trigger on DELETE'); + return; + } + + const handlerArn = event.ResourceProperties.HandlerArn; + if (!handlerArn) { + throw new Error('The "HandlerArn" property is required'); + } + + const invokeResponse = await invoke(handlerArn); + + if (invokeResponse.StatusCode !== 200) { + throw new Error(`Trigger handler failed with status code ${invokeResponse.StatusCode}`); + } + + // if the lambda function throws an error, parse the error message and fail + if (invokeResponse.FunctionError) { + throw new Error(parseError(invokeResponse.Payload?.toString())); + } +}; + +/** + * Parse the error message from the lambda function. + */ +function parseError(payload: string | undefined): string { + console.log(`Error payload: ${payload}`); + if (!payload) { return 'unknown handler error'; } + try { + const error = JSON.parse(payload); + const concat = [error.errorMessage, error.trace].filter(x => x).join('\n'); + return concat.length > 0 ? concat : payload; + } catch (e) { + // fall back to just returning the payload + return payload; + } +} diff --git a/packages/@aws-cdk/triggers/lib/trigger-function.ts b/packages/@aws-cdk/triggers/lib/trigger-function.ts new file mode 100644 index 0000000000000..6504c9f5d1334 --- /dev/null +++ b/packages/@aws-cdk/triggers/lib/trigger-function.ts @@ -0,0 +1,37 @@ +import * as lambda from '@aws-cdk/aws-lambda'; +import { Construct } from 'constructs'; +import { ITrigger, Trigger, TriggerOptions } from '.'; + +/** + * Props for `InvokeFunction`. + */ +export interface TriggerFunctionProps extends lambda.FunctionProps, TriggerOptions { +} + +/** + * Invokes an AWS Lambda function during deployment. + */ +export class TriggerFunction extends lambda.Function implements ITrigger { + + /** + * The underlying trigger resource. + */ + public readonly trigger: Trigger; + + constructor(scope: Construct, id: string, props: TriggerFunctionProps) { + super(scope, id, props); + + this.trigger = new Trigger(this, 'Trigger', { + ...props, + handler: this, + }); + } + + public executeAfter(...scopes: Construct[]): void { + this.trigger.executeAfter(...scopes); + } + + public executeBefore(...scopes: Construct[]): void { + this.trigger.executeBefore(...scopes); + } +} diff --git a/packages/@aws-cdk/triggers/lib/trigger.ts b/packages/@aws-cdk/triggers/lib/trigger.ts new file mode 100644 index 0000000000000..88299f2373294 --- /dev/null +++ b/packages/@aws-cdk/triggers/lib/trigger.ts @@ -0,0 +1,141 @@ +import { join } from 'path'; +import * as lambda from '@aws-cdk/aws-lambda'; +import { CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, IConstruct } from '@aws-cdk/core'; + +import { Construct, Node } from 'constructs'; + +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order +import { Construct as CoreConstruct } from '@aws-cdk/core'; + +/** + * Interface for triggers. + */ +export interface ITrigger extends IConstruct { + /** + * Adds trigger dependencies. Execute this trigger only after these construct + * scopes have been provisioned. + * + * @param scopes A list of construct scopes which this trigger will depend on. + */ + executeAfter(...scopes: Construct[]): void; + + /** + * Adds this trigger as a dependency on other constructs. This means that this + * trigger will get executed *before* the given construct(s). + * + * @param scopes A list of construct scopes which will take a dependency on + * this trigger. + */ + executeBefore(...scopes: Construct[]): void; +} + +/** + * Options for `Trigger`. + */ +export interface TriggerOptions { + /** + * Adds trigger dependencies. Execute this trigger only after these construct + * scopes have been provisioned. + * + * You can also use `trigger.executeAfter()` to add additional dependencies. + * + * @default [] + */ + readonly executeAfter?: Construct[]; + + /** + * Adds this trigger as a dependency on other constructs. This means that this + * trigger will get executed *before* the given construct(s). + * + * You can also use `trigger.executeBefore()` to add additional dependants. + * + * @default [] + */ + readonly executeBefore?: Construct[]; + + /** + * Re-executes the trigger every time the handler changes. + * + * This implies that the trigger is associated with the `currentVersion` of + * the handler, which gets recreated every time the handler or its + * configuration is updated. + * + * @default true + */ + readonly executeOnHandlerChange?: boolean; +} + +/** + * Props for `Trigger`. + */ +export interface TriggerProps extends TriggerOptions { + /** + * The AWS Lambda function of the handler to execute. + */ + readonly handler: lambda.Function; +} + +/** + * Triggers an AWS Lambda function during deployment. + */ +export class Trigger extends CoreConstruct implements ITrigger { + constructor(scope: Construct, id: string, props: TriggerProps) { + super(scope, id); + + const handlerArn = this.determineHandlerArn(props); + const provider = CustomResourceProvider.getOrCreateProvider(this, 'AWSCDK.TriggerCustomResourceProvider', { + runtime: CustomResourceProviderRuntime.NODEJS_14_X, + codeDirectory: join(__dirname, 'lambda'), + policyStatements: [ + { + Effect: 'Allow', + Action: ['lambda:InvokeFunction'], + Resource: [handlerArn], + }, + ], + }); + + new CustomResource(this, 'Default', { + resourceType: 'Custom::Trigger', + serviceToken: provider.serviceToken, + properties: { + HandlerArn: handlerArn, + }, + }); + + this.executeAfter(...props.executeAfter ?? []); + this.executeBefore(...props.executeBefore ?? []); + } + + public executeAfter(...scopes: Construct[]): void { + Node.of(this).addDependency(...scopes); + } + + public executeBefore(...scopes: Construct[]): void { + for (const s of scopes) { + Node.of(s).addDependency(this); + } + } + + private determineHandlerArn(props: TriggerProps) { + return props.handler.currentVersion.functionArn; + // const executeOnHandlerChange = props.executeOnHandlerChange ?? true; + // if (executeOnHandlerChange) { + // } + + // return props.handler.functionArn; + } +} + +/** + * Determines + */ +export enum TriggerInvalidation { + /** + * The trigger will be executed every time the handler (or its configuration) + * changes. This is implemented by associated the trigger with the `currentVersion` + * of the AWS Lambda function, which gets recreated every time the handler changes. + */ + HANDLER_CHANGE = 'WHEN_FUNCTION_CHANGES', +} \ No newline at end of file diff --git a/packages/@aws-cdk/triggers/package.json b/packages/@aws-cdk/triggers/package.json new file mode 100644 index 0000000000000..762ea94a0220b --- /dev/null +++ b/packages/@aws-cdk/triggers/package.json @@ -0,0 +1,117 @@ +{ + "name": "@aws-cdk/triggers", + "version": "0.0.0", + "description": "Execute AWS Lambda functions during deployment", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "targets": { + "java": { + "package": "software.amazon.awscdk.triggers", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "cdk-triggers" + } + }, + "dotnet": { + "namespace": "Amazon.CDK.Triggers", + "packageId": "Amazon.CDK.Triggers", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "python": { + "distName": "aws-cdk.triggers", + "module": "aws_cdk.triggers", + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ] + } + }, + "projectReferences": true, + "metadata": { + "jsii": { + "rosetta": { + "strict": true + } + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/triggers" + }, + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "build+test": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "rosetta:extract": "yarn --silent jsii-rosetta extract", + "build+extract": "yarn build && yarn rosetta:extract", + "build+test+extract": "yarn build+test && yarn rosetta:extract" + }, + "keywords": [ + "aws", + "cdk", + "example", + "construct", + "library", + "triggers" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/aws-sns": "0.0.0", + "aws-sdk": "^2.848.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^27.4.1", + "jest": "^27.5.1" + }, + "dependencies": { + "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "homepage": "https://github.com/aws/aws-cdk", + "peerDependencies": { + "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "stable", + "maturity": "stable", + "awscdkio": { + "announce": false + }, + "cdk-build": { + "env": { + "AWSLINT_BASE_CONSTRUCT": true + } + }, + "publishConfig": { + "tag": "latest" + }, + "awslint": { + "exclude": [ + "ref-via-interface:@aws-cdk/triggers.TriggerProps.handler" + ] + } +} diff --git a/packages/@aws-cdk/triggers/test/integ.triggers.expected.json b/packages/@aws-cdk/triggers/test/integ.triggers.expected.json new file mode 100644 index 0000000000000..2cc1fbdf44f0f --- /dev/null +++ b/packages/@aws-cdk/triggers/test/integ.triggers.expected.json @@ -0,0 +1,203 @@ +{ + "Resources": { + "Topic198E71B3E": { + "Type": "AWS::SNS::Topic", + "DependsOn": [ + "MyFunctionTriggerDB129D7B" + ] + }, + "Topic269377B75": { + "Type": "AWS::SNS::Topic" + }, + "MyFunctionServiceRole3C357FF2": { + "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" + ] + ] + } + ] + } + }, + "MyFunction3BAA72D1": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "exports.handler = function() { console.log(\"hi\"); };" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionServiceRole3C357FF2", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs12.x" + }, + "DependsOn": [ + "MyFunctionServiceRole3C357FF2" + ] + }, + "MyFunctionTriggerDB129D7B": { + "Type": "Custom::Trigger", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "AWSCDKTriggerCustomResourceProviderCustomResourceProviderHandler97BECD91", + "Arn" + ] + }, + "HandlerArn": { + "Ref": "MyFunctionCurrentVersion197490AF776ea8de2edf446759649703b18110a4" + } + }, + "DependsOn": [ + "Topic269377B75" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "MyFunctionCurrentVersion197490AF776ea8de2edf446759649703b18110a4": { + "Type": "AWS::Lambda::Version", + "Properties": { + "FunctionName": { + "Ref": "MyFunction3BAA72D1" + } + } + }, + "AWSCDKTriggerCustomResourceProviderCustomResourceProviderRoleE18FAF0A": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ], + "Policies": [ + { + "PolicyName": "Inline", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "lambda:InvokeFunction" + ], + "Resource": [ + { + "Ref": "MyFunctionCurrentVersion197490AF776ea8de2edf446759649703b18110a4" + } + ] + } + ] + } + } + ] + } + }, + "AWSCDKTriggerCustomResourceProviderCustomResourceProviderHandler97BECD91": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParameters2c42061ddceb234b56276636e22d41e1651d112e8086384492e236481b34021aS3BucketD06FCCA6" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters2c42061ddceb234b56276636e22d41e1651d112e8086384492e236481b34021aS3VersionKey096A7311" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters2c42061ddceb234b56276636e22d41e1651d112e8086384492e236481b34021aS3VersionKey096A7311" + } + ] + } + ] + } + ] + ] + } + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "__entrypoint__.handler", + "Role": { + "Fn::GetAtt": [ + "AWSCDKTriggerCustomResourceProviderCustomResourceProviderRoleE18FAF0A", + "Arn" + ] + }, + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "AWSCDKTriggerCustomResourceProviderCustomResourceProviderRoleE18FAF0A" + ] + } + }, + "Parameters": { + "AssetParameters2c42061ddceb234b56276636e22d41e1651d112e8086384492e236481b34021aS3BucketD06FCCA6": { + "Type": "String", + "Description": "S3 bucket for asset \"2c42061ddceb234b56276636e22d41e1651d112e8086384492e236481b34021a\"" + }, + "AssetParameters2c42061ddceb234b56276636e22d41e1651d112e8086384492e236481b34021aS3VersionKey096A7311": { + "Type": "String", + "Description": "S3 key for asset version \"2c42061ddceb234b56276636e22d41e1651d112e8086384492e236481b34021a\"" + }, + "AssetParameters2c42061ddceb234b56276636e22d41e1651d112e8086384492e236481b34021aArtifactHash5F581B6B": { + "Type": "String", + "Description": "Artifact hash for asset \"2c42061ddceb234b56276636e22d41e1651d112e8086384492e236481b34021a\"" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/triggers/test/integ.triggers.ts b/packages/@aws-cdk/triggers/test/integ.triggers.ts new file mode 100644 index 0000000000000..ad9a7e104438b --- /dev/null +++ b/packages/@aws-cdk/triggers/test/integ.triggers.ts @@ -0,0 +1,21 @@ +import * as lambda from '@aws-cdk/aws-lambda'; +import * as sns from '@aws-cdk/aws-sns'; +import { App, Stack } from '@aws-cdk/core'; +import * as triggers from '../lib'; + +const app = new App(); +const stack = new Stack(app, 'MyStack'); + +const topic1 = new sns.Topic(stack, 'Topic1'); +const topic2 = new sns.Topic(stack, 'Topic2'); + +const trigger = new triggers.TriggerFunction(stack, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = function() { console.log("hi"); };'), + executeBefore: [topic1], +}); + +trigger.executeAfter(topic2); + +app.synth(); \ No newline at end of file diff --git a/packages/@aws-cdk/triggers/test/trigger-handler.test.ts b/packages/@aws-cdk/triggers/test/trigger-handler.test.ts new file mode 100644 index 0000000000000..ab2081c86c572 --- /dev/null +++ b/packages/@aws-cdk/triggers/test/trigger-handler.test.ts @@ -0,0 +1,86 @@ +import * as lambda from '../lib/lambda'; + +afterEach(() => { + jest.resetAllMocks(); +}); + +const handlerArn = 'arn:aws:lambda:us-east-1:123456789012:function:MyTrigger'; +const mockRequest = { + LogicalResourceId: 'MyTrigger', + StackId: 'arn:aws:cloudformation:us-east-1:123456789012:stack/MyStack/12345678-1234-1234-1234-123456789012', + ResponseURL: 'https://cloudformation-custom-resource-response-MyTrigger/', + ResourceProperties: { + ServiceToken: 'arn:aws:lambda:us-east-1:123456789012:function:MyFunction', + HandlerArn: handlerArn, + }, + RequestId: 'MyRequestId', + ResourceType: 'Custom::Trigger', + ServiceToken: 'arn:aws:lambda:us-east-1:123456789012:function:MyFunction', +}; + +test('Create', async () => { + const invokeMock = jest.spyOn(lambda, 'invoke').mockResolvedValue({ + StatusCode: 200, + }); + + await lambda.handler({ RequestType: 'Create', ...mockRequest }); + + expect(invokeMock).toBeCalledTimes(1); + expect(invokeMock).toBeCalledWith(handlerArn); +}); + +test('Update', async () => { + const invokeMock = jest.spyOn(lambda, 'invoke').mockResolvedValue({ + StatusCode: 200, + }); + + await lambda.handler({ RequestType: 'Update', PhysicalResourceId: 'PRID', OldResourceProperties: {}, ...mockRequest }); + + expect(invokeMock).toBeCalledTimes(1); + expect(invokeMock).toBeCalledWith(handlerArn); +}); + +test('Delete - handler not called', async () => { + const invokeMock = jest.spyOn(lambda, 'invoke'); + await lambda.handler({ RequestType: 'Delete', PhysicalResourceId: 'PRID', ...mockRequest }); + expect(invokeMock).not.toBeCalled(); +}); + +test('non-200 status code throws an error', async () => { + const invokeMock = jest.spyOn(lambda, 'invoke').mockResolvedValue({ + StatusCode: 500, + }); + + await expect(lambda.handler({ RequestType: 'Create', ...mockRequest })) + .rejects + .toMatchObject({ message: 'Trigger handler failed with status code 500' }); + + expect(invokeMock).toBeCalledTimes(1); + expect(invokeMock).toBeCalledWith(handlerArn); +}); + +describe('function error', () => { + + const makeTest = (payload: string | undefined, expectedError: string) => { + return async () => { + const invokeMock = jest.spyOn(lambda, 'invoke').mockResolvedValue({ + StatusCode: 200, + FunctionError: 'Unhandled', + Payload: payload, + }); + + await expect(lambda.handler({ RequestType: 'Create', ...mockRequest })) + .rejects + .toMatchObject({ message: expectedError }); + + expect(invokeMock).toBeCalledTimes(1); + expect(invokeMock).toBeCalledWith(handlerArn); + }; + }; + + test('undefined payload', makeTest(undefined, 'unknown handler error')); + test('empty payload', makeTest('', 'unknown handler error')); + test('invalid JSON payload', makeTest('{', '{')); + test('valid JSON payload', makeTest('{"errorMessage": "my error"}', 'my error')); + test('with stack trace', makeTest('{"errorMessage": "my error", "trace": "my stack trace"}', 'my error\nmy stack trace')); +}); diff --git a/packages/@aws-cdk/triggers/test/triggers.test.ts b/packages/@aws-cdk/triggers/test/triggers.test.ts new file mode 100644 index 0000000000000..dd89046c6475a --- /dev/null +++ b/packages/@aws-cdk/triggers/test/triggers.test.ts @@ -0,0 +1,67 @@ +import { Template } from '@aws-cdk/assertions'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as sns from '@aws-cdk/aws-sns'; +import { Stack } from '@aws-cdk/core'; +import * as triggers from '../lib'; + +test('minimal', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new triggers.TriggerFunction(stack, 'MyTrigger', { + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromInline('foo'), + }); + + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Lambda::Function', {}); + template.hasResourceProperties('Custom::Trigger', { + HandlerArn: { Ref: 'MyTriggerCurrentVersion8802742B707afb4f5c680fa04113c095ec4e8b5d' }, + }); +}); + +test('before/after', () => { + // GIVEN + const stack = new Stack(); + const topic1 = new sns.Topic(stack, 'Topic1'); + const topic2 = new sns.Topic(stack, 'Topic2'); + const topic3 = new sns.Topic(stack, 'Topic3'); + const topic4 = new sns.Topic(stack, 'Topic4'); + + // WHEN + const myTrigger = new triggers.TriggerFunction(stack, 'MyTrigger', { + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromInline('zoo'), + handler: 'index.handler', + + // through props + executeAfter: [topic1], + executeBefore: [topic3], + }); + + // through methods + myTrigger.executeBefore(topic4); + myTrigger.executeAfter(topic2); + + // THEN + const triggerId = 'MyTrigger5A0C728D'; + const topic1Id = 'Topic198E71B3E'; + const topic2Id = 'Topic269377B75'; + const topic3Id = 'Topic3DEAE47A7'; + const topic4Id = 'Topic4F5C0CEE2'; + + const template = Template.fromStack(stack); + const resources = template.toJSON().Resources; + + const dependsOn = (sourceId: string, targetId: string) => { + expect(resources[sourceId].DependsOn).toContain(targetId); + }; + + dependsOn(triggerId, topic1Id); + dependsOn(triggerId, topic2Id); + dependsOn(topic3Id, triggerId); + dependsOn(topic4Id, triggerId); +}); diff --git a/packages/@aws-cdk/yaml-cfn/package.json b/packages/@aws-cdk/yaml-cfn/package.json index c30424077862f..819ed1a4c77d1 100644 --- a/packages/@aws-cdk/yaml-cfn/package.json +++ b/packages/@aws-cdk/yaml-cfn/package.json @@ -79,9 +79,9 @@ "@aws-cdk/assertions": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "@types/yaml": "^1.9.7", - "jest": "^27.4.7" + "jest": "^27.5.1" }, "bundledDependencies": [ "yaml" diff --git a/packages/@monocdk-experiment/assert/package.json b/packages/@monocdk-experiment/assert/package.json index a9b70fbf2e5c8..f32fe08ef148f 100644 --- a/packages/@monocdk-experiment/assert/package.json +++ b/packages/@monocdk-experiment/assert/package.json @@ -34,21 +34,21 @@ "license": "Apache-2.0", "devDependencies": { "@monocdk-experiment/rewrite-imports": "0.0.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "@types/node": "^10.17.60", "@aws-cdk/cdk-build-tools": "0.0.0", "constructs": "^3.3.69", - "jest": "^27.4.7", + "jest": "^27.5.1", "monocdk": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "ts-jest": "^27.1.3" + "ts-jest": "^27.1.4" }, "dependencies": { "@aws-cdk/cloudformation-diff": "0.0.0" }, "peerDependencies": { "constructs": "^3.3.69", - "jest": "^27.4.7", + "jest": "^27.5.1", "monocdk": "^0.0.0" }, "repository": { diff --git a/packages/@monocdk-experiment/rewrite-imports/package.json b/packages/@monocdk-experiment/rewrite-imports/package.json index fa08f9e613038..2e36b49a7b51f 100644 --- a/packages/@monocdk-experiment/rewrite-imports/package.json +++ b/packages/@monocdk-experiment/rewrite-imports/package.json @@ -36,7 +36,7 @@ }, "devDependencies": { "@types/glob": "^7.2.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "@types/node": "^10.17.60", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0" diff --git a/packages/aws-cdk-lib/README.md b/packages/aws-cdk-lib/README.md index 017a85437675c..b9c8689353109 100644 --- a/packages/aws-cdk-lib/README.md +++ b/packages/aws-cdk-lib/README.md @@ -88,6 +88,45 @@ organize their deployments with. If you want to vend a reusable construct, define it as a subclasses of `Construct`: the consumers of your construct will decide where to place it in their own stacks. +## Stack Synthesizers + +Each Stack has a *synthesizer*, an object that determines how and where +the Stack should be synthesized and deployed. The synthesizer controls +aspects like: + +- How does the stack reference assets? (Either through CloudFormation + parameters the CLI supplies, or because the Stack knows a predefined + location where assets will be uploaded). +- What roles are used to deploy the stack? These can be bootstrapped + roles, roles created in some other way, or just the CLI's current + credentials. + +The following synthesizers are available: + +- `DefaultStackSynthesizer`: recommended. Uses predefined asset locations and + roles created by the modern bootstrap template. Access control is done by + controlling who can assume the deploy role. This is the default stack + synthesizer in CDKv2. +- `LegacyStackSynthesizer`: Uses CloudFormation parameters to communicate + asset locations, and the CLI's current permissions to deploy stacks. The + is the default stack synthesizer in CDKv1. +- `CliCredentialsStackSynthesizer`: Uses predefined asset locations, and the + CLI's current permissions. + +Each of these synthesizers takes configuration arguments. To configure +a stack with a synthesizer, pass it as one of its properties: + +```ts +new MyStack(app, 'MyStack', { + synthesizer: new DefaultStackSynthesizer({ + fileAssetsBucketName: 'my-orgs-asset-bucket', + }), +}); +``` + +For more information on bootstrapping accounts and customizing synthesis, +see [Bootstrapping in the CDK Developer Guide](https://docs.aws.amazon.com/cdk/latest/guide/bootstrapping.html). + ## Nested Stacks [Nested stacks](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-nested-stacks.html) are stacks created as part of other stacks. You create a nested stack within another stack by using the `NestedStack` construct. diff --git a/packages/aws-cdk-lib/package.json b/packages/aws-cdk-lib/package.json index 9be61fb61fb43..f73f17f8c6c52 100644 --- a/packages/aws-cdk-lib/package.json +++ b/packages/aws-cdk-lib/package.json @@ -110,7 +110,7 @@ "fs-extra": "^9.1.0", "ignore": "^5.2.0", "jsonschema": "^1.4.0", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "punycode": "^2.1.1", "semver": "^7.3.5", "yaml": "1.10.2" @@ -147,6 +147,7 @@ "@aws-cdk/aws-autoscalingplans": "0.0.0", "@aws-cdk/aws-backup": "0.0.0", "@aws-cdk/aws-batch": "0.0.0", + "@aws-cdk/aws-billingconductor": "0.0.0", "@aws-cdk/aws-budgets": "0.0.0", "@aws-cdk/aws-cassandra": "0.0.0", "@aws-cdk/aws-ce": "0.0.0", @@ -233,6 +234,7 @@ "@aws-cdk/aws-iotanalytics": "0.0.0", "@aws-cdk/aws-iotcoredeviceadvisor": "0.0.0", "@aws-cdk/aws-iotevents": "0.0.0", + "@aws-cdk/aws-iotevents-actions": "0.0.0", "@aws-cdk/aws-iotfleethub": "0.0.0", "@aws-cdk/aws-iotsitewise": "0.0.0", "@aws-cdk/aws-iotthingsgraph": "0.0.0", @@ -282,6 +284,7 @@ "@aws-cdk/aws-opsworks": "0.0.0", "@aws-cdk/aws-opsworkscm": "0.0.0", "@aws-cdk/aws-panorama": "0.0.0", + "@aws-cdk/aws-personalize": "0.0.0", "@aws-cdk/aws-pinpoint": "0.0.0", "@aws-cdk/aws-pinpointemail": "0.0.0", "@aws-cdk/aws-qldb": "0.0.0", @@ -348,11 +351,12 @@ "@aws-cdk/pipelines": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@aws-cdk/region-info": "0.0.0", + "@aws-cdk/triggers": "0.0.0", "@aws-cdk/ubergen": "0.0.0", "@types/fs-extra": "^8.1.2", "@types/node": "^10.17.60", "constructs": "^3.3.69", - "esbuild": "^0.14.18", + "esbuild": "^0.14.29", "fs-extra": "^9.1.0", "ts-node": "^9.1.1", "typescript": "~3.8.3" @@ -410,6 +414,7 @@ "./aws-autoscalingplans": "./aws-autoscalingplans/index.js", "./aws-backup": "./aws-backup/index.js", "./aws-batch": "./aws-batch/index.js", + "./aws-billingconductor": "./aws-billingconductor/index.js", "./aws-budgets": "./aws-budgets/index.js", "./aws-cassandra": "./aws-cassandra/index.js", "./aws-ce": "./aws-ce/index.js", @@ -498,6 +503,7 @@ "./aws-iotthingsgraph": "./aws-iotthingsgraph/index.js", "./aws-iotwireless": "./aws-iotwireless/index.js", "./aws-ivs": "./aws-ivs/index.js", + "./aws-kafkaconnect": "./aws-kafkaconnect/index.js", "./aws-kendra": "./aws-kendra/index.js", "./aws-kinesis": "./aws-kinesis/index.js", "./aws-kinesisanalytics": "./aws-kinesisanalytics/index.js", @@ -537,6 +543,7 @@ "./aws-opsworks": "./aws-opsworks/index.js", "./aws-opsworkscm": "./aws-opsworkscm/index.js", "./aws-panorama": "./aws-panorama/index.js", + "./aws-personalize": "./aws-personalize/index.js", "./aws-pinpoint": "./aws-pinpoint/index.js", "./aws-pinpointemail": "./aws-pinpointemail/index.js", "./aws-qldb": "./aws-qldb/index.js", @@ -603,7 +610,8 @@ "./pipelines/.jsii": "./pipelines/.jsii", "./pipelines/.warnings.jsii.js": "./pipelines/.warnings.jsii.js", "./pipelines/lib/helpers-internal": "./pipelines/lib/helpers-internal/index.js", - "./region-info": "./region-info/index.js" + "./region-info": "./region-info/index.js", + "./triggers": "./triggers/index.js" }, "preferredCdkCliVersion": "2" } diff --git a/packages/aws-cdk-lib/scripts/verify-imports-resolve-same.ts b/packages/aws-cdk-lib/scripts/verify-imports-resolve-same.ts index ad15896f072b0..99b8ca286a1e2 100644 --- a/packages/aws-cdk-lib/scripts/verify-imports-resolve-same.ts +++ b/packages/aws-cdk-lib/scripts/verify-imports-resolve-same.ts @@ -84,7 +84,7 @@ async function compileAndResolve(fileName: string, contents: string, symbolName: } // Return the filename - const srcFile = sym.declarations?.[0].getSourceFile().fileName.replace(/.ts|.js|.d.ts/, ''); + const srcFile = sym.declarations?.[0].getSourceFile().fileName.replace(/[.](ts|js|d\.ts)$/, ''); if (!srcFile) { console.log(sym); throw new Error(`Symbol ${symbolName} in '${contents}' does not resolve to a source location`); diff --git a/packages/aws-cdk-migration/package.json b/packages/aws-cdk-migration/package.json index 5b0832f7cf86e..fc601186248ca 100644 --- a/packages/aws-cdk-migration/package.json +++ b/packages/aws-cdk-migration/package.json @@ -39,7 +39,7 @@ }, "devDependencies": { "@types/glob": "^7.2.0", - "@types/jest": "^27.4.0", + "@types/jest": "^27.4.1", "@types/node": "^10.17.60", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0" diff --git a/packages/aws-cdk/.eslintrc.js b/packages/aws-cdk/.eslintrc.js index b5ea7218b5f48..437c4f0c222e9 100644 --- a/packages/aws-cdk/.eslintrc.js +++ b/packages/aws-cdk/.eslintrc.js @@ -1,4 +1,5 @@ const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.ignorePatterns.push('lib/init-templates/**/typescript/**/*.ts'); +baseConfig.ignorePatterns.push('test/integ/cli/sam_cdk_integ_app/**/*.ts'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/aws-cdk/.npmignore b/packages/aws-cdk/.npmignore index ec9970641e3c8..7c198b16e73f8 100644 --- a/packages/aws-cdk/.npmignore +++ b/packages/aws-cdk/.npmignore @@ -27,6 +27,7 @@ tsconfig.json !test/integ/cli/jest.config.js !test/integ/uberpackage/jest.config.js !test/integ/cli-regression-patches/**/* +!test/integ/cli/sam_cdk_integ_app/**/*.ts .DS_Store diff --git a/packages/aws-cdk/NOTICE b/packages/aws-cdk/NOTICE index 1b7adbb891265..2fdce4d2a0591 100644 --- a/packages/aws-cdk/NOTICE +++ b/packages/aws-cdk/NOTICE @@ -1,2 +1,16 @@ AWS Cloud Development Kit (AWS CDK) Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Third party attributions of this package can be found in the THIRD_PARTY_LICENSES file \ No newline at end of file diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index f1c63975641ac..0ac2e08947ec8 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -11,18 +11,20 @@ The AWS CDK Toolkit provides the `cdk` command-line interface that can be used to work with AWS CDK applications. -Command | Description -----------------------------------|------------------------------------------------------------------------------------- -[`cdk docs`](#cdk-docs) | Access the online documentation -[`cdk init`](#cdk-init) | Start a new CDK project (app or library) -[`cdk list`](#cdk-list) | List stacks in an application -[`cdk synth`](#cdk-synthesize) | Synthesize a CDK app to CloudFormation template(s) -[`cdk diff`](#cdk-diff) | Diff stacks against current state -[`cdk deploy`](#cdk-deploy) | Deploy a stack into an AWS account -[`cdk watch`](#cdk-watch) | Watches a CDK app for deployable and hotswappable changes -[`cdk destroy`](#cdk-destroy) | Deletes a stack from an AWS account -[`cdk bootstrap`](#cdk-bootstrap) | Deploy a toolkit stack to support deploying large stacks & artifacts -[`cdk doctor`](#cdk-doctor) | Inspect the environment and produce information useful for troubleshooting +Command | Description +--------------------------------------|--------------------------------------------------------------------------------- +[`cdk docs`](#cdk-docs) | Access the online documentation +[`cdk init`](#cdk-init) | Start a new CDK project (app or library) +[`cdk list`](#cdk-list) | List stacks in an application +[`cdk synth`](#cdk-synthesize) | Synthesize a CDK app to CloudFormation template(s) +[`cdk diff`](#cdk-diff) | Diff stacks against current state +[`cdk deploy`](#cdk-deploy) | Deploy a stack into an AWS account +[`cdk watch`](#cdk-watch) | Watches a CDK app for deployable and hotswappable changes +[`cdk destroy`](#cdk-destroy) | Deletes a stack from an AWS account +[`cdk bootstrap`](#cdk-bootstrap) | Deploy a toolkit stack to support deploying large stacks & artifacts +[`cdk doctor`](#cdk-doctor) | Inspect the environment and produce information useful for troubleshooting +[`cdk acknowledge`](#cdk-acknowledge) | Acknowledge (and hide) a notice by issue number +[`cdk notices`](#cdk-notices) | List all relevant notices for the application This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. @@ -346,7 +348,8 @@ $ cdk deploy --hotswap [StackNames] This will attempt to perform a faster, short-circuit deployment if possible (for example, if you only changed the code of a Lambda function in your CDK app, but nothing else in your CDK code), -skipping CloudFormation, and updating the affected resources directly. +skipping CloudFormation, and updating the affected resources directly; +this includes changes to resources in nested stacks. If the tool detects that the change does not support hotswapping, it will fall back and perform a full CloudFormation deployment, exactly like `cdk deploy` does without the `--hotswap` flag. @@ -368,6 +371,7 @@ Hotswapping is currently supported for the following changes - Container asset changes of AWS ECS Services. - Website asset changes of AWS S3 Bucket Deployments. - Source and Environment changes of AWS CodeBuild Projects. +- VTL mapping template changes for AppSync Resolvers and Functions **⚠ Note #1**: This command deliberately introduces drift in CloudFormation stacks in order to speed up deployments. For this reason, only use it for development purposes. @@ -502,6 +506,102 @@ $ cdk doctor - AWS_SDK_LOAD_CONFIG = 1 ``` +## Notices + +CDK Notices are important messages regarding security vulnerabilities, regressions, and usage of unsupported +versions. Relevant notices appear on every command by default. For example, + +```console +$ cdk deploy + +... # Normal output of the command + +NOTICES + +16603 Toggling off auto_delete_objects for Bucket empties the bucket + + Overview: If a stack is deployed with an S3 bucket with + auto_delete_objects=True, and then re-deployed with + auto_delete_objects=False, all the objects in the bucket + will be deleted. + + Affected versions: <1.126.0. + + More information at: https://github.com/aws/aws-cdk/issues/16603 + + +17061 Error when building EKS cluster with monocdk import + + Overview: When using monocdk/aws-eks to build a stack containing + an EKS cluster, error is thrown about missing + lambda-layer-node-proxy-agent/layer/package.json. + + Affected versions: >=1.126.0 <=1.130.0. + + More information at: https://github.com/aws/aws-cdk/issues/17061 + + +If you don’t want to see an notice anymore, use "cdk acknowledge ID". For example, "cdk acknowledge 16603". +``` + +You can suppress warnings in a variety of ways: + +- per individual execution: + + `cdk deploy --no-notices` + +- disable all notices indefinitely through context in `cdk.json`: + + ```json + { + "notices": false, + "context": { + ... + } + } + ``` + +- acknowleding individual notices via `cdk acknowledge` (see below). + +### `cdk acknowledge` + +To hide a particular notice that has been addressed or does not apply, call `cdk acknowledge` with the ID of +the notice: + +```console +$cdk acknowledge 16603 +``` + +> Please note that the acknowledgements are made project by project. If you acknowledge an notice in one CDK +> project, it will still appear on other projects when you run any CDK commands, unless you have suppressed +> or disabled notices. + + +### `cdk notices` + +List the notices that are relevant to the current CDK repository, regardless of context flags or notices that +have been acknowledged: + +```console +$ cdk notices + +NOTICES + +16603 Toggling off auto_delete_objects for Bucket empties the bucket + + Overview: if a stack is deployed with an S3 bucket with + auto_delete_objects=True, and then re-deployed with + auto_delete_objects=False, all the objects in the bucket + will be deleted. + + Affected versions: framework: <=2.15.0 >=2.10.0 + + More information at: https://github.com/aws/aws-cdk/issues/16603 + + +If you don’t want to see a notice anymore, use "cdk acknowledge ". For example, "cdk acknowledge 16603". +``` + ### Bundling By default asset bundling is skipped for `cdk list` and `cdk destroy`. For `cdk deploy`, `cdk diff` @@ -522,6 +622,11 @@ role_arn=arn:aws:iam::123456789123:role/role_to_be_assumed mfa_serial=arn:aws:iam::123456789123:mfa/my_user ``` +## SSO support + +If you create an SSO profile with `aws configure sso` and run `aws sso login`, the CDK can use those credentials +if you set the profile name as the value of `AWS_PROFILE` or pass it to `--profile`. + ## Configuration On top of passing configuration through command-line arguments, it is possible to use JSON configuration files. The @@ -549,8 +654,8 @@ Some of the interesting keys that can be used in the JSON configuration files: ``` If specified, the command in the `build` key will be executed immediately before synthesis. -This can be used to build Lambda Functions, CDK Application code, or other assets. -`build` cannot be specified on the command line or in the User configuration, +This can be used to build Lambda Functions, CDK Application code, or other assets. +`build` cannot be specified on the command line or in the User configuration, and must be specified in the Project configuration. The command specified in `build` will be executed by the "watch" process before deployment. diff --git a/packages/aws-cdk/THIRD_PARTY_LICENSES b/packages/aws-cdk/THIRD_PARTY_LICENSES new file mode 100644 index 0000000000000..633c8be1c5002 --- /dev/null +++ b/packages/aws-cdk/THIRD_PARTY_LICENSES @@ -0,0 +1,3768 @@ +The aws-cdk package includes the following third-party software/licensing: + +** @jsii/check-node@1.55.1 - https://www.npmjs.com/package/@jsii/check-node/v/1.55.1 | Apache-2.0 +jsii +Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + +---------------- + +** @tootallnate/once@1.1.2 - https://www.npmjs.com/package/@tootallnate/once/v/1.1.2 | MIT + +---------------- + +** acorn-walk@8.2.0 - https://www.npmjs.com/package/acorn-walk/v/8.2.0 | MIT +MIT License + +Copyright (C) 2012-2020 by various contributors (see AUTHORS) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** acorn@8.7.0 - https://www.npmjs.com/package/acorn/v/8.7.0 | MIT +MIT License + +Copyright (C) 2012-2020 by various contributors (see AUTHORS) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** agent-base@6.0.2 - https://www.npmjs.com/package/agent-base/v/6.0.2 | MIT + +---------------- + +** ajv@8.11.0 - https://www.npmjs.com/package/ajv/v/8.11.0 | MIT +The MIT License (MIT) + +Copyright (c) 2015-2021 Evgeny Poberezkin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +---------------- + +** ansi-regex@5.0.1 - https://www.npmjs.com/package/ansi-regex/v/5.0.1 | MIT +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** ansi-styles@4.3.0 - https://www.npmjs.com/package/ansi-styles/v/4.3.0 | MIT +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** anymatch@3.1.2 - https://www.npmjs.com/package/anymatch/v/3.1.2 | ISC +The ISC License + +Copyright (c) 2019 Elan Shanker, Paul Miller (https://paulmillr.com) + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** archiver-utils@2.1.0 - https://www.npmjs.com/package/archiver-utils/v/2.1.0 | MIT +Copyright (c) 2015 Chris Talkington. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +---------------- + +** archiver@5.3.0 - https://www.npmjs.com/package/archiver/v/5.3.0 | MIT +Copyright (c) 2012-2014 Chris Talkington, contributors. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +---------------- + +** ast-types@0.13.4 - https://www.npmjs.com/package/ast-types/v/0.13.4 | MIT +Copyright (c) 2013 Ben Newman + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** astral-regex@2.0.0 - https://www.npmjs.com/package/astral-regex/v/2.0.0 | MIT +MIT License + +Copyright (c) Kevin Mårtensson (github.com/kevva) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** async@3.2.3 - https://www.npmjs.com/package/async/v/3.2.3 | MIT +Copyright (c) 2010-2018 Caolan McMahon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** at-least-node@1.0.0 - https://www.npmjs.com/package/at-least-node/v/1.0.0 | ISC +The ISC License +Copyright (c) 2020 Ryan Zimmerman + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** aws-sdk@2.1103.0 - https://www.npmjs.com/package/aws-sdk/v/2.1103.0 | Apache-2.0 +AWS SDK for JavaScript +Copyright 2012-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed at +Amazon Web Services, Inc. (http://aws.amazon.com/). + + +---------------- + +** balanced-match@1.0.2 - https://www.npmjs.com/package/balanced-match/v/1.0.2 | MIT + +---------------- + +** binary-extensions@2.2.0 - https://www.npmjs.com/package/binary-extensions/v/2.2.0 | MIT +MIT License + +Copyright (c) 2019 Sindre Sorhus (https://sindresorhus.com), Paul Miller (https://paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** bl@4.1.0 - https://www.npmjs.com/package/bl/v/4.1.0 | MIT + +---------------- + +** brace-expansion@1.1.11 - https://www.npmjs.com/package/brace-expansion/v/1.1.11 | MIT +MIT License + +Copyright (c) 2013 Julian Gruber + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +---------------- + +** brace-expansion@2.0.1 - https://www.npmjs.com/package/brace-expansion/v/2.0.1 | MIT +MIT License + +Copyright (c) 2013 Julian Gruber + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +---------------- + +** braces@3.0.2 - https://www.npmjs.com/package/braces/v/3.0.2 | MIT +The MIT License (MIT) + +Copyright (c) 2014-2018, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** buffer-crc32@0.2.13 - https://www.npmjs.com/package/buffer-crc32/v/0.2.13 | MIT +The MIT License + +Copyright (c) 2013 Brian J. Brennan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** buffer-from@1.1.2 - https://www.npmjs.com/package/buffer-from/v/1.1.2 | MIT +MIT License + +Copyright (c) 2016, 2018 Linus Unnebäck + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +---------------- + +** bytes@3.1.2 - https://www.npmjs.com/package/bytes/v/3.1.2 | MIT +(The MIT License) + +Copyright (c) 2012-2014 TJ Holowaychuk +Copyright (c) 2015 Jed Watson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** camelcase@6.3.0 - https://www.npmjs.com/package/camelcase/v/6.3.0 | MIT +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** chalk@4.1.2 - https://www.npmjs.com/package/chalk/v/4.1.2 | MIT +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** chokidar@3.5.3 - https://www.npmjs.com/package/chokidar/v/3.5.3 | MIT +The MIT License (MIT) + +Copyright (c) 2012-2019 Paul Miller (https://paulmillr.com), Elan Shanker + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** cliui@7.0.4 - https://www.npmjs.com/package/cliui/v/7.0.4 | ISC +Copyright (c) 2015, Contributors + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice +appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE +LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** color-convert@2.0.1 - https://www.npmjs.com/package/color-convert/v/2.0.1 | MIT +Copyright (c) 2011-2016 Heather Arthur + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +---------------- + +** color-name@1.1.4 - https://www.npmjs.com/package/color-name/v/1.1.4 | MIT +The MIT License (MIT) +Copyright (c) 2015 Dmitry Ivanov + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +---------------- + +** compress-commons@4.1.1 - https://www.npmjs.com/package/compress-commons/v/4.1.1 | MIT +Copyright (c) 2014 Chris Talkington, contributors. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +---------------- + +** concat-map@0.0.1 - https://www.npmjs.com/package/concat-map/v/0.0.1 | MIT +This software is released under the MIT license: + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** core-util-is@1.0.3 - https://www.npmjs.com/package/core-util-is/v/1.0.3 | MIT +Copyright Node.js contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + + +---------------- + +** crc-32@1.2.1 - https://www.npmjs.com/package/crc-32/v/1.2.1 | Apache-2.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (C) 2014-present SheetJS LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +---------------- + +** crc32-stream@4.0.2 - https://www.npmjs.com/package/crc32-stream/v/4.0.2 | MIT +Copyright (c) 2014 Chris Talkington, contributors. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +---------------- + +** data-uri-to-buffer@3.0.1 - https://www.npmjs.com/package/data-uri-to-buffer/v/3.0.1 | MIT + +---------------- + +** debug@4.3.4 - https://www.npmjs.com/package/debug/v/4.3.4 | MIT +(The MIT License) + +Copyright (c) 2014-2017 TJ Holowaychuk +Copyright (c) 2018-2021 Josh Junon + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software +and associated documentation files (the 'Software'), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +---------------- + +** decamelize@5.0.1 - https://www.npmjs.com/package/decamelize/v/5.0.1 | MIT +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** degenerator@3.0.2 - https://www.npmjs.com/package/degenerator/v/3.0.2 | MIT + +---------------- + +** depd@2.0.0 - https://www.npmjs.com/package/depd/v/2.0.0 | MIT +(The MIT License) + +Copyright (c) 2014-2018 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** diff@5.0.0 - https://www.npmjs.com/package/diff/v/5.0.0 | BSD-3-Clause +Software License Agreement (BSD License) + +Copyright (c) 2009-2015, Kevin Decker + +All rights reserved. + +Redistribution and use of this software in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of Kevin Decker nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------- + +** emoji-regex@8.0.0 - https://www.npmjs.com/package/emoji-regex/v/8.0.0 | MIT +Copyright Mathias Bynens + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** end-of-stream@1.4.4 - https://www.npmjs.com/package/end-of-stream/v/1.4.4 | MIT +The MIT License (MIT) + +Copyright (c) 2014 Mathias Buus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------- + +** escalade@3.1.1 - https://www.npmjs.com/package/escalade/v/3.1.1 | MIT +MIT License + +Copyright (c) Luke Edwards (lukeed.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** escodegen@1.14.3 - https://www.npmjs.com/package/escodegen/v/1.14.3 | BSD-2-Clause +Copyright (C) 2012 Yusuke Suzuki (twitter: @Constellation) and other contributors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +---------------- + +** esprima@4.0.1 - https://www.npmjs.com/package/esprima/v/4.0.1 | BSD-2-Clause +Copyright JS Foundation and other contributors, https://js.foundation/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +---------------- + +** estraverse@4.3.0 - https://www.npmjs.com/package/estraverse/v/4.3.0 | BSD-2-Clause +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +---------------- + +** esutils@2.0.3 - https://www.npmjs.com/package/esutils/v/2.0.3 | BSD-2-Clause +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +---------------- + +** fast-deep-equal@3.1.3 - https://www.npmjs.com/package/fast-deep-equal/v/3.1.3 | MIT +MIT License + +Copyright (c) 2017 Evgeny Poberezkin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +---------------- + +** file-uri-to-path@2.0.0 - https://www.npmjs.com/package/file-uri-to-path/v/2.0.0 | MIT +Copyright (c) 2014 Nathan Rajlich + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** fill-range@7.0.1 - https://www.npmjs.com/package/fill-range/v/7.0.1 | MIT +The MIT License (MIT) + +Copyright (c) 2014-present, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** fs-constants@1.0.0 - https://www.npmjs.com/package/fs-constants/v/1.0.0 | MIT +The MIT License (MIT) + +Copyright (c) 2018 Mathias Buus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** fs-extra@8.1.0 - https://www.npmjs.com/package/fs-extra/v/8.1.0 | MIT +(The MIT License) + +Copyright (c) 2011-2017 JP Richardson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +(the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** fs-extra@9.1.0 - https://www.npmjs.com/package/fs-extra/v/9.1.0 | MIT +(The MIT License) + +Copyright (c) 2011-2017 JP Richardson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +(the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** fs.realpath@1.0.0 - https://www.npmjs.com/package/fs.realpath/v/1.0.0 | ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---- + +This library bundles a version of the `fs.realpath` and `fs.realpathSync` +methods from Node.js v0.10 under the terms of the Node.js MIT license. + +Node's license follows, also included at the header of `old.js` which contains +the licensed code: + + Copyright Joyent, Inc. and other Node contributors. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + +---------------- + +** ftp@0.3.10 - https://www.npmjs.com/package/ftp/v/0.3.10 | MIT +Copyright Brian White. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + +---------------- + +** get-caller-file@2.0.5 - https://www.npmjs.com/package/get-caller-file/v/2.0.5 | ISC + +---------------- + +** get-uri@3.0.2 - https://www.npmjs.com/package/get-uri/v/3.0.2 | MIT + +---------------- + +** glob-parent@5.1.2 - https://www.npmjs.com/package/glob-parent/v/5.1.2 | ISC +The ISC License + +Copyright (c) 2015, 2019 Elan Shanker + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** glob@7.2.0 - https://www.npmjs.com/package/glob/v/7.2.0 | ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +## Glob Logo + +Glob's logo created by Tanya Brassie , licensed +under a Creative Commons Attribution-ShareAlike 4.0 International License +https://creativecommons.org/licenses/by-sa/4.0/ + + +---------------- + +** graceful-fs@4.2.9 - https://www.npmjs.com/package/graceful-fs/v/4.2.9 | ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter, Ben Noordhuis, and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** has-flag@4.0.0 - https://www.npmjs.com/package/has-flag/v/4.0.0 | MIT +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** http-errors@2.0.0 - https://www.npmjs.com/package/http-errors/v/2.0.0 | MIT + +The MIT License (MIT) + +Copyright (c) 2014 Jonathan Ong me@jongleberry.com +Copyright (c) 2016 Douglas Christopher Wilson doug@somethingdoug.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** http-proxy-agent@4.0.1 - https://www.npmjs.com/package/http-proxy-agent/v/4.0.1 | MIT + +---------------- + +** https-proxy-agent@5.0.0 - https://www.npmjs.com/package/https-proxy-agent/v/5.0.0 | MIT + +---------------- + +** iconv-lite@0.4.24 - https://www.npmjs.com/package/iconv-lite/v/0.4.24 | MIT +Copyright (c) 2011 Alexander Shtuchkin + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +---------------- + +** inflight@1.0.6 - https://www.npmjs.com/package/inflight/v/1.0.6 | ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** inherits@2.0.4 - https://www.npmjs.com/package/inherits/v/2.0.4 | ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + + + +---------------- + +** ip@1.1.5 - https://www.npmjs.com/package/ip/v/1.1.5 | MIT + +---------------- + +** is-binary-path@2.1.0 - https://www.npmjs.com/package/is-binary-path/v/2.1.0 | MIT +MIT License + +Copyright (c) 2019 Sindre Sorhus (https://sindresorhus.com), Paul Miller (https://paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** is-extglob@2.1.1 - https://www.npmjs.com/package/is-extglob/v/2.1.1 | MIT +The MIT License (MIT) + +Copyright (c) 2014-2016, Jon Schlinkert + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** is-fullwidth-code-point@3.0.0 - https://www.npmjs.com/package/is-fullwidth-code-point/v/3.0.0 | MIT +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** is-glob@4.0.3 - https://www.npmjs.com/package/is-glob/v/4.0.3 | MIT +The MIT License (MIT) + +Copyright (c) 2014-2017, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** is-number@7.0.0 - https://www.npmjs.com/package/is-number/v/7.0.0 | MIT +The MIT License (MIT) + +Copyright (c) 2014-present, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** isarray@0.0.1 - https://www.npmjs.com/package/isarray/v/0.0.1 | MIT + +---------------- + +** isarray@1.0.0 - https://www.npmjs.com/package/isarray/v/1.0.0 | MIT + +---------------- + +** jmespath@0.16.0 - https://www.npmjs.com/package/jmespath/v/0.16.0 | Apache-2.0 +Copyright 2014 James Saryerwinnie + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +---------------- + +** jsonfile@4.0.0 - https://www.npmjs.com/package/jsonfile/v/4.0.0 | MIT +(The MIT License) + +Copyright (c) 2012-2015, JP Richardson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +(the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** jsonfile@6.1.0 - https://www.npmjs.com/package/jsonfile/v/6.1.0 | MIT +(The MIT License) + +Copyright (c) 2012-2015, JP Richardson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +(the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** jsonschema@1.4.0 - https://www.npmjs.com/package/jsonschema/v/1.4.0 | MIT +jsonschema is licensed under MIT license. + +Copyright (C) 2012-2015 Tom de Grunt + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +---------------- + +** lazystream@1.0.1 - https://www.npmjs.com/package/lazystream/v/1.0.1 | MIT +Copyright (c) 2013 J. Pommerening, contributors. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + + + +---------------- + +** lodash.defaults@4.2.0 - https://www.npmjs.com/package/lodash.defaults/v/4.2.0 | MIT +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + + +---------------- + +** lodash.difference@4.5.0 - https://www.npmjs.com/package/lodash.difference/v/4.5.0 | MIT +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + + +---------------- + +** lodash.flatten@4.4.0 - https://www.npmjs.com/package/lodash.flatten/v/4.4.0 | MIT +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + + +---------------- + +** lodash.isplainobject@4.0.6 - https://www.npmjs.com/package/lodash.isplainobject/v/4.0.6 | MIT +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + + +---------------- + +** lodash.truncate@4.4.2 - https://www.npmjs.com/package/lodash.truncate/v/4.4.2 | MIT +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + + +---------------- + +** lodash.union@4.6.0 - https://www.npmjs.com/package/lodash.union/v/4.6.0 | MIT +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + + +---------------- + +** lru-cache@5.1.1 - https://www.npmjs.com/package/lru-cache/v/5.1.1 | ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** lru-cache@6.0.0 - https://www.npmjs.com/package/lru-cache/v/6.0.0 | ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** mime@2.6.0 - https://www.npmjs.com/package/mime/v/2.6.0 | MIT +The MIT License (MIT) + +Copyright (c) 2010 Benjamin Thomas, Robert Kieffer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** minimatch@3.1.2 - https://www.npmjs.com/package/minimatch/v/3.1.2 | ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** minimatch@5.0.1 - https://www.npmjs.com/package/minimatch/v/5.0.1 | ISC +The ISC License + +Copyright (c) 2011-2022 Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** ms@2.1.2 - https://www.npmjs.com/package/ms/v/2.1.2 | MIT + +---------------- + +** mute-stream@0.0.8 - https://www.npmjs.com/package/mute-stream/v/0.0.8 | ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** netmask@2.0.2 - https://www.npmjs.com/package/netmask/v/2.0.2 | MIT + +---------------- + +** normalize-path@3.0.0 - https://www.npmjs.com/package/normalize-path/v/3.0.0 | MIT +The MIT License (MIT) + +Copyright (c) 2014-2018, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** once@1.4.0 - https://www.npmjs.com/package/once/v/1.4.0 | ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** pac-proxy-agent@5.0.0 - https://www.npmjs.com/package/pac-proxy-agent/v/5.0.0 | MIT + +---------------- + +** pac-resolver@5.0.0 - https://www.npmjs.com/package/pac-resolver/v/5.0.0 | MIT + +---------------- + +** path-is-absolute@1.0.1 - https://www.npmjs.com/package/path-is-absolute/v/1.0.1 | MIT +The MIT License (MIT) + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** picomatch@2.3.1 - https://www.npmjs.com/package/picomatch/v/2.3.1 | MIT +The MIT License (MIT) + +Copyright (c) 2017-present, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** process-nextick-args@2.0.1 - https://www.npmjs.com/package/process-nextick-args/v/2.0.1 | MIT + +---------------- + +** promptly@3.2.0 - https://www.npmjs.com/package/promptly/v/3.2.0 | MIT +The MIT License (MIT) + +Copyright (c) 2018 Made With MOXY Lda + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** proxy-agent@5.0.0 - https://www.npmjs.com/package/proxy-agent/v/5.0.0 | MIT + +---------------- + +** proxy-from-env@1.1.0 - https://www.npmjs.com/package/proxy-from-env/v/1.1.0 | MIT +The MIT License + +Copyright (C) 2016-2018 Rob Wu + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** raw-body@2.5.1 - https://www.npmjs.com/package/raw-body/v/2.5.1 | MIT +The MIT License (MIT) + +Copyright (c) 2013-2014 Jonathan Ong +Copyright (c) 2014-2022 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** read@1.0.7 - https://www.npmjs.com/package/read/v/1.0.7 | ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** readable-stream@1.1.14 - https://www.npmjs.com/package/readable-stream/v/1.1.14 | MIT +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + + +---------------- + +** readable-stream@2.3.7 - https://www.npmjs.com/package/readable-stream/v/2.3.7 | MIT +Node.js is licensed for use as follows: + +""" +Copyright Node.js contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: + +""" +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + + +---------------- + +** readable-stream@3.6.0 - https://www.npmjs.com/package/readable-stream/v/3.6.0 | MIT +Node.js is licensed for use as follows: + +""" +Copyright Node.js contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: + +""" +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + + +---------------- + +** readdir-glob@1.1.1 - https://www.npmjs.com/package/readdir-glob/v/1.1.1 | Apache-2.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 Yann Armelin + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +---------------- + +** readdirp@3.6.0 - https://www.npmjs.com/package/readdirp/v/3.6.0 | MIT +MIT License + +Copyright (c) 2012-2019 Thorsten Lorenz, Paul Miller (https://paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +---------------- + +** require-directory@2.1.1 - https://www.npmjs.com/package/require-directory/v/2.1.1 | MIT +The MIT License (MIT) + +Copyright (c) 2011 Troy Goode + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** safe-buffer@5.1.2 - https://www.npmjs.com/package/safe-buffer/v/5.1.2 | MIT +The MIT License (MIT) + +Copyright (c) Feross Aboukhadijeh + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** safe-buffer@5.2.1 - https://www.npmjs.com/package/safe-buffer/v/5.2.1 | MIT +The MIT License (MIT) + +Copyright (c) Feross Aboukhadijeh + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** safer-buffer@2.1.2 - https://www.npmjs.com/package/safer-buffer/v/2.1.2 | MIT +MIT License + +Copyright (c) 2018 Nikita Skovoroda + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +---------------- + +** sax@1.2.4 - https://www.npmjs.com/package/sax/v/1.2.4 | ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +==== + +`String.fromCodePoint` by Mathias Bynens used according to terms of MIT +License, as follows: + + Copyright Mathias Bynens + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** semver@7.3.5 - https://www.npmjs.com/package/semver/v/7.3.5 | ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** setprototypeof@1.2.0 - https://www.npmjs.com/package/setprototypeof/v/1.2.0 | ISC +Copyright (c) 2015, Wes Todd + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** slice-ansi@4.0.0 - https://www.npmjs.com/package/slice-ansi/v/4.0.0 | MIT +MIT License + +Copyright (c) DC +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** smart-buffer@4.2.0 - https://www.npmjs.com/package/smart-buffer/v/4.2.0 | MIT +The MIT License (MIT) + +Copyright (c) 2013-2017 Josh Glazebrook + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** socks-proxy-agent@5.0.1 - https://www.npmjs.com/package/socks-proxy-agent/v/5.0.1 | MIT + +---------------- + +** socks@2.6.2 - https://www.npmjs.com/package/socks/v/2.6.2 | MIT +The MIT License (MIT) + +Copyright (c) 2013 Josh Glazebrook + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** source-map-support@0.5.21 - https://www.npmjs.com/package/source-map-support/v/0.5.21 | MIT + +---------------- + +** source-map@0.6.1 - https://www.npmjs.com/package/source-map/v/0.6.1 | BSD-3-Clause + +Copyright (c) 2009-2011, Mozilla Foundation and contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the names of the Mozilla Foundation nor the names of project + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +---------------- + +** statuses@2.0.1 - https://www.npmjs.com/package/statuses/v/2.0.1 | MIT + +The MIT License (MIT) + +Copyright (c) 2014 Jonathan Ong +Copyright (c) 2016 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** string_decoder@0.10.31 - https://www.npmjs.com/package/string_decoder/v/0.10.31 | MIT +Copyright Joyent, Inc. and other Node contributors. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** string_decoder@1.1.1 - https://www.npmjs.com/package/string_decoder/v/1.1.1 | MIT +Node.js is licensed for use as follows: + +""" +Copyright Node.js contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: + +""" +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + + + +---------------- + +** string_decoder@1.3.0 - https://www.npmjs.com/package/string_decoder/v/1.3.0 | MIT +Node.js is licensed for use as follows: + +""" +Copyright Node.js contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: + +""" +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + + + +---------------- + +** string-width@4.2.3 - https://www.npmjs.com/package/string-width/v/4.2.3 | MIT +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** strip-ansi@6.0.1 - https://www.npmjs.com/package/strip-ansi/v/6.0.1 | MIT +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** supports-color@7.2.0 - https://www.npmjs.com/package/supports-color/v/7.2.0 | MIT +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** table@6.8.0 - https://www.npmjs.com/package/table/v/6.8.0 | BSD-3-Clause +Copyright (c) 2018, Gajus Kuizinas (http://gajus.com/) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Gajus Kuizinas (http://gajus.com/) nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL ANUARY BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +---------------- + +** tar-stream@2.2.0 - https://www.npmjs.com/package/tar-stream/v/2.2.0 | MIT +The MIT License (MIT) + +Copyright (c) 2014 Mathias Buus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------- + +** to-regex-range@5.0.1 - https://www.npmjs.com/package/to-regex-range/v/5.0.1 | MIT +The MIT License (MIT) + +Copyright (c) 2015-present, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** toidentifier@1.0.1 - https://www.npmjs.com/package/toidentifier/v/1.0.1 | MIT +MIT License + +Copyright (c) 2016 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +---------------- + +** tslib@2.3.1 - https://www.npmjs.com/package/tslib/v/2.3.1 | 0BSD +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +---------------- + +** universalify@0.1.2 - https://www.npmjs.com/package/universalify/v/0.1.2 | MIT +(The MIT License) + +Copyright (c) 2017, Ryan Zimmerman + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the 'Software'), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** universalify@2.0.0 - https://www.npmjs.com/package/universalify/v/2.0.0 | MIT +(The MIT License) + +Copyright (c) 2017, Ryan Zimmerman + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the 'Software'), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** unpipe@1.0.0 - https://www.npmjs.com/package/unpipe/v/1.0.0 | MIT +(The MIT License) + +Copyright (c) 2015 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** util-deprecate@1.0.2 - https://www.npmjs.com/package/util-deprecate/v/1.0.2 | MIT +(The MIT License) + +Copyright (c) 2014 Nathan Rajlich + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** uuid@3.3.2 - https://www.npmjs.com/package/uuid/v/3.3.2 | MIT + +---------------- + +** uuid@8.3.2 - https://www.npmjs.com/package/uuid/v/8.3.2 | MIT + +---------------- + +** vm2@3.9.9 - https://www.npmjs.com/package/vm2/v/3.9.9 | MIT + +---------------- + +** wrap-ansi@7.0.0 - https://www.npmjs.com/package/wrap-ansi/v/7.0.0 | MIT +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** wrappy@1.0.2 - https://www.npmjs.com/package/wrappy/v/1.0.2 | ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** xml2js@0.4.19 - https://www.npmjs.com/package/xml2js/v/0.4.19 | MIT +Copyright 2010, 2011, 2012, 2013. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + + +---------------- + +** xmlbuilder@9.0.7 - https://www.npmjs.com/package/xmlbuilder/v/9.0.7 | MIT +The MIT License (MIT) + +Copyright (c) 2013 Ozgur Ozcitak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** xregexp@2.0.0 - https://www.npmjs.com/package/xregexp/v/2.0.0 | MIT + +---------------- + +** y18n@5.0.8 - https://www.npmjs.com/package/y18n/v/5.0.8 | ISC +Copyright (c) 2015, Contributors + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. + + +---------------- + +** yallist@3.1.1 - https://www.npmjs.com/package/yallist/v/3.1.1 | ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** yallist@4.0.0 - https://www.npmjs.com/package/yallist/v/4.0.0 | ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** yaml@1.10.2 - https://www.npmjs.com/package/yaml/v/1.10.2 | ISC +Copyright 2018 Eemeli Aro + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. + + +---------------- + +** yargs-parser@20.2.9 - https://www.npmjs.com/package/yargs-parser/v/20.2.9 | ISC +Copyright (c) 2016, Contributors + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice +appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE +LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** yargs@16.2.0 - https://www.npmjs.com/package/yargs/v/16.2.0 | MIT +MIT License + +Copyright 2010 James Halliday (mail@substack.net); Modified work Copyright 2014 Contributors (ben@npmjs.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** zip-stream@4.1.0 - https://www.npmjs.com/package/zip-stream/v/4.1.0 | MIT +Copyright (c) 2014 Chris Talkington, contributors. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +---------------- diff --git a/packages/aws-cdk/bin/cdk.ts b/packages/aws-cdk/bin/cdk.ts index 5b82a72eab5d2..4f2652b107236 100644 --- a/packages/aws-cdk/bin/cdk.ts +++ b/packages/aws-cdk/bin/cdk.ts @@ -1,539 +1,3 @@ -#!/usr/bin/env node -import 'source-map-support/register'; -import * as cxapi from '@aws-cdk/cx-api'; -import '@jsii/check-node/run'; -import * as chalk from 'chalk'; -import * as yargs from 'yargs'; +import { cli } from '../lib'; -import { SdkProvider } from '../lib/api/aws-auth'; -import { BootstrapSource, Bootstrapper } from '../lib/api/bootstrap'; -import { CloudFormationDeployments } from '../lib/api/cloudformation-deployments'; -import { StackSelector } from '../lib/api/cxapp/cloud-assembly'; -import { CloudExecutable } from '../lib/api/cxapp/cloud-executable'; -import { execProgram } from '../lib/api/cxapp/exec'; -import { ToolkitInfo } from '../lib/api/toolkit-info'; -import { StackActivityProgress } from '../lib/api/util/cloudformation/stack-activity-monitor'; -import { CdkToolkit } from '../lib/cdk-toolkit'; -import { RequireApproval } from '../lib/diff'; -import { availableInitLanguages, cliInit, printAvailableTemplates } from '../lib/init'; -import { data, debug, error, print, setLogLevel } from '../lib/logging'; -import { PluginHost } from '../lib/plugin'; -import { serializeStructure } from '../lib/serialize'; -import { Command, Configuration, Settings } from '../lib/settings'; -import * as version from '../lib/version'; - -/* eslint-disable max-len */ -/* eslint-disable @typescript-eslint/no-shadow */ // yargs - -async function parseCommandLineArguments() { - // Use the following configuration for array arguments: - // - // { type: 'array', default: [], nargs: 1, requiresArg: true } - // - // The default behavior of yargs is to eat all strings following an array argument: - // - // ./prog --arg one two positional => will parse to { arg: ['one', 'two', 'positional'], _: [] } (so no positional arguments) - // ./prog --arg one two -- positional => does not help, for reasons that I can't understand. Still gets parsed incorrectly. - // - // By using the config above, every --arg will only consume one argument, so you can do the following: - // - // ./prog --arg one --arg two position => will parse to { arg: ['one', 'two'], _: ['positional'] }. - - const initTemplateLanguages = await availableInitLanguages(); - return yargs - .env('CDK') - .usage('Usage: cdk -a COMMAND') - .option('app', { type: 'string', alias: 'a', desc: 'REQUIRED: command-line for executing your app or a cloud assembly directory (e.g. "node bin/my-app.js")', requiresArg: true }) - .option('context', { type: 'array', alias: 'c', desc: 'Add contextual string parameter (KEY=VALUE)', nargs: 1, requiresArg: true }) - .option('plugin', { type: 'array', alias: 'p', desc: 'Name or path of a node package that extend the CDK features. Can be specified multiple times', nargs: 1 }) - .option('trace', { type: 'boolean', desc: 'Print trace for stack warnings' }) - .option('strict', { type: 'boolean', desc: 'Do not construct stacks with warnings' }) - .option('lookups', { type: 'boolean', desc: 'Perform context lookups (synthesis fails if this is disabled and context lookups need to be performed)', default: true }) - .option('ignore-errors', { type: 'boolean', default: false, desc: 'Ignores synthesis errors, which will likely produce an invalid output' }) - .option('json', { type: 'boolean', alias: 'j', desc: 'Use JSON output instead of YAML when templates are printed to STDOUT', default: false }) - .option('verbose', { type: 'boolean', alias: 'v', desc: 'Show debug logs (specify multiple times to increase verbosity)', default: false }) - .count('verbose') - .option('debug', { type: 'boolean', desc: 'Enable emission of additional debugging information, such as creation stack traces of tokens', default: false }) - .option('profile', { type: 'string', desc: 'Use the indicated AWS profile as the default environment', requiresArg: true }) - .option('proxy', { type: 'string', desc: 'Use the indicated proxy. Will read from HTTPS_PROXY environment variable if not specified', requiresArg: true }) - .option('ca-bundle-path', { type: 'string', desc: 'Path to CA certificate to use when validating HTTPS requests. Will read from AWS_CA_BUNDLE environment variable if not specified', requiresArg: true }) - .option('ec2creds', { type: 'boolean', alias: 'i', default: undefined, desc: 'Force trying to fetch EC2 instance credentials. Default: guess EC2 instance status' }) - .option('version-reporting', { type: 'boolean', desc: 'Include the "AWS::CDK::Metadata" resource in synthesized templates (enabled by default)', default: undefined }) - .option('path-metadata', { type: 'boolean', desc: 'Include "aws:cdk:path" CloudFormation metadata for each resource (enabled by default)', default: true }) - .option('asset-metadata', { type: 'boolean', desc: 'Include "aws:asset:*" CloudFormation metadata for resources that uses assets (enabled by default)', default: true }) - .option('role-arn', { type: 'string', alias: 'r', desc: 'ARN of Role to use when invoking CloudFormation', default: undefined, requiresArg: true }) - .option('toolkit-stack-name', { type: 'string', desc: 'The name of the CDK toolkit stack', requiresArg: true }) - .option('staging', { type: 'boolean', desc: 'Copy assets to the output directory (use --no-staging to disable, needed for local debugging the source files with SAM CLI)', default: true }) - .option('output', { type: 'string', alias: 'o', desc: 'Emits the synthesized cloud assembly into a directory (default: cdk.out)', requiresArg: true }) - .option('no-color', { type: 'boolean', desc: 'Removes colors and other style from console output', default: false }) - .command(['list [STACKS..]', 'ls [STACKS..]'], 'Lists all stacks in the app', yargs => yargs - .option('long', { type: 'boolean', default: false, alias: 'l', desc: 'Display environment information for each stack' }), - ) - .command(['synthesize [STACKS..]', 'synth [STACKS..]'], 'Synthesizes and prints the CloudFormation template for this stack', yargs => yargs - .option('exclusively', { type: 'boolean', alias: 'e', desc: 'Only synthesize requested stacks, don\'t include dependencies' }) - .option('validation', { type: 'boolean', desc: 'After synthesis, validate stacks with the "validateOnSynth" attribute set (can also be controlled with CDK_VALIDATION)', default: true }) - .option('quiet', { type: 'boolean', alias: 'q', desc: 'Do not output CloudFormation Template to stdout', default: false })) - .command('bootstrap [ENVIRONMENTS..]', 'Deploys the CDK toolkit stack into an AWS environment', yargs => yargs - .option('bootstrap-bucket-name', { type: 'string', alias: ['b', 'toolkit-bucket-name'], desc: 'The name of the CDK toolkit bucket; bucket will be created and must not exist', default: undefined }) - .option('bootstrap-kms-key-id', { type: 'string', desc: 'AWS KMS master key ID used for the SSE-KMS encryption', default: undefined, conflicts: 'bootstrap-customer-key' }) - .option('bootstrap-customer-key', { type: 'boolean', desc: 'Create a Customer Master Key (CMK) for the bootstrap bucket (you will be charged but can customize permissions, modern bootstrapping only)', default: undefined, conflicts: 'bootstrap-kms-key-id' }) - .option('qualifier', { type: 'string', desc: 'String which must be unique for each bootstrap stack. You must configure it on your CDK app if you change this from the default.', default: undefined }) - .option('public-access-block-configuration', { type: 'boolean', desc: 'Block public access configuration on CDK toolkit bucket (enabled by default) ', default: undefined }) - .option('tags', { type: 'array', alias: 't', desc: 'Tags to add for the stack (KEY=VALUE)', nargs: 1, requiresArg: true, default: [] }) - .option('execute', { type: 'boolean', desc: 'Whether to execute ChangeSet (--no-execute will NOT execute the ChangeSet)', default: true }) - .option('trust', { type: 'array', desc: 'The AWS account IDs that should be trusted to perform deployments into this environment (may be repeated, modern bootstrapping only)', default: [], nargs: 1, requiresArg: true }) - .option('trust-for-lookup', { type: 'array', desc: 'The AWS account IDs that should be trusted to look up values in this environment (may be repeated, modern bootstrapping only)', default: [], nargs: 1, requiresArg: true }) - .option('cloudformation-execution-policies', { type: 'array', desc: 'The Managed Policy ARNs that should be attached to the role performing deployments into this environment (may be repeated, modern bootstrapping only)', default: [], nargs: 1, requiresArg: true }) - .option('force', { alias: 'f', type: 'boolean', desc: 'Always bootstrap even if it would downgrade template version', default: false }) - .option('termination-protection', { type: 'boolean', default: undefined, desc: 'Toggle CloudFormation termination protection on the bootstrap stacks' }) - .option('show-template', { type: 'boolean', desc: 'Instead of actual bootstrapping, print the current CLI\'s bootstrapping template to stdout for customization', default: false }) - .option('template', { type: 'string', requiresArg: true, desc: 'Use the template from the given file instead of the built-in one (use --show-template to obtain an example)' }), - ) - .command('deploy [STACKS..]', 'Deploys the stack(s) named STACKS into your AWS account', yargs => yargs - .option('all', { type: 'boolean', default: false, desc: 'Deploy all available stacks' }) - .option('build-exclude', { type: 'array', alias: 'E', nargs: 1, desc: 'Do not rebuild asset with the given ID. Can be specified multiple times', default: [] }) - .option('exclusively', { type: 'boolean', alias: 'e', desc: 'Only deploy requested stacks, don\'t include dependencies' }) - .option('require-approval', { type: 'string', choices: [RequireApproval.Never, RequireApproval.AnyChange, RequireApproval.Broadening], desc: 'What security-sensitive changes need manual approval' }) - .option('ci', { type: 'boolean', desc: 'Force CI detection', default: process.env.CI !== undefined }) - .option('notification-arns', { type: 'array', desc: 'ARNs of SNS topics that CloudFormation will notify with stack related events', nargs: 1, requiresArg: true }) - // @deprecated(v2) -- tags are part of the Cloud Assembly and tags specified here will be overwritten on the next deployment - .option('tags', { type: 'array', alias: 't', desc: 'Tags to add to the stack (KEY=VALUE), overrides tags from Cloud Assembly (deprecated)', nargs: 1, requiresArg: true }) - .option('execute', { type: 'boolean', desc: 'Whether to execute ChangeSet (--no-execute will NOT execute the ChangeSet)', default: true }) - .option('change-set-name', { type: 'string', desc: 'Name of the CloudFormation change set to create' }) - .option('force', { alias: 'f', type: 'boolean', desc: 'Always deploy stack even if templates are identical', default: false }) - .option('parameters', { type: 'array', desc: 'Additional parameters passed to CloudFormation at deploy time (STACK:KEY=VALUE)', nargs: 1, requiresArg: true, default: {} }) - .option('outputs-file', { type: 'string', alias: 'O', desc: 'Path to file where stack outputs will be written as JSON', requiresArg: true }) - .option('previous-parameters', { type: 'boolean', default: true, desc: 'Use previous values for existing parameters (you must specify all parameters on every deployment if this is disabled)' }) - .option('progress', { type: 'string', choices: [StackActivityProgress.BAR, StackActivityProgress.EVENTS], desc: 'Display mode for stack activity events' }) - .option('rollback', { - type: 'boolean', - desc: "Rollback stack to stable state on failure. Defaults to 'true', iterate more rapidly with --no-rollback or -R. " + - 'Note: do **not** disable this flag for deployments with resource replacements, as that will always fail', - }) - // Hack to get '-R' as an alias for '--no-rollback', suggested by: https://github.com/yargs/yargs/issues/1729 - .option('R', { type: 'boolean', hidden: true }).middleware(yargsNegativeAlias('R', 'rollback'), true) - .option('hotswap', { - type: 'boolean', - desc: "Attempts to perform a 'hotswap' deployment, " + - 'which skips CloudFormation and updates the resources directly, ' + - 'and falls back to a full deployment if that is not possible. ' + - 'Do not use this in production environments', - }) - .option('watch', { - type: 'boolean', - desc: 'Continuously observe the project files, ' + - 'and deploy the given stack(s) automatically when changes are detected. ' + - 'Implies --hotswap by default', - }) - .options('logs', { - type: 'boolean', - default: true, - desc: 'Show CloudWatch log events from all resources in the selected Stacks in the terminal. ' + - "'true' by default, use --no-logs to turn off. " + - "Only in effect if specified alongside the '--watch' option", - }), - ) - .command('watch [STACKS..]', "Shortcut for 'deploy --watch'", yargs => yargs - // I'm fairly certain none of these options, present for 'deploy', make sense for 'watch': - // .option('all', { type: 'boolean', default: false, desc: 'Deploy all available stacks' }) - // .option('ci', { type: 'boolean', desc: 'Force CI detection', default: process.env.CI !== undefined }) - // @deprecated(v2) -- tags are part of the Cloud Assembly and tags specified here will be overwritten on the next deployment - // .option('tags', { type: 'array', alias: 't', desc: 'Tags to add to the stack (KEY=VALUE), overrides tags from Cloud Assembly (deprecated)', nargs: 1, requiresArg: true }) - // .option('execute', { type: 'boolean', desc: 'Whether to execute ChangeSet (--no-execute will NOT execute the ChangeSet)', default: true }) - // These options, however, are more subtle - I could be convinced some of these should also be available for 'watch': - // .option('require-approval', { type: 'string', choices: [RequireApproval.Never, RequireApproval.AnyChange, RequireApproval.Broadening], desc: 'What security-sensitive changes need manual approval' }) - // .option('parameters', { type: 'array', desc: 'Additional parameters passed to CloudFormation at deploy time (STACK:KEY=VALUE)', nargs: 1, requiresArg: true, default: {} }) - // .option('previous-parameters', { type: 'boolean', default: true, desc: 'Use previous values for existing parameters (you must specify all parameters on every deployment if this is disabled)' }) - // .option('outputs-file', { type: 'string', alias: 'O', desc: 'Path to file where stack outputs will be written as JSON', requiresArg: true }) - // .option('notification-arns', { type: 'array', desc: 'ARNs of SNS topics that CloudFormation will notify with stack related events', nargs: 1, requiresArg: true }) - .option('build-exclude', { type: 'array', alias: 'E', nargs: 1, desc: 'Do not rebuild asset with the given ID. Can be specified multiple times', default: [] }) - .option('exclusively', { type: 'boolean', alias: 'e', desc: 'Only deploy requested stacks, don\'t include dependencies' }) - .option('change-set-name', { type: 'string', desc: 'Name of the CloudFormation change set to create' }) - .option('force', { alias: 'f', type: 'boolean', desc: 'Always deploy stack even if templates are identical', default: false }) - .option('progress', { type: 'string', choices: [StackActivityProgress.BAR, StackActivityProgress.EVENTS], desc: 'Display mode for stack activity events' }) - .option('rollback', { - type: 'boolean', - desc: "Rollback stack to stable state on failure. Defaults to 'true', iterate more rapidly with --no-rollback or -R. " + - 'Note: do **not** disable this flag for deployments with resource replacements, as that will always fail', - }) - // same hack for -R as above in 'deploy' - .option('R', { type: 'boolean', hidden: true }).middleware(yargsNegativeAlias('R', 'rollback'), true) - .option('hotswap', { - type: 'boolean', - desc: "Attempts to perform a 'hotswap' deployment, " + - 'which skips CloudFormation and updates the resources directly, ' + - 'and falls back to a full deployment if that is not possible. ' + - "'true' by default, use --no-hotswap to turn off", - }) - .options('logs', { - type: 'boolean', - default: true, - desc: 'Show CloudWatch log events from all resources in the selected Stacks in the terminal. ' + - "'true' by default, use --no-logs to turn off", - }), - ) - .command('destroy [STACKS..]', 'Destroy the stack(s) named STACKS', yargs => yargs - .option('all', { type: 'boolean', default: false, desc: 'Destroy all available stacks' }) - .option('exclusively', { type: 'boolean', alias: 'e', desc: 'Only destroy requested stacks, don\'t include dependees' }) - .option('force', { type: 'boolean', alias: 'f', desc: 'Do not ask for confirmation before destroying the stacks' })) - .command('diff [STACKS..]', 'Compares the specified stack with the deployed stack or a local template file, and returns with status 1 if any difference is found', yargs => yargs - .option('exclusively', { type: 'boolean', alias: 'e', desc: 'Only diff requested stacks, don\'t include dependencies' }) - .option('context-lines', { type: 'number', desc: 'Number of context lines to include in arbitrary JSON diff rendering', default: 3, requiresArg: true }) - .option('template', { type: 'string', desc: 'The path to the CloudFormation template to compare with', requiresArg: true }) - .option('strict', { type: 'boolean', desc: 'Do not filter out AWS::CDK::Metadata resources', default: false }) - .option('security-only', { type: 'boolean', desc: 'Only diff for broadened security changes', default: false }) - .option('fail', { type: 'boolean', desc: 'Fail with exit code 1 in case of diff', default: false })) - .command('metadata [STACK]', 'Returns all metadata associated with this stack') - .command('init [TEMPLATE]', 'Create a new, empty CDK project from a template.', yargs => yargs - .option('language', { type: 'string', alias: 'l', desc: 'The language to be used for the new project (default can be configured in ~/.cdk.json)', choices: initTemplateLanguages }) - .option('list', { type: 'boolean', desc: 'List the available templates' }) - .option('generate-only', { type: 'boolean', default: false, desc: 'If true, only generates project files, without executing additional operations such as setting up a git repo, installing dependencies or compiling the project' }), - ) - .commandDir('../lib/commands', { exclude: /^_.*/ }) - .version(version.DISPLAY_VERSION) - .demandCommand(1, '') // just print help - .recommendCommands() - .help() - .alias('h', 'help') - .epilogue([ - 'If your app has a single stack, there is no need to specify the stack name', - 'If one of cdk.json or ~/.cdk.json exists, options specified there will be used as defaults. Settings in cdk.json take precedence.', - ].join('\n\n')) - .argv; -} - -if (!process.stdout.isTTY) { - // Disable chalk color highlighting - process.env.FORCE_COLOR = '0'; -} - -async function initCommandLine() { - const argv = await parseCommandLineArguments(); - if (argv.verbose) { - setLogLevel(argv.verbose); - } - debug('CDK toolkit version:', version.DISPLAY_VERSION); - debug('Command line arguments:', argv); - - const configuration = new Configuration({ - commandLineArguments: { - ...argv, - _: argv._ as [Command, ...string[]], // TypeScript at its best - }, - }); - await configuration.load(); - - const sdkProvider = await SdkProvider.withAwsCliCompatibleDefaults({ - profile: configuration.settings.get(['profile']), - ec2creds: argv.ec2creds, - httpOptions: { - proxyAddress: argv.proxy, - caBundlePath: argv['ca-bundle-path'], - }, - }); - - const cloudFormation = new CloudFormationDeployments({ sdkProvider }); - - const cloudExecutable = new CloudExecutable({ - configuration, - sdkProvider, - synthesizer: execProgram, - }); - - /** Function to load plug-ins, using configurations additively. */ - function loadPlugins(...settings: Settings[]) { - const loaded = new Set(); - for (const source of settings) { - const plugins: string[] = source.get(['plugin']) || []; - for (const plugin of plugins) { - const resolved = tryResolve(plugin); - if (loaded.has(resolved)) { continue; } - debug(`Loading plug-in: ${chalk.green(plugin)} from ${chalk.blue(resolved)}`); - PluginHost.instance.load(plugin); - loaded.add(resolved); - } - } - - function tryResolve(plugin: string): string { - try { - return require.resolve(plugin); - } catch (e) { - error(`Unable to resolve plugin ${chalk.green(plugin)}: ${e.stack}`); - throw new Error(`Unable to resolve plug-in: ${plugin}`); - } - } - } - - loadPlugins(configuration.settings); - - const cmd = argv._[0]; - - if (typeof(cmd) !== 'string') { - throw new Error(`First argument should be a string. Got: ${cmd} (${typeof(cmd)})`); - } - - // Bundle up global objects so the commands have access to them - const commandOptions = { args: argv, configuration, aws: sdkProvider }; - - try { - const returnValue = argv.commandHandler - ? await (argv.commandHandler as (opts: typeof commandOptions) => any)(commandOptions) - : await main(cmd, argv); - if (typeof returnValue === 'object') { - return toJsonOrYaml(returnValue); - } else if (typeof returnValue === 'string') { - return returnValue; - } else { - return returnValue; - } - } finally { - await version.displayVersionMessage(); - } - - async function main(command: string, args: any): Promise { - const toolkitStackName: string = ToolkitInfo.determineName(configuration.settings.get(['toolkitStackName'])); - debug(`Toolkit stack: ${chalk.bold(toolkitStackName)}`); - - if (args.all && args.STACKS) { - throw new Error('You must either specify a list of Stacks or the `--all` argument'); - } - - args.STACKS = args.STACKS || []; - args.ENVIRONMENTS = args.ENVIRONMENTS || []; - - const selector: StackSelector = { - allTopLevel: args.all, - patterns: args.STACKS, - }; - - const cli = new CdkToolkit({ - cloudExecutable, - cloudFormation, - verbose: argv.trace || argv.verbose > 0, - ignoreErrors: argv['ignore-errors'], - strict: argv.strict, - configuration, - sdkProvider, - }); - - switch (command) { - case 'ls': - case 'list': - return cli.list(args.STACKS, { long: args.long }); - - case 'diff': - const enableDiffNoFail = isFeatureEnabled(configuration, cxapi.ENABLE_DIFF_NO_FAIL); - return cli.diff({ - stackNames: args.STACKS, - exclusively: args.exclusively, - templatePath: args.template, - strict: args.strict, - contextLines: args.contextLines, - securityOnly: args.securityOnly, - fail: args.fail || !enableDiffNoFail, - }); - - case 'bootstrap': - const source: BootstrapSource = determineBootsrapVersion(args, configuration); - - const bootstrapper = new Bootstrapper(source); - - if (args.showTemplate) { - return bootstrapper.showTemplate(); - } - - return cli.bootstrap(args.ENVIRONMENTS, bootstrapper, { - roleArn: args.roleArn, - force: argv.force, - toolkitStackName: toolkitStackName, - execute: args.execute, - tags: configuration.settings.get(['tags']), - terminationProtection: args.terminationProtection, - parameters: { - bucketName: configuration.settings.get(['toolkitBucket', 'bucketName']), - kmsKeyId: configuration.settings.get(['toolkitBucket', 'kmsKeyId']), - createCustomerMasterKey: args.bootstrapCustomerKey, - qualifier: args.qualifier, - publicAccessBlockConfiguration: args.publicAccessBlockConfiguration, - trustedAccounts: arrayFromYargs(args.trust), - trustedAccountsForLookup: arrayFromYargs(args.trustForLookup), - cloudFormationExecutionPolicies: arrayFromYargs(args.cloudformationExecutionPolicies), - }, - }); - - case 'deploy': - const parameterMap: { [name: string]: string | undefined } = {}; - for (const parameter of args.parameters) { - if (typeof parameter === 'string') { - const keyValue = (parameter as string).split('='); - parameterMap[keyValue[0]] = keyValue.slice(1).join('='); - } - } - return cli.deploy({ - selector, - exclusively: args.exclusively, - toolkitStackName, - roleArn: args.roleArn, - notificationArns: args.notificationArns, - requireApproval: configuration.settings.get(['requireApproval']), - reuseAssets: args['build-exclude'], - tags: configuration.settings.get(['tags']), - execute: args.execute, - changeSetName: args.changeSetName, - force: args.force, - parameters: parameterMap, - usePreviousParameters: args['previous-parameters'], - outputsFile: configuration.settings.get(['outputsFile']), - progress: configuration.settings.get(['progress']), - ci: args.ci, - rollback: configuration.settings.get(['rollback']), - hotswap: args.hotswap, - watch: args.watch, - traceLogs: args.logs, - }); - - case 'watch': - return cli.watch({ - selector, - // parameters: parameterMap, - // usePreviousParameters: args['previous-parameters'], - // outputsFile: configuration.settings.get(['outputsFile']), - // requireApproval: configuration.settings.get(['requireApproval']), - // notificationArns: args.notificationArns, - exclusively: args.exclusively, - toolkitStackName, - roleArn: args.roleArn, - reuseAssets: args['build-exclude'], - changeSetName: args.changeSetName, - force: args.force, - progress: configuration.settings.get(['progress']), - rollback: configuration.settings.get(['rollback']), - hotswap: args.hotswap, - traceLogs: args.logs, - }); - - case 'destroy': - return cli.destroy({ - selector, - exclusively: args.exclusively, - force: args.force, - roleArn: args.roleArn, - }); - - case 'synthesize': - case 'synth': - if (args.exclusively) { - return cli.synth(args.STACKS, args.exclusively, args.quiet, args.validation); - } else { - return cli.synth(args.STACKS, true, args.quiet, args.validation); - } - - - case 'metadata': - return cli.metadata(args.STACK); - - case 'init': - const language = configuration.settings.get(['language']); - if (args.list) { - return printAvailableTemplates(language); - } else { - return cliInit(args.TEMPLATE, language, undefined, args.generateOnly); - } - case 'version': - return data(version.DISPLAY_VERSION); - - default: - throw new Error('Unknown command: ' + command); - } - } - - function toJsonOrYaml(object: any): string { - return serializeStructure(object, argv.json); - } -} - -/** - * Determine which version of bootstrapping - * (legacy, or "new") should be used. - */ -function determineBootsrapVersion(args: { template?: string }, configuration: Configuration): BootstrapSource { - const isV1 = version.DISPLAY_VERSION.startsWith('1.'); - return isV1 ? determineV1BootstrapSource(args, configuration) : determineV2BootstrapSource(args); -} - -function determineV1BootstrapSource(args: { template?: string }, configuration: Configuration): BootstrapSource { - let source: BootstrapSource; - if (args.template) { - print(`Using bootstrapping template from ${args.template}`); - source = { source: 'custom', templateFile: args.template }; - } else if (process.env.CDK_NEW_BOOTSTRAP) { - print('CDK_NEW_BOOTSTRAP set, using new-style bootstrapping'); - source = { source: 'default' }; - } else if (isFeatureEnabled(configuration, cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT)) { - print(`'${cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT}' context set, using new-style bootstrapping`); - source = { source: 'default' }; - } else { - // in V1, the "legacy" bootstrapping is the default - source = { source: 'legacy' }; - } - return source; -} - -function determineV2BootstrapSource(args: { template?: string }): BootstrapSource { - let source: BootstrapSource; - if (args.template) { - print(`Using bootstrapping template from ${args.template}`); - source = { source: 'custom', templateFile: args.template }; - } else if (process.env.CDK_LEGACY_BOOTSTRAP) { - print('CDK_LEGACY_BOOTSTRAP set, using legacy-style bootstrapping'); - source = { source: 'legacy' }; - } else { - // in V2, the "new" bootstrapping is the default - source = { source: 'default' }; - } - return source; -} - -function isFeatureEnabled(configuration: Configuration, featureFlag: string) { - return configuration.context.get(featureFlag) ?? cxapi.futureFlagDefault(featureFlag); -} - -/** - * Translate a Yargs input array to something that makes more sense in a programming language - * model (telling the difference between absence and an empty array) - * - * - An empty array is the default case, meaning the user didn't pass any arguments. We return - * undefined. - * - If the user passed a single empty string, they did something like `--array=`, which we'll - * take to mean they passed an empty array. - */ -function arrayFromYargs(xs: string[]): string[] | undefined { - if (xs.length === 0) { return undefined; } - return xs.filter(x => x !== ''); -} - -function yargsNegativeAlias(shortName: S, longName: L) { - return (argv: T) => { - if (shortName in argv && argv[shortName]) { - (argv as any)[longName] = false; - } - return argv; - }; -} - -initCommandLine() - .then(value => { - if (value == null) { return; } - if (typeof value === 'string') { - data(value); - } else if (typeof value === 'number') { - process.exitCode = value; - } - }) - .catch(err => { - error(err.message); - if (err.stack) { - debug(err.stack); - } - process.exitCode = 1; - }); +cli(); diff --git a/packages/aws-cdk/lib/api/aws-auth/_env.ts b/packages/aws-cdk/lib/api/aws-auth/_env.ts new file mode 100644 index 0000000000000..a5df37a182412 --- /dev/null +++ b/packages/aws-cdk/lib/api/aws-auth/_env.ts @@ -0,0 +1,17 @@ +/** + * This file exists to expose and centralize some features that the files in this module expect from the surrounding + * CLI. + * + * The calls will be forwarded to whatever logging system is the "official" logging system for this CLI. + * + * Centralizing in this way makes it easy to copy/paste this directory out and have a single place to + * break dependencies and replace these functions. + */ + +export { debug, warning, trace } from '../../logging'; + +import { cdkCacheDir } from '../../util/directories'; + +export function accountCacheDir() { + return cdkCacheDir(); +} \ No newline at end of file diff --git a/packages/aws-cdk/lib/api/aws-auth/account-cache.ts b/packages/aws-cdk/lib/api/aws-auth/account-cache.ts index d7c753781c11f..fa7687b3293c3 100644 --- a/packages/aws-cdk/lib/api/aws-auth/account-cache.ts +++ b/packages/aws-cdk/lib/api/aws-auth/account-cache.ts @@ -1,7 +1,6 @@ import * as path from 'path'; import * as fs from 'fs-extra'; -import { debug } from '../../logging'; -import { cdkCacheDir } from '../../util/directories'; +import { accountCacheDir, debug } from './_env'; import { Account } from './sdk-provider'; /** @@ -22,7 +21,7 @@ export class AccountAccessKeyCache { * @param filePath Path to the cache file */ constructor(filePath?: string) { - this.cacheFile = filePath || path.join(cdkCacheDir(), 'accounts_partitions.json'); + this.cacheFile = filePath || path.join(accountCacheDir(), 'accounts_partitions.json'); } /** diff --git a/packages/aws-cdk/lib/api/aws-auth/awscli-compatible.ts b/packages/aws-cdk/lib/api/aws-auth/awscli-compatible.ts index eb141768b9644..3c5651396200e 100644 --- a/packages/aws-cdk/lib/api/aws-auth/awscli-compatible.ts +++ b/packages/aws-cdk/lib/api/aws-auth/awscli-compatible.ts @@ -5,7 +5,7 @@ import * as util from 'util'; import * as AWS from 'aws-sdk'; import * as fs from 'fs-extra'; import * as promptly from 'promptly'; -import { debug } from '../../logging'; +import { debug } from './_env'; import { PatchedSharedIniFileCredentials } from './aws-sdk-inifile'; import { SharedIniFile } from './sdk_ini_file'; @@ -33,17 +33,15 @@ export class AwsCliCompatible { * 4. Respects $AWS_DEFAULT_PROFILE in addition to $AWS_PROFILE. */ public static async credentialChain(options: CredentialChainOptions = {}) { + // Force reading the `config` file if it exists by setting the appropriate + // environment variable. + await forceSdkToReadConfigIfPresent(); // To match AWS CLI behavior, if a profile is explicitly given using --profile, // we use that to the exclusion of everything else (note: this does not apply // to AWS_PROFILE, environment credentials still take precedence over AWS_PROFILE) if (options.profile) { - await forceSdkToReadConfigIfPresent(); - const theProfile = options.profile; - return new AWS.CredentialProviderChain([ - () => profileCredentials(theProfile), - () => new AWS.ProcessCredentials({ profile: theProfile }), - ]); + return new AWS.CredentialProviderChain(iniFileCredentialFactories(options.profile)); } const implicitProfile = process.env.AWS_PROFILE || process.env.AWS_DEFAULT_PROFILE || 'default'; @@ -51,16 +49,9 @@ export class AwsCliCompatible { const sources = [ () => new AWS.EnvironmentCredentials('AWS'), () => new AWS.EnvironmentCredentials('AMAZON'), + ...iniFileCredentialFactories(implicitProfile), ]; - if (await fs.pathExists(credentialsFileName())) { - // Force reading the `config` file if it exists by setting the appropriate - // environment variable. - await forceSdkToReadConfigIfPresent(); - sources.push(() => profileCredentials(implicitProfile)); - sources.push(() => new AWS.ProcessCredentials({ profile: implicitProfile })); - } - if (options.containerCreds ?? hasEcsCredentials()) { sources.push(() => new AWS.ECSCredentials()); } else if (hasWebIdentityCredentials()) { @@ -83,6 +74,14 @@ export class AwsCliCompatible { tokenCodeFn, }); } + + function iniFileCredentialFactories(theProfile: string) { + return [ + () => profileCredentials(theProfile), + () => new AWS.SsoCredentials({ profile: theProfile }), + () => new AWS.ProcessCredentials({ profile: theProfile }), + ]; + } } /** diff --git a/packages/aws-cdk/lib/util/functions.ts b/packages/aws-cdk/lib/api/aws-auth/cached.ts similarity index 99% rename from packages/aws-cdk/lib/util/functions.ts rename to packages/aws-cdk/lib/api/aws-auth/cached.ts index 6c4f00480e17f..a6b295994377c 100644 --- a/packages/aws-cdk/lib/util/functions.ts +++ b/packages/aws-cdk/lib/api/aws-auth/cached.ts @@ -9,4 +9,4 @@ export function cached(obj: A, sym: symbol, fn: () => B): B (obj as any)[sym] = fn(); } return (obj as any)[sym]; -} \ No newline at end of file +} diff --git a/packages/aws-cdk/lib/api/aws-auth/credential-plugins.ts b/packages/aws-cdk/lib/api/aws-auth/credential-plugins.ts index d8ebb50d889af..bcb13a2d90df0 100644 --- a/packages/aws-cdk/lib/api/aws-auth/credential-plugins.ts +++ b/packages/aws-cdk/lib/api/aws-auth/credential-plugins.ts @@ -1,6 +1,6 @@ -import { debug } from '../../logging'; -import { PluginHost } from '../../plugin'; -import { CredentialProviderSource, Mode } from './credentials'; +import { CredentialProviderSource, PluginHost } from '../plugin'; +import { debug } from './_env'; +import { Mode } from './credentials'; /** * Cache for credential providers. diff --git a/packages/aws-cdk/lib/api/aws-auth/credentials.ts b/packages/aws-cdk/lib/api/aws-auth/credentials.ts index 8643f3d76eac3..b93cd43550a5c 100644 --- a/packages/aws-cdk/lib/api/aws-auth/credentials.ts +++ b/packages/aws-cdk/lib/api/aws-auth/credentials.ts @@ -1,31 +1,3 @@ -import * as aws from 'aws-sdk'; - -export enum Mode { - ForReading, - ForWriting -} - -/** - */ -export interface CredentialProviderSource { - name: string; - - /** - * Whether the credential provider is even online - * - * Guaranteed to be called before any of the other functions are called. - */ - isAvailable(): Promise; - - /** - * Whether the credential provider can provide credentials for the given account. - */ - canProvideCredentials(accountId: string): Promise; - - /** - * Construct a credential provider for the given account and the given access mode - * - * Guaranteed to be called only if canProvideCredentails() returned true at some point. - */ - getProvider(accountId: string, mode: Mode): Promise; -} +// Re-export this here because it used to be here and I don't want +// to change imports too much. +export { Mode } from '../plugin'; \ No newline at end of file diff --git a/packages/aws-cdk/lib/api/aws-auth/sdk-provider.ts b/packages/aws-cdk/lib/api/aws-auth/sdk-provider.ts index ad2af9f62ef61..39f7cd2f2a1b1 100644 --- a/packages/aws-cdk/lib/api/aws-auth/sdk-provider.ts +++ b/packages/aws-cdk/lib/api/aws-auth/sdk-provider.ts @@ -4,11 +4,11 @@ import * as cxapi from '@aws-cdk/cx-api'; import * as AWS from 'aws-sdk'; import type { ConfigurationOptions } from 'aws-sdk/lib/config-base'; import * as fs from 'fs-extra'; -import { debug, warning } from '../../logging'; -import { cached } from '../../util/functions'; -import { CredentialPlugins } from '../aws-auth/credential-plugins'; -import { Mode } from '../aws-auth/credentials'; +import { debug, warning } from './_env'; import { AwsCliCompatible } from './awscli-compatible'; +import { cached } from './cached'; +import { CredentialPlugins } from './credential-plugins'; +import { Mode } from './credentials'; import { ISDK, SDK } from './sdk'; diff --git a/packages/aws-cdk/lib/api/aws-auth/sdk.ts b/packages/aws-cdk/lib/api/aws-auth/sdk.ts index b805597cc010b..a325316ef150e 100644 --- a/packages/aws-cdk/lib/api/aws-auth/sdk.ts +++ b/packages/aws-cdk/lib/api/aws-auth/sdk.ts @@ -1,8 +1,8 @@ import * as AWS from 'aws-sdk'; import type { ConfigurationOptions } from 'aws-sdk/lib/config-base'; -import { debug, trace } from '../../logging'; -import { cached } from '../../util/functions'; +import { debug, trace } from './_env'; import { AccountAccessKeyCache } from './account-cache'; +import { cached } from './cached'; import { Account } from './sdk-provider'; // We need to map regions to domain suffixes, and the SDK already has a function to do this. @@ -63,6 +63,7 @@ export interface ISDK { stepFunctions(): AWS.StepFunctions; codeBuild(): AWS.CodeBuild cloudWatchLogs(): AWS.CloudWatchLogs; + appsync(): AWS.AppSync; } /** @@ -190,6 +191,10 @@ export class SDK implements ISDK { return this.wrapServiceErrorHandling(new AWS.CloudWatchLogs(this.config)); } + public appsync(): AWS.AppSync { + return this.wrapServiceErrorHandling(new AWS.AppSync(this.config)); + } + public async currentAccount(): Promise { // Get/refresh if necessary before we can access `accessKeyId` await this.forceCredentialRetrieval(); diff --git a/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts b/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts index 7877368710c5f..a7b63214a3c80 100644 --- a/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts +++ b/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts @@ -3,6 +3,7 @@ import * as path from 'path'; import * as cxapi from '@aws-cdk/cx-api'; import { warning } from '../../logging'; import { loadStructuredFile, toYAML } from '../../serialize'; +import { rootDir } from '../../util/directories'; import { SdkProvider } from '../aws-auth'; import { DeployStackResult } from '../deploy-stack'; import { BootstrapEnvironmentOptions, BootstrappingParameters } from './bootstrap-props'; @@ -170,7 +171,7 @@ export class Bootstrapper { case 'custom': return loadStructuredFile(this.source.templateFile); case 'default': - return loadStructuredFile(path.join(__dirname, 'bootstrap-template.yaml')); + return loadStructuredFile(path.join(rootDir(), 'lib', 'api', 'bootstrap', 'bootstrap-template.yaml')); case 'legacy': return legacyBootstrapTemplate(params); } diff --git a/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml b/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml index b7871900b3a46..15d7a22f1edfd 100644 --- a/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml +++ b/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml @@ -209,6 +209,20 @@ Resources: - HasCustomContainerAssetsRepositoryName - Fn::Sub: "${ContainerAssetsRepositoryName}" - Fn::Sub: cdk-${Qualifier}-container-assets-${AWS::AccountId}-${AWS::Region} + RepositoryPolicyText: + Version: "2012-10-17" + Statement: + # Necessary for Lambda container images + # https://docs.aws.amazon.com/lambda/latest/dg/configuration-images.html#configuration-images-permissions + - Sid: LambdaECRImageRetrievalPolicy + Effect: Allow + Principal: { Service: "lambda.amazonaws.com" } + Action: + - ecr:BatchGetImage + - ecr:GetDownloadUrlForLayer + Condition: + StringLike: + "aws:sourceArn": { "Fn::Sub": "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:*" } FilePublishingRole: Type: AWS::IAM::Role Properties: @@ -493,7 +507,7 @@ Resources: Type: String Name: Fn::Sub: '/cdk-bootstrap/${Qualifier}/version' - Value: '10' + Value: '11' Outputs: BucketName: Description: The name of the S3 bucket owned by the CDK toolkit stack diff --git a/packages/aws-cdk/lib/api/cloudformation-deployments.ts b/packages/aws-cdk/lib/api/cloudformation-deployments.ts index 835d8f9ad3015..ebf40bbb7442b 100644 --- a/packages/aws-cdk/lib/api/cloudformation-deployments.ts +++ b/packages/aws-cdk/lib/api/cloudformation-deployments.ts @@ -1,13 +1,13 @@ -import * as path from 'path'; import * as cxapi from '@aws-cdk/cx-api'; import { AssetManifest } from 'cdk-assets'; -import * as fs from 'fs-extra'; import { Tag } from '../cdk-toolkit'; import { debug, warning } from '../logging'; import { publishAssets } from '../util/asset-publishing'; -import { Mode, SdkProvider, ISDK } from './aws-auth'; +import { Mode } from './aws-auth/credentials'; +import { ISDK } from './aws-auth/sdk'; +import { SdkProvider } from './aws-auth/sdk-provider'; import { deployStack, DeployStackResult, destroyStack } from './deploy-stack'; -import { LazyListStackResources, ListStackResources } from './evaluate-cloudformation-template'; +import { loadCurrentTemplateWithNestedStacks, loadCurrentTemplate } from './nested-stack-helpers'; import { ToolkitInfo } from './toolkit-info'; import { CloudFormationStack, Template } from './util/cloudformation'; import { StackActivityProgress } from './util/cloudformation/stack-activity-monitor'; @@ -281,21 +281,13 @@ export class CloudFormationDeployments { public async readCurrentTemplateWithNestedStacks(rootStackArtifact: cxapi.CloudFormationStackArtifact): Promise