Skip to content

Commit 6c0bf4a

Browse files
Jimmy GaussenElad Ben-Israel
Jimmy Gaussen
authored and
Elad Ben-Israel
committed
feat(ecs): ECS optimized Windows images (#3376)
* 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
1 parent 750708b commit 6c0bf4a

File tree

3 files changed

+291
-10
lines changed

3 files changed

+291
-10
lines changed

packages/@aws-cdk/aws-ecs/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,9 @@ cluster.addCapacity('DefaultAutoScalingGroupCapacity', {
111111
const autoScalingGroup = new autoscaling.AutoScalingGroup(this, 'ASG', {
112112
vpc,
113113
instanceType: new ec2.InstanceType('t2.xlarge'),
114-
machineImage: new EcsOptimizedAmi(),
114+
machineImage: EcsOptimizedImage.amazonLinux(),
115115
// Or use Amazon ECS-Optimized Amazon Linux 2 AMI
116-
// machineImage: new EcsOptimizedAmi({ generation: ec2.AmazonLinuxGeneration.AmazonLinux2 }),
116+
// machineImage: EcsOptimizedImage.amazonLinux2(),
117117
desiredCapacity: 3,
118118
// ... other options here ...
119119
});

packages/@aws-cdk/aws-ecs/lib/cluster.ts

+115-7
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import ec2 = require('@aws-cdk/aws-ec2');
44
import iam = require('@aws-cdk/aws-iam');
55
import cloudmap = require('@aws-cdk/aws-servicediscovery');
66
import ssm = require('@aws-cdk/aws-ssm');
7-
import { Construct, Duration, IResource, Resource, Stack } from '@aws-cdk/core';
8-
import { InstanceDrainHook } from './drain-hook/instance-drain-hook';
9-
import { CfnCluster } from './ecs.generated';
7+
import {Construct, Duration, IResource, Resource, Stack} from '@aws-cdk/core';
8+
import {InstanceDrainHook} from './drain-hook/instance-drain-hook';
9+
import {CfnCluster} from './ecs.generated';
1010

1111
/**
1212
* The properties used to define an ECS cluster.
@@ -231,8 +231,23 @@ export class Cluster extends Resource implements ICluster {
231231
}
232232
}
233233

234+
/**
235+
* ECS-optimized Windows version list
236+
*/
237+
export enum WindowsOptimizedVersion {
238+
SERVER_2019 = '2019',
239+
SERVER_2016 = '2016',
240+
}
241+
242+
/*
243+
* TODO:v2.0.0
244+
* * remove `export` keyword
245+
* * remove @depracted
246+
*/
234247
/**
235248
* The properties that define which ECS-optimized AMI is used.
249+
*
250+
* @deprecated see {@link EcsOptimizedImage}
236251
*/
237252
export interface EcsOptimizedAmiProps {
238253
/**
@@ -242,6 +257,13 @@ export interface EcsOptimizedAmiProps {
242257
*/
243258
readonly generation?: ec2.AmazonLinuxGeneration;
244259

260+
/**
261+
* The Windows Server version to use.
262+
*
263+
* @default none, uses Linux generation
264+
*/
265+
readonly windowsVersion?: WindowsOptimizedVersion;
266+
245267
/**
246268
* The ECS-optimized AMI variant to use.
247269
*
@@ -250,11 +272,17 @@ export interface EcsOptimizedAmiProps {
250272
readonly hardwareType?: AmiHardwareType;
251273
}
252274

275+
/*
276+
* TODO:v2.0.0 remove EcsOptimizedAmi
277+
*/
253278
/**
254-
* Construct a Linux machine image from the latest ECS Optimized AMI published in SSM
279+
* Construct a Linux or Windows machine image from the latest ECS Optimized AMI published in SSM
280+
*
281+
* @deprecated see {@link EcsOptimizedImage#amazonLinux}, {@link EcsOptimizedImage#amazonLinux} and {@link EcsOptimizedImage#windows}
255282
*/
256283
export class EcsOptimizedAmi implements ec2.IMachineImage {
257-
private readonly generation: ec2.AmazonLinuxGeneration;
284+
private readonly generation?: ec2.AmazonLinuxGeneration;
285+
private readonly windowsVersion?: WindowsOptimizedVersion;
258286
private readonly hwType: AmiHardwareType;
259287

260288
private readonly amiParameterName: string;
@@ -267,9 +295,17 @@ export class EcsOptimizedAmi implements ec2.IMachineImage {
267295
if (props && props.generation) { // generation defined in the props object
268296
if (props.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX && this.hwType !== AmiHardwareType.STANDARD) {
269297
throw new Error(`Amazon Linux does not support special hardware type. Use Amazon Linux 2 instead`);
298+
} else if (props.windowsVersion) {
299+
throw new Error('"windowsVersion" and Linux image "generation" cannot be both set');
270300
} else {
271301
this.generation = props.generation;
272302
}
303+
} else if (props && props.windowsVersion) {
304+
if (this.hwType !== AmiHardwareType.STANDARD) {
305+
throw new Error('Windows Server does not support special hardware type');
306+
} else {
307+
this.windowsVersion = props.windowsVersion;
308+
}
273309
} else { // generation not defined in props object
274310
// always default to Amazon Linux v2 regardless of HW
275311
this.generation = ec2.AmazonLinuxGeneration.AMAZON_LINUX_2;
@@ -279,6 +315,7 @@ export class EcsOptimizedAmi implements ec2.IMachineImage {
279315
this.amiParameterName = "/aws/service/ecs/optimized-ami/"
280316
+ ( this.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX ? "amazon-linux/" : "" )
281317
+ ( this.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 ? "amazon-linux-2/" : "" )
318+
+ ( this.windowsVersion ? `windows_server/${this.windowsVersion}/english/full/` : "" )
282319
+ ( this.hwType === AmiHardwareType.GPU ? "gpu/" : "" )
283320
+ ( this.hwType === AmiHardwareType.ARM ? "arm64/" : "" )
284321
+ "recommended/image_id";
@@ -291,7 +328,78 @@ export class EcsOptimizedAmi implements ec2.IMachineImage {
291328
const ami = ssm.StringParameter.valueForStringParameter(scope, this.amiParameterName);
292329
return {
293330
imageId: ami,
294-
osType: ec2.OperatingSystemType.LINUX
331+
osType: this.windowsVersion ? ec2.OperatingSystemType.WINDOWS : ec2.OperatingSystemType.LINUX
332+
};
333+
}
334+
}
335+
336+
/**
337+
* Construct a Linux or Windows machine image from the latest ECS Optimized AMI published in SSM
338+
*/
339+
export class EcsOptimizedImage implements ec2.IMachineImage {
340+
/**
341+
* Construct an Amazon Linux 2 image from the latest ECS Optimized AMI published in SSM
342+
*
343+
* @param hardwareType ECS-optimized AMI variant to use
344+
*/
345+
public static amazonLinux2(hardwareType = AmiHardwareType.STANDARD): EcsOptimizedImage {
346+
return new EcsOptimizedImage({generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2, hardwareType});
347+
}
348+
349+
/**
350+
* Construct an Amazon Linux AMI image from the latest ECS Optimized AMI published in SSM
351+
*/
352+
public static amazonLinux(): EcsOptimizedImage {
353+
return new EcsOptimizedImage({generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX});
354+
}
355+
356+
/**
357+
* Construct a Windows image from the latest ECS Optimized AMI published in SSM
358+
*
359+
* @param windowsVersion Windows Version to use
360+
*/
361+
public static windows(windowsVersion: WindowsOptimizedVersion): EcsOptimizedImage {
362+
return new EcsOptimizedImage({windowsVersion});
363+
}
364+
365+
private readonly generation?: ec2.AmazonLinuxGeneration;
366+
private readonly windowsVersion?: WindowsOptimizedVersion;
367+
private readonly hwType?: AmiHardwareType;
368+
369+
private readonly amiParameterName: string;
370+
371+
/**
372+
* Constructs a new instance of the EcsOptimizedAmi class.
373+
*/
374+
private constructor(props: EcsOptimizedAmiProps) {
375+
this.hwType = props && props.hardwareType;
376+
377+
if (props.windowsVersion) {
378+
this.windowsVersion = props.windowsVersion;
379+
} else if (props.generation) {
380+
this.generation = props.generation;
381+
} else {
382+
throw new Error('This error should never be thrown');
383+
}
384+
385+
// set the SSM parameter name
386+
this.amiParameterName = "/aws/service/ecs/optimized-ami/"
387+
+ ( this.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX ? "amazon-linux/" : "" )
388+
+ ( this.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 ? "amazon-linux-2/" : "" )
389+
+ ( this.windowsVersion ? `windows_server/${this.windowsVersion}/english/full/` : "" )
390+
+ ( this.hwType === AmiHardwareType.GPU ? "gpu/" : "" )
391+
+ ( this.hwType === AmiHardwareType.ARM ? "arm64/" : "" )
392+
+ "recommended/image_id";
393+
}
394+
395+
/**
396+
* Return the correct image
397+
*/
398+
public getImage(scope: Construct): ec2.MachineImageConfig {
399+
const ami = ssm.StringParameter.valueForStringParameter(scope, this.amiParameterName);
400+
return {
401+
imageId: ami,
402+
osType: this.windowsVersion ? ec2.OperatingSystemType.WINDOWS : ec2.OperatingSystemType.LINUX
295403
};
296404
}
297405
}
@@ -510,7 +618,7 @@ export interface CloudMapNamespaceOptions {
510618
export enum AmiHardwareType {
511619

512620
/**
513-
* Use the Amazon ECS-optimized Amazon Linux 2 AMI.
621+
* Use the standard Amazon ECS-optimized AMI.
514622
*/
515623
STANDARD = 'Standard',
516624

0 commit comments

Comments
 (0)