Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cloudfront): adding support for inline KeyValueStore sources #29419

Merged
merged 17 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions packages/aws-cdk-lib/aws-cloudfront/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -548,14 +548,30 @@ To create an empty Key Value Store:
const store = new cloudfront.KeyValueStore(this, 'KeyValueStore');
```

To also include an initial set of value, the `source` property can be specified. For the
structure of this file, see [Creating a file of key value pairs](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/kvs-with-functions-create-s3-kvp.html).
To also include an initial set of value, the `source` property can be specified, either from a
ssennettau marked this conversation as resolved.
Show resolved Hide resolved
local file or an inline string. For the structure of this file, see [Creating a file of key value pairs](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/kvs-with-functions-create-s3-kvp.html).

```ts
const store = new cloudfront.KeyValueStore(this, 'KeyValueStore', {
keyValueStoreName: 'KeyValueStore',
const storeAsset = new cloudfront.KeyValueStore(this, 'KeyValueStoreAsset', {
keyValueStoreName: 'KeyValueStoreAsset',
source: cloudfront.ImportSource.fromAsset('path-to-data.json'),
});

const storeInline = new cloudfront.KeyValueStore(this, 'KeyValueStoreInline', {
keyValuestoreName: 'KeyValueStoreInline',
source: cloudfront.ImportSource.fromInline(JSON.stringify({
data: [
{
key: "key1",
value: "value1"
},
{
key: "key2",
value: "value2"
}
]
})),
})
```

The Key Value Store can then be associated to a function using the `cloudfront-js-2.0` runtime
Expand Down
57 changes: 56 additions & 1 deletion packages/aws-cdk-lib/aws-cloudfront/lib/key-value-store.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import * as fs from 'fs';
import { join } from 'path';

import { Construct } from 'constructs';
import { CfnKeyValueStore } from './cloudfront.generated';
import * as s3 from '../../aws-s3';
import * as s3_assets from '../../aws-s3-assets';
import { Resource, IResource, Lazy, Names, Stack, Arn, ArnFormat } from '../../core';
import { Resource, IResource, Lazy, Names, Stack, Arn, ArnFormat, FileSystem } from '../../core';

/**
* The data to be imported to the key value store.
Expand All @@ -28,6 +31,15 @@ export abstract class ImportSource {
return new AssetImportSource(path, options);
}

/**
* An import source that uses an inline string.
*
* @param data the contents of the KeyValueStore
*/
public static fromInline(data: string): ImportSource {
return new InlineImportSource(data);
}

/**
* Called when the key value store is initialized to allow the import source to
* be bound to the stack.
Expand Down Expand Up @@ -101,6 +113,49 @@ export class AssetImportSource extends ImportSource {
}
}

/**
* An import source from an inline string.
*/
export class InlineImportSource extends ImportSource {
private asset?: s3_assets.Asset;

/**
* @param data the contents of the KeyValueStore
*/
constructor(public readonly data: string) {
super();
}

/**
* @internal
*/
public _bind(scope: Construct): CfnKeyValueStore.ImportSourceProperty {

if (!this.asset) {
// CfnKeyValueStore does not support native in-line, so we need to use a
// temporary file to be uploaded with the S3 assets
const workdir = FileSystem.mkdtemp('key-value-store');
const outputPath = join(workdir, 'data.json');
fs.writeFileSync(outputPath, this.data);

this.asset = new s3_assets.Asset(scope, 'ImportSource', {
path: outputPath,
deployTime: true,
});
} else if (Stack.of(this.asset) !== Stack.of(scope)) {
throw new Error(
`Asset is already associated with another stack '${Stack.of(this.asset).stackName}. ` +
'Create a new ImportSource instance for every stack.',
);
}

return {
sourceType: 'S3',
sourceArn: this.asset.bucket.arnForObjects(this.asset.s3ObjectKey),
};
}
}

/**
* The properties to create a Key Value Store.
*/
Expand Down
29 changes: 29 additions & 0 deletions packages/aws-cdk-lib/aws-cloudfront/test/key-value-store.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,35 @@ describe('Key Value Store', () => {
});
});

test('with code from inline string', () => {
// GIVEN
const stack = new Stack();

// WHEN
new KeyValueStore(stack, 'TestStore', {
source: ImportSource.fromInline(JSON.stringify({
data: [
{
key: 'key1',
value: 'value1',
},
{
key: 'key2',
value: 'value2',
},
],
})),
});

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::KeyValueStore', {
ImportSource: {
SourceArn: Match.anyValue(),
SourceType: 'S3',
},
});
});

test('imported resource throws error when missing ID', () => {
// GIVEN
const stack = new Stack();
Expand Down
Loading