Skip to content

Commit

Permalink
feat(cloud9): support imageid when creating cloud9 environment (#21194)
Browse files Browse the repository at this point in the history
Allows users to include the imageId parameter to specify which EC2 AMI to be used when creating the environment.

closes: #20908.

Shout out to @jumic for beginning the fix.

Unable to run yarn integ due to breaking change.

BREAKING CHANGE: The imageId parameter is now required and deployments will fail without it

----

### All Submissions:

* [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md)

### Adding new Unconventional Dependencies:

* [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies)

### New Features

* [x] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)?
	* [x] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)?

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
sean-beath authored Jul 19, 2022
1 parent 1f0656e commit dcf3eb3
Show file tree
Hide file tree
Showing 17 changed files with 1,844 additions and 7 deletions.
18 changes: 17 additions & 1 deletion packages/@aws-cdk/aws-cloud9/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@ EC2 Environments are defined with `Ec2Environment`. To create an EC2 environment
```ts
// create a cloud9 ec2 environment in a new VPC
const vpc = new ec2.Vpc(this, 'VPC', { maxAzs: 3});
new cloud9.Ec2Environment(this, 'Cloud9Env', { vpc });
new cloud9.Ec2Environment(this, 'Cloud9Env', { vpc, imageId: cloud9.ImageId.AMAZON_LINUX_2, });

// or create the cloud9 environment in the default VPC with specific instanceType
const defaultVpc = ec2.Vpc.fromLookup(this, 'DefaultVPC', { isDefault: true });
new cloud9.Ec2Environment(this, 'Cloud9Env2', {
vpc: defaultVpc,
instanceType: new ec2.InstanceType('t3.large'),
imageId: cloud9.ImageId.AMAZON_LINUX_2,
});

// or specify in a different subnetSelection
Expand All @@ -57,12 +58,26 @@ const c9env = new cloud9.Ec2Environment(this, 'Cloud9Env3', {
subnetSelection: {
subnetType: ec2.SubnetType.PRIVATE_WITH_NAT,
},
imageId: cloud9.ImageId.AMAZON_LINUX_2,
});

// print the Cloud9 IDE URL in the output
new CfnOutput(this, 'URL', { value: c9env.ideUrl });
```

## Specifying EC2 AMI

Use `imageId` to specify the EC2 AMI image to be used:

```ts
const defaultVpc = ec2.Vpc.fromLookup(this, 'DefaultVPC', { isDefault: true });
new cloud9.Ec2Environment(this, 'Cloud9Env2', {
vpc: defaultVpc,
instanceType: new ec2.InstanceType('t3.large'),
imageId: cloud9.ImageId.UBUNTU_18_04,
});
```

## Cloning Repositories

