Skip to content

Commit

Permalink
feat(ec2): adds persist option to user data on windows instances (#21709
Browse files Browse the repository at this point in the history
)

To set the UserData for Windows instances to run on every instance start, rather than only the first startup, requires adding "<persist>true</persist>" to the end of the user data string. Currently, users must use an escape hatch to hack the userdata of
windows instances to add this string. This PR makes it possible to add this text directly on the UserData without using an escape hatch.

Implements: #21708

----

### 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

* [ ] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)?
	* [ ] 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
ddneilson authored Oct 12, 2022
1 parent e427fd6 commit cb1506f
Show file tree
Hide file tree
Showing 9 changed files with 1,707 additions and 4 deletions.
15 changes: 15 additions & 0 deletions packages/@aws-cdk/aws-ec2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1404,6 +1404,21 @@ instance.userData.addExecuteFileCommand({
asset.grantRead(instance.role);
```

### Persisting user data

By default, EC2 UserData is run once on only the first time that an instance is started. It is possible to make the
user data script run on every start of the instance.

When creating a Windows UserData you can use the `persist` option to set whether or not to add
`<persist>true</persist>` [to the user data script](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ec2-windows-user-data.html#user-data-scripts). it can be used as follows:

```ts
const windowsUserData = UserData.forWindows({ persist: true });
```

For a Linux instance, this can be accomplished by using a Multipart user data to configure cloud-config as detailed
in: https://aws.amazon.com/premiumsupport/knowledge-center/execute-user-data-ec2/

### Multipart user data

In addition, to above the `MultipartUserData` can be used to change instance startup behavior. Multipart user data are composed
Expand Down
26 changes: 22 additions & 4 deletions packages/@aws-cdk/aws-ec2/lib/user-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@ export interface LinuxUserDataOptions {
readonly shebang?: string;
}

/**
* Options when constructing UserData for Windows
*/
export interface WindowsUserDataOptions {
/**
* Set to true to set this userdata to persist through an instance reboot; allowing
* it to run on every instance start.
* By default, UserData is run only once during the first instance launch.
*
* For more information, see:
* https://aws.amazon.com/premiumsupport/knowledge-center/execute-user-data-ec2/
* https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ec2-windows-user-data.html#user-data-scripts
*
* @default false
*/
readonly persist?: boolean;
}

/**
* Options when downloading files from S3
*/
Expand Down Expand Up @@ -78,8 +96,8 @@ export abstract class UserData {
/**
* Create a userdata object for Windows hosts
*/
public static forWindows(): UserData {
return new WindowsUserData();
public static forWindows(options: WindowsUserDataOptions = {}): UserData {
return new WindowsUserData(options);
}

/**
Expand Down Expand Up @@ -197,7 +215,7 @@ class WindowsUserData extends UserData {
private readonly lines: string[] = [];
private readonly onExitLines: string[] = [];

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

Expand All @@ -214,7 +232,7 @@ class WindowsUserData extends UserData {
[...(this.renderOnExitLines()),
...this.lines,
...( this.onExitLines.length > 0 ? ['throw "Success"'] : [] )].join('\n')
}</powershell>`;
}</powershell>${(this.props.persist ?? false) ? '<persist>true</persist>' : ''}`;
}

public addS3DownloadCommand(params: S3DownloadOptions): string {
Expand Down
18 changes: 18 additions & 0 deletions packages/@aws-cdk/aws-ec2/test/integ.userdata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env node
import * as cdk from '@aws-cdk/core';
import * as ec2 from '../lib';

const app = new cdk.App();
const stack = new cdk.Stack(app, 'integ-userdata');

const vpc = new ec2.Vpc(stack, 'IntegUserdataVpc');

new ec2.Instance(stack, 'WindowsInstance', {
vpc,
vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC },
instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.MICRO),
machineImage: new ec2.WindowsImage(ec2.WindowsVersion.WINDOWS_SERVER_2022_ENGLISH_FULL_BASE),
userData: ec2.UserData.forWindows({ persist: true }),
});

app.synth();
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":"21.0.0"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"version": "21.0.0",
"files": {
"9f2c5f7def4ad32c13627dff08f2be0273546384a8fe510e265cc6a7083274e1": {
"source": {
"path": "integ-userdata.template.json",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "9f2c5f7def4ad32c13627dff08f2be0273546384a8fe510e265cc6a7083274e1.json",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
}
},
"dockerImages": {}
}
Loading

0 comments on commit cb1506f

Please sign in to comment.