From b217e6b7451218202711f63138e28f3ffe2bfb5e Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Thu, 2 Nov 2023 04:11:17 +0100 Subject: [PATCH 1/3] test(pipelines): create unit tests for approve lambda handler (#27777) Adds unit test for approve lambda handler. Closes #27727. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../private/approve-lambda-handler.test.ts | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 packages/aws-cdk-lib/pipelines/test/private/approve-lambda-handler.test.ts diff --git a/packages/aws-cdk-lib/pipelines/test/private/approve-lambda-handler.test.ts b/packages/aws-cdk-lib/pipelines/test/private/approve-lambda-handler.test.ts new file mode 100644 index 0000000000000..6e8a612abfd26 --- /dev/null +++ b/packages/aws-cdk-lib/pipelines/test/private/approve-lambda-handler.test.ts @@ -0,0 +1,171 @@ +const mockGetPipelineState = jest.fn(); +const mockPutApprovalResult = jest.fn(); +const mockCodePipeline = { + getPipelineState: mockGetPipelineState, + putApprovalResult: mockPutApprovalResult, +}; + +jest.mock('@aws-sdk/client-codepipeline', () => { + return { + CodePipeline: jest.fn(() => mockCodePipeline), + }; +}); + +jest.setTimeout(10_000); + +import { handler } from '../../lib/private/approve-lambda/index'; + +describe('approve-lambda handler', () => { + + beforeEach(() => { + jest.spyOn(global, 'setTimeout'); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('automatic approval works', async () => { + // GIVEN + mockGetPipelineState.mockImplementation(() => { + return { + stageStates: [{ + stageName: 'stage', + actionStates: [{ + actionName: 'action', + latestExecution: { + lastStatusChange: 1446137358.328, + status: 'Succeeded', + token: 'token', + }, + }], + }], + }; + }); + + const event = { + PipelineName: 'pipeline', + StageName: 'stage', + ActionName: 'action', + }; + + // WHEN + await handler(event, {}); + + // THEN + expect(mockPutApprovalResult).toHaveBeenCalled(); + }); + + test('does not approve if stageName not found', async () => { + // GIVEN + mockGetPipelineState.mockImplementation(async () => { + return { + stageStates: [{ + stageName: 'unknown', + actionStates: [{ + actionName: 'action', + latestExecution: { + lastStatusChange: 1446137358.328, + status: 'Succeeded', + token: 'token', + }, + }], + }], + }; + }); + + // expire deadline after first loop + jest.spyOn(Date, 'now') + .mockReturnValueOnce(0) + .mockReturnValueOnce(0) + .mockReturnValueOnce(10 * 60_000); + + const event = { + PipelineName: 'pipeline', + StageName: 'stage', + ActionName: 'action', + }; + + // WHEN + await handler(event, {}); + + // THEN + expect(setTimeout).toHaveBeenCalled(); + expect(mockPutApprovalResult).not.toHaveBeenCalled(); + }); + + test('does not approve if actionName not found', async () => { + // GIVEN + mockGetPipelineState.mockImplementation(async () => { + return { + stageStates: [{ + stageName: 'stage', + actionStates: [{ + actionName: 'unknown', + latestExecution: { + lastStatusChange: 1446137358.328, + status: 'Succeeded', + token: 'token', + }, + }], + }], + }; + }); + + // expire deadline after first loop + jest.spyOn(Date, 'now') + .mockReturnValueOnce(0) + .mockReturnValueOnce(0) + .mockReturnValueOnce(10 * 60_000); + + const event = { + PipelineName: 'pipeline', + StageName: 'stage', + ActionName: 'action', + }; + + // WHEN + await handler(event, {}); + + // THEN + expect(setTimeout).toHaveBeenCalled(); + expect(mockPutApprovalResult).not.toHaveBeenCalled(); + }); + + test('does not approve if token not present', async () => { + // GIVEN + mockGetPipelineState.mockImplementation(async () => { + return { + stageStates: [{ + stageName: 'stage', + actionStates: [{ + actionName: 'unknown', + latestExecution: { + lastStatusChange: 1446137358.328, + status: 'Succeeded', + }, + }], + }], + }; + }); + + // expire deadline after first loop + jest.spyOn(Date, 'now') + .mockReturnValueOnce(0) + .mockReturnValueOnce(0) + .mockReturnValueOnce(10 * 60_000); + + const event = { + PipelineName: 'pipeline', + StageName: 'stage', + ActionName: 'action', + }; + + // WHEN + await handler(event, {}); + + // THEN + expect(setTimeout).toHaveBeenCalled(); + expect(mockPutApprovalResult).not.toHaveBeenCalled(); + }); +}); From af1f6bd4ed6c9b51a579783cf675ae122414f98b Mon Sep 17 00:00:00 2001 From: Michael Sambol Date: Wed, 1 Nov 2023 21:42:31 -0600 Subject: [PATCH 2/3] fix(opensearchservice): IM4GN instances don't support EBS (#27765) Relevant docs https://aws.amazon.com/opensearch-service/pricing/ Closes #27757. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-opensearchservice/lib/domain.ts | 10 +++---- .../aws-opensearchservice/test/domain.test.ts | 28 +++++++++++++------ 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/packages/aws-cdk-lib/aws-opensearchservice/lib/domain.ts b/packages/aws-cdk-lib/aws-opensearchservice/lib/domain.ts index 8971cfc25e65c..830ed96724fed 100644 --- a/packages/aws-cdk-lib/aws-opensearchservice/lib/domain.ts +++ b/packages/aws-cdk-lib/aws-opensearchservice/lib/domain.ts @@ -1525,8 +1525,8 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable { // Validate against instance type restrictions, per // https://docs.aws.amazon.com/opensearch-service/latest/developerguide/supported-instance-types.html - if (isSomeInstanceType('i3', 'r6gd') && ebsEnabled) { - throw new Error('I3 and R6GD instance types do not support EBS storage volumes.'); + if (isSomeInstanceType('i3', 'r6gd', 'im4gn') && ebsEnabled) { + throw new Error('I3, R6GD, and IM4GN instance types do not support EBS storage volumes.'); } if (isSomeInstanceType('m3', 'r3', 't2') && encryptionAtRestEnabled) { @@ -1541,10 +1541,10 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable { throw new Error('T2 and T3 instance types do not support UltraWarm storage.'); } - // Only R3, I3 and r6gd support instance storage, per + // Only R3, I3, R6GD, and IM4GN support instance storage, per // https://aws.amazon.com/opensearch-service/pricing/ - if (!ebsEnabled && !isEveryDatanodeInstanceType('r3', 'i3', 'r6gd')) { - throw new Error('EBS volumes are required when using instance types other than r3, i3 or r6gd.'); + if (!ebsEnabled && !isEveryDatanodeInstanceType('r3', 'i3', 'r6gd', 'im4gn')) { + throw new Error('EBS volumes are required when using instance types other than R3, I3, R6GD, or IM4GN.'); } // Only for a valid ebs volume configuration, per diff --git a/packages/aws-cdk-lib/aws-opensearchservice/test/domain.test.ts b/packages/aws-cdk-lib/aws-opensearchservice/test/domain.test.ts index ccd97c4324ed5..7540af179c007 100644 --- a/packages/aws-cdk-lib/aws-opensearchservice/test/domain.test.ts +++ b/packages/aws-cdk-lib/aws-opensearchservice/test/domain.test.ts @@ -1809,8 +1809,8 @@ each(testedOpenSearchVersions).describe('custom error responses', (engineVersion })).toThrow(/Node-to-node encryption requires Elasticsearch version 6.0 or later or OpenSearch version 1.0 or later/); }); - test('error when i3 or r6g instance types are specified with EBS enabled', () => { - expect(() => new Domain(stack, 'Domain1', { + test('error when I3, R6GD, and IM4GN instance types are specified with EBS enabled', () => { + expect(() => new Domain(stack, 'Domain2', { version: engineVersion, capacity: { dataNodeInstanceType: 'i3.2xlarge.search', @@ -1819,8 +1819,8 @@ each(testedOpenSearchVersions).describe('custom error responses', (engineVersion volumeSize: 100, volumeType: EbsDeviceVolumeType.GENERAL_PURPOSE_SSD, }, - })).toThrow(/I3 and R6GD instance types do not support EBS storage volumes/); - expect(() => new Domain(stack, 'Domain2', { + })).toThrow(/I3, R6GD, and IM4GN instance types do not support EBS storage volumes./); + expect(() => new Domain(stack, 'Domain3', { version: engineVersion, capacity: { dataNodeInstanceType: 'r6gd.large.search', @@ -1829,7 +1829,17 @@ each(testedOpenSearchVersions).describe('custom error responses', (engineVersion volumeSize: 100, volumeType: EbsDeviceVolumeType.GENERAL_PURPOSE_SSD, }, - })).toThrow(/I3 and R6GD instance types do not support EBS storage volumes/); + })).toThrow(/I3, R6GD, and IM4GN instance types do not support EBS storage volumes./); + expect(() => new Domain(stack, 'Domain4', { + version: engineVersion, + capacity: { + dataNodeInstanceType: 'im4gn.2xlarge.search', + }, + ebs: { + volumeSize: 100, + volumeType: EbsDeviceVolumeType.GENERAL_PURPOSE_SSD, + }, + })).toThrow(/I3, R6GD, and IM4GN instance types do not support EBS storage volumes./); }); test('error when m3, r3, or t2 instance types are specified with encryption at rest enabled', () => { @@ -1872,7 +1882,7 @@ each(testedOpenSearchVersions).describe('custom error responses', (engineVersion })).toThrow(/t2.micro.search instance type supports only Elasticsearch versions 1.5 and 2.3/); }); - test('error when any instance type other than R3, I3 and R6GD are specified without EBS enabled', () => { + test('error when any instance type other than R3, I3, R6GD, or IM4GN are specified without EBS enabled', () => { expect(() => new Domain(stack, 'Domain1', { version: engineVersion, ebs: { @@ -1881,16 +1891,16 @@ each(testedOpenSearchVersions).describe('custom error responses', (engineVersion capacity: { masterNodeInstanceType: 'm5.large.search', }, - })).toThrow(/EBS volumes are required when using instance types other than r3, i3 or r6gd/); + })).toThrow(/EBS volumes are required when using instance types other than R3, I3, R6GD, or IM4GN./); expect(() => new Domain(stack, 'Domain2', { version: engineVersion, ebs: { enabled: false, }, capacity: { - dataNodeInstanceType: 'm5.large.search', + dataNodeInstanceType: 'r5.large.search', }, - })).toThrow(/EBS volumes are required when using instance types other than r3, i3 or r6gd/); + })).toThrow(/EBS volumes are required when using instance types other than R3, I3, R6GD, or IM4GN./); }); test('can use compatible master instance types that does not have local storage when data node type is i3 or r6gd', () => { From 23b8f8f99306b2184d072936ed69482de2935055 Mon Sep 17 00:00:00 2001 From: Tatsuya Mori Date: Thu, 2 Nov 2023 13:12:19 +0900 Subject: [PATCH 3/3] feat(ec2): support for m6in, m6idn, r6in and r6idn instance types in aws-ec2 (#27795) The M6in, M6idn, R6in and R6idn instance types were [introduced](https://aws.amazon.com/about-aws/whats-new/2022/11/amazon-ec2-m6in-m6idn-r6in-r6idn-network-optimized-instances/) in November 2022. The instance types are supported in [CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-instance.html#cfn-ec2-instance-instancetype). ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-cdk-lib/aws-ec2/lib/instance-types.ts | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/packages/aws-cdk-lib/aws-ec2/lib/instance-types.ts b/packages/aws-cdk-lib/aws-ec2/lib/instance-types.ts index 4da2094aa8f63..ae619d72522d3 100644 --- a/packages/aws-cdk-lib/aws-ec2/lib/instance-types.ts +++ b/packages/aws-cdk-lib/aws-ec2/lib/instance-types.ts @@ -158,6 +158,26 @@ export enum InstanceClass { */ R6ID = 'r6id', + /** + * Memory optimized instances for high performance computing powered by Intel Xeon Scalable processors (code named Ice Lake), 6th generation + */ + MEMORY6_INTEL_HIGH_PERFORMANCE = 'memory6-intel-high-performance', + + /** + * Memory optimized instances for high performance computing powered by Intel Xeon Scalable processors (code named Ice Lake), 6th generation + */ + R6IN = 'r6in', + + /** + * Memory optimized instances with local NVME drive for high performance computing powered by Intel Xeon Scalable processors (code named Ice Lake), 6th generation + */ + MEMORY6_INTEL_NVME_DRIVE_HIGH_PERFORMANCE = 'memory6-intel-nvme-drive-high-performance', + + /** + * Memory optimized instances with local NVME drive for high performance computing powered by Intel Xeon Scalable processors (code named Ice Lake), 6th generation + */ + R6IDN = 'r6idn', + /** * Memory optimized instances for high performance computing, 5th generation */ @@ -900,6 +920,26 @@ export enum InstanceClass { */ M6ID = 'm6id', + /** + * Standard instances for high performance computing powered by Intel Xeon Scalable processors (code named Ice Lake), 6th generation. + */ + STANDARD6_INTEL_HIGH_PERFORMANCE = 'standard6-intel-high-performance', + + /** + * Standard instances for high performance computing powered by Intel Xeon Scalable processors (code named Ice Lake), 6th generation. + */ + M6IN = 'm6in', + + /** + * Standard instances with local NVME drive for high performance computing powered by Intel Xeon Scalable processors (code named Ice Lake), 6th generation. + */ + STANDARD6_INTEL_NVME_DRIVE_HIGH_PERFORMANCE = 'standard6-intel-nvme-drive-high-performance', + + /** + * Standard instances with local NVME drive for high performance computing powered by Intel Xeon Scalable processors (code named Ice Lake), 6th generation. + */ + M6IDN = 'm6idn', + /** * Standard instances based on 3rd Gen AMD EPYC processors, 6th generation. */ @@ -1219,6 +1259,10 @@ export class InstanceType { [InstanceClass.R6I]: 'r6i', [InstanceClass.MEMORY6_INTEL_NVME_DRIVE]: 'r6id', [InstanceClass.R6ID]: 'r6id', + [InstanceClass.MEMORY6_INTEL_HIGH_PERFORMANCE]: 'r6in', + [InstanceClass.R6IN]: 'r6in', + [InstanceClass.MEMORY6_INTEL_NVME_DRIVE_HIGH_PERFORMANCE]: 'r6idn', + [InstanceClass.R6IDN]: 'r6idn', [InstanceClass.MEMORY5_HIGH_PERFORMANCE]: 'r5n', [InstanceClass.R5N]: 'r5n', [InstanceClass.MEMORY5_NVME_DRIVE]: 'r5d', @@ -1355,6 +1399,10 @@ export class InstanceType { [InstanceClass.M6I]: 'm6i', [InstanceClass.STANDARD6_INTEL_NVME_DRIVE]: 'm6id', [InstanceClass.M6ID]: 'm6id', + [InstanceClass.STANDARD6_INTEL_HIGH_PERFORMANCE]: 'm6in', + [InstanceClass.M6IN]: 'm6in', + [InstanceClass.STANDARD6_INTEL_NVME_DRIVE_HIGH_PERFORMANCE]: 'm6idn', + [InstanceClass.M6IDN]: 'm6idn', [InstanceClass.STANDARD6_AMD]: 'm6a', [InstanceClass.M6A]: 'm6a', [InstanceClass.STANDARD6_GRAVITON2_NVME_DRIVE]: 'm6gd',