diff --git a/package.json b/package.json index eecc83ce460de..89f1dbfff0c73 100644 --- a/package.json +++ b/package.json @@ -119,6 +119,8 @@ "@aws-cdk/core/minimatch/**", "@aws-cdk/core/table", "@aws-cdk/core/table/**", + "@aws-cdk/core/yaml", + "@aws-cdk/core/yaml/**", "@aws-cdk/cx-api/semver", "@aws-cdk/cx-api/semver/**", "@aws-cdk/pipelines/aws-sdk", diff --git a/packages/@aws-cdk/aws-s3-deployment/README.md b/packages/@aws-cdk/aws-s3-deployment/README.md index 8e445f13bb67b..9cad6df9e5515 100644 --- a/packages/@aws-cdk/aws-s3-deployment/README.md +++ b/packages/@aws-cdk/aws-s3-deployment/README.md @@ -86,6 +86,8 @@ The following source types are supported for bucket deployments: (supports [deploy-time values](#data-with-deploy-time-values)) - JSON data: `s3deploy.Source.jsonData('object-key.json', { json: 'object' })` (supports [deploy-time values](#data-with-deploy-time-values)) +- YAML data: `s3deploy.Source.yamlData('object-key.yaml', { yaml: 'object' })` + (supports [deploy-time values](#data-with-deploy-time-values)) To create a source from a single file, you can pass `AssetOptions` to exclude all but a single file: @@ -313,7 +315,7 @@ new s3deploy.BucketDeployment(this, 'DeployMeWithEfsStorage', { ## Data with deploy-time values -The content passed to `Source.data()` or `Source.jsonData()` can include +The content passed to `Source.data()`, `Source.jsonData()`, or `Source.yamlData()` can include references that will get resolved only during deployment. For example: diff --git a/packages/@aws-cdk/aws-s3-deployment/lib/source.ts b/packages/@aws-cdk/aws-s3-deployment/lib/source.ts index a570f84cfacdb..05791088332e5 100644 --- a/packages/@aws-cdk/aws-s3-deployment/lib/source.ts +++ b/packages/@aws-cdk/aws-s3-deployment/lib/source.ts @@ -58,7 +58,8 @@ export interface ISource { * Source.asset('/local/path/to/directory') * Source.asset('/local/path/to/a/file.zip') * Source.data('hello/world/file.txt', 'Hello, world!') - * Source.data('config.json', { baz: topic.topicArn }) + * Source.dataJson('config.json', { baz: topic.topicArn }) + * Source.dataYaml('config.yaml', { baz: topic.topicArn }) * */ export class Source { @@ -125,6 +126,7 @@ export class Source { * will get resolved only during deployment. * * To store a JSON object use `Source.jsonData()`. + * To store YAML content use `Source.yamlData()`. * * @param objectKey The destination S3 object key (relative to the root of the * S3 deployment). @@ -165,5 +167,22 @@ export class Source { }; } + /** + * Deploys an object with the specified JSON object formatted as YAML into the bucket. + * The object can include deploy-time values (such as `snsTopic.topicArn`) that + * will get resolved only during deployment. + * + * @param objectKey The destination S3 object key (relative to the root of the + * S3 deployment). + * @param obj A JSON object. + */ + public static yamlData(objectKey: string, obj: any): ISource { + return { + bind: (scope: Construct, context?: DeploymentSourceContext) => { + return Source.data(objectKey, Stack.of(scope).toYamlString(obj)).bind(scope, context); + }, + }; + } + private constructor() { } } 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 83fcdde0b1982..5c7d31690a7b4 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 @@ -1387,6 +1387,32 @@ test('Source.jsonData() can be used to create a file with a JSON object', () => }); }); +test('Source.yamlData() can be used to create a file with YAML content', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Test'); + const bucket = new s3.Bucket(stack, 'Bucket'); + + const config = { + foo: 'bar', + sub: { + hello: bucket.bucketArn, + }, + }; + + new s3deploy.BucketDeployment(stack, 'DeployWithVpc3', { + sources: [s3deploy.Source.yamlData('app-config.yaml', config)], + destinationBucket: bucket, + }); + + const result = app.synth(); + const output = readDataFile(result, 'app-config.yaml'); + expect(output.trim()).toEqual([ + 'foo: bar', + 'sub:', + ' hello: <>', + ].join('\n')); +}); + test('can add sources with addSource', () => { const app = new cdk.App(); const stack = new cdk.Stack(app, 'Test'); diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/TestBucketDeploymentContent.assets.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/TestBucketDeploymentContent.assets.json index c70f8f4c0bfec..ccc616488fb19 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/TestBucketDeploymentContent.assets.json +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/TestBucketDeploymentContent.assets.json @@ -1,28 +1,28 @@ { - "version": "20.0.0", + "version": "31.0.0", "files": { - "39ee629321f531fffd853b944b2d6f3fa7b5276431c9a4fd4dc681303ab15080": { + "68b22621fff135f9e3f225bad7ff80fdf2f45c3d9910af601206a0d9b279933a": { "source": { - "path": "asset.39ee629321f531fffd853b944b2d6f3fa7b5276431c9a4fd4dc681303ab15080.zip", + "path": "asset.68b22621fff135f9e3f225bad7ff80fdf2f45c3d9910af601206a0d9b279933a.zip", "packaging": "file" }, "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "39ee629321f531fffd853b944b2d6f3fa7b5276431c9a4fd4dc681303ab15080.zip", + "objectKey": "68b22621fff135f9e3f225bad7ff80fdf2f45c3d9910af601206a0d9b279933a.zip", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } }, - "f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da": { + "2bc265c5e0569aeb24a6349c15bd54e76e845892376515e036627ab0cc70bb64": { "source": { - "path": "asset.f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da", + "path": "asset.2bc265c5e0569aeb24a6349c15bd54e76e845892376515e036627ab0cc70bb64", "packaging": "zip" }, "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da.zip", + "objectKey": "2bc265c5e0569aeb24a6349c15bd54e76e845892376515e036627ab0cc70bb64.zip", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } @@ -53,20 +53,33 @@ } } }, - "0d7be86c2a7d62be64fcbe2cbaa36c912a72d445022cc17c37af4f99f1b97a5a": { + "27eff729291aea0a2b33592996b9a764c233dc3387bd9cfd58c6f064073f177f": { "source": { - "path": "asset.0d7be86c2a7d62be64fcbe2cbaa36c912a72d445022cc17c37af4f99f1b97a5a", + "path": "asset.27eff729291aea0a2b33592996b9a764c233dc3387bd9cfd58c6f064073f177f", "packaging": "zip" }, "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "0d7be86c2a7d62be64fcbe2cbaa36c912a72d445022cc17c37af4f99f1b97a5a.zip", + "objectKey": "27eff729291aea0a2b33592996b9a764c233dc3387bd9cfd58c6f064073f177f.zip", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } }, - "55549864d8c27c2125682e2e817e0a7fede6b77576ccd6e21178645f08472948": { + "939a4ab8b51f1a1cccb59d97f04c318ad41c1d404e666c158ca2810894bc5f5f": { + "source": { + "path": "asset.939a4ab8b51f1a1cccb59d97f04c318ad41c1d404e666c158ca2810894bc5f5f", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "939a4ab8b51f1a1cccb59d97f04c318ad41c1d404e666c158ca2810894bc5f5f.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "2961e8222a48394849f4466d2789ae256aa88adc4ccbf79feb35306b850c08dc": { "source": { "path": "TestBucketDeploymentContent.template.json", "packaging": "file" @@ -74,7 +87,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "55549864d8c27c2125682e2e817e0a7fede6b77576ccd6e21178645f08472948.json", + "objectKey": "2961e8222a48394849f4466d2789ae256aa88adc4ccbf79feb35306b850c08dc.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/TestBucketDeploymentContent.template.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/TestBucketDeploymentContent.template.json index 598684832244d..bb2763ba24063 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/TestBucketDeploymentContent.template.json +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/TestBucketDeploymentContent.template.json @@ -20,7 +20,7 @@ "S3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "S3Key": "39ee629321f531fffd853b944b2d6f3fa7b5276431c9a4fd4dc681303ab15080.zip" + "S3Key": "68b22621fff135f9e3f225bad7ff80fdf2f45c3d9910af601206a0d9b279933a.zip" }, "Description": "/opt/awscli/aws" } @@ -41,6 +41,9 @@ { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" } @@ -48,7 +51,8 @@ "SourceObjectKeys": [ "d09271be89b6cb0398f793b40c1531fd9b076aa92ba80b5e436914b1808fe18d.zip", "0f14dedeaf4386031c978375cbda0f65d7b52b29452cabb8873eb8f0d0fa936b.zip", - "0d7be86c2a7d62be64fcbe2cbaa36c912a72d445022cc17c37af4f99f1b97a5a.zip" + "27eff729291aea0a2b33592996b9a764c233dc3387bd9cfd58c6f064073f177f.zip", + "939a4ab8b51f1a1cccb59d97f04c318ad41c1d404e666c158ca2810894bc5f5f.zip" ], "SourceMarkers": [ {}, @@ -57,6 +61,14 @@ "Ref": "Bucket83908E77" } }, + { + "<>": { + "Fn::GetAtt": [ + "Bucket83908E77", + "WebsiteURL" + ] + } + }, { "<>": { "Fn::GetAtt": [ @@ -208,7 +220,7 @@ "S3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "S3Key": "f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da.zip" + "S3Key": "2bc265c5e0569aeb24a6349c15bd54e76e845892376515e036627ab0cc70bb64.zip" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.0d7be86c2a7d62be64fcbe2cbaa36c912a72d445022cc17c37af4f99f1b97a5a/my/config.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.27eff729291aea0a2b33592996b9a764c233dc3387bd9cfd58c6f064073f177f/my-json/config.json similarity index 100% rename from packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.0d7be86c2a7d62be64fcbe2cbaa36c912a72d445022cc17c37af4f99f1b97a5a/my/config.json rename to packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.27eff729291aea0a2b33592996b9a764c233dc3387bd9cfd58c6f064073f177f/my-json/config.json diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da/index.py b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.2bc265c5e0569aeb24a6349c15bd54e76e845892376515e036627ab0cc70bb64/index.py similarity index 92% rename from packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da/index.py rename to packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.2bc265c5e0569aeb24a6349c15bd54e76e845892376515e036627ab0cc70bb64/index.py index 877b78a8452ee..e013fae72f87d 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da/index.py +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.2bc265c5e0569aeb24a6349c15bd54e76e845892376515e036627ab0cc70bb64/index.py @@ -49,6 +49,7 @@ def cfn_error(message=None): source_markers = props.get('SourceMarkers', None) dest_bucket_name = props['DestinationBucketName'] dest_bucket_prefix = props.get('DestinationBucketKeyPrefix', '') + extract = props.get('Extract', 'true') == 'true' retain_on_delete = props.get('RetainOnDelete', "true") == "true" distribution_id = props.get('DistributionId', '') user_metadata = props.get('UserMetadata', {}) @@ -113,14 +114,15 @@ def cfn_error(message=None): aws_command("s3", "rm", old_s3_dest, "--recursive") if request_type == "Update" or request_type == "Create": - s3_deploy(s3_source_zips, s3_dest, user_metadata, system_metadata, prune, exclude, include, source_markers) + s3_deploy(s3_source_zips, s3_dest, user_metadata, system_metadata, prune, exclude, include, source_markers, extract) if distribution_id: cloudfront_invalidate(distribution_id, distribution_paths) cfn_send(event, context, CFN_SUCCESS, physicalResourceId=physical_id, responseData={ # Passing through the ARN sequences dependencees on the deployment - 'DestinationBucketArn': props.get('DestinationBucketArn') + 'DestinationBucketArn': props.get('DestinationBucketArn'), + 'SourceObjectKeys': props.get('SourceObjectKeys'), }) except KeyError as e: cfn_error("invalid request. Missing key %s" % str(e)) @@ -130,7 +132,7 @@ def cfn_error(message=None): #--------------------------------------------------------------------------------------------------- # populate all files from s3_source_zips to a destination bucket -def s3_deploy(s3_source_zips, s3_dest, user_metadata, system_metadata, prune, exclude, include, source_markers): +def s3_deploy(s3_source_zips, s3_dest, user_metadata, system_metadata, prune, exclude, include, source_markers, extract): # list lengths are equal if len(s3_source_zips) != len(source_markers): raise Exception("'source_markers' and 's3_source_zips' must be the same length") @@ -154,12 +156,16 @@ def s3_deploy(s3_source_zips, s3_dest, user_metadata, system_metadata, prune, ex s3_source_zip = s3_source_zips[i] markers = source_markers[i] - archive=os.path.join(workdir, str(uuid4())) - logger.info("archive: %s" % archive) - aws_command("s3", "cp", s3_source_zip, archive) - logger.info("| extracting archive to: %s\n" % contents_dir) - logger.info("| markers: %s" % markers) - extract_and_replace_markers(archive, contents_dir, markers) + if extract: + archive=os.path.join(workdir, str(uuid4())) + logger.info("archive: %s" % archive) + aws_command("s3", "cp", s3_source_zip, archive) + logger.info("| extracting archive to: %s\n" % contents_dir) + logger.info("| markers: %s" % markers) + extract_and_replace_markers(archive, contents_dir, markers) + else: + logger.info("| copying archive to: %s\n" % contents_dir) + aws_command("s3", "cp", s3_source_zip, contents_dir) # sync from "contents" to destination @@ -230,7 +236,6 @@ def aws_command(*args): def cfn_send(event, context, responseStatus, responseData={}, physicalResourceId=None, noEcho=False, reason=None): responseUrl = event['ResponseURL'] - logger.info(responseUrl) responseBody = {} responseBody['Status'] = responseStatus @@ -285,7 +290,7 @@ def extract_and_replace_markers(archive, contents_dir, markers): for file in zip.namelist(): file_path = os.path.join(contents_dir, file) if os.path.isdir(file_path): continue - replace_markers(file_path, markers) + replace_markers(file_path, markers) def replace_markers(filename, markers): # convert the dict of string markers to binary markers @@ -300,4 +305,4 @@ def replace_markers(filename, markers): # # delete the original file and rename the new one to the original os.remove(filename) - os.rename(outfile, filename) \ No newline at end of file + os.rename(outfile, filename) diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.39ee629321f531fffd853b944b2d6f3fa7b5276431c9a4fd4dc681303ab15080.zip b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.68b22621fff135f9e3f225bad7ff80fdf2f45c3d9910af601206a0d9b279933a.zip similarity index 66% rename from packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.39ee629321f531fffd853b944b2d6f3fa7b5276431c9a4fd4dc681303ab15080.zip rename to packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.68b22621fff135f9e3f225bad7ff80fdf2f45c3d9910af601206a0d9b279933a.zip index d1ef73915c9a0..156315e053998 100644 Binary files a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.39ee629321f531fffd853b944b2d6f3fa7b5276431c9a4fd4dc681303ab15080.zip and b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.68b22621fff135f9e3f225bad7ff80fdf2f45c3d9910af601206a0d9b279933a.zip differ diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.939a4ab8b51f1a1cccb59d97f04c318ad41c1d404e666c158ca2810894bc5f5f/my-yaml/config.yaml b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.939a4ab8b51f1a1cccb59d97f04c318ad41c1d404e666c158ca2810894bc5f5f/my-yaml/config.yaml new file mode 100644 index 0000000000000..9859c130637a5 --- /dev/null +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/asset.939a4ab8b51f1a1cccb59d97f04c318ad41c1d404e666c158ca2810894bc5f5f/my-yaml/config.yaml @@ -0,0 +1 @@ +website_url: <> diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/cdk.out b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/cdk.out index 8ecc185e9dbee..7925065efbcc4 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/cdk.out +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"21.0.0"} \ No newline at end of file +{"version":"31.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/integ.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/integ.json index aa6d25c71cf09..825c0e8038359 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/integ.json +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/integ.json @@ -1,14 +1,12 @@ { - "version": "21.0.0", + "version": "31.0.0", "testCases": { - "integ.bucket-deployment-data": { + "integ-test-bucket-deployment-data/DefaultTest": { "stacks": [ "TestBucketDeploymentContent" ], - "diffAssets": false, - "stackUpdateWorkflow": true + "assertionStack": "integ-test-bucket-deployment-data/DefaultTest/DeployAssert", + "assertionStackName": "integtestbucketdeploymentdataDefaultTestDeployAssert6FF3075D" } - }, - "synthContext": {}, - "enableLookups": false + } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/integtestbucketdeploymentdataDefaultTestDeployAssert6FF3075D.assets.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/integtestbucketdeploymentdataDefaultTestDeployAssert6FF3075D.assets.json new file mode 100644 index 0000000000000..27cb2ff6f7dfb --- /dev/null +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/integtestbucketdeploymentdataDefaultTestDeployAssert6FF3075D.assets.json @@ -0,0 +1,19 @@ +{ + "version": "31.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "integtestbucketdeploymentdataDefaultTestDeployAssert6FF3075D.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/integtestbucketdeploymentdataDefaultTestDeployAssert6FF3075D.template.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/integtestbucketdeploymentdataDefaultTestDeployAssert6FF3075D.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/integtestbucketdeploymentdataDefaultTestDeployAssert6FF3075D.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/manifest.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/manifest.json index b6d404a34e210..a376f8de22e76 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/manifest.json +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/manifest.json @@ -1,12 +1,6 @@ { - "version": "20.0.0", + "version": "31.0.0", "artifacts": { - "Tree": { - "type": "cdk:tree", - "properties": { - "file": "tree.json" - } - }, "TestBucketDeploymentContent.assets": { "type": "cdk:asset-manifest", "properties": { @@ -23,7 +17,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/55549864d8c27c2125682e2e817e0a7fede6b77576ccd6e21178645f08472948.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/2961e8222a48394849f4466d2789ae256aa88adc4ccbf79feb35306b850c08dc.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -48,10 +42,7 @@ "/TestBucketDeploymentContent/DeployMeHere/AwsCliLayer/Resource": [ { "type": "aws:cdk:logicalId", - "data": "DeployMeHereAwsCliLayerDDC2FE7D", - "trace": [ - "!!DESTRUCTIVE_CHANGES: WILL_REPLACE" - ] + "data": "DeployMeHereAwsCliLayerDDC2FE7D" } ], "/TestBucketDeploymentContent/DeployMeHere/CustomResource/Default": [ @@ -98,6 +89,59 @@ ] }, "displayName": "TestBucketDeploymentContent" + }, + "integtestbucketdeploymentdataDefaultTestDeployAssert6FF3075D.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integtestbucketdeploymentdataDefaultTestDeployAssert6FF3075D.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integtestbucketdeploymentdataDefaultTestDeployAssert6FF3075D": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integtestbucketdeploymentdataDefaultTestDeployAssert6FF3075D.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "integtestbucketdeploymentdataDefaultTestDeployAssert6FF3075D.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "integtestbucketdeploymentdataDefaultTestDeployAssert6FF3075D.assets" + ], + "metadata": { + "/integ-test-bucket-deployment-data/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integ-test-bucket-deployment-data/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integ-test-bucket-deployment-data/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/tree.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/tree.json index 4d3d0ad494849..3916908e8708f 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/tree.json +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.js.snapshot/tree.json @@ -4,14 +4,6 @@ "id": "App", "path": "", "children": { - "Tree": { - "id": "Tree", - "path": "Tree", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" - } - }, "TestBucketDeploymentContent": { "id": "TestBucketDeploymentContent", "path": "TestBucketDeploymentContent", @@ -61,8 +53,8 @@ "id": "Stage", "path": "TestBucketDeploymentContent/DeployMeHere/AwsCliLayer/Code/Stage", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" } }, "AssetBucket": { @@ -89,7 +81,7 @@ "s3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "s3Key": "39ee629321f531fffd853b944b2d6f3fa7b5276431c9a4fd4dc681303ab15080.zip" + "s3Key": "68b22621fff135f9e3f225bad7ff80fdf2f45c3d9910af601206a0d9b279933a.zip" }, "description": "/opt/awscli/aws" } @@ -121,8 +113,8 @@ "id": "Stage", "path": "TestBucketDeploymentContent/DeployMeHere/Asset1/Stage", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" } }, "AssetBucket": { @@ -147,8 +139,8 @@ "id": "Stage", "path": "TestBucketDeploymentContent/DeployMeHere/Asset2/Stage", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" } }, "AssetBucket": { @@ -165,6 +157,24 @@ "version": "0.0.0" } }, + "CustomResource": { + "id": "CustomResource", + "path": "TestBucketDeploymentContent/DeployMeHere/CustomResource", + "children": { + "Default": { + "id": "Default", + "path": "TestBucketDeploymentContent/DeployMeHere/CustomResource/Default", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResource", + "version": "0.0.0" + } + }, "Asset3": { "id": "Asset3", "path": "TestBucketDeploymentContent/DeployMeHere/Asset3", @@ -173,8 +183,8 @@ "id": "Stage", "path": "TestBucketDeploymentContent/DeployMeHere/Asset3/Stage", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" } }, "AssetBucket": { @@ -191,22 +201,30 @@ "version": "0.0.0" } }, - "CustomResource": { - "id": "CustomResource", - "path": "TestBucketDeploymentContent/DeployMeHere/CustomResource", + "Asset4": { + "id": "Asset4", + "path": "TestBucketDeploymentContent/DeployMeHere/Asset4", "children": { - "Default": { - "id": "Default", - "path": "TestBucketDeploymentContent/DeployMeHere/CustomResource/Default", + "Stage": { + "id": "Stage", + "path": "TestBucketDeploymentContent/DeployMeHere/Asset4/Stage", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "TestBucketDeploymentContent/DeployMeHere/Asset4/AssetBucket", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/aws-s3.BucketBase", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/aws-s3-assets.Asset", + "version": "0.0.0" } } }, @@ -223,6 +241,14 @@ "id": "ServiceRole", "path": "TestBucketDeploymentContent/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole", "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "TestBucketDeploymentContent/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, "Resource": { "id": "Resource", "path": "TestBucketDeploymentContent/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/Resource", @@ -388,8 +414,8 @@ "id": "Stage", "path": "TestBucketDeploymentContent/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/Code/Stage", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" } }, "AssetBucket": { @@ -416,7 +442,7 @@ "s3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "s3Key": "f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da.zip" + "s3Key": "2bc265c5e0569aeb24a6349c15bd54e76e845892376515e036627ab0cc70bb64.zip" }, "role": { "Fn::GetAtt": [ @@ -449,20 +475,98 @@ "id": "BucketName", "path": "TestBucketDeploymentContent/BucketName", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "TestBucketDeploymentContent/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "TestBucketDeploymentContent/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" } } }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "integ-test-bucket-deployment-data": { + "id": "integ-test-bucket-deployment-data", + "path": "integ-test-bucket-deployment-data", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "integ-test-bucket-deployment-data/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "integ-test-bucket-deployment-data/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "integ-test-bucket-deployment-data/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "integ-test-bucket-deployment-data/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "integ-test-bucket-deployment-data/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.85" + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.ts b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.ts index 3cdf333cded63..4e79d0ca886a7 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.ts +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-data.ts @@ -1,5 +1,6 @@ import { Bucket } from '@aws-cdk/aws-s3'; import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { IntegTest } from '@aws-cdk/integ-tests'; import { BucketDeployment, Source } from '../lib'; const app = new App(); @@ -8,7 +9,8 @@ const bucket = new Bucket(stack, 'Bucket'); const file1 = Source.data('file1.txt', 'boom'); const file2 = Source.data('path/to/file2.txt', `bam! ${bucket.bucketName}`); -const file3 = Source.jsonData('my/config.json', { website_url: bucket.bucketWebsiteUrl }); +const file3 = Source.jsonData('my-json/config.json', { website_url: bucket.bucketWebsiteUrl }); +const file4 = Source.yamlData('my-yaml/config.yaml', { website_url: bucket.bucketWebsiteUrl }); const deployment = new BucketDeployment(stack, 'DeployMeHere', { destinationBucket: bucket, @@ -17,7 +19,12 @@ const deployment = new BucketDeployment(stack, 'DeployMeHere', { retainOnDelete: false, // default is true, which will block the integration test cleanup }); deployment.addSource(file3); +deployment.addSource(file4); new CfnOutput(stack, 'BucketName', { value: bucket.bucketName }); +new IntegTest(app, 'integ-test-bucket-deployment-data', { + testCases: [stack], +}); + app.synth(); diff --git a/packages/@aws-cdk/core/lib/private/cloudformation-lang.ts b/packages/@aws-cdk/core/lib/private/cloudformation-lang.ts index c34f286707b9a..6d787582c582b 100644 --- a/packages/@aws-cdk/core/lib/private/cloudformation-lang.ts +++ b/packages/@aws-cdk/core/lib/private/cloudformation-lang.ts @@ -1,5 +1,6 @@ import { CfnUtils } from './cfn-utils-provider'; import { INTRINSIC_KEY_PREFIX, resolvedTypeHint } from './resolve'; +import * as yaml_cfn from './yaml-cfn'; import { Lazy } from '../lazy'; import { DefaultTokenResolver, IFragmentConcatenator, IResolveContext } from '../resolvable'; import { Stack } from '../stack'; @@ -32,6 +33,24 @@ export class CloudFormationLang { }); } + /** + * Turn an arbitrary structure potentially containing Tokens into a YAML string. + * + * Returns a Token which will evaluate to CloudFormation expression that + * will be evaluated by CloudFormation to the YAML representation of the + * input structure. + * + * All Tokens substituted in this way must return strings, or the evaluation + * in CloudFormation will fail. + * + * @param obj The object to stringify + */ + public static toYAML(obj: any): string { + return Lazy.uncachedString({ + produce: () => yaml_cfn.serialize(obj), + }); + } + /** * Produce a CloudFormation expression to concat two arbitrary expressions when resolving */ diff --git a/packages/@aws-cdk/core/lib/private/yaml-cfn.ts b/packages/@aws-cdk/core/lib/private/yaml-cfn.ts new file mode 100644 index 0000000000000..355093b396df5 --- /dev/null +++ b/packages/@aws-cdk/core/lib/private/yaml-cfn.ts @@ -0,0 +1,18 @@ +import * as yaml from 'yaml'; +import * as yaml_types from 'yaml/types'; + +/** + * Serializes the given data structure into valid YAML. + * + * @param obj the data structure to serialize + * @returns a string containing the YAML representation of {@param obj} + */ +export function serialize(obj: any): string { + const oldFold = yaml_types.strOptions.fold.lineWidth; + try { + yaml_types.strOptions.fold.lineWidth = 0; + return yaml.stringify(obj, { schema: 'yaml-1.1' }); + } finally { + yaml_types.strOptions.fold.lineWidth = oldFold; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/stack.ts b/packages/@aws-cdk/core/lib/stack.ts index 9ec612d651eec..88f8fe59c4a97 100644 --- a/packages/@aws-cdk/core/lib/stack.ts +++ b/packages/@aws-cdk/core/lib/stack.ts @@ -545,6 +545,13 @@ export class Stack extends Construct implements ITaggable { return CloudFormationLang.toJSON(obj, space).toString(); } + /** + * Convert an object, potentially containing tokens, to a YAML string + */ + public toYamlString(obj: any): string { + return CloudFormationLang.toYAML(obj).toString(); + } + /** * DEPRECATED * @deprecated use `reportMissingContextKey()` diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index 8504d383b11a1..8ca8e10e5e240 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -215,14 +215,16 @@ "fs-extra": "^9.1.0", "ignore": "^5.2.4", "minimatch": "^3.1.2", - "table": "^6.8.1" + "table": "^6.8.1", + "yaml": "1.10.2" }, "bundledDependencies": [ "fs-extra", "minimatch", "@balena/dockerignore", "ignore", - "table" + "table", + "yaml" ], "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": {