diff --git a/docs/pack-docs.sh b/docs/pack-docs.sh new file mode 100755 index 0000000000000..110161bb78ade --- /dev/null +++ b/docs/pack-docs.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# Development script to build all docs packages and rsync them into $root/dist so that build-docs.sh can work. +set -euo pipefail +cd .. + +dist=$(pwd)/dist +pacmak=$(pwd)/tools/cdk-build-tools/node_modules/.bin/jsii-pacmak +scopes=$(lerna ls 2>/dev/null | grep -v "(private)" | cut -d" " -f1 | xargs -n1 -I{} echo "--scope {}" | tr "\n" " ") + +mkdir -p $dist +node_modules/.bin/lerna exec --no-bail ${scopes} -- $pacmak -t sphinx -o dist/sphinx || echo 'Swallowing error' +node_modules/.bin/lerna exec --no-bail ${scopes} -- rsync -av dist/ $dist/ || echo 'Swallowing error' diff --git a/packages/@aws-cdk/aws-autoscaling/README.md b/packages/@aws-cdk/aws-autoscaling/README.md index b3e8b348dc21a..81374519b8bb0 100644 --- a/packages/@aws-cdk/aws-autoscaling/README.md +++ b/packages/@aws-cdk/aws-autoscaling/README.md @@ -23,32 +23,24 @@ new autoscaling.AutoScalingGroup(stack, 'ASG', { > internet) which is set to `true` by default. Be sure to set this to `false` if you don't want > your instances to be able to start arbitrary connections. -### AMIs +### Machine Images (AMIs) -AMIs control the OS that gets launched when you start your instance. +AMIs control the OS that gets launched when you start your EC2 instance. The EC2 +library contains constructs to select the AMI you want to use. Depending on the type of AMI, you select it a different way. -The latest version of Windows images are regionally published under labels, -so you can select Windows images like this: +The latest version of Amazon Linux and Microsoft Windows images are +selectable by instantiating one of these classes: - new ec2.WindowsImage(WindowsVersion.WindowsServer2016EnglishNanoBase) +[example of creating images](test/example.images.lit.ts) -You can select the latest Amazon Linux image like this: - - new ec2.AmazonLinuxImage() - -Other Linux images are unfortunately not currently published this way, so you have -to supply a region-to-AMI map when creating a Linux image: - - machineImage: new ec2.GenericLinuxImage({ - 'us-east-1': 'ami-97785bed', - 'eu-west-1': 'ami-12345678', - // ... - }) - -> NOTE: Selecting Linux images will change when the information is published in an automatically -> consumable way. +> NOTE: The Amazon Linux images selected will be cached in your `cdk.json`, so that your +> AutoScalingGroups don't automatically change out from under you when you're making unrelated +> changes. To update to the latest version of Amazon Linux, remove the cache entry from the `context` +> section of your `cdk.json`. +> +> We will add command-line options to make this step easier in the future. ### Allowing Connections diff --git a/packages/@aws-cdk/aws-autoscaling/test/example.images.lit.ts b/packages/@aws-cdk/aws-autoscaling/test/example.images.lit.ts new file mode 100644 index 0000000000000..a95240f25ceb8 --- /dev/null +++ b/packages/@aws-cdk/aws-autoscaling/test/example.images.lit.ts @@ -0,0 +1,28 @@ +import ec2 = require("@aws-cdk/aws-ec2"); + +/// !show +// Pick a Windows edition to use +const windows = new ec2.WindowsImage(ec2.WindowsVersion.WindowsServer2016EnglishNanoBase); + +// Pick the right Amazon Linux edition. All arguments shown are optional +// and will default to these values when omitted. +const amznLinux = new ec2.AmazonLinuxImage({ + generation: ec2.AmazonLinuxGeneration.AmazonLinux, + edition: ec2.AmazonLinuxEdition.Standard, + virtualization: ec2.AmazonLinuxVirt.HVM, + storage: ec2.AmazonLinuxStorage.GeneralPurpose, +}); + +// For other custom (Linux) images, instantiate a `GenericLinuxImage` with +// a map giving the AMI to in for each region: + +const linux = new ec2.GenericLinuxImage({ + 'us-east-1': 'ami-97785bed', + 'eu-west-1': 'ami-12345678', + // ... +}); +/// !hide + +Array.isArray(windows); +Array.isArray(amznLinux); +Array.isArray(linux); diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.amazonlinux2.expected.json b/packages/@aws-cdk/aws-autoscaling/test/integ.amazonlinux2.expected.json new file mode 100644 index 0000000000000..2cea5b897dfec --- /dev/null +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.amazonlinux2.expected.json @@ -0,0 +1,414 @@ +{ + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC" + } + ] + } + }, + "VPCPublicSubnet1SubnetB4246D30": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableAssociation0B0896DC": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "VPCPublicSubnet1DefaultRoute91CEF279": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, + "VPCPublicSubnet1EIP6AD938E8": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc" + } + }, + "VPCPublicSubnet1NATGatewayE0556630": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet2Subnet74179F39": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTableAssociation5A808732": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "VPCPublicSubnet2DefaultRouteB7481BBA": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, + "VPCPublicSubnet2EIP4947BC00": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc" + } + }, + "VPCPublicSubnet2NATGateway3C070193": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPrivateSubnet1Subnet8BCA10E0": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableBE8A6027": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableAssociation347902D1": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + } + } + }, + "VPCPrivateSubnet1DefaultRouteAE1D6490": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet1NATGatewayE0556630" + } + } + }, + "VPCPrivateSubnet2SubnetCFCDAA7A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTable0A19E10E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTableAssociation0C73D413": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + } + }, + "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet2NATGateway3C070193" + } + } + }, + "VPCIGWB7E252D3": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, + "FleetInstanceSecurityGroupA8C3D7AD": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-cdk-autoscaling-integ/Fleet/InstanceSecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [], + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/Fleet" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "FleetInstanceRoleA605DB82": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ec2.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "FleetInstanceProfileC6192A66": { + "Type": "AWS::IAM::InstanceProfile", + "Properties": { + "Roles": [ + { + "Ref": "FleetInstanceRoleA605DB82" + } + ] + } + }, + "FleetLaunchConfig59F79D36": { + "Type": "AWS::AutoScaling::LaunchConfiguration", + "Properties": { + "ImageId": "ami-1234", + "InstanceType": "t2.micro", + "IamInstanceProfile": { + "Ref": "FleetInstanceProfileC6192A66" + }, + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "FleetInstanceSecurityGroupA8C3D7AD", + "GroupId" + ] + } + ], + "UserData": { + "Fn::Base64": "#!/bin/bash\n" + } + }, + "DependsOn": [ + "FleetInstanceRoleA605DB82" + ] + }, + "FleetASG3971DFE5": { + "Type": "AWS::AutoScaling::AutoScalingGroup", + "Properties": { + "MaxSize": "1", + "MinSize": "1", + "DesiredCapacity": "1", + "LaunchConfigurationName": { + "Ref": "FleetLaunchConfig59F79D36" + }, + "Tags": [ + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "aws-cdk-autoscaling-integ/Fleet" + } + ], + "VPCZoneIdentifier": [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + ] + }, + "UpdatePolicy": { + "AutoScalingScheduledAction": { + "IgnoreUnmodifiedGroupSizeProperties": true + } + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.amazonlinux2.ts b/packages/@aws-cdk/aws-autoscaling/test/integ.amazonlinux2.ts new file mode 100644 index 0000000000000..059995a4177d0 --- /dev/null +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.amazonlinux2.ts @@ -0,0 +1,19 @@ +#!/usr/bin/env node +import ec2 = require('@aws-cdk/aws-ec2'); +import cdk = require('@aws-cdk/cdk'); +import autoscaling = require('../lib'); + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-cdk-autoscaling-integ'); + +const vpc = new ec2.VpcNetwork(stack, 'VPC', { + maxAZs: 2 +}); + +new autoscaling.AutoScalingGroup(stack, 'Fleet', { + vpc, + instanceType: new ec2.InstanceTypePair(ec2.InstanceClass.Burstable2, ec2.InstanceSize.Micro), + machineImage: new ec2.AmazonLinuxImage({ generation: ec2.AmazonLinuxGeneration.AmazonLinux2 }), +}); + +app.run(); diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index 9249905c54bad..bbb3b6fd7a59e 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -198,7 +198,7 @@ EC2 instances or other VPC-connected resources) will all have security groups automatically assigned. Those constructs have an attribute called **connections**, which is an object that makes it convenient to update the security groups. If you want to allow connections between two constructs that -have security groups, you have to add an **Egress* rule to one Security Group, +have security groups, you have to add an **Egress** rule to one Security Group, and an **Ingress** rule to the other. The connections object will automatically take care of this for you: @@ -270,3 +270,22 @@ listener.connections.allowDefaultPortFromAnyIpv4('Allow public'); // Port implicit in peer fleet.connections.allowToDefaultPort(rdsDatabase, 'Fleet can access database'); ``` + +### Machine Images (AMIs) + +AMIs control the OS that gets launched when you start your EC2 instance. The EC2 +library contains constructs to select the AMI you want to use. + +Depending on the type of AMI, you select it a different way. + +The latest version of Amazon Linux and Microsoft Windows images are +selectable by instantiating one of these classes: + +[example of creating images](test/example.images.lit.ts) + +> NOTE: The Amazon Linux images selected will be cached in your `cdk.json`, so that your +> AutoScalingGroups don't automatically change out from under you when you're making unrelated +> changes. To update to the latest version of Amazon Linux, remove the cache entry from the `context` +> section of your `cdk.json`. +> +> We will add command-line options to make this step easier in the future. diff --git a/packages/@aws-cdk/aws-ec2/lib/machine-image.ts b/packages/@aws-cdk/aws-ec2/lib/machine-image.ts index 1dc5a6d4bcf2c..6bca12accf619 100644 --- a/packages/@aws-cdk/aws-ec2/lib/machine-image.ts +++ b/packages/@aws-cdk/aws-ec2/lib/machine-image.ts @@ -45,6 +45,13 @@ export class WindowsImage implements IMachineImageSource { * Amazon Linux image properties */ export interface AmazonLinuxImageProps { + /** + * What generation of Amazon Linux to use + * + * @default AmazonLinux + */ + generation?: AmazonLinuxGeneration; + /** * What edition of Amazon Linux to use * @@ -73,13 +80,13 @@ export interface AmazonLinuxImageProps { * The AMI ID is selected using the values published to the SSM parameter store. */ export class AmazonLinuxImage implements IMachineImageSource { - private readonly edition?: AmazonLinuxEdition; - - private readonly virtualization?: AmazonLinuxVirt; - - private readonly storage?: AmazonLinuxStorage; + private readonly generation: AmazonLinuxGeneration; + private readonly edition: AmazonLinuxEdition; + private readonly virtualization: AmazonLinuxVirt; + private readonly storage: AmazonLinuxStorage; constructor(props?: AmazonLinuxImageProps) { + this.generation = (props && props.generation) || AmazonLinuxGeneration.AmazonLinux; this.edition = (props && props.edition) || AmazonLinuxEdition.Standard; this.virtualization = (props && props.virtualization) || AmazonLinuxVirt.HVM; this.storage = (props && props.storage) || AmazonLinuxStorage.GeneralPurpose; @@ -90,7 +97,8 @@ export class AmazonLinuxImage implements IMachineImageSource { */ public getImage(parent: Construct): MachineImage { const parts: Array = [ - 'amzn-ami', + this.generation, + 'ami', this.edition !== AmazonLinuxEdition.Standard ? this.edition : undefined, this.virtualization, 'x86_64', // No 32-bits images vended through this @@ -107,6 +115,21 @@ export class AmazonLinuxImage implements IMachineImageSource { } } +/** + * What generation of Amazon Linux to use + */ +export enum AmazonLinuxGeneration { + /** + * Amazon Linux + */ + AmazonLinux = 'amzn', + + /** + * Amazon Linux 2 + */ + AmazonLinux2 = 'amzn2', +} + /** * Amazon Linux edition */ diff --git a/packages/@aws-cdk/aws-ec2/test/example.images.lit.ts b/packages/@aws-cdk/aws-ec2/test/example.images.lit.ts new file mode 100644 index 0000000000000..43eb518b301a3 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/example.images.lit.ts @@ -0,0 +1,28 @@ +import ec2 = require("../lib"); + +/// !show +// Pick a Windows edition to use +const windows = new ec2.WindowsImage(ec2.WindowsVersion.WindowsServer2016EnglishNanoBase); + +// Pick the right Amazon Linux edition. All arguments shown are optional +// and will default to these values when omitted. +const amznLinux = new ec2.AmazonLinuxImage({ + generation: ec2.AmazonLinuxGeneration.AmazonLinux, + edition: ec2.AmazonLinuxEdition.Standard, + virtualization: ec2.AmazonLinuxVirt.HVM, + storage: ec2.AmazonLinuxStorage.GeneralPurpose, +}); + +// For other custom (Linux) images, instantiate a `GenericLinuxImage` with +// a map giving the AMI to in for each region: + +const linux = new ec2.GenericLinuxImage({ + 'us-east-1': 'ami-97785bed', + 'eu-west-1': 'ami-12345678', + // ... +}); +/// !hide + +Array.isArray(windows); +Array.isArray(amznLinux); +Array.isArray(linux); diff --git a/tools/cdk-integ-tools/lib/integ-helpers.ts b/tools/cdk-integ-tools/lib/integ-helpers.ts index 9a48d4d856e6a..f7686401c3d7f 100644 --- a/tools/cdk-integ-tools/lib/integ-helpers.ts +++ b/tools/cdk-integ-tools/lib/integ-helpers.ts @@ -90,6 +90,7 @@ export const STATIC_TEST_CONTEXT = { [DEFAULT_REGION_CONTEXT_KEY]: "test-region", "availability-zones:account=12345678:region=test-region": [ "test-region-1a", "test-region-1b", "test-region-1c" ], "ssm:account=12345678:parameterName=/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2:region=test-region": "ami-1234", + "ssm:account=12345678:parameterName=/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2:region=test-region": "ami-1234", }; /**