Skip to content

Commit

Permalink
feat(aws-ec2): Allow ApplyCloudformationInitOptions to set additional…
Browse files Browse the repository at this point in the history
… params (aws#16121)

Resolves aws#16004 

When using CloudformationInit, can opt to include the `--role` and `--url` argument to `cfn-init` and `cfn-signal` ([ref](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-init.html#cfn-init-Syntax)).

User can do this by including [InitOptions](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.ApplyCloudFormationInitOptions.html) that include `includeUrl` and `includeRole`

```typescript
ec2.Instance(this, 'MyInstance', {
  init: // init config,
  initOptions: {
    includeUrl: true,
    includeRole: true,
  }
}
```

It's possible to _always_ include these added arguments, but not sure whether that would cause regressions.

Open to any suggestions on a better way to implement

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
maafk authored and david-doyle-as24 committed Sep 7, 2021
1 parent 665d038 commit a076d24
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 1 deletion.
21 changes: 21 additions & 0 deletions packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,8 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements
embedFingerprint: options.embedFingerprint,
printLog: options.printLog,
ignoreFailures: options.ignoreFailures,
includeRole: options.includeRole,
includeUrl: options.includeUrl,
});
}

Expand Down Expand Up @@ -1780,4 +1782,23 @@ export interface ApplyCloudFormationInitOptions {
* @default false
*/
readonly ignoreFailures?: boolean;

/**
* Include --url argument when running cfn-init and cfn-signal commands
*
* This will be the cloudformation endpoint in the deployed region
* e.g. https://cloudformation.us-east-1.amazonaws.com
*
* @default false
*/
readonly includeUrl?: boolean;

/**
* Include --role argument when running cfn-init and cfn-signal commands
*
* This will be the IAM instance profile attached to the EC2 instance
*
* @default false
*/
readonly includeRole?: boolean;
}
6 changes: 6 additions & 0 deletions packages/@aws-cdk/aws-ec2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,12 @@ new ec2.Instance(this, 'Instance', {

// Optional, how long the installation is expected to take (5 minutes by default)
timeout: Duration.minutes(30),

// Optional, whether to include the --url argument when running cfn-init and cfn-signal commands (false by default)
includeUrl: true

// Optional, whether to include the --role argument when running cfn-init and cfn-signal commands (false by default)
includeRole: true
},
});
```
Expand Down
29 changes: 28 additions & 1 deletion packages/@aws-cdk/aws-ec2/lib/cfn-init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,15 @@ export class CloudFormationInit {

// To identify the resources that have the metadata and where the signal
// needs to be sent, we need { region, stackName, logicalId }
const resourceLocator = `--region ${Aws.REGION} --stack ${Aws.STACK_NAME} --resource ${attachedResource.logicalId}`;
let resourceLocator = `--region ${Aws.REGION} --stack ${Aws.STACK_NAME} --resource ${attachedResource.logicalId}`;

// If specified in attachOptions, include arguments in cfn-init/cfn-signal commands
if (attachOptions.includeUrl) {
resourceLocator = `${resourceLocator} --url https://cloudformation.${Aws.REGION}.${Aws.URL_SUFFIX}`;
}
if (attachOptions.includeRole) {
resourceLocator = `${resourceLocator} --role ${attachOptions.instanceRole}`;
}
const configSets = (attachOptions.configSets ?? ['default']).join(',');
const printLog = attachOptions.printLog ?? true;

Expand Down Expand Up @@ -346,6 +354,25 @@ export interface AttachInitOptions {
*/
readonly instanceRole: iam.IRole;

/**
* Include --url argument when running cfn-init and cfn-signal commands
*
* This will be the cloudformation endpoint in the deployed region
* e.g. https://cloudformation.us-east-1.amazonaws.com
*
* @default false
*/
readonly includeUrl?: boolean;

/**
* Include --role argument when running cfn-init and cfn-signal commands
*
* This will be the IAM instance profile attached to the EC2 instance
*
* @default false
*/
readonly includeRole?: boolean;

/**
* OS Platform the init config will be used for
*/
Expand Down
21 changes: 21 additions & 0 deletions packages/@aws-cdk/aws-ec2/lib/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,8 @@ export class Instance extends Resource implements IInstance {
embedFingerprint: options.embedFingerprint,
printLog: options.printLog,
ignoreFailures: options.ignoreFailures,
includeRole: options.includeRole,
includeUrl: options.includeUrl,
});
this.waitForResourceSignal(options.timeout ?? Duration.minutes(5));
}
Expand Down Expand Up @@ -557,4 +559,23 @@ export interface ApplyCloudFormationInitOptions {
* @default false
*/
readonly ignoreFailures?: boolean;

/**
* Include --url argument when running cfn-init and cfn-signal commands
*
* This will be the cloudformation endpoint in the deployed region
* e.g. https://cloudformation.us-east-1.amazonaws.com
*
* @default false
*/
readonly includeUrl?: boolean;

/**
* Include --role argument when running cfn-init and cfn-signal commands
*
* This will be the IAM instance profile attached to the EC2 instance
*
* @default false
*/
readonly includeRole?: boolean;
}
28 changes: 28 additions & 0 deletions packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,34 @@ describe('userdata', () => {
expectLine(lines, /fingerprint/);
});

test('linux userdata contains right commands when url and role included', () => {
// WHEN
simpleInit.attach(resource, {
platform: ec2.OperatingSystemType.LINUX,
instanceRole,
includeUrl: true,
includeRole: true,
userData: linuxUserData,
});

// THEN
const lines = linuxUserData.render().split('\n');
expectLine(lines, cmdArg('cfn-init', `--region ${Aws.REGION}`));
expectLine(lines, cmdArg('cfn-init', `--stack ${Aws.STACK_NAME}`));
expectLine(lines, cmdArg('cfn-init', `--resource ${resource.logicalId}`));
expectLine(lines, cmdArg('cfn-init', `--role ${instanceRole}`));
expectLine(lines, cmdArg('cfn-init', `--url https://cloudformation.${Aws.REGION}.${Aws.URL_SUFFIX}`));
expectLine(lines, cmdArg('cfn-init', '-c default'));
expectLine(lines, cmdArg('cfn-signal', `--region ${Aws.REGION}`));
expectLine(lines, cmdArg('cfn-signal', `--stack ${Aws.STACK_NAME}`));
expectLine(lines, cmdArg('cfn-signal', `--resource ${resource.logicalId}`));
expectLine(lines, cmdArg('cfn-init', `--role ${instanceRole}`));
expectLine(lines, cmdArg('cfn-init', `--url https://cloudformation.${Aws.REGION}.${Aws.URL_SUFFIX}`));
expectLine(lines, cmdArg('cfn-signal', '-e $?'));
expectLine(lines, cmdArg('cat', 'cfn-init.log'));
expectLine(lines, /fingerprint/);
});

test('Windows userdata contains right commands', () => {
// WHEN
const windowsUserData = ec2.UserData.forWindows();
Expand Down

0 comments on commit a076d24

Please sign in to comment.