From d5afb555b983c8c034f63dd58d1fa24b82b6e9fe Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Thu, 17 Dec 2020 10:20:39 +0100 Subject: [PATCH 01/15] fix(lambda-nodejs): local bundling fails with relative depsLockFilePath (#12125) Ensure it's a file and make it absolute. Closes #12115 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/aws-lambda-nodejs/lib/function.ts | 5 ++++- .../aws-lambda-nodejs/test/function.test.ts | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts index a1c7611e64825..5e4e160eaa717 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts @@ -87,7 +87,10 @@ export class NodejsFunction extends lambda.Function { if (!fs.existsSync(props.depsLockFilePath)) { throw new Error(`Lock file at ${props.depsLockFilePath} doesn't exist`); } - depsLockFilePath = props.depsLockFilePath; + if (!fs.statSync(props.depsLockFilePath).isFile()) { + throw new Error('`depsLockFilePath` should point to a file'); + } + depsLockFilePath = path.resolve(props.depsLockFilePath); } else { const lockFile = findUp(LockFile.YARN) ?? findUp(LockFile.NPM); if (!lockFile) { diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/function.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/function.test.ts index 743526d0e3899..d898d312be92c 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/function.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/function.test.ts @@ -107,6 +107,22 @@ test('throws with non existing lock file', () => { })).toThrow(/Lock file at \/does\/not\/exist.lock doesn't exist/); }); +test('throws when depsLockFilePath is not a file', () => { + expect(() => new NodejsFunction(stack, 'handler1', { + depsLockFilePath: __dirname, + })).toThrow(/\`depsLockFilePath\` should point to a file/); +}); + +test('resolves depsLockFilePath to an absolute path', () => { + new NodejsFunction(stack, 'handler1', { + depsLockFilePath: './package.json', + }); + + expect(Bundling.bundle).toHaveBeenCalledWith(expect.objectContaining({ + depsLockFilePath: expect.stringMatching(/@aws-cdk\/aws-lambda-nodejs\/package.json$/), + })); +}); + test('resolves entry to an absolute path', () => { // WHEN new NodejsFunction(stack, 'fn', { From 7a120f3d181f019da1445b31bffe9d3ddc6e9b78 Mon Sep 17 00:00:00 2001 From: Deepyaman Datta Date: Thu, 17 Dec 2020 12:57:24 -0500 Subject: [PATCH 02/15] chore(logs): Fix typo (#12133) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-logs/lib/log-group.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-logs/lib/log-group.ts b/packages/@aws-cdk/aws-logs/lib/log-group.ts index 83c4a8e170b89..8b24506f11ba0 100644 --- a/packages/@aws-cdk/aws-logs/lib/log-group.ts +++ b/packages/@aws-cdk/aws-logs/lib/log-group.ts @@ -154,7 +154,7 @@ abstract class LogGroupBase extends Resource implements ILogGroup { } /** - * Give permissions to write to create and write to streams in this log group + * Give permissions to create and write to streams in this log group */ public grantWrite(grantee: iam.IGrantable) { return this.grant(grantee, 'logs:CreateLogStream', 'logs:PutLogEvents'); From 4e1d951f39b171759db14223175324e28d03e582 Mon Sep 17 00:00:00 2001 From: Hiroyuki ANAI Date: Fri, 18 Dec 2020 03:32:14 +0900 Subject: [PATCH 03/15] chore(iam): fix typo in policy.ts (#12124) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-iam/lib/policy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iam/lib/policy.ts b/packages/@aws-cdk/aws-iam/lib/policy.ts index 6c006c6576120..795049a1cc163 100644 --- a/packages/@aws-cdk/aws-iam/lib/policy.ts +++ b/packages/@aws-cdk/aws-iam/lib/policy.ts @@ -78,7 +78,7 @@ export interface PolicyProps { * creating invalid--and hence undeployable--CloudFormation templates. * * In cases where you know the policy must be created and it is actually - * an error if no statements have been added to it, you can se this to `true`. + * an error if no statements have been added to it, you can set this to `true`. * * @default false */ From 23d10dfa23d597d9a42160f6f579ca3d3b49ac14 Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Fri, 18 Dec 2020 12:05:50 +0000 Subject: [PATCH 04/15] chore: compat script will now also install peer dependencies (#12142) In cdkv2, the package `aws-cdk-lib` has changed its dependency model to move to use peerDependencies + devDependencies, instead of regular dependencies. As part of this, the `constructs` package is now a peer dependency. jsii-diff requires this package to also be installed to load the jsii assembly. Change the check-api-compatibility.sh to use npm7 which installs all declared peer dependencies as part of `npm install`. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- scripts/check-api-compatibility.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/check-api-compatibility.sh b/scripts/check-api-compatibility.sh index ca15553418f72..e49d684e8b98c 100755 --- a/scripts/check-api-compatibility.sh +++ b/scripts/check-api-compatibility.sh @@ -68,7 +68,8 @@ if ! ${SKIP_DOWNLOAD:-false}; then mkdir -p $tmpdir echo "Installing from NPM..." >&2 - (cd $tmpdir && npm install --prefix $tmpdir $existing_names) + # use npm7 to automatically install peer dependencies + (cd $tmpdir && npx npm@^7.0.0 install --prefix $tmpdir $existing_names) fi #---------------------------------------------------------------------- From ecc98ac75acb1adbb4f5e66f853dc3226e490c98 Mon Sep 17 00:00:00 2001 From: Hassan Azhar <57677979+hassanazharkhan@users.noreply.github.com> Date: Mon, 21 Dec 2020 23:25:11 +0500 Subject: [PATCH 05/15] feat(lambda-nodejs): Expose optional props for advanced usage of esbuild (#12123) 1. Normally the build API automatically discovers tsconfig.json files and reads their contents during a build. However, we can also configure a custom tsconfig.json file to use instead for advanced use cases. 2. Added option to generate meta-file. 3. Added option to add comments in the bundled files Closes [12122](https://github.com/aws/aws-cdk/issues/12122) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-lambda-nodejs/README.md | 4 ++ .../aws-lambda-nodejs/lib/bundling.ts | 9 +++ .../@aws-cdk/aws-lambda-nodejs/lib/types.ts | 67 ++++++++++++++++++- .../aws-lambda-nodejs/test/bundling.test.ts | 8 ++- 4 files changed, 86 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda-nodejs/README.md b/packages/@aws-cdk/aws-lambda-nodejs/README.md index aceb450596bb5..723ce157c6fbb 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/README.md +++ b/packages/@aws-cdk/aws-lambda-nodejs/README.md @@ -145,6 +145,10 @@ new lambda.NodejsFunction(this, 'my-handler', { }, logLevel: LogLevel.SILENT, // defaults to LogLevel.WARNING keepNames: true, // defaults to false + tsconfig: 'custom-tsconfig.json' // use custom-tsconfig.json instead of default, + metafile: true, // include meta file, defaults to false + banner : '/* comments */', // by default no comments are passed + footer : '/* comments */', // by default no comments are passed }, }); ``` diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts index 2620a37a81f67..137f641eb439a 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts @@ -54,6 +54,7 @@ export class Bundling implements cdk.BundlingOptions { public readonly local?: cdk.ILocalBundling; private readonly relativeEntryPath: string; + private readonly relativeTsconfigPath?: string; private readonly externals: string[]; constructor(private readonly props: BundlingProps) { @@ -64,6 +65,10 @@ export class Bundling implements cdk.BundlingOptions { const projectRoot = path.dirname(props.depsLockFilePath); this.relativeEntryPath = path.relative(projectRoot, path.resolve(props.entry)); + if (props.tsconfig) { + this.relativeTsconfigPath = path.relative(projectRoot, path.resolve(props.tsconfig)); + } + this.externals = [ ...props.externalModules ?? ['aws-sdk'], // Mark aws-sdk as external by default (available in the runtime) ...props.nodeModules ?? [], // Mark the modules that we are going to install as externals also @@ -140,6 +145,10 @@ export class Bundling implements cdk.BundlingOptions { ...loaders.map(([ext, name]) => `--loader:${ext}=${name}`), ...this.props.logLevel ? [`--log-level=${this.props.logLevel}`] : [], ...this.props.keepNames ? ['--keep-names'] : [], + ...this.relativeTsconfigPath ? [`--tsconfig=${pathJoin(inputDir, this.relativeTsconfigPath)}`] : [], + ...this.props.metafile ? [`--metafile=${pathJoin(outputDir, 'index.meta.json')}`] : [], + ...this.props.banner ? [`--banner='${this.props.banner}'`] : [], + ...this.props.footer ? [`--footer='${this.props.footer}'`] : [], ].join(' '); let depsCommand = ''; diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts index e71d6adbfee0c..f1008dc7b0368 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts @@ -66,6 +66,71 @@ export interface BundlingOptions { */ readonly keepNames?: boolean; + /** + * Normally the esbuild automatically discovers `tsconfig.json` files and reads their contents during a build. + * + * However, you can also configure a custom `tsconfig.json` file to use instead. + * + * This is similar to entry path, you need to provide path to your custom `tsconfig.json`. + * + * This can be useful if you need to do multiple builds of the same code with different settings. + * + * @example { 'tsconfig': 'path/custom.tsconfig.json' } + * + * @default - automatically discovered by `esbuild` + */ + readonly tsconfig? : string + + /** + * This option tells esbuild to write out a JSON file relative to output directory with metadata about the build. + * + * The metadata in this JSON file follows this schema (specified using TypeScript syntax): + * + * ```typescript + * { + * outputs: { + * [path: string]: { + * bytes: number + * inputs: { + * [path: string]: { bytesInOutput: number } + * } + * imports: { path: string }[] + * exports: string[] + * } + * } + * } + * } + * ``` + * This data can then be analyzed by other tools. For example, + * bundle buddy can consume esbuild's metadata format and generates a treemap visualization + * of the modules in your bundle and how much space each one takes up. + * @see https://esbuild.github.io/api/#metafile + * @default - false + */ + readonly metafile?: boolean + + /** + * Use this to insert an arbitrary string at the beginning of generated JavaScript files. + * + * This is similar to footer which inserts at the end instead of the beginning. + * + * This is commonly used to insert comments: + * + * @default - no comments are passed + */ + readonly banner? : string + + /** + * Use this to insert an arbitrary string at the end of generated JavaScript files. + * + * This is similar to banner which inserts at the beginning instead of the end. + * + * This is commonly used to insert comments + * + * @default - no comments are passed + */ + readonly footer? : string + /** * Environment variables defined when bundling runs. * @@ -83,7 +148,7 @@ export interface BundlingOptions { /** * A list of modules that should be installed instead of bundled. Modules are - * installed in a Lambda compatible environnment only when bundling runs in + * installed in a Lambda compatible environment only when bundling runs in * Docker. * * @default - all modules are bundled 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 3f999de35c07c..e3f6a07144b88 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts @@ -28,6 +28,7 @@ beforeEach(() => { let depsLockFilePath = '/project/yarn.lock'; let entry = '/project/lib/handler.ts'; +let tsconfig = '/project/lib/custom-tsconfig.ts'; test('esbuild bundling in Docker', () => { Bundling.bundle({ @@ -161,6 +162,10 @@ test('esbuild bundling with esbuild options', () => { }, logLevel: LogLevel.SILENT, keepNames: true, + tsconfig, + metafile: true, + banner: '/* comments */', + footer: '/* comments */', forceDockerBundling: true, }); @@ -174,7 +179,8 @@ test('esbuild bundling with esbuild options', () => { 'npx esbuild --bundle /asset-input/lib/handler.ts', '--target=es2020 --platform=node --outfile=/asset-output/index.js', '--minify --sourcemap --external:aws-sdk --loader:.png=dataurl', - '--log-level=silent --keep-names', + '--log-level=silent --keep-names --tsconfig=/asset-input/lib/custom-tsconfig.ts', + '--metafile=/asset-output/index.meta.json --banner=\'/* comments */\' --footer=\'/* comments */\'', ].join(' '), ], }), From eaa82222349fcce1ef4b80e873a35002d6f036e5 Mon Sep 17 00:00:00 2001 From: Eli Polonsky Date: Mon, 21 Dec 2020 21:04:39 +0200 Subject: [PATCH 06/15] feat(eks): connect all custom resources to the cluster VPC (#10200) Allow all our lambda handlers to be provisioned inside the cluster VPC. The `KubectlProvider` handlers were already placed inside the VPC is they could have, the missing was to include the `ClusterHandler`. This is now possible via the `placeClusterHandlerInVpc` (names are welcome) property. Default value remains `false` because if the VPC happens to be isolated (i.e no outbound internet access) this would break the deployment. (See https://github.com/aws/aws-cdk/issues/12171) Closes https://github.com/aws/aws-cdk/issues/9509 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-eks/README.md | 21 +- .../aws-eks/lib/cluster-resource-provider.ts | 23 + .../@aws-cdk/aws-eks/lib/cluster-resource.ts | 5 + packages/@aws-cdk/aws-eks/lib/cluster.ts | 24 +- .../@aws-cdk/aws-eks/lib/kubectl-provider.ts | 2 + ...teg.eks-cluster-handlers-vpc.expected.json | 1394 +++++++++++++++++ .../test/integ.eks-cluster-handlers-vpc.ts | 25 + ...eks-cluster-private-endpoint.expected.json | 41 +- .../test/integ.eks-cluster.expected.json | 21 +- .../test/integ.fargate-cluster.expected.json | 21 +- .../@aws-cdk/aws-eks/test/test.cluster.ts | 63 + .../lib/provider-framework/provider.ts | 25 + .../@aws-cdk/custom-resources/package.json | 2 + .../test/provider-framework/provider.test.ts | 56 + 14 files changed, 1680 insertions(+), 43 deletions(-) create mode 100644 packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json create mode 100644 packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.ts diff --git a/packages/@aws-cdk/aws-eks/README.md b/packages/@aws-cdk/aws-eks/README.md index 57b8d64fe1b66..d1b62a5c8a37f 100644 --- a/packages/@aws-cdk/aws-eks/README.md +++ b/packages/@aws-cdk/aws-eks/README.md @@ -433,6 +433,8 @@ new eks.Cluster(this, 'HelloEKS', { }); ``` +> Note: Isolated VPCs (i.e with no internet access) are not currently supported. See https://github.com/aws/aws-cdk/issues/12171 + If you do not specify a VPC, one will be created on your behalf, which you can then access via `cluster.vpc`. The cluster VPC will be associated to any EKS managed capacity (i.e Managed Node Groups and Fargate Profiles). If you allocate self managed capacity, you can specify which subnets should the auto-scaling group use: @@ -444,8 +446,7 @@ cluster.addAutoScalingGroupCapacity('nodes', { }); ``` -In addition to the cluster and the capacity, there are two additional components you might want to -provision within a VPC. +There are two additional components you might want to provision within the VPC. #### Kubectl Handler @@ -459,7 +460,18 @@ If the endpoint does not expose private access (via `EndpointAccess.PUBLIC`) **o #### Cluster Handler -The `ClusterHandler` is a Lambda function responsible to interact the EKS API in order to control the cluster lifecycle. At the moment, this function cannot be provisioned inside the VPC. See [Attach all Lambda Function to a VPC](https://github.com/aws/aws-cdk/issues/9509) for more details. +The `ClusterHandler` is a Lambda function responsible to interact with the EKS API in order to control the cluster lifecycle. To provision this function inside the VPC, set the `placeClusterHandlerInVpc` property to `true`. This will place the function inside the private subnets of the VPC based on the selection strategy specified in the [`vpcSubnets`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-eks.Cluster.html#vpcsubnetsspan-classapi-icon-api-icon-experimental-titlethis-api-element-is-experimental-it-may-change-without-noticespan) property. + +You can configure the environment of this function by specifying it at cluster instantiation. For example, this can be useful in order to configure an http proxy: + +```ts +const cluster = new eks.Cluster(this, 'hello-eks', { + version: eks.KubernetesVersion.V1_18, + clusterHandlerEnvironment: { + 'http_proxy': 'http://proxy.myproxy.com' + } +}); +``` ### Kubectl Support @@ -1122,6 +1134,5 @@ Kubernetes [endpoint access](#endpoint-access), you must also specify: ## Known Issues and Limitations * [One cluster per stack](https://github.com/aws/aws-cdk/issues/10073) -* [Object pruning](https://github.com/aws/aws-cdk/issues/10495) * [Service Account dependencies](https://github.com/aws/aws-cdk/issues/9910) -* [Attach all Lambda Functions to VPC](https://github.com/aws/aws-cdk/issues/9509) +* [Support isolated VPCs](https://github.com/aws/aws-cdk/issues/12171) diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts index fa5da2d80807e..12839a3ee6044 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts @@ -1,4 +1,5 @@ import * as path from 'path'; +import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; import { Duration, NestedStack, Stack } from '@aws-cdk/core'; @@ -17,6 +18,21 @@ export interface ClusterResourceProviderProps { * The IAM role to assume in order to interact with the cluster. */ readonly adminRole: iam.IRole; + + /** + * The VPC to provision the functions in. + */ + readonly vpc?: ec2.IVpc; + + /** + * The subnets to place the functions in. + */ + readonly subnets?: ec2.ISubnet[]; + + /** + * Environment to add to the handler. + */ + readonly environment?: { [key: string]: string }; } /** @@ -46,8 +62,11 @@ export class ClusterResourceProvider extends NestedStack { code: lambda.Code.fromAsset(HANDLER_DIR), description: 'onEvent handler for EKS cluster resource provider', runtime: HANDLER_RUNTIME, + environment: props.environment, handler: 'index.onEvent', timeout: Duration.minutes(1), + vpc: props.subnets ? props.vpc : undefined, + vpcSubnets: props.subnets ? { subnets: props.subnets } : undefined, }); const isComplete = new lambda.Function(this, 'IsCompleteHandler', { @@ -56,6 +75,8 @@ export class ClusterResourceProvider extends NestedStack { runtime: HANDLER_RUNTIME, handler: 'index.isComplete', timeout: Duration.minutes(1), + vpc: props.subnets ? props.vpc : undefined, + vpcSubnets: props.subnets ? { subnets: props.subnets } : undefined, }); this.provider = new cr.Provider(this, 'Provider', { @@ -63,6 +84,8 @@ export class ClusterResourceProvider extends NestedStack { isCompleteHandler: isComplete, totalTimeout: Duration.hours(1), queryInterval: Duration.minutes(1), + vpc: props.subnets ? props.vpc : undefined, + vpcSubnets: props.subnets ? { subnets: props.subnets } : undefined, }); props.adminRole.grant(onEvent.role!, 'sts:AssumeRole'); diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts index 788210c987dbe..5d89741026aa9 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts @@ -21,6 +21,8 @@ export interface ClusterResourceProps { readonly endpointPublicAccess: boolean; readonly publicAccessCidrs?: string[]; readonly vpc: ec2.IVpc; + readonly environment?: { [key: string]: string }; + readonly subnets?: ec2.ISubnet[]; readonly secretsEncryptionKey?: kms.IKey; } @@ -57,6 +59,9 @@ export class ClusterResource extends CoreConstruct { const provider = ClusterResourceProvider.getOrCreate(this, { adminRole: this.adminRole, + subnets: props.subnets, + vpc: props.vpc, + environment: props.environment, }); const resource = new CustomResource(this, 'Resource', { diff --git a/packages/@aws-cdk/aws-eks/lib/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster.ts index d497a854bb8c7..5697493aad3cb 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster.ts @@ -428,6 +428,13 @@ export interface ClusterOptions extends CommonClusterOptions { */ readonly kubectlEnvironment?: { [key: string]: string }; + /** + * Custom environment variables when interacting with the EKS endpoint to manage the cluster lifecycle. + * + * @default - No environment variables. + */ + readonly clusterHandlerEnvironment?: { [key: string]: string }; + /** * An AWS Lambda Layer which includes `kubectl`, Helm and the AWS CLI. * @@ -468,6 +475,14 @@ export interface ClusterOptions extends CommonClusterOptions { * @default true */ readonly prune?: boolean; + + /** + * If set to true, the cluster handler functions will be placed in the private subnets + * of the cluster vpc, subject to the `vpcSubnets` selection strategy. + * + * @default false + */ + readonly placeClusterHandlerInVpc?: boolean; } /** @@ -859,7 +874,6 @@ export class Cluster extends ClusterBase { /** * Custom environment variables when running `kubectl` against this cluster. - * @default - no additional environment variables */ public readonly kubectlEnvironment?: { [key: string]: string }; @@ -1020,8 +1034,15 @@ export class Cluster extends ClusterBase { throw new Error('Vpc must contain private subnets when public endpoint access is restricted'); } + const placeClusterHandlerInVpc = props.placeClusterHandlerInVpc ?? false; + + if (placeClusterHandlerInVpc && privateSubents.length === 0) { + throw new Error('Cannot place cluster handler in the VPC since no private subnets could be selected'); + } + const resource = this._clusterResource = new ClusterResource(this, 'Resource', { name: this.physicalName, + environment: props.clusterHandlerEnvironment, roleArn: this.role.roleArn, version: props.version.version, resourcesVpcConfig: { @@ -1041,6 +1062,7 @@ export class Cluster extends ClusterBase { publicAccessCidrs: this.endpointAccess._config.publicCidrs, secretsEncryptionKey: props.secretsEncryptionKey, vpc: this.vpc, + subnets: placeClusterHandlerInVpc ? privateSubents : undefined, }); if (this.endpointAccess._config.privateAccess && privateSubents.length !== 0) { diff --git a/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts b/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts index 4cf2d254099f6..359eb79b970a5 100644 --- a/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts +++ b/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts @@ -97,6 +97,8 @@ export class KubectlProvider extends NestedStack { const provider = new cr.Provider(this, 'Provider', { onEventHandler: handler, + vpc: cluster.kubectlPrivateSubnets ? cluster.vpc : undefined, + vpcSubnets: cluster.kubectlPrivateSubnets ? { subnets: cluster.kubectlPrivateSubnets } : undefined, }); this.serviceToken = provider.serviceToken; 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 new file mode 100644 index 0000000000000..64485db691f5b --- /dev/null +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json @@ -0,0 +1,1394 @@ +{ + "Resources": { + "EksAllHandlersInVpcStackDefaultVpcBE11D4AE": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-eks-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1SubnetEA05A5C7": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/19", + "VpcId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + }, + "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-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1RouteTable183714C5": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1RouteTableAssociation1012ACB8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1RouteTable183714C5" + }, + "SubnetId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1SubnetEA05A5C7" + } + } + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1DefaultRoute8E294BC5": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1RouteTable183714C5" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcIGW916D42F1" + } + }, + "DependsOn": [ + "EksAllHandlersInVpcStackDefaultVpcVPCGW5DC3BDB4" + ] + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1EIP9380B54C": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1NATGatewayFD57AC6C": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1EIP9380B54C", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1SubnetEA05A5C7" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2Subnet8A9F7D50": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.32.0/19", + "VpcId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + }, + "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-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2RouteTableE4762B74": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2RouteTableAssociation5DFA3BFD": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2RouteTableE4762B74" + }, + "SubnetId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2Subnet8A9F7D50" + } + } + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2DefaultRouteC7B27F81": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2RouteTableE4762B74" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcIGW916D42F1" + } + }, + "DependsOn": [ + "EksAllHandlersInVpcStackDefaultVpcVPCGW5DC3BDB4" + ] + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2EIP9186922F": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2NATGatewayEC0B8252": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2EIP9186922F", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2Subnet8A9F7D50" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3SubnetB436275F": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/19", + "VpcId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + }, + "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-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3RouteTable85E4266C": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3RouteTableAssociationEA306E19": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3RouteTable85E4266C" + }, + "SubnetId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3SubnetB436275F" + } + } + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3DefaultRoute965D74B7": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3RouteTable85E4266C" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcIGW916D42F1" + } + }, + "DependsOn": [ + "EksAllHandlersInVpcStackDefaultVpcVPCGW5DC3BDB4" + ] + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3EIPBF5ED908": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3NATGateway7AE6F6B3": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3EIPBF5ED908", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3SubnetB436275F" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1SubnetE2B86978": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.96.0/19", + "VpcId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + }, + "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-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PrivateSubnet1" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1RouteTableF214D04E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PrivateSubnet1" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1RouteTableAssociationC09E4B48": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1RouteTableF214D04E" + }, + "SubnetId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1SubnetE2B86978" + } + } + }, + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1DefaultRoute27B45BF6": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1RouteTableF214D04E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1NATGatewayFD57AC6C" + } + } + }, + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2SubnetFBAAF3E3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/19", + "VpcId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + }, + "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-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PrivateSubnet2" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2RouteTable22627B70": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PrivateSubnet2" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2RouteTableAssociation475205D6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2RouteTable22627B70" + }, + "SubnetId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2SubnetFBAAF3E3" + } + } + }, + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2DefaultRoute8A741F7F": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2RouteTable22627B70" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2NATGatewayEC0B8252" + } + } + }, + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3SubnetA75A8BA9": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.160.0/19", + "VpcId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + }, + "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-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PrivateSubnet3" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3RouteTable19D4047C": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc/PrivateSubnet3" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3RouteTableAssociationC07A6A83": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3RouteTable19D4047C" + }, + "SubnetId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3SubnetA75A8BA9" + } + } + }, + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3DefaultRoute203EAFA4": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3RouteTable19D4047C" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3NATGateway7AE6F6B3" + } + } + }, + "EksAllHandlersInVpcStackDefaultVpcIGW916D42F1": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-eks-handlers-in-vpc-test/EksAllHandlersInVpcStack/DefaultVpc" + } + ] + } + }, + "EksAllHandlersInVpcStackDefaultVpcVPCGW5DC3BDB4": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + }, + "InternetGatewayId": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcIGW916D42F1" + } + } + }, + "EksAllHandlersInVpcStackRoleC36F09F0": { + "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" + ] + ] + } + ] + } + }, + "EksAllHandlersInVpcStackControlPlaneSecurityGroup10B6E594": { + "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": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + } + } + }, + "EksAllHandlersInVpcStackCreationRole0BAA4CDC": { + "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": [ + "EksAllHandlersInVpcStackDefaultVpcIGW916D42F1", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1DefaultRoute27B45BF6", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1RouteTableF214D04E", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1RouteTableAssociationC09E4B48", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1SubnetE2B86978", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2DefaultRoute8A741F7F", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2RouteTable22627B70", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2RouteTableAssociation475205D6", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2SubnetFBAAF3E3", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3DefaultRoute203EAFA4", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3RouteTable19D4047C", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3RouteTableAssociationC07A6A83", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3SubnetA75A8BA9", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1DefaultRoute8E294BC5", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1EIP9380B54C", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1NATGatewayFD57AC6C", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1RouteTable183714C5", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1RouteTableAssociation1012ACB8", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1SubnetEA05A5C7", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2DefaultRouteC7B27F81", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2EIP9186922F", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2NATGatewayEC0B8252", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2RouteTableE4762B74", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2RouteTableAssociation5DFA3BFD", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2Subnet8A9F7D50", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3DefaultRoute965D74B7", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3EIPBF5ED908", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3NATGateway7AE6F6B3", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3RouteTable85E4266C", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3RouteTableAssociationEA306E19", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3SubnetB436275F", + "EksAllHandlersInVpcStackDefaultVpcBE11D4AE", + "EksAllHandlersInVpcStackDefaultVpcVPCGW5DC3BDB4" + ] + }, + "EksAllHandlersInVpcStackCreationRoleDefaultPolicy783D59F3": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "iam:PassRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStackRoleC36F09F0", + "Arn" + ] + } + }, + { + "Action": [ + "ec2:DescribeSubnets", + "ec2:DescribeRouteTables" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "eks:CreateCluster", + "eks:DescribeCluster", + "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": [ + "iam:GetRole", + "iam:listAttachedRolePolicies" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "iam:CreateServiceLinkedRole", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "ec2:DescribeVpcs", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ec2:test-region:12345678:vpc/", + { + "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + } + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "EksAllHandlersInVpcStackCreationRoleDefaultPolicy783D59F3", + "Roles": [ + { + "Ref": "EksAllHandlersInVpcStackCreationRole0BAA4CDC" + } + ] + }, + "DependsOn": [ + "EksAllHandlersInVpcStackDefaultVpcIGW916D42F1", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1DefaultRoute27B45BF6", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1RouteTableF214D04E", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1RouteTableAssociationC09E4B48", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1SubnetE2B86978", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2DefaultRoute8A741F7F", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2RouteTable22627B70", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2RouteTableAssociation475205D6", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2SubnetFBAAF3E3", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3DefaultRoute203EAFA4", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3RouteTable19D4047C", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3RouteTableAssociationC07A6A83", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3SubnetA75A8BA9", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1DefaultRoute8E294BC5", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1EIP9380B54C", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1NATGatewayFD57AC6C", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1RouteTable183714C5", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1RouteTableAssociation1012ACB8", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1SubnetEA05A5C7", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2DefaultRouteC7B27F81", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2EIP9186922F", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2NATGatewayEC0B8252", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2RouteTableE4762B74", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2RouteTableAssociation5DFA3BFD", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2Subnet8A9F7D50", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3DefaultRoute965D74B7", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3EIPBF5ED908", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3NATGateway7AE6F6B3", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3RouteTable85E4266C", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3RouteTableAssociationEA306E19", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3SubnetB436275F", + "EksAllHandlersInVpcStackDefaultVpcBE11D4AE", + "EksAllHandlersInVpcStackDefaultVpcVPCGW5DC3BDB4" + ] + }, + "EksAllHandlersInVpcStack9ED695D7": { + "Type": "Custom::AWSCDK-EKS-Cluster", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "awscdkawseksClusterResourceProviderNestedStackawscdkawseksClusterResourceProviderNestedStackResource9827C454", + "Outputs.awscdkekshandlersinvpctestawscdkawseksClusterResourceProviderframeworkonEvent5C6C2463Arn" + ] + }, + "Config": { + "version": "1.18", + "roleArn": { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStackRoleC36F09F0", + "Arn" + ] + }, + "resourcesVpcConfig": { + "subnetIds": [ + { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1SubnetEA05A5C7" + }, + { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2Subnet8A9F7D50" + }, + { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3SubnetB436275F" + }, + { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1SubnetE2B86978" + }, + { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2SubnetFBAAF3E3" + }, + { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3SubnetA75A8BA9" + } + ], + "securityGroupIds": [ + { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStackControlPlaneSecurityGroup10B6E594", + "GroupId" + ] + } + ], + "endpointPublicAccess": true, + "endpointPrivateAccess": true + } + }, + "AssumeRoleArn": { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStackCreationRole0BAA4CDC", + "Arn" + ] + }, + "AttributesRevision": 2 + }, + "DependsOn": [ + "EksAllHandlersInVpcStackDefaultVpcIGW916D42F1", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1DefaultRoute27B45BF6", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1RouteTableF214D04E", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1RouteTableAssociationC09E4B48", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1SubnetE2B86978", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2DefaultRoute8A741F7F", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2RouteTable22627B70", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2RouteTableAssociation475205D6", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2SubnetFBAAF3E3", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3DefaultRoute203EAFA4", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3RouteTable19D4047C", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3RouteTableAssociationC07A6A83", + "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3SubnetA75A8BA9", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1DefaultRoute8E294BC5", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1EIP9380B54C", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1NATGatewayFD57AC6C", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1RouteTable183714C5", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1RouteTableAssociation1012ACB8", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1SubnetEA05A5C7", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2DefaultRouteC7B27F81", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2EIP9186922F", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2NATGatewayEC0B8252", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2RouteTableE4762B74", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2RouteTableAssociation5DFA3BFD", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2Subnet8A9F7D50", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3DefaultRoute965D74B7", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3EIPBF5ED908", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3NATGateway7AE6F6B3", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3RouteTable85E4266C", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3RouteTableAssociationEA306E19", + "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3SubnetB436275F", + "EksAllHandlersInVpcStackDefaultVpcBE11D4AE", + "EksAllHandlersInVpcStackDefaultVpcVPCGW5DC3BDB4", + "EksAllHandlersInVpcStackCreationRoleDefaultPolicy783D59F3", + "EksAllHandlersInVpcStackCreationRole0BAA4CDC" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "EksAllHandlersInVpcStackKubectlReadyBarrier8687350F": { + "Type": "AWS::SSM::Parameter", + "Properties": { + "Type": "String", + "Value": "aws:cdk:eks:kubectl-ready" + }, + "DependsOn": [ + "EksAllHandlersInVpcStackCreationRoleDefaultPolicy783D59F3", + "EksAllHandlersInVpcStackCreationRole0BAA4CDC", + "EksAllHandlersInVpcStack9ED695D7" + ] + }, + "EksAllHandlersInVpcStackMastersRole825EE5E6": { + "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" + } + } + }, + "EksAllHandlersInVpcStackAwsAuthmanifest66335CD9": { + "Type": "Custom::AWSCDK-EKS-KubernetesResource", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B", + "Outputs.awscdkekshandlersinvpctestawscdkawseksKubectlProviderframeworkonEventB8D0A5E7Arn" + ] + }, + "Manifest": { + "Fn::Join": [ + "", + [ + "[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"aws-auth\",\"namespace\":\"kube-system\",\"labels\":{\"aws.cdk.eks/prune-c8fa2698c0d935568a51a7732ad19350286b302ae8\":\"\"}},\"data\":{\"mapRoles\":\"[{\\\"rolearn\\\":\\\"", + { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStackMastersRole825EE5E6", + "Arn" + ] + }, + "\\\",\\\"username\\\":\\\"", + { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStackMastersRole825EE5E6", + "Arn" + ] + }, + "\\\",\\\"groups\\\":[\\\"system:masters\\\"]},{\\\"rolearn\\\":\\\"", + { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStackNodegroupDefaultCapacityNodeGroupRoleFFBF949C", + "Arn" + ] + }, + "\\\",\\\"username\\\":\\\"system:node:{{EC2PrivateDNSName}}\\\",\\\"groups\\\":[\\\"system:bootstrappers\\\",\\\"system:nodes\\\"]}]\",\"mapUsers\":\"[]\",\"mapAccounts\":\"[]\"}}]" + ] + ] + }, + "ClusterName": { + "Ref": "EksAllHandlersInVpcStack9ED695D7" + }, + "RoleArn": { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStackCreationRole0BAA4CDC", + "Arn" + ] + }, + "PruneLabel": "aws.cdk.eks/prune-c8fa2698c0d935568a51a7732ad19350286b302ae8", + "Overwrite": true + }, + "DependsOn": [ + "EksAllHandlersInVpcStackKubectlReadyBarrier8687350F" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "EksAllHandlersInVpcStackNodegroupDefaultCapacityNodeGroupRoleFFBF949C": { + "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" + ] + ] + } + ] + } + }, + "EksAllHandlersInVpcStackNodegroupDefaultCapacityD8DD5ECF": { + "Type": "AWS::EKS::Nodegroup", + "Properties": { + "ClusterName": { + "Ref": "EksAllHandlersInVpcStack9ED695D7" + }, + "NodeRole": { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStackNodegroupDefaultCapacityNodeGroupRoleFFBF949C", + "Arn" + ] + }, + "Subnets": [ + { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1SubnetE2B86978" + }, + { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2SubnetFBAAF3E3" + }, + { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3SubnetA75A8BA9" + } + ], + "AmiType": "AL2_x86_64", + "ForceUpdateEnabled": true, + "InstanceTypes": [ + "m5.large" + ], + "ScalingConfig": { + "DesiredSize": 2, + "MaxSize": 2, + "MinSize": 2 + } + } + }, + "awscdkawseksClusterResourceProviderNestedStackawscdkawseksClusterResourceProviderNestedStackResource9827C454": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.test-region.", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "AssetParameters1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172cS3Bucket151BE34C" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172cS3VersionKey89E7CC67" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172cS3VersionKey89E7CC67" + } + ] + } + ] + } + ] + ] + }, + "Parameters": { + "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackCreationRoleADAAC7FDArn": { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStackCreationRole0BAA4CDC", + "Arn" + ] + }, + "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcE40EA7ACRef": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + }, + "referencetoawscdkekshandlersinvpctestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket020723FERef": { + "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9" + }, + "referencetoawscdkekshandlersinvpctestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyEC505E3ARef": { + "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F" + }, + "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcPrivateSubnet1Subnet9479BAA8Ref": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1SubnetE2B86978" + }, + "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcPrivateSubnet2Subnet9480A740Ref": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2SubnetFBAAF3E3" + }, + "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcPrivateSubnet3Subnet1B127970Ref": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3SubnetA75A8BA9" + }, + "referencetoawscdkekshandlersinvpctestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket9D7E9998Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + }, + "referencetoawscdkekshandlersinvpctestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyE6908FD8Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + } + } + } + }, + "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.test-region.", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "AssetParameters6d292454aff7fb0ebe25e490b924c9c6b388e55e40b8969d458dc14694f8e195S3BucketED10A01F" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters6d292454aff7fb0ebe25e490b924c9c6b388e55e40b8969d458dc14694f8e195S3VersionKey4F604E85" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters6d292454aff7fb0ebe25e490b924c9c6b388e55e40b8969d458dc14694f8e195S3VersionKey4F604E85" + } + ] + } + ] + } + ] + ] + }, + "Parameters": { + "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStack429D29C0Arn": { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStack9ED695D7", + "Arn" + ] + }, + "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackCreationRoleADAAC7FDArn": { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStackCreationRole0BAA4CDC", + "Arn" + ] + }, + "referencetoawscdkekshandlersinvpctestAssetParametersd01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34fS3BucketAC8D81C6Ref": { + "Ref": "AssetParametersd01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34fS3Bucket81EA5F11" + }, + "referencetoawscdkekshandlersinvpctestAssetParametersd01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34fS3VersionKeyA25C9B33Ref": { + "Ref": "AssetParametersd01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34fS3VersionKey32DED07C" + }, + "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcPrivateSubnet1Subnet9479BAA8Ref": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1SubnetE2B86978" + }, + "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcPrivateSubnet2Subnet9480A740Ref": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet2SubnetFBAAF3E3" + }, + "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcPrivateSubnet3Subnet1B127970Ref": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3SubnetA75A8BA9" + }, + "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStack429D29C0ClusterSecurityGroupId": { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStack9ED695D7", + "ClusterSecurityGroupId" + ] + }, + "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcE40EA7ACRef": { + "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + }, + "referencetoawscdkekshandlersinvpctestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket9D7E9998Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + }, + "referencetoawscdkekshandlersinvpctestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyE6908FD8Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + } + } + } + } + }, + "Outputs": { + "EksAllHandlersInVpcStackConfigCommandE25F67E8": { + "Value": { + "Fn::Join": [ + "", + [ + "aws eks update-kubeconfig --name ", + { + "Ref": "EksAllHandlersInVpcStack9ED695D7" + }, + " --region test-region --role-arn ", + { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStackMastersRole825EE5E6", + "Arn" + ] + } + ] + ] + } + }, + "EksAllHandlersInVpcStackGetTokenCommand5EB9ED5B": { + "Value": { + "Fn::Join": [ + "", + [ + "aws eks get-token --cluster-name ", + { + "Ref": "EksAllHandlersInVpcStack9ED695D7" + }, + " --region test-region --role-arn ", + { + "Fn::GetAtt": [ + "EksAllHandlersInVpcStackMastersRole825EE5E6", + "Arn" + ] + } + ] + ] + } + } + }, + "Parameters": { + "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9": { + "Type": "String", + "Description": "S3 bucket for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + }, + "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F": { + "Type": "String", + "Description": "S3 key for asset version \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + }, + "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaArtifactHash54822A43": { + "Type": "String", + "Description": "Artifact hash for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "Type": "String", + "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "Type": "String", + "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "Type": "String", + "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParametersd01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34fS3Bucket81EA5F11": { + "Type": "String", + "Description": "S3 bucket for asset \"d01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34f\"" + }, + "AssetParametersd01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34fS3VersionKey32DED07C": { + "Type": "String", + "Description": "S3 key for asset version \"d01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34f\"" + }, + "AssetParametersd01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34fArtifactHashE68669BA": { + "Type": "String", + "Description": "Artifact hash for asset \"d01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34f\"" + }, + "AssetParameters1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172cS3Bucket151BE34C": { + "Type": "String", + "Description": "S3 bucket for asset \"1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172c\"" + }, + "AssetParameters1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172cS3VersionKey89E7CC67": { + "Type": "String", + "Description": "S3 key for asset version \"1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172c\"" + }, + "AssetParameters1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172cArtifactHashAEE8C2AB": { + "Type": "String", + "Description": "Artifact hash for asset \"1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172c\"" + }, + "AssetParameters6d292454aff7fb0ebe25e490b924c9c6b388e55e40b8969d458dc14694f8e195S3BucketED10A01F": { + "Type": "String", + "Description": "S3 bucket for asset \"6d292454aff7fb0ebe25e490b924c9c6b388e55e40b8969d458dc14694f8e195\"" + }, + "AssetParameters6d292454aff7fb0ebe25e490b924c9c6b388e55e40b8969d458dc14694f8e195S3VersionKey4F604E85": { + "Type": "String", + "Description": "S3 key for asset version \"6d292454aff7fb0ebe25e490b924c9c6b388e55e40b8969d458dc14694f8e195\"" + }, + "AssetParameters6d292454aff7fb0ebe25e490b924c9c6b388e55e40b8969d458dc14694f8e195ArtifactHashFB75BE03": { + "Type": "String", + "Description": "Artifact hash for asset \"6d292454aff7fb0ebe25e490b924c9c6b388e55e40b8969d458dc14694f8e195\"" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.ts b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.ts new file mode 100644 index 0000000000000..ec9fe15d081da --- /dev/null +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.ts @@ -0,0 +1,25 @@ +/// !cdk-integ pragma:ignore-assets +import { App } from '@aws-cdk/core'; +import * as eks from '../lib'; +import { TestStack } from './util'; + +const CLUSTER_VERSION = eks.KubernetesVersion.V1_18; + + +class EksAllHandlersInVpcStack extends TestStack { + + constructor(scope: App, id: string) { + super(scope, id); + + new eks.Cluster(this, 'EksAllHandlersInVpcStack', { + version: CLUSTER_VERSION, + placeClusterHandlerInVpc: true, + }); + } +} + +const app = new App(); + +new EksAllHandlersInVpcStack(app, 'aws-cdk-eks-handlers-in-vpc-test'); + +app.synth(); \ 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 32d3c5a987aad..1b3b3db682b51 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 @@ -1129,7 +1129,7 @@ }, "/", { - "Ref": "AssetParameterseeb4fa933b4519eba8df76051f9b605d447e254cadff1caf25e8f95bd9b580b8S3BucketDC07F45A" + "Ref": "AssetParameters82a02b024ddccd7e1020d7fb799652ba63ec9fc1b0605b3011233acd374b1601S3Bucket69FEE662" }, "/", { @@ -1139,7 +1139,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterseeb4fa933b4519eba8df76051f9b605d447e254cadff1caf25e8f95bd9b580b8S3VersionKey10075D53" + "Ref": "AssetParameters82a02b024ddccd7e1020d7fb799652ba63ec9fc1b0605b3011233acd374b1601S3VersionKeyF62FBF50" } ] } @@ -1152,7 +1152,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterseeb4fa933b4519eba8df76051f9b605d447e254cadff1caf25e8f95bd9b580b8S3VersionKey10075D53" + "Ref": "AssetParameters82a02b024ddccd7e1020d7fb799652ba63ec9fc1b0605b3011233acd374b1601S3VersionKeyF62FBF50" } ] } @@ -1174,11 +1174,11 @@ "Arn" ] }, - "referencetoawscdkeksclusterprivateendpointtestAssetParameterse4ce1c625ef8590bc63f26160777b1c74421c8f5290dc5d15227810eedff2e6cS3BucketF8806B76Ref": { - "Ref": "AssetParameterse4ce1c625ef8590bc63f26160777b1c74421c8f5290dc5d15227810eedff2e6cS3BucketD473D2B6" + "referencetoawscdkeksclusterprivateendpointtestAssetParametersd01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34fS3Bucket254F28AERef": { + "Ref": "AssetParametersd01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34fS3Bucket81EA5F11" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParameterse4ce1c625ef8590bc63f26160777b1c74421c8f5290dc5d15227810eedff2e6cS3VersionKeyB0AD1257Ref": { - "Ref": "AssetParameterse4ce1c625ef8590bc63f26160777b1c74421c8f5290dc5d15227810eedff2e6cS3VersionKey8213FD47" + "referencetoawscdkeksclusterprivateendpointtestAssetParametersd01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34fS3VersionKeyE913A985Ref": { + "Ref": "AssetParametersd01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34fS3VersionKey32DED07C" }, "referencetoawscdkeksclusterprivateendpointtestVpcPrivateSubnet1Subnet94DAD769Ref": { "Ref": "VpcPrivateSubnet1Subnet536B997A" @@ -1195,6 +1195,9 @@ "ClusterSecurityGroupId" ] }, + "referencetoawscdkeksclusterprivateendpointtestVpcFCD064BFRef": { + "Ref": "Vpc8378EB38" + }, "referencetoawscdkeksclusterprivateendpointtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket7DDAFC04Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" }, @@ -1272,17 +1275,17 @@ "Type": "String", "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParameterse4ce1c625ef8590bc63f26160777b1c74421c8f5290dc5d15227810eedff2e6cS3BucketD473D2B6": { + "AssetParametersd01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34fS3Bucket81EA5F11": { "Type": "String", - "Description": "S3 bucket for asset \"e4ce1c625ef8590bc63f26160777b1c74421c8f5290dc5d15227810eedff2e6c\"" + "Description": "S3 bucket for asset \"d01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34f\"" }, - "AssetParameterse4ce1c625ef8590bc63f26160777b1c74421c8f5290dc5d15227810eedff2e6cS3VersionKey8213FD47": { + "AssetParametersd01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34fS3VersionKey32DED07C": { "Type": "String", - "Description": "S3 key for asset version \"e4ce1c625ef8590bc63f26160777b1c74421c8f5290dc5d15227810eedff2e6c\"" + "Description": "S3 key for asset version \"d01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34f\"" }, - "AssetParameterse4ce1c625ef8590bc63f26160777b1c74421c8f5290dc5d15227810eedff2e6cArtifactHashDEE5AB5C": { + "AssetParametersd01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34fArtifactHashE68669BA": { "Type": "String", - "Description": "Artifact hash for asset \"e4ce1c625ef8590bc63f26160777b1c74421c8f5290dc5d15227810eedff2e6c\"" + "Description": "Artifact hash for asset \"d01b2d8959358117de0017e6f18135905e5680cfc8a83e406229c02671c2b34f\"" }, "AssetParameters84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08beS3Bucket9E737267": { "Type": "String", @@ -1296,17 +1299,17 @@ "Type": "String", "Description": "Artifact hash for asset \"84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08be\"" }, - "AssetParameterseeb4fa933b4519eba8df76051f9b605d447e254cadff1caf25e8f95bd9b580b8S3BucketDC07F45A": { + "AssetParameters82a02b024ddccd7e1020d7fb799652ba63ec9fc1b0605b3011233acd374b1601S3Bucket69FEE662": { "Type": "String", - "Description": "S3 bucket for asset \"eeb4fa933b4519eba8df76051f9b605d447e254cadff1caf25e8f95bd9b580b8\"" + "Description": "S3 bucket for asset \"82a02b024ddccd7e1020d7fb799652ba63ec9fc1b0605b3011233acd374b1601\"" }, - "AssetParameterseeb4fa933b4519eba8df76051f9b605d447e254cadff1caf25e8f95bd9b580b8S3VersionKey10075D53": { + "AssetParameters82a02b024ddccd7e1020d7fb799652ba63ec9fc1b0605b3011233acd374b1601S3VersionKeyF62FBF50": { "Type": "String", - "Description": "S3 key for asset version \"eeb4fa933b4519eba8df76051f9b605d447e254cadff1caf25e8f95bd9b580b8\"" + "Description": "S3 key for asset version \"82a02b024ddccd7e1020d7fb799652ba63ec9fc1b0605b3011233acd374b1601\"" }, - "AssetParameterseeb4fa933b4519eba8df76051f9b605d447e254cadff1caf25e8f95bd9b580b8ArtifactHash329E94D2": { + "AssetParameters82a02b024ddccd7e1020d7fb799652ba63ec9fc1b0605b3011233acd374b1601ArtifactHash2BC15E4C": { "Type": "String", - "Description": "Artifact hash for asset \"eeb4fa933b4519eba8df76051f9b605d447e254cadff1caf25e8f95bd9b580b8\"" + "Description": "Artifact hash for asset \"82a02b024ddccd7e1020d7fb799652ba63ec9fc1b0605b3011233acd374b1601\"" } } } \ 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 c6ffd1c00444a..cb1c0010b5d41 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 @@ -3867,7 +3867,7 @@ }, "/", { - "Ref": "AssetParameters752d247b8d517e792000798030be8ebb727fc47c48ee1ae0502fd4fe447543a4S3BucketC467D75F" + "Ref": "AssetParameters9a25dd6d9e57e25d745576dc7750da1634d4b890ca4f11546b8c1cf5411957c2S3BucketBE7D619F" }, "/", { @@ -3877,7 +3877,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters752d247b8d517e792000798030be8ebb727fc47c48ee1ae0502fd4fe447543a4S3VersionKeyFB61265A" + "Ref": "AssetParameters9a25dd6d9e57e25d745576dc7750da1634d4b890ca4f11546b8c1cf5411957c2S3VersionKeyB0752C6A" } ] } @@ -3890,7 +3890,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters752d247b8d517e792000798030be8ebb727fc47c48ee1ae0502fd4fe447543a4S3VersionKeyFB61265A" + "Ref": "AssetParameters9a25dd6d9e57e25d745576dc7750da1634d4b890ca4f11546b8c1cf5411957c2S3VersionKeyB0752C6A" } ] } @@ -3933,6 +3933,9 @@ "ClusterSecurityGroupId" ] }, + "referencetoawscdkeksclustertestVpc9A302ADDRef": { + "Ref": "Vpc8378EB38" + }, "referencetoawscdkeksclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket0815E7B5Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" }, @@ -4632,17 +4635,17 @@ "Type": "String", "Description": "Artifact hash for asset \"a69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0c\"" }, - "AssetParameters752d247b8d517e792000798030be8ebb727fc47c48ee1ae0502fd4fe447543a4S3BucketC467D75F": { + "AssetParameters9a25dd6d9e57e25d745576dc7750da1634d4b890ca4f11546b8c1cf5411957c2S3BucketBE7D619F": { "Type": "String", - "Description": "S3 bucket for asset \"752d247b8d517e792000798030be8ebb727fc47c48ee1ae0502fd4fe447543a4\"" + "Description": "S3 bucket for asset \"9a25dd6d9e57e25d745576dc7750da1634d4b890ca4f11546b8c1cf5411957c2\"" }, - "AssetParameters752d247b8d517e792000798030be8ebb727fc47c48ee1ae0502fd4fe447543a4S3VersionKeyFB61265A": { + "AssetParameters9a25dd6d9e57e25d745576dc7750da1634d4b890ca4f11546b8c1cf5411957c2S3VersionKeyB0752C6A": { "Type": "String", - "Description": "S3 key for asset version \"752d247b8d517e792000798030be8ebb727fc47c48ee1ae0502fd4fe447543a4\"" + "Description": "S3 key for asset version \"9a25dd6d9e57e25d745576dc7750da1634d4b890ca4f11546b8c1cf5411957c2\"" }, - "AssetParameters752d247b8d517e792000798030be8ebb727fc47c48ee1ae0502fd4fe447543a4ArtifactHash638D9167": { + "AssetParameters9a25dd6d9e57e25d745576dc7750da1634d4b890ca4f11546b8c1cf5411957c2ArtifactHash332C2FA3": { "Type": "String", - "Description": "Artifact hash for asset \"752d247b8d517e792000798030be8ebb727fc47c48ee1ae0502fd4fe447543a4\"" + "Description": "Artifact hash for asset \"9a25dd6d9e57e25d745576dc7750da1634d4b890ca4f11546b8c1cf5411957c2\"" }, "SsmParameterValueawsserviceeksoptimizedami118amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { "Type": "AWS::SSM::Parameter::Value", 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 72e2b8af54606..f5d7700c1a775 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 @@ -1206,7 +1206,7 @@ }, "/", { - "Ref": "AssetParametersacf32c87c31efb4722eb278661a3b1910a7e18604a7c03d378957406b1a676dfS3Bucket055DB2DD" + "Ref": "AssetParameters8fce5bde577fa3ab216c79574e335882996439da94b6d9183329e4fc4bff4eafS3Bucket36A38A03" }, "/", { @@ -1216,7 +1216,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersacf32c87c31efb4722eb278661a3b1910a7e18604a7c03d378957406b1a676dfS3VersionKey768DC253" + "Ref": "AssetParameters8fce5bde577fa3ab216c79574e335882996439da94b6d9183329e4fc4bff4eafS3VersionKey5B11B043" } ] } @@ -1229,7 +1229,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersacf32c87c31efb4722eb278661a3b1910a7e18604a7c03d378957406b1a676dfS3VersionKey768DC253" + "Ref": "AssetParameters8fce5bde577fa3ab216c79574e335882996439da94b6d9183329e4fc4bff4eafS3VersionKey5B11B043" } ] } @@ -1272,6 +1272,9 @@ "ClusterSecurityGroupId" ] }, + "referencetoawscdkeksfargateclustertestFargateClusterDefaultVpcBD3C976FRef": { + "Ref": "FargateClusterDefaultVpcE69D3A13" + }, "referencetoawscdkeksfargateclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket8EEF0922Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" }, @@ -1373,17 +1376,17 @@ "Type": "String", "Description": "Artifact hash for asset \"ae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48\"" }, - "AssetParametersacf32c87c31efb4722eb278661a3b1910a7e18604a7c03d378957406b1a676dfS3Bucket055DB2DD": { + "AssetParameters8fce5bde577fa3ab216c79574e335882996439da94b6d9183329e4fc4bff4eafS3Bucket36A38A03": { "Type": "String", - "Description": "S3 bucket for asset \"acf32c87c31efb4722eb278661a3b1910a7e18604a7c03d378957406b1a676df\"" + "Description": "S3 bucket for asset \"8fce5bde577fa3ab216c79574e335882996439da94b6d9183329e4fc4bff4eaf\"" }, - "AssetParametersacf32c87c31efb4722eb278661a3b1910a7e18604a7c03d378957406b1a676dfS3VersionKey768DC253": { + "AssetParameters8fce5bde577fa3ab216c79574e335882996439da94b6d9183329e4fc4bff4eafS3VersionKey5B11B043": { "Type": "String", - "Description": "S3 key for asset version \"acf32c87c31efb4722eb278661a3b1910a7e18604a7c03d378957406b1a676df\"" + "Description": "S3 key for asset version \"8fce5bde577fa3ab216c79574e335882996439da94b6d9183329e4fc4bff4eaf\"" }, - "AssetParametersacf32c87c31efb4722eb278661a3b1910a7e18604a7c03d378957406b1a676dfArtifactHash6B525785": { + "AssetParameters8fce5bde577fa3ab216c79574e335882996439da94b6d9183329e4fc4bff4eafArtifactHashE40CA470": { "Type": "String", - "Description": "Artifact hash for asset \"acf32c87c31efb4722eb278661a3b1910a7e18604a7c03d378957406b1a676df\"" + "Description": "Artifact hash for asset \"8fce5bde577fa3ab216c79574e335882996439da94b6d9183329e4fc4bff4eaf\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/test.cluster.ts b/packages/@aws-cdk/aws-eks/test/test.cluster.ts index 7c23d49a0b2f3..0c8f1dac31f10 100644 --- a/packages/@aws-cdk/aws-eks/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/test.cluster.ts @@ -22,6 +22,42 @@ const CLUSTER_VERSION = eks.KubernetesVersion.V1_18; export = { + 'can specify custom environment to cluster resource handler'(test: Test) { + + const { stack } = testFixture(); + + new eks.Cluster(stack, 'Cluster', { + version: CLUSTER_VERSION, + clusterHandlerEnvironment: { + foo: 'bar', + }, + }); + + const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.ClusterResourceProvider') as cdk.NestedStack; + + test.deepEqual(expect(nested).value.Resources.OnEventHandler42BEBAE0.Properties.Environment, { Variables: { foo: 'bar' } }); + test.done(); + + }, + + 'throws when trying to place cluster handlers in a vpc with no private subnets'(test: Test) { + + const { stack } = testFixture(); + + const vpc = new ec2.Vpc(stack, 'Vpc'); + + test.throws(() => { + new eks.Cluster(stack, 'Cluster', { + version: CLUSTER_VERSION, + placeClusterHandlerInVpc: true, + vpc: vpc, + vpcSubnets: [{ subnetType: ec2.SubnetType.PUBLIC }], + }); + }, /Cannot place cluster handler in the VPC since no private subnets could be selected/); + + test.done(); + }, + 'throws when accessing cluster security group for imported cluster without cluster security group id'(test: Test) { const { stack } = testFixture(); @@ -35,6 +71,33 @@ export = { }, + 'can place cluster handlers in the cluster vpc'(test: Test) { + + const { stack } = testFixture(); + + new eks.Cluster(stack, 'Cluster', { + version: CLUSTER_VERSION, + placeClusterHandlerInVpc: true, + }); + + const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.ClusterResourceProvider') as cdk.NestedStack; + + function assertFunctionPlacedInVpc(id: string) { + test.deepEqual(expect(nested).value.Resources[id].Properties.VpcConfig.SubnetIds, [ + { Ref: 'referencetoStackClusterDefaultVpcPrivateSubnet1SubnetA64D1BF0Ref' }, + { Ref: 'referencetoStackClusterDefaultVpcPrivateSubnet2Subnet32D85AB8Ref' }, + ]); + } + + assertFunctionPlacedInVpc('OnEventHandler42BEBAE0'); + assertFunctionPlacedInVpc('IsCompleteHandler7073F4DA'); + assertFunctionPlacedInVpc('ProviderframeworkonEvent83C1D0A7'); + assertFunctionPlacedInVpc('ProviderframeworkisComplete26D7B0CB'); + assertFunctionPlacedInVpc('ProviderframeworkonTimeout0B47CA38'); + + test.done(); + }, + 'can access cluster security group for imported cluster with cluster security group id'(test: Test) { const { stack } = testFixture(); diff --git a/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts b/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts index a61e7ab475939..3ae10fdf2e560 100644 --- a/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts +++ b/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts @@ -1,5 +1,6 @@ import * as path from 'path'; import * as cfn from '@aws-cdk/aws-cloudformation'; +import * as ec2 from '@aws-cdk/aws-ec2'; import * as lambda from '@aws-cdk/aws-lambda'; import * as logs from '@aws-cdk/aws-logs'; import { Construct as CoreConstruct, Duration } from '@aws-cdk/core'; @@ -70,6 +71,24 @@ export interface ProviderProps { * @default logs.RetentionDays.INFINITE */ readonly logRetention?: logs.RetentionDays; + + /** + * The vpc to provision the lambda functions in. + * + * @default - functions are not provisioned inside a vpc. + */ + readonly vpc?: ec2.IVpc; + + /** + * Which subnets from the VPC to place the lambda functions in. + * + * Only used if 'vpc' is supplied. Note: internet access for Lambdas + * requires a NAT gateway, so picking Public subnets is not allowed. + * + * @default - the Vpc default strategy if not specified + */ + readonly vpcSubnets?: ec2.SubnetSelection; + } /** @@ -97,6 +116,8 @@ export class Provider extends CoreConstruct implements cfn.ICustomResourceProvid private readonly entrypoint: lambda.Function; private readonly logRetention?: logs.RetentionDays; + private readonly vpc?: ec2.IVpc; + private readonly vpcSubnets?: ec2.SubnetSelection; constructor(scope: Construct, id: string, props: ProviderProps) { super(scope, id); @@ -110,6 +131,8 @@ export class Provider extends CoreConstruct implements cfn.ICustomResourceProvid this.isCompleteHandler = props.isCompleteHandler; this.logRetention = props.logRetention; + this.vpc = props.vpc; + this.vpcSubnets = props.vpcSubnets; const onEventFunction = this.createFunction(consts.FRAMEWORK_ON_EVENT_HANDLER_NAME); @@ -153,6 +176,8 @@ export class Provider extends CoreConstruct implements cfn.ICustomResourceProvid handler: `framework.${entrypoint}`, timeout: FRAMEWORK_HANDLER_TIMEOUT, logRetention: this.logRetention, + vpc: this.vpc, + vpcSubnets: this.vpcSubnets, }); fn.addEnvironment(consts.USER_ON_EVENT_FUNCTION_ARN_ENV, this.onEventHandler.functionArn); diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index 61908e19814c2..d291d6b66815b 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -96,6 +96,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.2.0" }, @@ -106,6 +107,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.2.0" }, diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts index 0d0f98f634d07..deed031d8909f 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts @@ -1,4 +1,5 @@ import * as path from 'path'; +import * as ec2 from '@aws-cdk/aws-ec2'; import * as lambda from '@aws-cdk/aws-lambda'; import * as logs from '@aws-cdk/aws-logs'; import { Duration, Stack } from '@aws-cdk/core'; @@ -7,6 +8,61 @@ import * as util from '../../lib/provider-framework/util'; import '@aws-cdk/assert/jest'; +test('vpc is applied to all framework functions', () => { + + // GIVEN + const stack = new Stack(); + + const vpc = new ec2.Vpc(stack, 'Vpc'); + + // WHEN + new cr.Provider(stack, 'MyProvider', { + onEventHandler: new lambda.Function(stack, 'OnEvent', { + code: lambda.Code.fromInline('foo'), + handler: 'index.onEvent', + runtime: lambda.Runtime.NODEJS_10_X, + }), + isCompleteHandler: new lambda.Function(stack, 'IsComplete', { + code: lambda.Code.fromInline('foo'), + handler: 'index.isComplete', + runtime: lambda.Runtime.NODEJS_10_X, + }), + vpc: vpc, + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE }, + }); + + expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Handler: 'framework.onEvent', + VpcConfig: { + SubnetIds: [ + { Ref: 'VpcPrivateSubnet1Subnet536B997A' }, + { Ref: 'VpcPrivateSubnet2Subnet3788AAA1' }, + ], + }, + }); + + expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Handler: 'framework.isComplete', + VpcConfig: { + SubnetIds: [ + { Ref: 'VpcPrivateSubnet1Subnet536B997A' }, + { Ref: 'VpcPrivateSubnet2Subnet3788AAA1' }, + ], + }, + }); + + expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Handler: 'framework.onTimeout', + VpcConfig: { + SubnetIds: [ + { Ref: 'VpcPrivateSubnet1Subnet536B997A' }, + { Ref: 'VpcPrivateSubnet2Subnet3788AAA1' }, + ], + }, + }); + +}); + test('minimal setup', () => { // GIVEN const stack = new Stack(); From 71cd38c8fac276e34b79ad416305b214a57af25a Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 21 Dec 2020 20:39:43 +0100 Subject: [PATCH 07/15] fix(core): capturing stack traces still takes a long time (#12180) Stack trace captured was intended to be disabled by default in #11170. However, due to a logic error that didn't actually happen. This change *actually* disables stack trace capture. The intent of the original change was to capture *Token* stack traces if and only if `CDK_DEBUG=true` was set. *Metadata* and *Construct* stack traces are managed in the `constructs` library, no longer in CDK. BREAKING CHANGE: Creation stack traces for `Lazy` values are no longer captured by default in order to speed up tests. Run with `CDK_DEBUG=true` (or `cdk --debug`) to capture stack traces. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/core/lib/stack-trace.ts | 9 +++------ packages/@aws-cdk/core/test/tokens.test.ts | 1 + 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/@aws-cdk/core/lib/stack-trace.ts b/packages/@aws-cdk/core/lib/stack-trace.ts index 67e47dea5010a..2782799c75453 100644 --- a/packages/@aws-cdk/core/lib/stack-trace.ts +++ b/packages/@aws-cdk/core/lib/stack-trace.ts @@ -8,11 +8,8 @@ import { debugModeEnabled } from './debug'; * large. Consequently, users are stronly advised to condition capturing stack * traces to specific user opt-in. * - * If the `CDK_DISABLE_STACK_TRACE` environment variable is set (to any value, - * except for an empty string), no stack traces will be captured, and instead - * the literal value `['stack traces disabled']` will be returned instead. This - * is only true if the `CDK_DEBUG` environment variable is not set to `'true'` - * or '1', in which case stack traces are *always* captured. + * Stack traces will only be captured if the `CDK_DEBUG` environment variable + * is set to `'true'` or `1`. * * @param below an optional function starting from which stack frames will be * ignored. Defaults to the `captureStackTrace` function itself. @@ -26,7 +23,7 @@ export function captureStackTrace( below: Function = captureStackTrace, limit = Number.MAX_SAFE_INTEGER, ): string[] { - if (process.env.CDK_DISABLE_STACK_TRACE && !debugModeEnabled()) { + if (!debugModeEnabled()) { return ['stack traces disabled']; } diff --git a/packages/@aws-cdk/core/test/tokens.test.ts b/packages/@aws-cdk/core/test/tokens.test.ts index 72b37d0881f73..eba1e75686048 100644 --- a/packages/@aws-cdk/core/test/tokens.test.ts +++ b/packages/@aws-cdk/core/test/tokens.test.ts @@ -656,6 +656,7 @@ nodeunitShim({ } const previousValue = process.env.CDK_DEBUG; + process.env.CDK_DEBUG = 'true'; const x = showMeInTheStackTrace(); let message; From 7951756d3325e894498f152030c46f975c4f703d Mon Sep 17 00:00:00 2001 From: Neta Nir Date: Mon, 21 Dec 2020 14:33:57 -0800 Subject: [PATCH 08/15] chore: rename .github/semantic.yaml to .github/semantic.yml (no "a") (#12186) Currently the `semantic.yaml` file is not respected. This is crucial escpacilly so that `titleOnly: true` will be respected, and single commit PR will not be blocked ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .github/{semantic.yaml => semantic.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{semantic.yaml => semantic.yml} (100%) diff --git a/.github/semantic.yaml b/.github/semantic.yml similarity index 100% rename from .github/semantic.yaml rename to .github/semantic.yml From 73ef6b180c8a7c3d8e984b308149eeb9eb78b40b Mon Sep 17 00:00:00 2001 From: Rob Wenger Date: Mon, 21 Dec 2020 19:35:40 -0500 Subject: [PATCH 09/15] feat(ec2): Add VPC endpoints for Athena and Glue (#12073) Fixes #12072 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts | 2 ++ packages/@aws-cdk/aws-ec2/package.json | 2 ++ 2 files changed, 4 insertions(+) diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts b/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts index 2efcfbc69b68a..83ef63d885b57 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts @@ -257,6 +257,7 @@ export class InterfaceVpcEndpointService implements IInterfaceVpcEndpointService */ export class InterfaceVpcEndpointAwsService implements IInterfaceVpcEndpointService { public static readonly SAGEMAKER_NOTEBOOK = new InterfaceVpcEndpointAwsService('notebook', 'aws.sagemaker'); + public static readonly ATHENA = new InterfaceVpcEndpointAwsService('athena'); public static readonly CLOUDFORMATION = new InterfaceVpcEndpointAwsService('cloudformation'); public static readonly CLOUDTRAIL = new InterfaceVpcEndpointAwsService('cloudtrail'); public static readonly CODEBUILD = new InterfaceVpcEndpointAwsService('codebuild'); @@ -280,6 +281,7 @@ export class InterfaceVpcEndpointAwsService implements IInterfaceVpcEndpointServ public static readonly APIGATEWAY = new InterfaceVpcEndpointAwsService('execute-api'); public static readonly CODECOMMIT_GIT = new InterfaceVpcEndpointAwsService('git-codecommit'); public static readonly CODECOMMIT_GIT_FIPS = new InterfaceVpcEndpointAwsService('git-codecommit-fips'); + public static readonly GLUE = new InterfaceVpcEndpointAwsService('glue'); public static readonly KINESIS_STREAMS = new InterfaceVpcEndpointAwsService('kinesis-streams'); public static readonly KINESIS_FIREHOSE = new InterfaceVpcEndpointAwsService('kinesis-firehose'); public static readonly KMS = new InterfaceVpcEndpointAwsService('kms'); diff --git a/packages/@aws-cdk/aws-ec2/package.json b/packages/@aws-cdk/aws-ec2/package.json index a875368de30d9..bb73e8b467e48 100644 --- a/packages/@aws-cdk/aws-ec2/package.json +++ b/packages/@aws-cdk/aws-ec2/package.json @@ -206,6 +206,7 @@ "docs-public-apis:@aws-cdk/aws-ec2.GatewayVpcEndpointAwsService.DYNAMODB", "docs-public-apis:@aws-cdk/aws-ec2.GatewayVpcEndpointAwsService.S3", "docs-public-apis:@aws-cdk/aws-ec2.InterfaceVpcEndpointAwsService.APIGATEWAY", + "docs-public-apis:@aws-cdk/aws-ec2.InterfaceVpcEndpointAwsService.ATHENA", "docs-public-apis:@aws-cdk/aws-ec2.InterfaceVpcEndpointAwsService.CLOUDFORMATION", "docs-public-apis:@aws-cdk/aws-ec2.InterfaceVpcEndpointAwsService.CLOUDTRAIL", "docs-public-apis:@aws-cdk/aws-ec2.InterfaceVpcEndpointAwsService.CLOUDWATCH", @@ -230,6 +231,7 @@ "docs-public-apis:@aws-cdk/aws-ec2.InterfaceVpcEndpointAwsService.ELASTIC_FILESYSTEM_FIPS", "docs-public-apis:@aws-cdk/aws-ec2.InterfaceVpcEndpointAwsService.ELASTIC_INFERENCE_RUNTIME", "docs-public-apis:@aws-cdk/aws-ec2.InterfaceVpcEndpointAwsService.ELASTIC_LOAD_BALANCING", + "docs-public-apis:@aws-cdk/aws-ec2.InterfaceVpcEndpointAwsService.GLUE", "docs-public-apis:@aws-cdk/aws-ec2.InterfaceVpcEndpointAwsService.KINESIS_STREAMS", "docs-public-apis:@aws-cdk/aws-ec2.InterfaceVpcEndpointAwsService.KINESIS_FIREHOSE", "docs-public-apis:@aws-cdk/aws-ec2.InterfaceVpcEndpointAwsService.KMS", From b1318bda54d1c0955a371eccce76b748d312b570 Mon Sep 17 00:00:00 2001 From: Hsing-Hui Hsu Date: Mon, 21 Dec 2020 17:43:45 -0800 Subject: [PATCH 10/15] feat(ecs-patterns): add ruleName optional parameter for ScheduledTask constructs (#12190) Closes https://github.com/aws/aws-cdk/pull/11007 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ecs-patterns/README.md | 3 ++- .../aws-ecs-patterns/lib/base/scheduled-task-base.ts | 9 +++++++++ .../aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts | 2 ++ .../test/fargate/test.scheduled-fargate-task.ts | 2 ++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-ecs-patterns/README.md b/packages/@aws-cdk/aws-ecs-patterns/README.md index c3e7c93995bbe..e196abcae34a2 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/README.md +++ b/packages/@aws-cdk/aws-ecs-patterns/README.md @@ -302,7 +302,8 @@ const ecsScheduledTask = new ScheduledEc2Task(stack, 'ScheduledTask', { memoryLimitMiB: 256, environment: { name: 'TRIGGER', value: 'CloudWatch Events' }, }, - schedule: events.Schedule.expression('rate(1 minute)') + schedule: events.Schedule.expression('rate(1 minute)'), + ruleName: 'sample-scheduled-task-rule' }); ``` 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 899ded10cbc41..259e375b1973c 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 @@ -38,6 +38,14 @@ export interface ScheduledTaskBaseProps { */ readonly schedule: Schedule; + /** + * A name for the rule. + * + * @default - AWS CloudFormation generates a unique physical ID and uses that ID + * for the rule name. For more information, see [Name Type](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-name.html). + */ + readonly ruleName?: string; + /** * The desired number of instantiations of the task definition to keep running on the service. * @@ -139,6 +147,7 @@ export abstract class ScheduledTaskBase extends CoreConstruct { // An EventRule that describes the event trigger (in this case a scheduled run) this.eventRule = new Rule(this, 'ScheduledEventRule', { schedule: props.schedule, + ruleName: props.ruleName, }); } diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts index f4a0abcf1e410..d96c8cd2edc7d 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts @@ -86,10 +86,12 @@ export = { }, desiredTaskCount: 2, schedule: events.Schedule.expression('rate(1 minute)'), + ruleName: 'sample-scheduled-task-rule', }); // THEN expect(stack).to(haveResource('AWS::Events::Rule', { + Name: 'sample-scheduled-task-rule', Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts index dea31584246c8..27367249ee3cb 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts @@ -98,10 +98,12 @@ export = { }, desiredTaskCount: 2, schedule: events.Schedule.expression('rate(1 minute)'), + ruleName: 'sample-scheduled-task-rule', }); // THEN expect(stack).to(haveResource('AWS::Events::Rule', { + Name: 'sample-scheduled-task-rule', Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, From ab5a38379999bb57f28bbf22ec09d315df6b358a Mon Sep 17 00:00:00 2001 From: Adam Ruka Date: Tue, 22 Dec 2020 01:52:10 -0800 Subject: [PATCH 11/15] fix(dynamodb): allow global replicas with Provisioned billing mode (#12159) We previously had validation inside the Table construct that would prevent creating global replicas when billing mode was `PROVISIONED`. However, it turns out that was too restrictive, and it's actually possible to use the `PROVISIONED` mode, but only if the Table has write auto-scaling enabled with a scaling policy. Fixes #11346 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-dynamodb/README.md | 17 + .../lib/scalable-table-attribute.ts | 9 + packages/@aws-cdk/aws-dynamodb/lib/table.ts | 36 +- .../aws-dynamodb/test/dynamodb.test.ts | 119 ++++-- ....global-replicas-provisioned.expected.json | 372 ++++++++++++++++++ .../test/integ.global-replicas-provisioned.ts | 19 + .../test/replica-provider.test.ts | 11 + 7 files changed, 549 insertions(+), 34 deletions(-) create mode 100644 packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json create mode 100644 packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.ts diff --git a/packages/@aws-cdk/aws-dynamodb/README.md b/packages/@aws-cdk/aws-dynamodb/README.md index 72d10f35c1c15..acd3f1820c156 100644 --- a/packages/@aws-cdk/aws-dynamodb/README.md +++ b/packages/@aws-cdk/aws-dynamodb/README.md @@ -92,6 +92,23 @@ const globalTable = new dynamodb.Table(this, 'Table', { When doing so, a CloudFormation Custom Resource will be added to the stack in order to create the replica tables in the selected regions. +The default billing mode for Global Tables is `PAY_PER_REQUEST`. +If you want to use `PROVISIONED`, +you have to make sure write auto-scaling is enabled for that Table: + +```ts +const globalTable = new dynamodb.Table(this, 'Table', { + partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING }, + replicationRegions: ['us-east-1', 'us-east-2', 'us-west-2'], + billingMode: BillingMode.PROVISIONED, +}); + +globalTable.autoScaleWriteCapacity({ + minCapacity: 1, + maxCapacity: 10, +}).scaleOnUtilization({ targetUtilizationPercent: 75 }); +``` + ## Encryption All user data stored in Amazon DynamoDB is fully encrypted at rest. When creating a new table, you can choose to encrypt using the following customer master keys (CMK) to encrypt your table: diff --git a/packages/@aws-cdk/aws-dynamodb/lib/scalable-table-attribute.ts b/packages/@aws-cdk/aws-dynamodb/lib/scalable-table-attribute.ts index 4ec8e1365773f..fc2a538e2545d 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/scalable-table-attribute.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/scalable-table-attribute.ts @@ -5,10 +5,13 @@ import { UtilizationScalingProps } from './scalable-attribute-api'; * A scalable table attribute */ export class ScalableTableAttribute extends appscaling.BaseScalableAttribute { + private scalingPolicyCreated = false; + /** * Scale out or in based on time */ public scaleOnSchedule(id: string, action: appscaling.ScalingSchedule) { + this.scalingPolicyCreated = true; super.doScaleOnSchedule(id, action); } @@ -20,6 +23,7 @@ export class ScalableTableAttribute extends appscaling.BaseScalableAttribute { // eslint-disable-next-line max-len throw new RangeError(`targetUtilizationPercent for DynamoDB scaling must be between 10 and 90 percent, got: ${props.targetUtilizationPercent}`); } + this.scalingPolicyCreated = true; const predefinedMetric = this.props.dimension.indexOf('ReadCapacity') === -1 ? appscaling.PredefinedMetric.DYANMODB_WRITE_CAPACITY_UTILIZATION : appscaling.PredefinedMetric.DYNAMODB_READ_CAPACITY_UTILIZATION; @@ -33,6 +37,11 @@ export class ScalableTableAttribute extends appscaling.BaseScalableAttribute { predefinedMetric, }); } + + /** @internal */ + public get _scalingPolicyCreated(): boolean { + return this.scalingPolicyCreated; + } } /** diff --git a/packages/@aws-cdk/aws-dynamodb/lib/table.ts b/packages/@aws-cdk/aws-dynamodb/lib/table.ts index dfcae3146ad56..792f68f4cca3e 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/table.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/table.ts @@ -1064,6 +1064,8 @@ export class Table extends TableBase { private readonly indexScaling = new Map(); private readonly scalingRole: iam.IRole; + private readonly globalReplicaCustomResources = new Array(); + constructor(scope: Construct, id: string, props: TableProps) { super(scope, id, { physicalName: props.tableName, @@ -1071,9 +1073,6 @@ export class Table extends TableBase { const { sseSpecification, encryptionKey } = this.parseEncryption(props); - this.billingMode = props.billingMode || BillingMode.PROVISIONED; - this.validateProvisioning(props); - let streamSpecification: CfnTable.StreamSpecificationProperty | undefined; if (props.replicationRegions) { if (props.stream && props.stream !== StreamViewType.NEW_AND_OLD_IMAGES) { @@ -1081,13 +1080,14 @@ export class Table extends TableBase { } streamSpecification = { streamViewType: StreamViewType.NEW_AND_OLD_IMAGES }; - if (props.billingMode && props.billingMode !== BillingMode.PAY_PER_REQUEST) { - throw new Error('The `PAY_PER_REQUEST` billing mode must be used when specifying `replicationRegions`'); + this.billingMode = props.billingMode ?? BillingMode.PAY_PER_REQUEST; + } else { + this.billingMode = props.billingMode ?? BillingMode.PROVISIONED; + if (props.stream) { + streamSpecification = { streamViewType: props.stream }; } - this.billingMode = BillingMode.PAY_PER_REQUEST; - } else if (props.stream) { - streamSpecification = { streamViewType: props.stream }; } + this.validateProvisioning(props); this.table = new CfnTable(this, 'Resource', { tableName: this.physicalName, @@ -1222,13 +1222,17 @@ export class Table extends TableBase { throw new Error('AutoScaling is not available for tables with PAY_PER_REQUEST billing mode'); } - return this.tableScaling.scalableWriteAttribute = new ScalableTableAttribute(this, 'WriteScaling', { + this.tableScaling.scalableWriteAttribute = new ScalableTableAttribute(this, 'WriteScaling', { serviceNamespace: appscaling.ServiceNamespace.DYNAMODB, resourceId: `table/${this.tableName}`, dimension: 'dynamodb:table:WriteCapacityUnits', role: this.scalingRole, ...props, }); + for (const globalReplicaCustomResource of this.globalReplicaCustomResources) { + globalReplicaCustomResource.node.addDependency(this.tableScaling.scalableWriteAttribute); + } + return this.tableScaling.scalableWriteAttribute; } /** @@ -1298,6 +1302,17 @@ export class Table extends TableBase { errors.push('a sort key of the table must be specified to add local secondary indexes'); } + if (this.globalReplicaCustomResources.length > 0 && this.billingMode === BillingMode.PROVISIONED) { + const writeAutoScaleAttribute = this.tableScaling.scalableWriteAttribute; + if (!writeAutoScaleAttribute) { + errors.push('A global Table that uses PROVISIONED as the billing mode needs auto-scaled write capacity. ' + + 'Use the autoScaleWriteCapacity() method to enable it.'); + } else if (!writeAutoScaleAttribute._scalingPolicyCreated) { + errors.push('A global Table that uses PROVISIONED as the billing mode needs auto-scaled write capacity with a policy. ' + + 'Call one of the scaleOn*() methods of the object returned from autoScaleWriteCapacity()'); + } + } + return errors; } @@ -1467,6 +1482,7 @@ export class Table extends TableBase { onEventHandlerPolicy.policy, isCompleteHandlerPolicy.policy, ); + this.globalReplicaCustomResources.push(currentRegion); // Deploy time check to prevent from creating a replica in the region // where this stack is deployed. Only needed for environment agnostic @@ -1681,4 +1697,4 @@ class SourceTableAttachedPrincipal extends iam.PrincipalBase { statementAdded: true, }; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts index 550a47f81ec1d..119043b54464a 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts @@ -836,27 +836,40 @@ test('when specifying PAY_PER_REQUEST billing mode', () => { ); }); -test('error when specifying read or write capacity with a PAY_PER_REQUEST billing mode', () => { - const stack = new Stack(); - expect(() => new Table(stack, 'Table A', { - tableName: TABLE_NAME, - billingMode: BillingMode.PAY_PER_REQUEST, - partitionKey: TABLE_PARTITION_KEY, - readCapacity: 1, - })).toThrow(/PAY_PER_REQUEST/); - expect(() => new Table(stack, 'Table B', { - tableName: TABLE_NAME, - billingMode: BillingMode.PAY_PER_REQUEST, - partitionKey: TABLE_PARTITION_KEY, - writeCapacity: 1, - })).toThrow(/PAY_PER_REQUEST/); - expect(() => new Table(stack, 'Table C', { - tableName: TABLE_NAME, - billingMode: BillingMode.PAY_PER_REQUEST, - partitionKey: TABLE_PARTITION_KEY, - readCapacity: 1, - writeCapacity: 1, - })).toThrow(/PAY_PER_REQUEST/); +describe('when billing mode is PAY_PER_REQUEST', () => { + let stack: Stack; + + beforeEach(() => { + stack = new Stack(); + }); + + test('creating the Table fails when readCapacity is specified', () => { + expect(() => new Table(stack, 'Table A', { + tableName: TABLE_NAME, + partitionKey: TABLE_PARTITION_KEY, + billingMode: BillingMode.PAY_PER_REQUEST, + readCapacity: 1, + })).toThrow(/PAY_PER_REQUEST/); + }); + + test('creating the Table fails when writeCapacity is specified', () => { + expect(() => new Table(stack, 'Table B', { + tableName: TABLE_NAME, + partitionKey: TABLE_PARTITION_KEY, + billingMode: BillingMode.PAY_PER_REQUEST, + writeCapacity: 1, + })).toThrow(/PAY_PER_REQUEST/); + }); + + test('creating the Table fails when both readCapacity and writeCapacity are specified', () => { + expect(() => new Table(stack, 'Table C', { + tableName: TABLE_NAME, + partitionKey: TABLE_PARTITION_KEY, + billingMode: BillingMode.PAY_PER_REQUEST, + readCapacity: 1, + writeCapacity: 1, + })).toThrow(/PAY_PER_REQUEST/); + }); }); test('when adding a global secondary index with hash key only', () => { @@ -2766,12 +2779,62 @@ describe('global', () => { }); }); - test('throws with PROVISIONED billing mode', () => { + test('throws when PROVISIONED billing mode is used without auto-scaled writes', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new Table(stack, 'Table', { + partitionKey: { + name: 'id', + type: AttributeType.STRING, + }, + replicationRegions: [ + 'eu-west-2', + 'eu-central-1', + ], + billingMode: BillingMode.PROVISIONED, + }); + + // THEN + expect(() => { + SynthUtils.synthesize(stack); + }).toThrow(/A global Table that uses PROVISIONED as the billing mode needs auto-scaled write capacity/); + }); + + test('throws when PROVISIONED billing mode is used with auto-scaled writes, but without a policy', () => { // GIVEN const stack = new Stack(); + // WHEN + const table = new Table(stack, 'Table', { + partitionKey: { + name: 'id', + type: AttributeType.STRING, + }, + replicationRegions: [ + 'eu-west-2', + 'eu-central-1', + ], + billingMode: BillingMode.PROVISIONED, + }); + table.autoScaleWriteCapacity({ + minCapacity: 1, + maxCapacity: 10, + }); + // THEN - expect(() => new Table(stack, 'Table', { + expect(() => { + SynthUtils.synthesize(stack); + }).toThrow(/A global Table that uses PROVISIONED as the billing mode needs auto-scaled write capacity with a policy/); + }); + + test('allows PROVISIONED billing mode when auto-scaled writes with a policy are specified', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const table = new Table(stack, 'Table', { partitionKey: { name: 'id', type: AttributeType.STRING, @@ -2781,7 +2844,15 @@ describe('global', () => { 'eu-central-1', ], billingMode: BillingMode.PROVISIONED, - })).toThrow(/`PAY_PER_REQUEST`/); + }); + table.autoScaleWriteCapacity({ + minCapacity: 1, + maxCapacity: 10, + }).scaleOnUtilization({ targetUtilizationPercent: 75 }); + + expect(stack).toHaveResourceLike('AWS::DynamoDB::Table', { + BillingMode: ABSENT, // PROVISIONED is the default + }); }); test('throws when stream is set and not set to NEW_AND_OLD_IMAGES', () => { 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 new file mode 100644 index 0000000000000..7bfa6b9637bcd --- /dev/null +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json @@ -0,0 +1,372 @@ +{ + "Resources": { + "TableCD117FA1": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "KeySchema": [ + { + "AttributeName": "hashKey", + "KeyType": "HASH" + } + ], + "AttributeDefinitions": [ + { + "AttributeName": "hashKey", + "AttributeType": "S" + } + ], + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + }, + "StreamSpecification": { + "StreamViewType": "NEW_AND_OLD_IMAGES" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "TableSourceTableAttachedPolicyawscdkdynamodbglobalreplicasprovisionedawscdkawsdynamodbReplicaProviderOnEventHandlerServiceRoleD9856B77945CD5DF": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "dynamodb:*", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "TableCD117FA1", + "Arn" + ] + }, + { + "Ref": "AWS::NoValue" + } + ] + }, + { + "Action": "dynamodb:*", + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":dynamodb:us-east-2:", + { + "Ref": "AWS::AccountId" + }, + ":table/", + { + "Ref": "TableCD117FA1" + } + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":dynamodb:eu-west-3:", + { + "Ref": "AWS::AccountId" + }, + ":table/", + { + "Ref": "TableCD117FA1" + } + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "leAttachedPolicyawscdkdynamodbglobalreplicasprovisionedawscdkawsdynamodbReplicaProviderOnEventHandlerServiceRoleD9856B77945CD5DF", + "Roles": [ + { + "Fn::GetAtt": [ + "awscdkawsdynamodbReplicaProviderNestedStackawscdkawsdynamodbReplicaProviderNestedStackResource18E3F12D", + "Outputs.awscdkdynamodbglobalreplicasprovisionedawscdkawsdynamodbReplicaProviderOnEventHandlerServiceRole348A0C9ARef" + ] + } + ] + } + }, + "TableSourceTableAttachedPolicyawscdkdynamodbglobalreplicasprovisionedawscdkawsdynamodbReplicaProviderIsCompleteHandlerServiceRoleBE2B1C1AE3D3CF6D": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "dynamodb:DescribeTable", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "TableCD117FA1", + "Arn" + ] + }, + { + "Ref": "AWS::NoValue" + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ttachedPolicyawscdkdynamodbglobalreplicasprovisionedawscdkawsdynamodbReplicaProviderIsCompleteHandlerServiceRoleBE2B1C1AE3D3CF6D", + "Roles": [ + { + "Fn::GetAtt": [ + "awscdkawsdynamodbReplicaProviderNestedStackawscdkawsdynamodbReplicaProviderNestedStackResource18E3F12D", + "Outputs.awscdkdynamodbglobalreplicasprovisionedawscdkawsdynamodbReplicaProviderIsCompleteHandlerServiceRole750F1EE9Ref" + ] + } + ] + } + }, + "TableReplicauseast28A15C236": { + "Type": "Custom::DynamoDBReplica", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "awscdkawsdynamodbReplicaProviderNestedStackawscdkawsdynamodbReplicaProviderNestedStackResource18E3F12D", + "Outputs.awscdkdynamodbglobalreplicasprovisionedawscdkawsdynamodbReplicaProviderframeworkonEventACC2C387Arn" + ] + }, + "TableName": { + "Ref": "TableCD117FA1" + }, + "Region": "us-east-2" + }, + "DependsOn": [ + "TableSourceTableAttachedPolicyawscdkdynamodbglobalreplicasprovisionedawscdkawsdynamodbReplicaProviderIsCompleteHandlerServiceRoleBE2B1C1AE3D3CF6D", + "TableSourceTableAttachedPolicyawscdkdynamodbglobalreplicasprovisionedawscdkawsdynamodbReplicaProviderOnEventHandlerServiceRoleD9856B77945CD5DF", + "TableWriteScalingTargetE5669214", + "TableWriteScalingTargetTrackingD78DCCD8" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete", + "Condition": "TableStackRegionNotEqualsuseast2D20A1E77" + }, + "TableReplicaeuwest314C3E552": { + "Type": "Custom::DynamoDBReplica", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "awscdkawsdynamodbReplicaProviderNestedStackawscdkawsdynamodbReplicaProviderNestedStackResource18E3F12D", + "Outputs.awscdkdynamodbglobalreplicasprovisionedawscdkawsdynamodbReplicaProviderframeworkonEventACC2C387Arn" + ] + }, + "TableName": { + "Ref": "TableCD117FA1" + }, + "Region": "eu-west-3" + }, + "DependsOn": [ + "TableReplicauseast28A15C236", + "TableSourceTableAttachedPolicyawscdkdynamodbglobalreplicasprovisionedawscdkawsdynamodbReplicaProviderIsCompleteHandlerServiceRoleBE2B1C1AE3D3CF6D", + "TableSourceTableAttachedPolicyawscdkdynamodbglobalreplicasprovisionedawscdkawsdynamodbReplicaProviderOnEventHandlerServiceRoleD9856B77945CD5DF", + "TableWriteScalingTargetE5669214", + "TableWriteScalingTargetTrackingD78DCCD8" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete", + "Condition": "TableStackRegionNotEqualseuwest302B3591C" + }, + "TableWriteScalingTargetE5669214": { + "Type": "AWS::ApplicationAutoScaling::ScalableTarget", + "Properties": { + "MaxCapacity": 10, + "MinCapacity": 5, + "ResourceId": { + "Fn::Join": [ + "", + [ + "table/", + { + "Ref": "TableCD117FA1" + } + ] + ] + }, + "RoleARN": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable" + ] + ] + }, + "ScalableDimension": "dynamodb:table:WriteCapacityUnits", + "ServiceNamespace": "dynamodb" + } + }, + "TableWriteScalingTargetTrackingD78DCCD8": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awscdkdynamodbglobalreplicasprovisionedTableWriteScalingTargetTrackingD631E2EC", + "PolicyType": "TargetTrackingScaling", + "ScalingTargetId": { + "Ref": "TableWriteScalingTargetE5669214" + }, + "TargetTrackingScalingPolicyConfiguration": { + "PredefinedMetricSpecification": { + "PredefinedMetricType": "DynamoDBWriteCapacityUtilization" + }, + "TargetValue": 75 + } + } + }, + "awscdkawsdynamodbReplicaProviderNestedStackawscdkawsdynamodbReplicaProviderNestedStackResource18E3F12D": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "AssetParametersa8adade98e50c02310e9b63ef8d0d201926ed756455b604d8eb5d1bc4f5deefcS3Bucket150DFE4F" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersa8adade98e50c02310e9b63ef8d0d201926ed756455b604d8eb5d1bc4f5deefcS3VersionKey304CC738" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersa8adade98e50c02310e9b63ef8d0d201926ed756455b604d8eb5d1bc4f5deefcS3VersionKey304CC738" + } + ] + } + ] + } + ] + ] + }, + "Parameters": { + "referencetoawscdkdynamodbglobalreplicasprovisionedAssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3Bucket50997EC4Ref": { + "Ref": "AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3Bucket1C6779E0" + }, + "referencetoawscdkdynamodbglobalreplicasprovisionedAssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3VersionKey0F47C425Ref": { + "Ref": "AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3VersionKey5C1D9275" + }, + "referencetoawscdkdynamodbglobalreplicasprovisionedAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket6C51C355Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + }, + "referencetoawscdkdynamodbglobalreplicasprovisionedAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey84AB7371Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + } + } + } + } + }, + "Conditions": { + "TableStackRegionNotEqualsuseast2D20A1E77": { + "Fn::Not": [ + { + "Fn::Equals": [ + "us-east-2", + { + "Ref": "AWS::Region" + } + ] + } + ] + }, + "TableStackRegionNotEqualseuwest302B3591C": { + "Fn::Not": [ + { + "Fn::Equals": [ + "eu-west-3", + { + "Ref": "AWS::Region" + } + ] + } + ] + } + }, + "Parameters": { + "AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3Bucket1C6779E0": { + "Type": "String", + "Description": "S3 bucket for asset \"f13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714\"" + }, + "AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3VersionKey5C1D9275": { + "Type": "String", + "Description": "S3 key for asset version \"f13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714\"" + }, + "AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714ArtifactHash477AAEA7": { + "Type": "String", + "Description": "Artifact hash for asset \"f13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "Type": "String", + "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "Type": "String", + "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "Type": "String", + "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParametersa8adade98e50c02310e9b63ef8d0d201926ed756455b604d8eb5d1bc4f5deefcS3Bucket150DFE4F": { + "Type": "String", + "Description": "S3 bucket for asset \"a8adade98e50c02310e9b63ef8d0d201926ed756455b604d8eb5d1bc4f5deefc\"" + }, + "AssetParametersa8adade98e50c02310e9b63ef8d0d201926ed756455b604d8eb5d1bc4f5deefcS3VersionKey304CC738": { + "Type": "String", + "Description": "S3 key for asset version \"a8adade98e50c02310e9b63ef8d0d201926ed756455b604d8eb5d1bc4f5deefc\"" + }, + "AssetParametersa8adade98e50c02310e9b63ef8d0d201926ed756455b604d8eb5d1bc4f5deefcArtifactHash6868817F": { + "Type": "String", + "Description": "Artifact hash for asset \"a8adade98e50c02310e9b63ef8d0d201926ed756455b604d8eb5d1bc4f5deefc\"" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.ts b/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.ts new file mode 100644 index 0000000000000..8403538c2bd50 --- /dev/null +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.ts @@ -0,0 +1,19 @@ +import * as cdk from '@aws-cdk/core'; +import * as dynamodb from '../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-cdk-dynamodb-global-replicas-provisioned'); + +const table = new dynamodb.Table(stack, 'Table', { + partitionKey: { name: 'hashKey', type: dynamodb.AttributeType.STRING }, + removalPolicy: cdk.RemovalPolicy.DESTROY, + replicationRegions: ['us-east-2', 'eu-west-3'], + billingMode: dynamodb.BillingMode.PROVISIONED, +}); + +table.autoScaleWriteCapacity({ + minCapacity: 5, + maxCapacity: 10, +}).scaleOnUtilization({ targetUtilizationPercent: 75 }); + +app.synth(); diff --git a/packages/@aws-cdk/aws-dynamodb/test/replica-provider.test.ts b/packages/@aws-cdk/aws-dynamodb/test/replica-provider.test.ts index cddd4c258689b..3a1d97bd4b345 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/replica-provider.test.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/replica-provider.test.ts @@ -3,6 +3,17 @@ import * as AWS from 'aws-sdk-mock'; import * as sinon from 'sinon'; import { isCompleteHandler, onEventHandler } from '../lib/replica-handler'; +let oldConsoleLog: any; + +beforeAll(() => { + oldConsoleLog = global.console.log; + global.console.log = jest.fn(); +}); + +afterAll(() => { + global.console.log = oldConsoleLog; +}); + AWS.setSDK(require.resolve('aws-sdk')); const createEvent: OnEventRequest = { From 6a20e61dd2ed8366cbff1451c943a02b79380de2 Mon Sep 17 00:00:00 2001 From: Eli Polonsky Date: Tue, 22 Dec 2020 12:28:16 +0200 Subject: [PATCH 12/15] chore(eks): Remove legacy and deprecated code (#12189) Removing `LegacyCluster` and the `kubectlEnabled` property. Closes https://github.com/aws/aws-cdk/issues/11929 BREAKING CHANGE: `LegacyCluster` was removed since it existed only for a transition period to allow gradual migration to the current cluster class. - eks: `kubectlEnabled` property was removed, all clusters now support `kubectl`. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-eks/lib/cluster.ts | 30 - .../@aws-cdk/aws-eks/lib/fargate-cluster.ts | 1 - packages/@aws-cdk/aws-eks/lib/index.ts | 1 - .../@aws-cdk/aws-eks/lib/legacy-cluster.ts | 552 --------- ...eks-cluster.kubectl-disabled.expected.json | 1094 ----------------- .../integ.eks-cluster.kubectl-disabled.ts | 37 - .../aws-eks/test/test.legacy-cluster.ts | 635 ---------- .../@aws-cdk/aws-eks/test/test.nodegroup.ts | 29 +- 8 files changed, 1 insertion(+), 2378 deletions(-) delete mode 100644 packages/@aws-cdk/aws-eks/lib/legacy-cluster.ts delete mode 100644 packages/@aws-cdk/aws-eks/test/integ.eks-cluster.kubectl-disabled.expected.json delete mode 100644 packages/@aws-cdk/aws-eks/test/integ.eks-cluster.kubectl-disabled.ts delete mode 100644 packages/@aws-cdk/aws-eks/test/test.legacy-cluster.ts diff --git a/packages/@aws-cdk/aws-eks/lib/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster.ts index 5697493aad3cb..dfbb347bb1e5d 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster.ts @@ -583,28 +583,6 @@ export class EndpointAccess { * Common configuration props for EKS clusters. */ export interface ClusterProps extends ClusterOptions { - /** - * NOT SUPPORTED: We no longer allow disabling kubectl-support. Setting this - * option to `false` will throw an error. - * - * To temporary allow you to retain existing clusters created with - * `kubectlEnabled: false`, you can use `eks.LegacyCluster` class, which is a - * drop-in replacement for `eks.Cluster` with `kubectlEnabled: false`. - * - * Bear in mind that this is a temporary workaround. We have plans to remove - * `eks.LegacyCluster`. If you have a use case for using `eks.LegacyCluster`, - * please add a comment here https://github.com/aws/aws-cdk/issues/9332 and - * let us know so we can make sure to continue to support your use case with - * `eks.Cluster`. This issue also includes additional context into why this - * class is being removed. - * - * @deprecated `eks.LegacyCluster` is __temporarily__ provided as a drop-in - * replacement until you are able to migrate to `eks.Cluster`. - * - * @see https://github.com/aws/aws-cdk/issues/9332 - * @default true - */ - readonly kubectlEnabled?: boolean; /** * Number of instances to allocate as an initial capacity for this cluster. @@ -976,14 +954,6 @@ export class Cluster extends ClusterBase { physicalName: props.clusterName, }); - if (props.kubectlEnabled === false) { - throw new Error( - 'The "eks.Cluster" class no longer allows disabling kubectl support. ' + - 'As a temporary workaround, you can use the drop-in replacement class `eks.LegacyCluster`, ' + - 'but bear in mind that this class will soon be removed and will no longer receive additional ' + - 'features or bugfixes. See https://github.com/aws/aws-cdk/issues/9332 for more details'); - } - const stack = Stack.of(this); this.prune = props.prune ?? true; diff --git a/packages/@aws-cdk/aws-eks/lib/fargate-cluster.ts b/packages/@aws-cdk/aws-eks/lib/fargate-cluster.ts index 60265a67c0eee..11036875a9d30 100644 --- a/packages/@aws-cdk/aws-eks/lib/fargate-cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/fargate-cluster.ts @@ -27,7 +27,6 @@ export class FargateCluster extends Cluster { super(scope, id, { ...props, defaultCapacity: 0, - kubectlEnabled: true, coreDnsComputeType: props.coreDnsComputeType ?? CoreDnsComputeType.FARGATE, version: props.version, }); diff --git a/packages/@aws-cdk/aws-eks/lib/index.ts b/packages/@aws-cdk/aws-eks/lib/index.ts index 633b51cc9ca30..eac2aa14eebc2 100644 --- a/packages/@aws-cdk/aws-eks/lib/index.ts +++ b/packages/@aws-cdk/aws-eks/lib/index.ts @@ -1,7 +1,6 @@ export * from './aws-auth'; export * from './aws-auth-mapping'; export * from './cluster'; -export * from './legacy-cluster'; export * from './eks.generated'; export * from './fargate-profile'; export * from './helm-chart'; diff --git a/packages/@aws-cdk/aws-eks/lib/legacy-cluster.ts b/packages/@aws-cdk/aws-eks/lib/legacy-cluster.ts deleted file mode 100644 index bc83da531c638..0000000000000 --- a/packages/@aws-cdk/aws-eks/lib/legacy-cluster.ts +++ /dev/null @@ -1,552 +0,0 @@ -import * as autoscaling from '@aws-cdk/aws-autoscaling'; -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 ssm from '@aws-cdk/aws-ssm'; -import { Annotations, CfnOutput, Resource, Stack, Token, Tags } from '@aws-cdk/core'; -import { Construct } from 'constructs'; -import { ICluster, ClusterAttributes, KubernetesVersion, NodeType, DefaultCapacityType, EksOptimizedImage, AutoScalingGroupCapacityOptions, MachineImageType, AutoScalingGroupOptions, CommonClusterOptions } from './cluster'; -import { clusterArnComponents } from './cluster-resource'; -import { CfnCluster, CfnClusterProps } from './eks.generated'; -import { HelmChartOptions, HelmChart } from './helm-chart'; -import { KubernetesManifest } from './k8s-manifest'; -import { Nodegroup, NodegroupOptions } from './managed-nodegroup'; -import { ServiceAccount, ServiceAccountOptions } from './service-account'; -import { renderAmazonLinuxUserData, renderBottlerocketUserData } from './user-data'; - -// defaults are based on https://eksctl.io -const DEFAULT_CAPACITY_COUNT = 2; -const DEFAULT_CAPACITY_TYPE = ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.LARGE); - -/** - * Common configuration props for EKS clusters. - */ -export interface LegacyClusterProps extends CommonClusterOptions { - /** - * Number of instances to allocate as an initial capacity for this cluster. - * Instance type can be configured through `defaultCapacityInstanceType`, - * which defaults to `m5.large`. - * - * Use `cluster.addCapacity` to add additional customized capacity. Set this - * to `0` is you wish to avoid the initial capacity allocation. - * - * @default 2 - */ - readonly defaultCapacity?: number; - - /** - * The instance type to use for the default capacity. This will only be taken - * into account if `defaultCapacity` is > 0. - * - * @default m5.large - */ - readonly defaultCapacityInstance?: ec2.InstanceType; - - /** - * The default capacity type for the cluster. - * - * @default NODEGROUP - */ - readonly defaultCapacityType?: DefaultCapacityType; - - /** - * KMS secret for envelope encryption for Kubernetes secrets. - * - * @default - By default, Kubernetes stores all secret object data within etcd and - * all etcd volumes used by Amazon EKS are encrypted at the disk-level - * using AWS-Managed encryption keys. - */ - readonly secretsEncryptionKey?: kms.IKey; -} - -/** - * A Cluster represents a managed Kubernetes Service (EKS) - * - * This is a fully managed cluster of API Servers (control-plane) - * The user is still required to create the worker nodes. - * - * @resource AWS::EKS::Cluster - */ -export class LegacyCluster extends Resource implements ICluster { - /** - * Import an existing cluster - * - * @param scope the construct scope, in most cases 'this' - * @param id the id or name to import as - * @param attrs the cluster properties to use for importing information - */ - public static fromClusterAttributes(scope: Construct, id: string, attrs: ClusterAttributes): ICluster { - return new ImportedCluster(scope, id, attrs); - } - - /** - * The VPC in which this Cluster was created - */ - public readonly vpc: ec2.IVpc; - - /** - * The Name of the created EKS Cluster - */ - public readonly clusterName: string; - - /** - * The AWS generated ARN for the Cluster resource - * - * @example arn:aws:eks:us-west-2:666666666666:cluster/prod - */ - public readonly clusterArn: string; - - /** - * The endpoint URL for the Cluster - * - * This is the URL inside the kubeconfig file to use with kubectl - * - * @example https://5E1D0CEXAMPLEA591B746AFC5AB30262.yl4.us-west-2.eks.amazonaws.com - */ - public readonly clusterEndpoint: string; - - /** - * The certificate-authority-data for your cluster. - */ - public readonly clusterCertificateAuthorityData: string; - - /** - * The id of the cluster security group that was created by Amazon EKS for the cluster. - */ - public readonly clusterSecurityGroupId: string; - - /** - * The cluster security group that was created by Amazon EKS for the cluster. - */ - public readonly clusterSecurityGroup: ec2.ISecurityGroup; - - - /** - * Amazon Resource Name (ARN) or alias of the customer master key (CMK). - */ - public readonly clusterEncryptionConfigKeyArn: string; - - /** - * Manages connection rules (Security Group Rules) for the cluster - * - * @type {ec2.Connections} - * @memberof Cluster - */ - public readonly connections: ec2.Connections; - - /** - * IAM role assumed by the EKS Control Plane - */ - public readonly role: iam.IRole; - - /** - * The auto scaling group that hosts the default capacity for this cluster. - * This will be `undefined` if the `defaultCapacityType` is not `EC2` or - * `defaultCapacityType` is `EC2` but default capacity is set to 0. - */ - public readonly defaultCapacity?: autoscaling.AutoScalingGroup; - - /** - * The node group that hosts the default capacity for this cluster. - * This will be `undefined` if the `defaultCapacityType` is `EC2` or - * `defaultCapacityType` is `NODEGROUP` but default capacity is set to 0. - */ - public readonly defaultNodegroup?: Nodegroup; - - public readonly prune: boolean = false; - - private readonly version: KubernetesVersion; - - /** - * Initiates an EKS Cluster with the supplied arguments - * - * @param scope a Construct, most likely a cdk.Stack created - * @param name the name of the Construct to create - * @param props properties in the IClusterProps interface - */ - constructor(scope: Construct, id: string, props: LegacyClusterProps) { - super(scope, id, { - physicalName: props.clusterName, - }); - - const stack = Stack.of(this); - - this.vpc = props.vpc || new ec2.Vpc(this, 'DefaultVpc'); - this.version = props.version; - - this.tagSubnets(); - - // this is the role used by EKS when interacting with AWS resources - this.role = props.role || new iam.Role(this, 'Role', { - assumedBy: new iam.ServicePrincipal('eks.amazonaws.com'), - managedPolicies: [ - iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEKSClusterPolicy'), - ], - }); - - const securityGroup = props.securityGroup || new ec2.SecurityGroup(this, 'ControlPlaneSecurityGroup', { - vpc: this.vpc, - description: 'EKS Control Plane Security Group', - }); - - this.connections = new ec2.Connections({ - securityGroups: [securityGroup], - defaultPort: ec2.Port.tcp(443), // Control Plane has an HTTPS API - }); - - // Get subnetIds for all selected subnets - const placements = props.vpcSubnets || [{ subnetType: ec2.SubnetType.PUBLIC }, { subnetType: ec2.SubnetType.PRIVATE }]; - const subnetIds = [...new Set(Array().concat(...placements.map(s => this.vpc.selectSubnets(s).subnetIds)))]; - - const clusterProps: CfnClusterProps = { - name: this.physicalName, - roleArn: this.role.roleArn, - version: props.version.version, - resourcesVpcConfig: { - securityGroupIds: [securityGroup.securityGroupId], - subnetIds, - }, - ...(props.secretsEncryptionKey ? { - encryptionConfig: [{ - provider: { - keyArn: props.secretsEncryptionKey.keyArn, - }, - resources: ['secrets'], - }], - } : {} ), - }; - - const resource = new CfnCluster(this, 'Resource', clusterProps); - - this.clusterName = this.getResourceNameAttribute(resource.ref); - this.clusterArn = this.getResourceArnAttribute(resource.attrArn, clusterArnComponents(this.physicalName)); - - this.clusterEndpoint = resource.attrEndpoint; - this.clusterCertificateAuthorityData = resource.attrCertificateAuthorityData; - this.clusterSecurityGroupId = resource.attrClusterSecurityGroupId; - this.clusterSecurityGroup = ec2.SecurityGroup.fromSecurityGroupId(this, 'ClusterSecurityGroup', this.clusterSecurityGroupId); - this.clusterEncryptionConfigKeyArn = resource.attrEncryptionConfigKeyArn; - - const updateConfigCommandPrefix = `aws eks update-kubeconfig --name ${this.clusterName}`; - const getTokenCommandPrefix = `aws eks get-token --cluster-name ${this.clusterName}`; - const commonCommandOptions = [`--region ${stack.region}`]; - - if (props.outputClusterName) { - new CfnOutput(this, 'ClusterName', { value: this.clusterName }); - } - - // allocate default capacity if non-zero (or default). - const minCapacity = props.defaultCapacity === undefined ? DEFAULT_CAPACITY_COUNT : props.defaultCapacity; - if (minCapacity > 0) { - const instanceType = props.defaultCapacityInstance || DEFAULT_CAPACITY_TYPE; - this.defaultCapacity = props.defaultCapacityType === DefaultCapacityType.EC2 ? - this.addCapacity('DefaultCapacity', { instanceType, minCapacity }) : undefined; - - this.defaultNodegroup = props.defaultCapacityType !== DefaultCapacityType.EC2 ? - this.addNodegroup('DefaultCapacity', { instanceType, minSize: minCapacity }) : undefined; - } - - const outputConfigCommand = props.outputConfigCommand === undefined ? true : props.outputConfigCommand; - if (outputConfigCommand) { - const postfix = commonCommandOptions.join(' '); - new CfnOutput(this, 'ConfigCommand', { value: `${updateConfigCommandPrefix} ${postfix}` }); - new CfnOutput(this, 'GetTokenCommand', { value: `${getTokenCommandPrefix} ${postfix}` }); - } - } - - public addServiceAccount(_id: string, _options?: ServiceAccountOptions): ServiceAccount { - throw new Error('legacy cluster does not support adding service accounts'); - } - - /** - * Since we dont really want to make it required on the top-level ICluster - * we do this trick here in return type to match interface type - */ - public get openIdConnectProvider(): iam.IOpenIdConnectProvider { - throw new Error('legacy cluster does not support open id connect providers'); - } - - /** - * Add nodes to this EKS cluster - * - * The nodes will automatically be configured with the right VPC and AMI - * for the instance type and Kubernetes version. - * - * Spot instances will be labeled `lifecycle=Ec2Spot` and tainted with `PreferNoSchedule`. - */ - public addCapacity(id: string, options: AutoScalingGroupCapacityOptions): autoscaling.AutoScalingGroup { - if (options.machineImageType === MachineImageType.BOTTLEROCKET && options.bootstrapOptions !== undefined ) { - throw new Error('bootstrapOptions is not supported for Bottlerocket'); - } - const asg = new autoscaling.AutoScalingGroup(this, id, { - ...options, - vpc: this.vpc, - machineImage: options.machineImageType === MachineImageType.BOTTLEROCKET ? - new BottleRocketImage() : - new EksOptimizedImage({ - nodeType: nodeTypeForInstanceType(options.instanceType), - kubernetesVersion: this.version.version, - }), - updateType: options.updateType || autoscaling.UpdateType.ROLLING_UPDATE, - instanceType: options.instanceType, - }); - - this.addAutoScalingGroup(asg, { - mapRole: options.mapRole, - bootstrapOptions: options.bootstrapOptions, - bootstrapEnabled: options.bootstrapEnabled, - machineImageType: options.machineImageType, - }); - - return asg; - } - - /** - * Add managed nodegroup to this Amazon EKS cluster - * - * This method will create a new managed nodegroup and add into the capacity. - * - * @see https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html - * @param id The ID of the nodegroup - * @param options options for creating a new nodegroup - */ - public addNodegroup(id: string, options?: NodegroupOptions): Nodegroup { - return new Nodegroup(this, `Nodegroup${id}`, { - cluster: this, - ...options, - }); - } - - /** - * Add compute capacity to this EKS cluster in the form of an AutoScalingGroup - * - * The AutoScalingGroup must be running an EKS-optimized AMI containing the - * /etc/eks/bootstrap.sh script. This method will configure Security Groups, - * add the right policies to the instance role, apply the right tags, and add - * the required user data to the instance's launch configuration. - * - * Spot instances will be labeled `lifecycle=Ec2Spot` and tainted with `PreferNoSchedule`. - * If kubectl is enabled, the - * [spot interrupt handler](https://github.com/awslabs/ec2-spot-labs/tree/master/ec2-spot-eks-solution/spot-termination-handler) - * daemon will be installed on all spot instances to handle - * [EC2 Spot Instance Termination Notices](https://aws.amazon.com/blogs/aws/new-ec2-spot-instance-termination-notices/). - * - * Prefer to use `addCapacity` if possible. - * - * @see https://docs.aws.amazon.com/eks/latest/userguide/launch-workers.html - * @param autoScalingGroup [disable-awslint:ref-via-interface] - * @param options options for adding auto scaling groups, like customizing the bootstrap script - */ - public addAutoScalingGroup(autoScalingGroup: autoscaling.AutoScalingGroup, options: AutoScalingGroupOptions) { - // self rules - autoScalingGroup.connections.allowInternally(ec2.Port.allTraffic()); - - // Cluster to:nodes rules - autoScalingGroup.connections.allowFrom(this, ec2.Port.tcp(443)); - autoScalingGroup.connections.allowFrom(this, ec2.Port.tcpRange(1025, 65535)); - - // Allow HTTPS from Nodes to Cluster - autoScalingGroup.connections.allowTo(this, ec2.Port.tcp(443)); - - // Allow all node outbound traffic - autoScalingGroup.connections.allowToAnyIpv4(ec2.Port.allTcp()); - autoScalingGroup.connections.allowToAnyIpv4(ec2.Port.allUdp()); - autoScalingGroup.connections.allowToAnyIpv4(ec2.Port.allIcmp()); - - const bootstrapEnabled = options.bootstrapEnabled !== undefined ? options.bootstrapEnabled : true; - if (options.bootstrapOptions && !bootstrapEnabled) { - throw new Error('Cannot specify "bootstrapOptions" if "bootstrapEnabled" is false'); - } - - if (bootstrapEnabled) { - const userData = options.machineImageType === MachineImageType.BOTTLEROCKET ? - renderBottlerocketUserData(this) : - renderAmazonLinuxUserData(this.clusterName, autoScalingGroup, options.bootstrapOptions); - autoScalingGroup.addUserData(...userData); - } - - autoScalingGroup.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEKSWorkerNodePolicy')); - autoScalingGroup.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEKS_CNI_Policy')); - autoScalingGroup.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEC2ContainerRegistryReadOnly')); - - // EKS Required Tags - Tags.of(autoScalingGroup).add(`kubernetes.io/cluster/${this.clusterName}`, 'owned', { - applyToLaunchedInstances: true, - }); - - if (options.mapRole) { - throw new Error('Cannot map instance IAM role to RBAC if kubectl is disabled for the cluster'); - } - - // since we are not mapping the instance role to RBAC, synthesize an - // output so it can be pasted into `aws-auth-cm.yaml` - new CfnOutput(autoScalingGroup, 'InstanceRoleARN', { - value: autoScalingGroup.role.roleArn, - }); - } - - public addManifest(_id: string, ..._manifest: Record[]): KubernetesManifest { - throw new Error('legacy cluster does not support adding kubernetes manifests'); - } - - public addHelmChart(_id: string, _options: HelmChartOptions): HelmChart { - throw new Error('legacy cluster does not support adding helm charts'); - } - - public addCdk8sChart(_id: string, _chart: Construct): KubernetesManifest { - throw new Error('legacy cluster does not support adding cdk8s charts'); - } - - /** - * Opportunistically tag subnets with the required tags. - * - * If no subnets could be found (because this is an imported VPC), add a warning. - * - * @see https://docs.aws.amazon.com/eks/latest/userguide/network_reqs.html - */ - private tagSubnets() { - const tagAllSubnets = (type: string, subnets: ec2.ISubnet[], tag: string) => { - for (const subnet of subnets) { - // if this is not a concrete subnet, attach a construct warning - if (!ec2.Subnet.isVpcSubnet(subnet)) { - // message (if token): "could not auto-tag public/private subnet with tag..." - // message (if not token): "count not auto-tag public/private subnet xxxxx with tag..." - const subnetID = Token.isUnresolved(subnet.subnetId) ? '' : ` ${subnet.subnetId}`; - Annotations.of(this).addWarning(`Could not auto-tag ${type} subnet${subnetID} with "${tag}=1", please remember to do this manually`); - continue; - } - - Tags.of(subnet).add(tag, '1'); - } - }; - - // https://docs.aws.amazon.com/eks/latest/userguide/network_reqs.html - tagAllSubnets('private', this.vpc.privateSubnets, 'kubernetes.io/role/internal-elb'); - tagAllSubnets('public', this.vpc.publicSubnets, 'kubernetes.io/role/elb'); - } -} - -/** - * Import a cluster to use in another stack - */ -class ImportedCluster extends Resource implements ICluster { - public readonly clusterName: string; - public readonly clusterArn: string; - public readonly connections = new ec2.Connections(); - public readonly prune: boolean = false; - - constructor(scope: Construct, id: string, private readonly props: ClusterAttributes) { - super(scope, id); - - this.clusterName = props.clusterName; - this.clusterArn = this.stack.formatArn(clusterArnComponents(props.clusterName)); - - let i = 1; - for (const sgid of props.securityGroupIds ?? []) { - this.connections.addSecurityGroup(ec2.SecurityGroup.fromSecurityGroupId(this, `SecurityGroup${i}`, sgid)); - i++; - } - } - - public addManifest(_id: string, ..._manifest: Record[]): KubernetesManifest { - throw new Error('legacy cluster does not support adding kubernetes manifests'); - } - - public addHelmChart(_id: string, _options: HelmChartOptions): HelmChart { - throw new Error('legacy cluster does not support adding helm charts'); - } - - public addCdk8sChart(_id: string, _chart: Construct): KubernetesManifest { - throw new Error('legacy cluster does not support adding cdk8s charts'); - } - - public addServiceAccount(_id: string, _options?: ServiceAccountOptions): ServiceAccount { - throw new Error('legacy cluster does not support adding service accounts'); - } - - public get openIdConnectProvider(): iam.IOpenIdConnectProvider { - throw new Error('legacy cluster does not support open id connect providers'); - } - - public get vpc() { - if (!this.props.vpc) { - throw new Error('"vpc" is not defined for this imported cluster'); - } - return this.props.vpc; - } - - public get clusterSecurityGroup(): ec2.ISecurityGroup { - // we are getting rid of this class very soon, no real need to support this here. - throw new Error("Unsupported operation. Use 'clusterSecurityGroupId' instead."); - } - - public get clusterSecurityGroupId(): string { - if (!this.props.clusterSecurityGroupId) { - throw new Error('"clusterSecurityGroupId" is not defined for this imported cluster'); - } - return this.props.clusterSecurityGroupId; - } - - public get clusterEndpoint(): string { - if (!this.props.clusterEndpoint) { - throw new Error('"clusterEndpoint" is not defined for this imported cluster'); - } - return this.props.clusterEndpoint; - } - - public get clusterCertificateAuthorityData(): string { - if (!this.props.clusterCertificateAuthorityData) { - throw new Error('"clusterCertificateAuthorityData" is not defined for this imported cluster'); - } - return this.props.clusterCertificateAuthorityData; - } - - public get clusterEncryptionConfigKeyArn(): string { - if (!this.props.clusterEncryptionConfigKeyArn) { - throw new Error('"clusterEncryptionConfigKeyArn" is not defined for this imported cluster'); - } - return this.props.clusterEncryptionConfigKeyArn; - } - -} - -/** - * Construct an Bottlerocket image from the latest AMI published in SSM - */ -class BottleRocketImage implements ec2.IMachineImage { - private readonly kubernetesVersion?: string; - - private readonly amiParameterName: string; - - /** - * Constructs a new instance of the BottleRocketImage class. - */ - public constructor() { - // only 1.15 is currently available - this.kubernetesVersion = '1.15'; - - // set the SSM parameter name - this.amiParameterName = `/aws/service/bottlerocket/aws-k8s-${this.kubernetesVersion}/x86_64/latest/image_id`; - } - - /** - * Return the correct image - */ - public getImage(scope: Construct): ec2.MachineImageConfig { - const ami = ssm.StringParameter.valueForStringParameter(scope, this.amiParameterName); - return { - imageId: ami, - osType: ec2.OperatingSystemType.LINUX, - userData: ec2.UserData.custom(''), - }; - } -} - -const GPU_INSTANCETYPES = ['p2', 'p3', 'g4']; -const INFERENTIA_INSTANCETYPES = ['inf1']; - -function nodeTypeForInstanceType(instanceType: ec2.InstanceType) { - return GPU_INSTANCETYPES.includes(instanceType.toString().substring(0, 2)) ? NodeType.GPU : - INFERENTIA_INSTANCETYPES.includes(instanceType.toString().substring(0, 4)) ? NodeType.INFERENTIA : - NodeType.STANDARD; -} diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.kubectl-disabled.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.kubectl-disabled.expected.json deleted file mode 100644 index bf7ee135b983d..0000000000000 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.kubectl-disabled.expected.json +++ /dev/null @@ -1,1094 +0,0 @@ -{ - "Resources": { - "VPCB9E5F0B4": { - "Type": "AWS::EC2::VPC", - "Properties": { - "CidrBlock": "10.0.0.0/16", - "EnableDnsHostnames": true, - "EnableDnsSupport": true, - "InstanceTenancy": "default", - "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC" - } - ] - } - }, - "VPCPublicSubnet1SubnetB4246D30": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.0.0/19", - "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": "kubernetes.io/role/elb", - "Value": "1" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" - } - ] - } - }, - "VPCPublicSubnet1RouteTableFEE4B781": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "Tags": [ - { - "Key": "kubernetes.io/role/elb", - "Value": "1" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/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": "kubernetes.io/role/elb", - "Value": "1" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" - } - ] - } - }, - "VPCPublicSubnet1NATGatewayE0556630": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "VPCPublicSubnet1EIP6AD938E8", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, - "Tags": [ - { - "Key": "kubernetes.io/role/elb", - "Value": "1" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" - } - ] - } - }, - "VPCPublicSubnet2Subnet74179F39": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.32.0/19", - "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": "kubernetes.io/role/elb", - "Value": "1" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" - } - ] - } - }, - "VPCPublicSubnet2RouteTable6F1A15F1": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "Tags": [ - { - "Key": "kubernetes.io/role/elb", - "Value": "1" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/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": "kubernetes.io/role/elb", - "Value": "1" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" - } - ] - } - }, - "VPCPublicSubnet2NATGateway3C070193": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "VPCPublicSubnet2EIP4947BC00", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, - "Tags": [ - { - "Key": "kubernetes.io/role/elb", - "Value": "1" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" - } - ] - } - }, - "VPCPublicSubnet3Subnet631C5E25": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.64.0/19", - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "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": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" - } - ] - } - }, - "VPCPublicSubnet3RouteTable98AE0E14": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "Tags": [ - { - "Key": "kubernetes.io/role/elb", - "Value": "1" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" - } - ] - } - }, - "VPCPublicSubnet3RouteTableAssociation427FE0C6": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VPCPublicSubnet3RouteTable98AE0E14" - }, - "SubnetId": { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - } - } - }, - "VPCPublicSubnet3DefaultRouteA0D29D46": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VPCPublicSubnet3RouteTable98AE0E14" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "GatewayId": { - "Ref": "VPCIGWB7E252D3" - } - }, - "DependsOn": [ - "VPCVPCGW99B986DC" - ] - }, - "VPCPublicSubnet3EIPAD4BC883": { - "Type": "AWS::EC2::EIP", - "Properties": { - "Domain": "vpc", - "Tags": [ - { - "Key": "kubernetes.io/role/elb", - "Value": "1" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" - } - ] - } - }, - "VPCPublicSubnet3NATGatewayD3048F5C": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "VPCPublicSubnet3EIPAD4BC883", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - }, - "Tags": [ - { - "Key": "kubernetes.io/role/elb", - "Value": "1" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" - } - ] - } - }, - "VPCPrivateSubnet1Subnet8BCA10E0": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.96.0/19", - "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": "kubernetes.io/role/internal-elb", - "Value": "1" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet1" - } - ] - } - }, - "VPCPrivateSubnet1RouteTableBE8A6027": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "Tags": [ - { - "Key": "kubernetes.io/role/internal-elb", - "Value": "1" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/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.128.0/19", - "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": "kubernetes.io/role/internal-elb", - "Value": "1" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet2" - } - ] - } - }, - "VPCPrivateSubnet2RouteTable0A19E10E": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "Tags": [ - { - "Key": "kubernetes.io/role/internal-elb", - "Value": "1" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/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" - } - } - }, - "VPCPrivateSubnet3Subnet3EDCD457": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.160.0/19", - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "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": "eks-integ-kubectl-disabled/VPC/PrivateSubnet3" - } - ] - } - }, - "VPCPrivateSubnet3RouteTable192186F8": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "Tags": [ - { - "Key": "kubernetes.io/role/internal-elb", - "Value": "1" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet3" - } - ] - } - }, - "VPCPrivateSubnet3RouteTableAssociationC28D144E": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VPCPrivateSubnet3RouteTable192186F8" - }, - "SubnetId": { - "Ref": "VPCPrivateSubnet3Subnet3EDCD457" - } - } - }, - "VPCPrivateSubnet3DefaultRoute27F311AE": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VPCPrivateSubnet3RouteTable192186F8" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { - "Ref": "VPCPublicSubnet3NATGatewayD3048F5C" - } - } - }, - "VPCIGWB7E252D3": { - "Type": "AWS::EC2::InternetGateway", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC" - } - ] - } - }, - "VPCVPCGW99B986DC": { - "Type": "AWS::EC2::VPCGatewayAttachment", - "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "InternetGatewayId": { - "Ref": "VPCIGWB7E252D3" - } - } - }, - "SecretsKey317DCF94": { - "Type": "AWS::KMS::Key", - "Properties": { - "KeyPolicy": { - "Statement": [ - { - "Action": [ - "kms:Create*", - "kms:Describe*", - "kms:Enable*", - "kms:List*", - "kms:Put*", - "kms:Update*", - "kms:Revoke*", - "kms:Disable*", - "kms:Get*", - "kms:Delete*", - "kms:ScheduleKeyDeletion", - "kms:CancelKeyDeletion", - "kms:GenerateDataKey", - "kms:TagResource", - "kms:UntagResource" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::12345678:root" - ] - ] - } - }, - "Resource": "*" - } - ], - "Version": "2012-10-17" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "EKSClusterRoleC0AEAC3D": { - "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" - ] - ] - } - ] - } - }, - "EKSClusterControlPlaneSecurityGroup580AD1FE": { - "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": "VPCB9E5F0B4" - } - } - }, - "EKSClusterControlPlaneSecurityGroupfromeksintegkubectldisabledEKSClusterNodesInstanceSecurityGroup1E8EEB07443828A1FF0": { - "Type": "AWS::EC2::SecurityGroupIngress", - "Properties": { - "IpProtocol": "tcp", - "Description": "from eksintegkubectldisabledEKSClusterNodesInstanceSecurityGroup1E8EEB07:443", - "FromPort": 443, - "GroupId": { - "Fn::GetAtt": [ - "EKSClusterControlPlaneSecurityGroup580AD1FE", - "GroupId" - ] - }, - "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "EKSClusterNodesInstanceSecurityGroup460A275E", - "GroupId" - ] - }, - "ToPort": 443 - } - }, - "EKSClusterBA6ECF8F": { - "Type": "AWS::EKS::Cluster", - "Properties": { - "ResourcesVpcConfig": { - "SecurityGroupIds": [ - { - "Fn::GetAtt": [ - "EKSClusterControlPlaneSecurityGroup580AD1FE", - "GroupId" - ] - } - ], - "SubnetIds": [ - { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, - { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, - { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - }, - { - "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" - }, - { - "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" - }, - { - "Ref": "VPCPrivateSubnet3Subnet3EDCD457" - } - ] - }, - "RoleArn": { - "Fn::GetAtt": [ - "EKSClusterRoleC0AEAC3D", - "Arn" - ] - }, - "EncryptionConfig": [ - { - "Provider": { - "KeyArn": { - "Fn::GetAtt": [ - "SecretsKey317DCF94", - "Arn" - ] - } - }, - "Resources": [ - "secrets" - ] - } - ], - "Version": "1.18" - } - }, - "EKSClusterNodesInstanceSecurityGroup460A275E": { - "Type": "AWS::EC2::SecurityGroup", - "Properties": { - "GroupDescription": "eks-integ-kubectl-disabled/EKSCluster/Nodes/InstanceSecurityGroup", - "SecurityGroupEgress": [ - { - "CidrIp": "0.0.0.0/0", - "Description": "Allow all outbound traffic by default", - "IpProtocol": "-1" - } - ], - "Tags": [ - { - "Key": { - "Fn::Join": [ - "", - [ - "kubernetes.io/cluster/", - { - "Ref": "EKSClusterBA6ECF8F" - } - ] - ] - }, - "Value": "owned" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/EKSCluster/Nodes" - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "EKSClusterNodesInstanceSecurityGroupfromeksintegkubectldisabledEKSClusterNodesInstanceSecurityGroup1E8EEB07ALLTRAFFIC813BA9BB": { - "Type": "AWS::EC2::SecurityGroupIngress", - "Properties": { - "IpProtocol": "-1", - "Description": "from eksintegkubectldisabledEKSClusterNodesInstanceSecurityGroup1E8EEB07:ALL TRAFFIC", - "GroupId": { - "Fn::GetAtt": [ - "EKSClusterNodesInstanceSecurityGroup460A275E", - "GroupId" - ] - }, - "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "EKSClusterNodesInstanceSecurityGroup460A275E", - "GroupId" - ] - } - } - }, - "EKSClusterNodesInstanceSecurityGroupfromeksintegkubectldisabledEKSClusterControlPlaneSecurityGroupA8D847C7443405A887C": { - "Type": "AWS::EC2::SecurityGroupIngress", - "Properties": { - "IpProtocol": "tcp", - "Description": "from eksintegkubectldisabledEKSClusterControlPlaneSecurityGroupA8D847C7:443", - "FromPort": 443, - "GroupId": { - "Fn::GetAtt": [ - "EKSClusterNodesInstanceSecurityGroup460A275E", - "GroupId" - ] - }, - "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "EKSClusterControlPlaneSecurityGroup580AD1FE", - "GroupId" - ] - }, - "ToPort": 443 - } - }, - "EKSClusterNodesInstanceSecurityGroupfromeksintegkubectldisabledEKSClusterControlPlaneSecurityGroupA8D847C71025655350C1AD63E": { - "Type": "AWS::EC2::SecurityGroupIngress", - "Properties": { - "IpProtocol": "tcp", - "Description": "from eksintegkubectldisabledEKSClusterControlPlaneSecurityGroupA8D847C7:1025-65535", - "FromPort": 1025, - "GroupId": { - "Fn::GetAtt": [ - "EKSClusterNodesInstanceSecurityGroup460A275E", - "GroupId" - ] - }, - "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "EKSClusterControlPlaneSecurityGroup580AD1FE", - "GroupId" - ] - }, - "ToPort": 65535 - } - }, - "EKSClusterNodesInstanceRoleEE5595D6": { - "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" - ] - ] - } - ], - "Tags": [ - { - "Key": { - "Fn::Join": [ - "", - [ - "kubernetes.io/cluster/", - { - "Ref": "EKSClusterBA6ECF8F" - } - ] - ] - }, - "Value": "owned" - }, - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/EKSCluster/Nodes" - } - ] - } - }, - "EKSClusterNodesInstanceProfile0F2DB3B9": { - "Type": "AWS::IAM::InstanceProfile", - "Properties": { - "Roles": [ - { - "Ref": "EKSClusterNodesInstanceRoleEE5595D6" - } - ] - } - }, - "EKSClusterNodesLaunchConfig921F1106": { - "Type": "AWS::AutoScaling::LaunchConfiguration", - "Properties": { - "ImageId": { - "Ref": "SsmParameterValueawsserviceeksoptimizedami118amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" - }, - "InstanceType": "t2.medium", - "IamInstanceProfile": { - "Ref": "EKSClusterNodesInstanceProfile0F2DB3B9" - }, - "SecurityGroups": [ - { - "Fn::GetAtt": [ - "EKSClusterNodesInstanceSecurityGroup460A275E", - "GroupId" - ] - } - ], - "UserData": { - "Fn::Base64": { - "Fn::Join": [ - "", - [ - "#!/bin/bash\nset -o xtrace\n/etc/eks/bootstrap.sh ", - { - "Ref": "EKSClusterBA6ECF8F" - }, - " --kubelet-extra-args \"--node-labels lifecycle=OnDemand\" --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack eks-integ-kubectl-disabled --resource EKSClusterNodesASGC2597E34 --region test-region" - ] - ] - } - } - }, - "DependsOn": [ - "EKSClusterNodesInstanceRoleEE5595D6" - ] - }, - "EKSClusterNodesASGC2597E34": { - "Type": "AWS::AutoScaling::AutoScalingGroup", - "Properties": { - "MaxSize": "1", - "MinSize": "1", - "LaunchConfigurationName": { - "Ref": "EKSClusterNodesLaunchConfig921F1106" - }, - "Tags": [ - { - "Key": { - "Fn::Join": [ - "", - [ - "kubernetes.io/cluster/", - { - "Ref": "EKSClusterBA6ECF8F" - } - ] - ] - }, - "PropagateAtLaunch": true, - "Value": "owned" - }, - { - "Key": "Name", - "PropagateAtLaunch": true, - "Value": "eks-integ-kubectl-disabled/EKSCluster/Nodes" - } - ], - "VPCZoneIdentifier": [ - { - "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" - }, - { - "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" - }, - { - "Ref": "VPCPrivateSubnet3Subnet3EDCD457" - } - ] - }, - "UpdatePolicy": { - "AutoScalingRollingUpdate": { - "WaitOnResourceSignals": false, - "PauseTime": "PT0S", - "SuspendProcesses": [ - "HealthCheck", - "ReplaceUnhealthy", - "AZRebalance", - "AlarmNotification", - "ScheduledActions" - ] - }, - "AutoScalingScheduledAction": { - "IgnoreUnmodifiedGroupSizeProperties": true - } - } - } - }, - "Outputs": { - "EKSClusterConfigCommand3809C9C9": { - "Value": { - "Fn::Join": [ - "", - [ - "aws eks update-kubeconfig --name ", - { - "Ref": "EKSClusterBA6ECF8F" - }, - " --region test-region" - ] - ] - } - }, - "EKSClusterGetTokenCommand10DBF41A": { - "Value": { - "Fn::Join": [ - "", - [ - "aws eks get-token --cluster-name ", - { - "Ref": "EKSClusterBA6ECF8F" - }, - " --region test-region" - ] - ] - } - }, - "EKSClusterNodesInstanceRoleARN10992C84": { - "Value": { - "Fn::GetAtt": [ - "EKSClusterNodesInstanceRoleEE5595D6", - "Arn" - ] - } - } - }, - "Parameters": { - "SsmParameterValueawsserviceeksoptimizedami118amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { - "Type": "AWS::SSM::Parameter::Value", - "Default": "/aws/service/eks/optimized-ami/1.18/amazon-linux-2/recommended/image_id" - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.kubectl-disabled.ts b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.kubectl-disabled.ts deleted file mode 100644 index 6bf5fd6f7dad0..0000000000000 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.kubectl-disabled.ts +++ /dev/null @@ -1,37 +0,0 @@ -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as kms from '@aws-cdk/aws-kms'; -import * as cdk from '@aws-cdk/core'; -import * as eks from '../lib'; -import { TestStack } from './util'; - -const CLUSTER_VERSION = eks.KubernetesVersion.V1_18; - -class EksClusterStack extends TestStack { - constructor(scope: cdk.App, id: string) { - super(scope, id); - - const vpc = new ec2.Vpc(this, 'VPC'); - - const secretsEncryptionKey = new kms.Key(this, 'SecretsKey'); - - const cluster = new eks.LegacyCluster(this, 'EKSCluster', { - vpc, - defaultCapacity: 0, - version: CLUSTER_VERSION, - secretsEncryptionKey, - }); - - cluster.addCapacity('Nodes', { - instanceType: new ec2.InstanceType('t2.medium'), - minCapacity: 1, // Raise this number to add more nodes - }); - } -} - -const app = new cdk.App(); - -// since the EKS optimized AMI is hard-coded here based on the region, -// we need to actually pass in a specific region. -new EksClusterStack(app, 'eks-integ-kubectl-disabled'); - -app.synth(); diff --git a/packages/@aws-cdk/aws-eks/test/test.legacy-cluster.ts b/packages/@aws-cdk/aws-eks/test/test.legacy-cluster.ts deleted file mode 100644 index 6395990fb909d..0000000000000 --- a/packages/@aws-cdk/aws-eks/test/test.legacy-cluster.ts +++ /dev/null @@ -1,635 +0,0 @@ -import { expect, haveResource, haveResourceLike, not } from '@aws-cdk/assert'; -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 { Test } from 'nodeunit'; -import * as eks from '../lib'; -import { testFixture, testFixtureNoVpc } from './util'; - -/* eslint-disable max-len */ - -const CLUSTER_VERSION = eks.KubernetesVersion.V1_16; - -export = { - 'a default cluster spans all subnets'(test: Test) { - // GIVEN - const { stack, vpc } = testFixture(); - - // WHEN - new eks.LegacyCluster(stack, 'Cluster', { vpc, defaultCapacity: 0, version: CLUSTER_VERSION }); - - // THEN - expect(stack).to(haveResourceLike('AWS::EKS::Cluster', { - ResourcesVpcConfig: { - SubnetIds: [ - { Ref: 'VPCPublicSubnet1SubnetB4246D30' }, - { Ref: 'VPCPublicSubnet2Subnet74179F39' }, - { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, - { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, - ], - }, - })); - - test.done(); - }, - - 'if "vpc" is not specified, vpc with default configuration will be created'(test: Test) { - // GIVEN - const { stack } = testFixtureNoVpc(); - - // WHEN - new eks.LegacyCluster(stack, 'cluster', { version: CLUSTER_VERSION }) ; - - // THEN - expect(stack).to(haveResource('AWS::EC2::VPC')); - test.done(); - }, - - 'default capacity': { - - 'x2 m5.large by default'(test: Test) { - // GIVEN - const { stack } = testFixtureNoVpc(); - - // WHEN - const cluster = new eks.LegacyCluster(stack, 'cluster', { version: CLUSTER_VERSION }); - - // THEN - test.ok(cluster.defaultNodegroup); - expect(stack).to(haveResource('AWS::EKS::Nodegroup', { - InstanceTypes: [ - 'm5.large', - ], - ScalingConfig: { - DesiredSize: 2, - MaxSize: 2, - MinSize: 2, - }, - })); - test.done(); - }, - - 'quantity and type can be customized'(test: Test) { - // GIVEN - const { stack } = testFixtureNoVpc(); - - // WHEN - const cluster = new eks.LegacyCluster(stack, 'cluster', { - defaultCapacity: 10, - defaultCapacityInstance: new ec2.InstanceType('m2.xlarge'), - version: CLUSTER_VERSION, - }); - - // THEN - test.ok(cluster.defaultNodegroup); - expect(stack).to(haveResource('AWS::EKS::Nodegroup', { - ScalingConfig: { - DesiredSize: 10, - MaxSize: 10, - MinSize: 10, - }, - })); - // expect(stack).to(haveResource('AWS::AutoScaling::LaunchConfiguration', { InstanceType: 'm2.xlarge' })); - test.done(); - }, - - 'defaultCapacity=0 will not allocate at all'(test: Test) { - // GIVEN - const { stack } = testFixtureNoVpc(); - - // WHEN - const cluster = new eks.LegacyCluster(stack, 'cluster', { defaultCapacity: 0, version: CLUSTER_VERSION }); - - // THEN - test.ok(!cluster.defaultCapacity); - expect(stack).notTo(haveResource('AWS::AutoScaling::AutoScalingGroup')); - expect(stack).notTo(haveResource('AWS::AutoScaling::LaunchConfiguration')); - test.done(); - }, - }, - - 'creating a cluster tags the private VPC subnets'(test: Test) { - // GIVEN - const { stack, vpc } = testFixture(); - - // WHEN - new eks.LegacyCluster(stack, 'Cluster', { vpc, defaultCapacity: 0, version: CLUSTER_VERSION }); - - // THEN - expect(stack).to(haveResource('AWS::EC2::Subnet', { - 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: 'Stack/VPC/PrivateSubnet1' }, - ], - })); - - test.done(); - }, - - 'creating a cluster tags the public VPC subnets'(test: Test) { - // GIVEN - const { stack, vpc } = testFixture(); - - // WHEN - new eks.LegacyCluster(stack, 'Cluster', { vpc, defaultCapacity: 0, version: CLUSTER_VERSION }); - - // THEN - expect(stack).to(haveResource('AWS::EC2::Subnet', { - 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: 'Stack/VPC/PublicSubnet1' }, - ], - })); - - test.done(); - }, - - 'adding capacity creates an ASG with tags'(test: Test) { - // GIVEN - const { stack, vpc } = testFixture(); - const cluster = new eks.LegacyCluster(stack, 'Cluster', { - vpc, - defaultCapacity: 0, - version: CLUSTER_VERSION, - }); - - // WHEN - cluster.addCapacity('Default', { - instanceType: new ec2.InstanceType('t2.medium'), - }); - - // THEN - expect(stack).to(haveResource('AWS::AutoScaling::AutoScalingGroup', { - Tags: [ - { - Key: { 'Fn::Join': ['', ['kubernetes.io/cluster/', { Ref: 'ClusterEB0386A7' }]] }, - PropagateAtLaunch: true, - Value: 'owned', - }, - { - Key: 'Name', - PropagateAtLaunch: true, - Value: 'Stack/Cluster/Default', - }, - ], - })); - - test.done(); - }, - - 'create nodegroup with existing role'(test: Test) { - // GIVEN - const { stack } = testFixtureNoVpc(); - - // WHEN - const cluster = new eks.LegacyCluster(stack, 'cluster', { - defaultCapacity: 10, - defaultCapacityInstance: new ec2.InstanceType('m2.xlarge'), - version: CLUSTER_VERSION, - }); - - const existingRole = new iam.Role(stack, 'ExistingRole', { - assumedBy: new iam.AccountRootPrincipal(), - }); - - new eks.Nodegroup(stack, 'Nodegroup', { - cluster, - nodeRole: existingRole, - }); - - // THEN - test.ok(cluster.defaultNodegroup); - expect(stack).to(haveResource('AWS::EKS::Nodegroup', { - ScalingConfig: { - DesiredSize: 10, - MaxSize: 10, - MinSize: 10, - }, - })); - test.done(); - }, - - 'adding bottlerocket capacity creates an ASG with tags'(test: Test) { - // GIVEN - const { stack, vpc } = testFixture(); - const cluster = new eks.LegacyCluster(stack, 'Cluster', { - vpc, - defaultCapacity: 0, - version: CLUSTER_VERSION, - }); - - // WHEN - cluster.addCapacity('Bottlerocket', { - instanceType: new ec2.InstanceType('t2.medium'), - machineImageType: eks.MachineImageType.BOTTLEROCKET, - }); - - // THEN - expect(stack).to(haveResource('AWS::AutoScaling::AutoScalingGroup', { - Tags: [ - { - Key: { 'Fn::Join': ['', ['kubernetes.io/cluster/', { Ref: 'ClusterEB0386A7' }]] }, - PropagateAtLaunch: true, - Value: 'owned', - }, - { - Key: 'Name', - PropagateAtLaunch: true, - Value: 'Stack/Cluster/Bottlerocket', - }, - ], - })); - test.done(); - }, - - 'adding bottlerocket capacity with bootstrapOptions throws error'(test: Test) { - // GIVEN - const { stack, vpc } = testFixture(); - const cluster = new eks.LegacyCluster(stack, 'Cluster', { - vpc, - defaultCapacity: 0, - version: CLUSTER_VERSION, - }); - - test.throws(() => cluster.addCapacity('Bottlerocket', { - instanceType: new ec2.InstanceType('t2.medium'), - machineImageType: eks.MachineImageType.BOTTLEROCKET, - bootstrapOptions: {}, - }), /bootstrapOptions is not supported for Bottlerocket/); - test.done(); - }, - - 'exercise export/import'(test: Test) { - // GIVEN - const { stack: stack1, vpc, app } = testFixture(); - const stack2 = new cdk.Stack(app, 'stack2', { env: { region: 'us-east-1' } }); - const cluster = new eks.LegacyCluster(stack1, 'Cluster', { - vpc, - defaultCapacity: 0, - version: CLUSTER_VERSION, - }); - - // WHEN - const imported = eks.LegacyCluster.fromClusterAttributes(stack2, 'Imported', { - vpc: cluster.vpc, - clusterEndpoint: cluster.clusterEndpoint, - clusterName: cluster.clusterName, - securityGroupIds: cluster.connections.securityGroups.map(s => s.securityGroupId), - clusterCertificateAuthorityData: cluster.clusterCertificateAuthorityData, - clusterSecurityGroupId: cluster.clusterSecurityGroupId, - clusterEncryptionConfigKeyArn: cluster.clusterEncryptionConfigKeyArn, - }); - - // this should cause an export/import - new cdk.CfnOutput(stack2, 'ClusterARN', { value: imported.clusterArn }); - - // THEN - expect(stack2).toMatch({ - Outputs: { - ClusterARN: { - Value: { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':eks:us-east-1:', - { - Ref: 'AWS::AccountId', - }, - ':cluster/', - { - 'Fn::ImportValue': 'Stack:ExportsOutputRefClusterEB0386A796A0E3FE', - }, - ], - ], - }, - }, - }, - }); - test.done(); - }, - - 'disabled features when kubectl is disabled'(test: Test) { - // GIVEN - const { stack, vpc } = testFixture(); - const cluster = new eks.LegacyCluster(stack, 'Cluster', { - vpc, - defaultCapacity: 0, - version: CLUSTER_VERSION, - }); - - test.throws(() => cluster.addCapacity('boo', { instanceType: new ec2.InstanceType('r5d.24xlarge'), mapRole: true }), - /Cannot map instance IAM role to RBAC if kubectl is disabled for the cluster/); - test.done(); - }, - - 'addCapacity will *not* map the IAM role if mapRole is false'(test: Test) { - // GIVEN - const { stack, vpc } = testFixture(); - const cluster = new eks.LegacyCluster(stack, 'Cluster', { - vpc, - defaultCapacity: 0, - version: CLUSTER_VERSION, - }); - - // WHEN - cluster.addCapacity('default', { - instanceType: new ec2.InstanceType('t2.nano'), - mapRole: false, - }); - - // THEN - expect(stack).to(not(haveResource(eks.KubernetesManifest.RESOURCE_TYPE))); - test.done(); - }, - - 'addCapacity will *not* map the IAM role if kubectl is disabled'(test: Test) { - // GIVEN - const { stack, vpc } = testFixture(); - const cluster = new eks.LegacyCluster(stack, 'Cluster', { - vpc, - defaultCapacity: 0, - version: CLUSTER_VERSION, - }); - - // WHEN - cluster.addCapacity('default', { - instanceType: new ec2.InstanceType('t2.nano'), - }); - - // THEN - expect(stack).to(not(haveResource(eks.KubernetesManifest.RESOURCE_TYPE))); - test.done(); - }, - - 'outputs': { - 'aws eks update-kubeconfig is the only output synthesized by default'(test: Test) { - // GIVEN - const { app, stack } = testFixtureNoVpc(); - - // WHEN - new eks.LegacyCluster(stack, 'Cluster', { version: CLUSTER_VERSION }); - - // THEN - const assembly = app.synth(); - const template = assembly.getStackByName(stack.stackName).template; - test.deepEqual(template.Outputs, { - ClusterConfigCommand43AAE40F: { Value: { 'Fn::Join': ['', ['aws eks update-kubeconfig --name ', { Ref: 'ClusterEB0386A7' }, ' --region us-east-1']] } }, - ClusterGetTokenCommand06AE992E: { Value: { 'Fn::Join': ['', ['aws eks get-token --cluster-name ', { Ref: 'ClusterEB0386A7' }, ' --region us-east-1']] } }, - }); - test.done(); - }, - - 'if `outputConfigCommand=false` will disabled the output'(test: Test) { - // GIVEN - const { app, stack } = testFixtureNoVpc(); - - // WHEN - new eks.LegacyCluster(stack, 'Cluster', { - outputConfigCommand: false, - version: CLUSTER_VERSION, - }); - - // THEN - const assembly = app.synth(); - const template = assembly.getStackByName(stack.stackName).template; - test.ok(!template.Outputs); // no outputs - test.done(); - }, - - '`outputClusterName` can be used to synthesize an output with the cluster name'(test: Test) { - // GIVEN - const { app, stack } = testFixtureNoVpc(); - - // WHEN - new eks.LegacyCluster(stack, 'Cluster', { - outputConfigCommand: false, - outputClusterName: true, - version: CLUSTER_VERSION, - }); - - // THEN - const assembly = app.synth(); - const template = assembly.getStackByName(stack.stackName).template; - test.deepEqual(template.Outputs, { - ClusterClusterNameEB26049E: { Value: { Ref: 'ClusterEB0386A7' } }, - }); - test.done(); - }, - - 'boostrap user-data': { - - 'rendered by default for ASGs'(test: Test) { - // GIVEN - const { app, stack } = testFixtureNoVpc(); - const cluster = new eks.LegacyCluster(stack, 'Cluster', { defaultCapacity: 0, version: CLUSTER_VERSION }); - - // WHEN - cluster.addCapacity('MyCapcity', { instanceType: new ec2.InstanceType('m3.xlargs') }); - - // THEN - const template = app.synth().getStackByName(stack.stackName).template; - const userData = template.Resources.ClusterMyCapcityLaunchConfig58583345.Properties.UserData; - test.deepEqual(userData, { 'Fn::Base64': { 'Fn::Join': ['', ['#!/bin/bash\nset -o xtrace\n/etc/eks/bootstrap.sh ', { Ref: 'ClusterEB0386A7' }, ' --kubelet-extra-args "--node-labels lifecycle=OnDemand" --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack Stack --resource ClusterMyCapcityASGD4CD8B97 --region us-east-1']] } }); - test.done(); - }, - - 'not rendered if bootstrap is disabled'(test: Test) { - // GIVEN - const { app, stack } = testFixtureNoVpc(); - const cluster = new eks.LegacyCluster(stack, 'Cluster', { defaultCapacity: 0, version: CLUSTER_VERSION }); - - // WHEN - cluster.addCapacity('MyCapcity', { - instanceType: new ec2.InstanceType('m3.xlargs'), - bootstrapEnabled: false, - }); - - // THEN - const template = app.synth().getStackByName(stack.stackName).template; - const userData = template.Resources.ClusterMyCapcityLaunchConfig58583345.Properties.UserData; - test.deepEqual(userData, { 'Fn::Base64': '#!/bin/bash' }); - test.done(); - }, - - // cursory test for options: see test.user-data.ts for full suite - 'bootstrap options'(test: Test) { - // GIVEN - const { app, stack } = testFixtureNoVpc(); - const cluster = new eks.LegacyCluster(stack, 'Cluster', { defaultCapacity: 0, version: CLUSTER_VERSION }); - - // WHEN - cluster.addCapacity('MyCapcity', { - instanceType: new ec2.InstanceType('m3.xlargs'), - bootstrapOptions: { - kubeletExtraArgs: '--node-labels FOO=42', - }, - }); - - // THEN - const template = app.synth().getStackByName(stack.stackName).template; - const userData = template.Resources.ClusterMyCapcityLaunchConfig58583345.Properties.UserData; - test.deepEqual(userData, { 'Fn::Base64': { 'Fn::Join': ['', ['#!/bin/bash\nset -o xtrace\n/etc/eks/bootstrap.sh ', { Ref: 'ClusterEB0386A7' }, ' --kubelet-extra-args "--node-labels lifecycle=OnDemand --node-labels FOO=42" --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack Stack --resource ClusterMyCapcityASGD4CD8B97 --region us-east-1']] } }); - test.done(); - }, - - 'spot instances': { - - 'nodes labeled an tainted accordingly'(test: Test) { - // GIVEN - const { app, stack } = testFixtureNoVpc(); - const cluster = new eks.LegacyCluster(stack, 'Cluster', { defaultCapacity: 0, version: CLUSTER_VERSION }); - - // WHEN - cluster.addCapacity('MyCapcity', { - instanceType: new ec2.InstanceType('m3.xlargs'), - spotPrice: '0.01', - }); - - // THEN - const template = app.synth().getStackByName(stack.stackName).template; - const userData = template.Resources.ClusterMyCapcityLaunchConfig58583345.Properties.UserData; - test.deepEqual(userData, { 'Fn::Base64': { 'Fn::Join': ['', ['#!/bin/bash\nset -o xtrace\n/etc/eks/bootstrap.sh ', { Ref: 'ClusterEB0386A7' }, ' --kubelet-extra-args "--node-labels lifecycle=Ec2Spot --register-with-taints=spotInstance=true:PreferNoSchedule" --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack Stack --resource ClusterMyCapcityASGD4CD8B97 --region us-east-1']] } }); - test.done(); - }, - - 'if kubectl is disabled, interrupt handler is not added'(test: Test) { - // GIVEN - const { stack } = testFixtureNoVpc(); - const cluster = new eks.LegacyCluster(stack, 'Cluster', { - defaultCapacity: 0, - version: CLUSTER_VERSION, - }); - - // WHEN - cluster.addCapacity('MyCapcity', { - instanceType: new ec2.InstanceType('m3.xlargs'), - spotPrice: '0.01', - }); - - // THEN - expect(stack).notTo(haveResource(eks.KubernetesManifest.RESOURCE_TYPE)); - test.done(); - }, - - }, - - }, - - 'if bootstrap is disabled cannot specify options'(test: Test) { - // GIVEN - const { stack } = testFixtureNoVpc(); - const cluster = new eks.LegacyCluster(stack, 'Cluster', { defaultCapacity: 0, version: CLUSTER_VERSION }); - - // THEN - test.throws(() => cluster.addCapacity('MyCapcity', { - instanceType: new ec2.InstanceType('m3.xlargs'), - bootstrapEnabled: false, - bootstrapOptions: { awsApiRetryAttempts: 10 }, - }), /Cannot specify "bootstrapOptions" if "bootstrapEnabled" is false/); - test.done(); - }, - - 'EksOptimizedImage() with no nodeType always uses STANDARD with LATEST_KUBERNETES_VERSION'(test: Test) { - // GIVEN - const { app, stack } = testFixtureNoVpc(); - const LATEST_KUBERNETES_VERSION = '1.14'; - - // WHEN - new eks.EksOptimizedImage().getImage(stack); - - // THEN - const assembly = app.synth(); - const parameters = assembly.getStackByName(stack.stackName).template.Parameters; - test.ok(Object.entries(parameters).some( - ([k, v]) => k.startsWith('SsmParameterValueawsserviceeksoptimizedami') && - (v as any).Default.includes('/amazon-linux-2/'), - ), 'EKS STANDARD AMI should be in ssm parameters'); - test.ok(Object.entries(parameters).some( - ([k, v]) => k.startsWith('SsmParameterValueawsserviceeksoptimizedami') && - (v as any).Default.includes(LATEST_KUBERNETES_VERSION), - ), 'LATEST_KUBERNETES_VERSION should be in ssm parameters'); - test.done(); - }, - - 'EksOptimizedImage() with specific kubernetesVersion return correct AMI'(test: Test) { - // GIVEN - const { app, stack } = testFixtureNoVpc(); - - // WHEN - new eks.EksOptimizedImage({ kubernetesVersion: '1.15' }).getImage(stack); - - // THEN - const assembly = app.synth(); - const parameters = assembly.getStackByName(stack.stackName).template.Parameters; - test.ok(Object.entries(parameters).some( - ([k, v]) => k.startsWith('SsmParameterValueawsserviceeksoptimizedami') && - (v as any).Default.includes('/amazon-linux-2/'), - ), 'EKS STANDARD AMI should be in ssm parameters'); - test.ok(Object.entries(parameters).some( - ([k, v]) => k.startsWith('SsmParameterValueawsserviceeksoptimizedami') && - (v as any).Default.includes('/1.15/'), - ), 'kubernetesVersion should be in ssm parameters'); - test.done(); - }, - - 'EKS-Optimized AMI with GPU support when addCapacity'(test: Test) { - // GIVEN - const { app, stack } = testFixtureNoVpc(); - - // WHEN - new eks.LegacyCluster(stack, 'cluster', { - defaultCapacity: 0, - version: CLUSTER_VERSION, - }).addCapacity('GPUCapacity', { - instanceType: new ec2.InstanceType('g4dn.xlarge'), - }); - - // THEN - const assembly = app.synth(); - const parameters = assembly.getStackByName(stack.stackName).template.Parameters; - test.ok(Object.entries(parameters).some( - ([k, v]) => k.startsWith('SsmParameterValueawsserviceeksoptimizedami') && (v as any).Default.includes('amazon-linux-2-gpu'), - ), 'EKS AMI with GPU should be in ssm parameters'); - test.done(); - }, - }, - - 'create a cluster with secrets encryption using KMS CMK'(test: Test) { - // GIVEN - const { stack, vpc } = testFixture(); - - // WHEN - new eks.LegacyCluster(stack, 'Cluster', { - vpc, - version: CLUSTER_VERSION, - secretsEncryptionKey: new kms.Key(stack, 'Key'), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::EKS::Cluster', { - EncryptionConfig: [{ - Provider: { - KeyArn: { - 'Fn::GetAtt': [ - 'Key961B73FD', - 'Arn', - ], - }, - }, - Resources: ['secrets'], - }], - })); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-eks/test/test.nodegroup.ts b/packages/@aws-cdk/aws-eks/test/test.nodegroup.ts index 29d683d2c0d09..a6cdf5889574a 100644 --- a/packages/@aws-cdk/aws-eks/test/test.nodegroup.ts +++ b/packages/@aws-cdk/aws-eks/test/test.nodegroup.ts @@ -1,4 +1,4 @@ -import { countResources, expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; @@ -17,7 +17,6 @@ export = { // WHEN const cluster = new eks.Cluster(stack, 'Cluster', { vpc, - kubectlEnabled: true, defaultCapacity: 0, version: CLUSTER_VERSION, }); @@ -59,7 +58,6 @@ export = { // WHEN const cluster = new eks.Cluster(stack, 'Cluster', { vpc, - kubectlEnabled: true, defaultCapacity: 0, version: CLUSTER_VERSION, }); @@ -117,7 +115,6 @@ export = { // WHEN const cluster = new eks.Cluster(stack, 'Cluster', { vpc, - kubectlEnabled: true, defaultCapacity: 0, version: CLUSTER_VERSION, }); @@ -152,7 +149,6 @@ export = { // WHEN const cluster = new eks.Cluster(stack, 'Cluster', { vpc, - kubectlEnabled: true, defaultCapacity: 0, version: CLUSTER_VERSION, }); @@ -165,22 +161,6 @@ export = { )); test.done(); }, - 'create nodegroups with kubectlEnabled is false'(test: Test) { - // GIVEN - const { stack, vpc } = testFixture(); - - // WHEN - const cluster = new eks.LegacyCluster(stack, 'Cluster', { - vpc, - defaultCapacity: 2, - version: CLUSTER_VERSION, - }); - // add a extra nodegroup - cluster.addNodegroup('extra-ng'); - // THEN - expect(stack).to(countResources('AWS::EKS::Nodegroup', 2)); - test.done(); - }, 'create nodegroup with instanceType provided'(test: Test) { // GIVEN const { stack, vpc } = testFixture(); @@ -188,7 +168,6 @@ export = { // WHEN const cluster = new eks.Cluster(stack, 'Cluster', { vpc, - kubectlEnabled: true, defaultCapacity: 0, version: CLUSTER_VERSION, }); @@ -266,7 +245,6 @@ export = { const { stack, vpc } = testFixture(); const cluster = new eks.Cluster(stack, 'Cluster', { vpc, - kubectlEnabled: true, defaultCapacity: 0, version: CLUSTER_VERSION, }); @@ -308,7 +286,6 @@ export = { const { stack, vpc } = testFixture(); const cluster = new eks.Cluster(stack, 'Cluster', { vpc, - kubectlEnabled: true, defaultCapacity: 0, version: CLUSTER_VERSION, }); @@ -321,7 +298,6 @@ export = { const { stack, vpc } = testFixture(); const cluster = new eks.Cluster(stack, 'Cluster', { vpc, - kubectlEnabled: true, defaultCapacity: 0, version: CLUSTER_VERSION, }); @@ -336,7 +312,6 @@ export = { // WHEN const cluster = new eks.Cluster(stack, 'Cluster', { vpc, - kubectlEnabled: true, defaultCapacity: 0, version: CLUSTER_VERSION, }); @@ -383,7 +358,6 @@ export = { // WHEN const cluster = new eks.Cluster(stack, 'Cluster', { vpc, - kubectlEnabled: true, defaultCapacity: 0, version: CLUSTER_VERSION, }); @@ -417,7 +391,6 @@ export = { // WHEN const cluster = new eks.Cluster(stack, 'Cluster', { vpc, - kubectlEnabled: true, defaultCapacity: 0, version: CLUSTER_VERSION, }); From 2ab7db6b4f76dbcfbe3de9ed9b890e36683e11b0 Mon Sep 17 00:00:00 2001 From: AWS CDK Team Date: Tue, 22 Dec 2020 10:51:19 +0000 Subject: [PATCH 13/15] chore(release): 1.80.0 --- CHANGELOG.md | 29 +++++++++++++++++++++++++++++ version.v1.json | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61aaf8da350cb..5da5166a16c5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,35 @@ 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.80.0](https://github.com/aws/aws-cdk/compare/v1.79.0...v1.80.0) (2020-12-22) + + +### ⚠ BREAKING CHANGES TO EXPERIMENTAL FEATURES + +* **eks:** `LegacyCluster` was removed since it existed only for a transition period to allow gradual migration to the current cluster class. + +- eks: `kubectlEnabled` property was removed, all clusters now support `kubectl`. +* **core:** Creation stack traces for `Lazy` values are no longer +captured by default in order to speed up tests. Run with +`CDK_DEBUG=true` (or `cdk --debug`) to capture stack traces. + +### Features + +* **ec2:** Add VPC endpoints for Athena and Glue ([#12073](https://github.com/aws/aws-cdk/issues/12073)) ([73ef6b1](https://github.com/aws/aws-cdk/commit/73ef6b180c8a7c3d8e984b308149eeb9eb78b40b)), closes [#12072](https://github.com/aws/aws-cdk/issues/12072) +* **ecs-patterns:** add ruleName optional parameter for ScheduledTask constructs ([#12190](https://github.com/aws/aws-cdk/issues/12190)) ([b1318bd](https://github.com/aws/aws-cdk/commit/b1318bda54d1c0955a371eccce76b748d312b570)) +* **eks:** connect all custom resources to the cluster VPC ([#10200](https://github.com/aws/aws-cdk/issues/10200)) ([eaa8222](https://github.com/aws/aws-cdk/commit/eaa82222349fcce1ef4b80e873a35002d6f036e5)) +* **lambda-nodejs:** Expose optional props for advanced usage of esbuild ([#12123](https://github.com/aws/aws-cdk/issues/12123)) ([ecc98ac](https://github.com/aws/aws-cdk/commit/ecc98ac75acb1adbb4f5e66f853dc3226e490c98)) + + +### Bug Fixes + +* **core:** capturing stack traces still takes a long time ([#12180](https://github.com/aws/aws-cdk/issues/12180)) ([71cd38c](https://github.com/aws/aws-cdk/commit/71cd38c8fac276e34b79ad416305b214a57af25a)), closes [#11170](https://github.com/aws/aws-cdk/issues/11170) +* **dynamodb:** allow global replicas with Provisioned billing mode ([#12159](https://github.com/aws/aws-cdk/issues/12159)) ([ab5a383](https://github.com/aws/aws-cdk/commit/ab5a38379999bb57f28bbf22ec09d315df6b358a)), closes [#11346](https://github.com/aws/aws-cdk/issues/11346) +* **lambda-nodejs:** local bundling fails with relative depsLockFilePath ([#12125](https://github.com/aws/aws-cdk/issues/12125)) ([d5afb55](https://github.com/aws/aws-cdk/commit/d5afb555b983c8c034f63dd58d1fa24b82b6e9fe)), closes [#12115](https://github.com/aws/aws-cdk/issues/12115) + + +* **eks:** Remove legacy and deprecated code ([#12189](https://github.com/aws/aws-cdk/issues/12189)) ([6a20e61](https://github.com/aws/aws-cdk/commit/6a20e61dd2ed8366cbff1451c943a02b79380de2)) + ## [1.79.0](https://github.com/aws/aws-cdk/compare/v1.78.0...v1.79.0) (2020-12-17) diff --git a/version.v1.json b/version.v1.json index 1d87fb5f6b025..bfcd3a035b942 100644 --- a/version.v1.json +++ b/version.v1.json @@ -1,3 +1,3 @@ { - "version": "1.79.0" + "version": "1.80.0" } From bcce0274357c65d36db12c23935ef2cdafccd9d7 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 22 Dec 2020 12:54:40 +0200 Subject: [PATCH 14/15] Update CHANGELOG.md --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5da5166a16c5b..4fffe539c15ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,8 +27,6 @@ captured by default in order to speed up tests. Run with * **core:** capturing stack traces still takes a long time ([#12180](https://github.com/aws/aws-cdk/issues/12180)) ([71cd38c](https://github.com/aws/aws-cdk/commit/71cd38c8fac276e34b79ad416305b214a57af25a)), closes [#11170](https://github.com/aws/aws-cdk/issues/11170) * **dynamodb:** allow global replicas with Provisioned billing mode ([#12159](https://github.com/aws/aws-cdk/issues/12159)) ([ab5a383](https://github.com/aws/aws-cdk/commit/ab5a38379999bb57f28bbf22ec09d315df6b358a)), closes [#11346](https://github.com/aws/aws-cdk/issues/11346) * **lambda-nodejs:** local bundling fails with relative depsLockFilePath ([#12125](https://github.com/aws/aws-cdk/issues/12125)) ([d5afb55](https://github.com/aws/aws-cdk/commit/d5afb555b983c8c034f63dd58d1fa24b82b6e9fe)), closes [#12115](https://github.com/aws/aws-cdk/issues/12115) - - * **eks:** Remove legacy and deprecated code ([#12189](https://github.com/aws/aws-cdk/issues/12189)) ([6a20e61](https://github.com/aws/aws-cdk/commit/6a20e61dd2ed8366cbff1451c943a02b79380de2)) ## [1.79.0](https://github.com/aws/aws-cdk/compare/v1.78.0...v1.79.0) (2020-12-17) From e425ffacaaf4c7aae9c9513cbc7c9c50373251a7 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 22 Dec 2020 12:54:47 +0200 Subject: [PATCH 15/15] Update CHANGELOG.md --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fffe539c15ce..19b456a9e607b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,7 @@ All notable changes to this project will be documented in this file. See [standa ### ⚠ BREAKING CHANGES TO EXPERIMENTAL FEATURES * **eks:** `LegacyCluster` was removed since it existed only for a transition period to allow gradual migration to the current cluster class. - -- eks: `kubectlEnabled` property was removed, all clusters now support `kubectl`. +* **eks:** `kubectlEnabled` property was removed, all clusters now support `kubectl`. * **core:** Creation stack traces for `Lazy` values are no longer captured by default in order to speed up tests. Run with `CDK_DEBUG=true` (or `cdk --debug`) to capture stack traces.