Skip to content

Commit

Permalink
Merge branch 'master' into fix/r5ad
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Apr 21, 2021
2 parents 1f0589b + 63a4e92 commit 30d3910
Show file tree
Hide file tree
Showing 8 changed files with 1,052 additions and 2 deletions.
17 changes: 17 additions & 0 deletions packages/@aws-cdk/aws-autoscaling/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,23 @@ new autoscaling.AutoScalingGroup(stack, 'ASG', {
});
```

## Protecting new instances from being terminated on scale-in

By default, Auto Scaling can terminate an instance at any time after launch when
scaling in an Auto Scaling Group, subject to the group's [termination
policy](https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-instance-termination.html).

However, you may wish to protect newly-launched instances from being scaled in
if they are going to run critical applications that should not be prematurely
terminated. This protection can be removed after launch.

```ts
new autoscaling.AutoScalingGroup(stack, 'ASG', {
newInstancesProtectedFromScaleIn: true,
// ...
});
```

## Future work

* [ ] CloudWatch Events (impossible to add currently as the AutoScalingGroup ARN is
Expand Down
18 changes: 18 additions & 0 deletions packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,23 @@ export interface CommonAutoScalingGroupProps {
*/
readonly updatePolicy?: UpdatePolicy;

/**
* Whether newly-launched instances are protected from termination by Amazon
* EC2 Auto Scaling when scaling in.
*
* By default, Auto Scaling can terminate an instance at any time after launch
* when scaling in an Auto Scaling Group, subject to the group's termination
* policy. However, you may wish to protect newly-launched instances from
* being scaled in if they are going to run critical applications that should
* not beß prematurely terminated.
*
* This flag must be enabled if the Auto Scaling Group will be associated with
* an ECS Capacity Provider with managed termination protection.
*
* @default false
*/
readonly newInstancesProtectedFromScaleIn?: boolean;

/**
* The name of the Auto Scaling group. This name must be unique per Region per account.
* @default - Auto generated by CloudFormation
Expand Down Expand Up @@ -1021,6 +1038,7 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements
healthCheckType: props.healthCheck && props.healthCheck.type,
healthCheckGracePeriod: props.healthCheck && props.healthCheck.gracePeriod && props.healthCheck.gracePeriod.toSeconds(),
maxInstanceLifetime: this.maxInstanceLifetime ? this.maxInstanceLifetime.toSeconds() : undefined,
newInstancesProtectedFromScaleIn: props.newInstancesProtectedFromScaleIn,
};

if (!hasPublic && props.associatePublicIpAddress) {
Expand Down
19 changes: 19 additions & 0 deletions packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1351,6 +1351,25 @@ test('Can set autoScalingGroupName', () => {
}));
});

test('Can protect new instances from scale-in', () => {
// GIVEN
const stack = new cdk.Stack();
const vpc = mockVpc(stack);

// WHEN
new autoscaling.AutoScalingGroup(stack, 'MyASG', {
instanceType: ec2.InstanceType.of(ec2.InstanceClass.M4, ec2.InstanceSize.MICRO),
machineImage: new ec2.AmazonLinuxImage(),
vpc,
newInstancesProtectedFromScaleIn: true,
});

// THEN
expect(stack).to(haveResourceLike('AWS::AutoScaling::AutoScalingGroup', {
NewInstancesProtectedFromScaleIn: true,
}));
});

test('can use Vpc imported from unparseable list tokens', () => {
// GIVEN
const stack = new cdk.Stack();
Expand Down
40 changes: 38 additions & 2 deletions packages/@aws-cdk/aws-ec2/lib/nat.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as iam from '@aws-cdk/aws-iam';
import { Fn, Token } from '@aws-cdk/core';
import { Connections, IConnectable } from './connections';
import { Instance } from './instance';
import { InstanceType } from './instance-types';
Expand Down Expand Up @@ -59,8 +60,8 @@ export abstract class NatProvider {
*
* @see https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html
*/
public static gateway(): NatProvider {
return new NatGatewayProvider();
public static gateway(props: NatGatewayProps = {}): NatProvider {
return new NatGatewayProvider(props);
}

/**
Expand Down Expand Up @@ -122,6 +123,19 @@ export interface ConfigureNatOptions {
readonly privateSubnets: PrivateSubnet[];
}

/**
* Properties for a NAT gateway
*
*/
export interface NatGatewayProps {
/**
* EIP allocation IDs for the NAT gateways
*
* @default - No fixed EIPs allocated for the NAT gateways
*/
readonly eipAllocationIds?: string[];
}

/**
* Properties for a NAT instance
*
Expand Down Expand Up @@ -203,11 +217,20 @@ export interface NatInstanceProps {
class NatGatewayProvider extends NatProvider {
private gateways: PrefSet<string> = new PrefSet<string>();

constructor(private readonly props: NatGatewayProps = {}) {
super();
}

public configureNat(options: ConfigureNatOptions) {
// Create the NAT gateways
let i = 0;
for (const sub of options.natSubnets) {
const gateway = sub.addNatGateway();
if (this.props.eipAllocationIds) {
gateway.allocationId = pickN(i, this.props.eipAllocationIds);
}
this.gateways.add(sub.availabilityZone, gateway.ref);
i++;
}

// Add routes to them in the private subnets
Expand Down Expand Up @@ -377,4 +400,17 @@ function isOutboundAllowed(direction: NatTrafficDirection) {

function isInboundAllowed(direction: NatTrafficDirection) {
return direction === NatTrafficDirection.INBOUND_AND_OUTBOUND;
}

/**
* Token-aware pick index function
*/
function pickN(i: number, xs: string[]) {
if (Token.isUnresolved(xs)) { return Fn.select(i, xs); }

if (i >= xs.length) {
throw new Error(`Cannot get element ${i} from ${xs}`);
}

return xs[i];
}
18 changes: 18 additions & 0 deletions packages/@aws-cdk/aws-ec2/test/vpc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,24 @@ nodeunitShim({

test.done();
},

'NAT gateway provider with EIP allocations'(test: Test) {
const stack = new Stack();
const natGatewayProvider = NatProvider.gateway({
eipAllocationIds: ['a', 'b', 'c', 'd'],
});
new Vpc(stack, 'VpcNetwork', { natGatewayProvider });

cdkExpect(stack).to(haveResource('AWS::EC2::NatGateway', {
AllocationId: 'a',
}));
cdkExpect(stack).to(haveResource('AWS::EC2::NatGateway', {
AllocationId: 'b',
}));

test.done();
},

'Can add an IPv6 route'(test: Test) {
// GIVEN
const stack = getTestStack();
Expand Down
4 changes: 4 additions & 0 deletions packages/@aws-cdk/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Guide](https://docs.aws.amazon.com/cdk/latest/guide/home.html) for
information of most of the capabilities of this library. The rest of this
README will only cover topics not already covered in the Developer Guide.

<!--BEGIN CORE DOCUMENTATION-->

## Stacks and Stages

A `Stack` is the smallest physical unit of deployment, and maps directly onto
Expand Down Expand Up @@ -911,3 +913,5 @@ When deploying to AWS CloudFormation, it needs to keep in check the amount of re
It's possible to synthesize the project with more Resources than the allowed (or even reduce the number of Resources).

Set the context key `@aws-cdk/core:stackResourceLimit` with the proper value, being 0 for disable the limit of resources.

<!--END CORE DOCUMENTATION-->
Loading

0 comments on commit 30d3910

Please sign in to comment.