Skip to content

Commit

Permalink
feat(ecs): ECS optimized Windows images (#3376)
Browse files Browse the repository at this point in the history
* deprecate `EcsOptimizedAmi` for `EcsOptimizedImage`
* constructor(props) replaced by strongly typed static methods
* Windows AMI support
* deprecate `EcsOptimizedAmi`, `EcsOptimizedAmiProps`
* will require changes on v2 shipment #3398

Fixes #2574
  • Loading branch information
Jimmy Gaussen authored and Elad Ben-Israel committed Jul 25, 2019
1 parent 750708b commit 6c0bf4a
Show file tree
Hide file tree
Showing 3 changed files with 291 additions and 10 deletions.
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-ecs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@ cluster.addCapacity('DefaultAutoScalingGroupCapacity', {
const autoScalingGroup = new autoscaling.AutoScalingGroup(this, 'ASG', {
vpc,
instanceType: new ec2.InstanceType('t2.xlarge'),
machineImage: new EcsOptimizedAmi(),
machineImage: EcsOptimizedImage.amazonLinux(),
// Or use Amazon ECS-Optimized Amazon Linux 2 AMI
// machineImage: new EcsOptimizedAmi({ generation: ec2.AmazonLinuxGeneration.AmazonLinux2 }),
// machineImage: EcsOptimizedImage.amazonLinux2(),
desiredCapacity: 3,
// ... other options here ...
});
Expand Down
122 changes: 115 additions & 7 deletions packages/@aws-cdk/aws-ecs/lib/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import ec2 = require('@aws-cdk/aws-ec2');
import iam = require('@aws-cdk/aws-iam');
import cloudmap = require('@aws-cdk/aws-servicediscovery');
import ssm = require('@aws-cdk/aws-ssm');
import { Construct, Duration, IResource, Resource, Stack } from '@aws-cdk/core';
import { InstanceDrainHook } from './drain-hook/instance-drain-hook';
import { CfnCluster } from './ecs.generated';
import {Construct, Duration, IResource, Resource, Stack} from '@aws-cdk/core';
import {InstanceDrainHook} from './drain-hook/instance-drain-hook';
import {CfnCluster} from './ecs.generated';

/**
* The properties used to define an ECS cluster.
Expand Down Expand Up @@ -231,8 +231,23 @@ export class Cluster extends Resource implements ICluster {
}
}

/**
* ECS-optimized Windows version list
*/
export enum WindowsOptimizedVersion {
SERVER_2019 = '2019',
SERVER_2016 = '2016',
}

/*
* TODO:v2.0.0
* * remove `export` keyword
* * remove @depracted
*/
/**
* The properties that define which ECS-optimized AMI is used.
*
* @deprecated see {@link EcsOptimizedImage}
*/
export interface EcsOptimizedAmiProps {
/**
Expand All @@ -242,6 +257,13 @@ export interface EcsOptimizedAmiProps {
*/
readonly generation?: ec2.AmazonLinuxGeneration;

/**
* The Windows Server version to use.
*
* @default none, uses Linux generation
*/
readonly windowsVersion?: WindowsOptimizedVersion;

/**
* The ECS-optimized AMI variant to use.
*
Expand All @@ -250,11 +272,17 @@ export interface EcsOptimizedAmiProps {
readonly hardwareType?: AmiHardwareType;
}

/*
* TODO:v2.0.0 remove EcsOptimizedAmi
*/
/**
* Construct a Linux machine image from the latest ECS Optimized AMI published in SSM
* Construct a Linux or Windows machine image from the latest ECS Optimized AMI published in SSM
*
* @deprecated see {@link EcsOptimizedImage#amazonLinux}, {@link EcsOptimizedImage#amazonLinux} and {@link EcsOptimizedImage#windows}
*/
export class EcsOptimizedAmi implements ec2.IMachineImage {
private readonly generation: ec2.AmazonLinuxGeneration;
private readonly generation?: ec2.AmazonLinuxGeneration;
private readonly windowsVersion?: WindowsOptimizedVersion;
private readonly hwType: AmiHardwareType;

private readonly amiParameterName: string;
Expand All @@ -267,9 +295,17 @@ export class EcsOptimizedAmi implements ec2.IMachineImage {
if (props && props.generation) { // generation defined in the props object
if (props.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX && this.hwType !== AmiHardwareType.STANDARD) {
throw new Error(`Amazon Linux does not support special hardware type. Use Amazon Linux 2 instead`);
} else if (props.windowsVersion) {
throw new Error('"windowsVersion" and Linux image "generation" cannot be both set');
} else {
this.generation = props.generation;
}
} else if (props && props.windowsVersion) {
if (this.hwType !== AmiHardwareType.STANDARD) {
throw new Error('Windows Server does not support special hardware type');
} else {
this.windowsVersion = props.windowsVersion;
}
} else { // generation not defined in props object
// always default to Amazon Linux v2 regardless of HW
this.generation = ec2.AmazonLinuxGeneration.AMAZON_LINUX_2;
Expand All @@ -279,6 +315,7 @@ export class EcsOptimizedAmi implements ec2.IMachineImage {
this.amiParameterName = "/aws/service/ecs/optimized-ami/"
+ ( this.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX ? "amazon-linux/" : "" )
+ ( this.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 ? "amazon-linux-2/" : "" )
+ ( this.windowsVersion ? `windows_server/${this.windowsVersion}/english/full/` : "" )
+ ( this.hwType === AmiHardwareType.GPU ? "gpu/" : "" )
+ ( this.hwType === AmiHardwareType.ARM ? "arm64/" : "" )
+ "recommended/image_id";
Expand All @@ -291,7 +328,78 @@ export class EcsOptimizedAmi implements ec2.IMachineImage {
const ami = ssm.StringParameter.valueForStringParameter(scope, this.amiParameterName);
return {
imageId: ami,
osType: ec2.OperatingSystemType.LINUX
osType: this.windowsVersion ? ec2.OperatingSystemType.WINDOWS : ec2.OperatingSystemType.LINUX
};
}
}

/**
* Construct a Linux or Windows machine image from the latest ECS Optimized AMI published in SSM
*/
export class EcsOptimizedImage implements ec2.IMachineImage {
/**
* Construct an Amazon Linux 2 image from the latest ECS Optimized AMI published in SSM
*
* @param hardwareType ECS-optimized AMI variant to use
*/
public static amazonLinux2(hardwareType = AmiHardwareType.STANDARD): EcsOptimizedImage {
return new EcsOptimizedImage({generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2, hardwareType});
}

/**
* Construct an Amazon Linux AMI image from the latest ECS Optimized AMI published in SSM
*/
public static amazonLinux(): EcsOptimizedImage {
return new EcsOptimizedImage({generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX});
}

/**
* Construct a Windows image from the latest ECS Optimized AMI published in SSM
*
* @param windowsVersion Windows Version to use
*/
public static windows(windowsVersion: WindowsOptimizedVersion): EcsOptimizedImage {
return new EcsOptimizedImage({windowsVersion});
}

private readonly generation?: ec2.AmazonLinuxGeneration;
private readonly windowsVersion?: WindowsOptimizedVersion;
private readonly hwType?: AmiHardwareType;

private readonly amiParameterName: string;

/**
* Constructs a new instance of the EcsOptimizedAmi class.
*/
private constructor(props: EcsOptimizedAmiProps) {
this.hwType = props && props.hardwareType;

if (props.windowsVersion) {
this.windowsVersion = props.windowsVersion;
} else if (props.generation) {
this.generation = props.generation;
} else {
throw new Error('This error should never be thrown');
}

// set the SSM parameter name
this.amiParameterName = "/aws/service/ecs/optimized-ami/"
+ ( this.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX ? "amazon-linux/" : "" )
+ ( this.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 ? "amazon-linux-2/" : "" )
+ ( this.windowsVersion ? `windows_server/${this.windowsVersion}/english/full/` : "" )
+ ( this.hwType === AmiHardwareType.GPU ? "gpu/" : "" )
+ ( this.hwType === AmiHardwareType.ARM ? "arm64/" : "" )
+ "recommended/image_id";
}

/**
* Return the correct image
*/
public getImage(scope: Construct): ec2.MachineImageConfig {
const ami = ssm.StringParameter.valueForStringParameter(scope, this.amiParameterName);
return {
imageId: ami,
osType: this.windowsVersion ? ec2.OperatingSystemType.WINDOWS : ec2.OperatingSystemType.LINUX
};
}
}
Expand Down Expand Up @@ -510,7 +618,7 @@ export interface CloudMapNamespaceOptions {
export enum AmiHardwareType {

/**
* Use the Amazon ECS-optimized Amazon Linux 2 AMI.
* Use the standard Amazon ECS-optimized AMI.
*/
STANDARD = 'Standard',

Expand Down

0 comments on commit 6c0bf4a

Please sign in to comment.