Skip to content

Commit

Permalink
chore(release): 1.80.0 (#12195)
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] committed Dec 22, 2020
2 parents 8b3bf9c + e425ffa commit 31132ca
Show file tree
Hide file tree
Showing 48 changed files with 2,390 additions and 2,469 deletions.
File renamed without changes.
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,32 @@

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)


Expand Down
17 changes: 17 additions & 0 deletions packages/@aws-cdk/aws-dynamodb/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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;
Expand All @@ -33,6 +37,11 @@ export class ScalableTableAttribute extends appscaling.BaseScalableAttribute {
predefinedMetric,
});
}

/** @internal */
public get _scalingPolicyCreated(): boolean {
return this.scalingPolicyCreated;
}
}

/**
Expand Down
36 changes: 26 additions & 10 deletions packages/@aws-cdk/aws-dynamodb/lib/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1064,30 +1064,30 @@ export class Table extends TableBase {
private readonly indexScaling = new Map<string, ScalableAttributePair>();
private readonly scalingRole: iam.IRole;

private readonly globalReplicaCustomResources = new Array<CustomResource>();

constructor(scope: Construct, id: string, props: TableProps) {
super(scope, id, {
physicalName: props.tableName,
});

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) {
throw new Error('`stream` must be set to `NEW_AND_OLD_IMAGES` when specifying `replicationRegions`');
}
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,
Expand Down Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1681,4 +1697,4 @@ class SourceTableAttachedPrincipal extends iam.PrincipalBase {
statementAdded: true,
};
}
}
}
119 changes: 95 additions & 24 deletions packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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,
Expand All @@ -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', () => {
Expand Down
Loading

0 comments on commit 31132ca

Please sign in to comment.