Use `clonedRepositories` to clone one or multiple AWS Codecommit repositories into the environment:
Expand All @@ -86,5 +101,6 @@ new cloud9.Ec2Environment(this, 'C9Env', {
cloud9.CloneRepository.fromCodeCommit(repoNew, '/src/new-repo'),
cloud9.CloneRepository.fromCodeCommit(repoExisting, '/src/existing-repo'),
],
imageId: cloud9.ImageId.AMAZON_LINUX_2,
});
```
27 changes: 26 additions & 1 deletion packages/@aws-cdk/aws-cloud9/lib/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export interface IEc2Environment extends cdk.IResource {
*/
export enum ConnectionType {
/**
* Conect through SSH
* Connect through SSH
*/
CONNECT_SSH = 'CONNECT_SSH',
/**
Expand All @@ -38,6 +38,20 @@ export enum ConnectionType {
CONNECT_SSM = 'CONNECT_SSM'
}

/**
* The image ID used for creating an Amazon EC2 environment.
*/
export enum ImageId {
/**
* Create using Amazon Linux 2
*/
AMAZON_LINUX_2 = 'amazonlinux-2-x86_64',
/**
* Create using Ubunut 18.04
*/
UBUNTU_18_04 = 'ubuntu-18.04-x86_64'
}

/**
* Properties for Ec2Environment
*/
Expand Down Expand Up @@ -93,6 +107,12 @@ export interface Ec2EnvironmentProps {
* @default - CONNECT_SSH
*/
readonly connectionType?: ConnectionType

/**
* The image ID used for creating an Amazon EC2 environment.
*
*/
readonly imageId: ImageId
}

/**
Expand Down Expand Up @@ -152,6 +172,10 @@ export class Ec2Environment extends cdk.Resource implements IEc2Environment {
throw new Error('no subnetSelection specified and no public subnet found in the vpc, please specify subnetSelection');
}

if (!props.imageId) {
throw new Error('No imageId specified, please specify imageId');
}

const vpcSubnets = props.subnetSelection ?? { subnetType: ec2.SubnetType.PUBLIC };
const c9env = new CfnEnvironmentEC2(this, 'Resource', {
name: props.ec2EnvironmentName,
Expand All @@ -163,6 +187,7 @@ export class Ec2Environment extends cdk.Resource implements IEc2Environment {
pathComponent: r.pathComponent,
})) : undefined,
connectionType: props.connectionType ?? ConnectionType.CONNECT_SSH,
imageId: props.imageId,
});
this.environmentId = c9env.ref;
this.ec2EnvironmentArn = c9env.getAtt('Arn').toString();
Expand Down
3 changes: 2 additions & 1 deletion packages/@aws-cdk/aws-cloud9/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,10 @@
"@aws-cdk/assertions": "0.0.0",
"@aws-cdk/aws-codecommit": "0.0.0",
"@aws-cdk/cdk-build-tools": "0.0.0",
"@aws-cdk/integ-runner": "0.0.0",
"@aws-cdk/cfn2ts": "0.0.0",
"@aws-cdk/integ-runner": "0.0.0",
"@aws-cdk/pkglint": "0.0.0",
"@aws-cdk/integ-tests": "0.0.0",
"@types/jest": "^27.5.2"
},
"dependencies": {
Expand Down
32 changes: 28 additions & 4 deletions packages/@aws-cdk/aws-cloud9/test/cloud9.environment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as codecommit from '@aws-cdk/aws-codecommit';
import * as ec2 from '@aws-cdk/aws-ec2';
import * as cdk from '@aws-cdk/core';
import * as cloud9 from '../lib';
import { ConnectionType } from '../lib';
import { ConnectionType, ImageId } from '../lib';

let stack: cdk.Stack;
let vpc: ec2.IVpc;
Expand All @@ -13,20 +13,24 @@ beforeEach(() => {
vpc = new ec2.Vpc(stack, 'VPC');
});

test('create resource correctly with only vpc provide', () => {
test('create resource correctly with only vpc and imageId provided', () => {
// WHEN
new cloud9.Ec2Environment(stack, 'C9Env', { vpc });
new cloud9.Ec2Environment(stack, 'C9Env', {
vpc,
imageId: cloud9.ImageId.AMAZON_LINUX_2,
});
// THEN
Template.fromStack(stack).resourceCountIs('AWS::Cloud9::EnvironmentEC2', 1);
});

test('create resource correctly with both vpc and subnetSelectio', () => {
test('create resource correctly with vpc, imageId, and subnetSelection', () => {
// WHEN
new cloud9.Ec2Environment(stack, 'C9Env', {
vpc,
subnetSelection: {
subnetType: ec2.SubnetType.PRIVATE_WITH_NAT,
},
imageId: cloud9.ImageId.AMAZON_LINUX_2,
});
// THEN
Template.fromStack(stack).resourceCountIs('AWS::Cloud9::EnvironmentEC2', 1);
Expand All @@ -44,6 +48,7 @@ test('create correctly with instanceType specified', () => {
new cloud9.Ec2Environment(stack, 'C9Env', {
vpc,
instanceType: ec2.InstanceType.of(ec2.InstanceClass.C5, ec2.InstanceSize.LARGE),
imageId: cloud9.ImageId.AMAZON_LINUX_2,
});
// THEN
Template.fromStack(stack).resourceCountIs('AWS::Cloud9::EnvironmentEC2', 1);
Expand All @@ -66,6 +71,7 @@ test('throw error when subnetSelection not specified and the provided VPC has no
new cloud9.Ec2Environment(stack, 'C9Env', {
vpc: privateOnlyVpc,
instanceType: ec2.InstanceType.of(ec2.InstanceClass.C5, ec2.InstanceSize.LARGE),
imageId: cloud9.ImageId.AMAZON_LINUX_2,
});
}).toThrow(/no subnetSelection specified and no public subnet found in the vpc, please specify subnetSelection/);
});
Expand All @@ -79,6 +85,7 @@ test('can use CodeCommit repositories', () => {
clonedRepositories: [
cloud9.CloneRepository.fromCodeCommit(repo, '/src'),
],
imageId: cloud9.ImageId.AMAZON_LINUX_2,
});
// THEN
Template.fromStack(stack).hasResourceProperties('AWS::Cloud9::EnvironmentEC2', {
Expand Down Expand Up @@ -115,11 +122,28 @@ test.each([
new cloud9.Ec2Environment(stack, 'C9Env', {
vpc,
connectionType,
imageId: cloud9.ImageId.AMAZON_LINUX_2,
});

Template.fromStack(stack).hasResourceProperties('AWS::Cloud9::EnvironmentEC2', {
InstanceType: Match.anyValue(),
ConnectionType: expected,
SubnetId: Match.anyValue(),
});
});

test.each([
[ImageId.AMAZON_LINUX_2, 'amazonlinux-2-x86_64'],
[ImageId.UBUNTU_18_04, 'ubuntu-18.04-x86_64'],
])('has image ID property (%s)', (imageId, expected) => {
new cloud9.Ec2Environment(stack, 'C9Env', {
vpc,
imageId: imageId,
});

Template.fromStack(stack).hasResourceProperties('AWS::Cloud9::EnvironmentEC2', {
InstanceType: Match.anyValue(),
ImageId: expected,
SubnetId: Match.anyValue(),
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@
"Type": "AWS::Cloud9::EnvironmentEC2",
"Properties": {
"ConnectionType": "CONNECT_SSH",
"ImageId": "amazonlinux-2-x86_64",
"InstanceType": "t2.micro",
"Repositories": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@
"Type": "AWS::Cloud9::EnvironmentEC2",
"Properties": {
"ConnectionType": "CONNECT_SSM",
"ImageId": "amazonlinux-2-x86_64",
"InstanceType": "t2.micro",
"Repositories": [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"version": "20.0.0",
"files": {
"f9e7c320234302f703a47f0be7da188a1e91f7863c71a04835efd508d926216c": {
"source": {
"path": "C9Stack.template.json",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "f9e7c320234302f703a47f0be7da188a1e91f7863c71a04835efd508d926216c.json",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
}
},
"dockerImages": {}
}
Loading

0 comments on commit dcf3eb3

Please sign in to comment.