Skip to content

Commit 0d7a7d4

Browse files
author
Tarun Belani
committed
Addressed review comments
1 parent a31c5a2 commit 0d7a7d4

File tree

11 files changed

+248
-91
lines changed

11 files changed

+248
-91
lines changed

packages/@aws-cdk/aws-imagebuilder-alpha/README.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ Create a component with the required properties: platform and component data.
5353

5454
```ts
5555
const component = new imagebuilder.Component(this, 'MyComponent', {
56-
platform: imagebuilder.OSVersion.LINUX,
56+
platform: imagebuilder.Platform.LINUX,
5757
data: imagebuilder.ComponentData.fromJsonObject({
5858
schemaVersion: imagebuilder.ComponentSchemaVersion.V1_0,
5959
phases: [
@@ -82,7 +82,7 @@ Use `ComponentData.fromInline()` for existing YAML/JSON definitions:
8282

8383
```ts
8484
const component = new imagebuilder.Component(this, 'InlineComponent', {
85-
platform: imagebuilder.OSVersion.LINUX,
85+
platform: imagebuilder.Platform.LINUX,
8686
data: imagebuilder.ComponentData.fromInline(`
8787
name: my-component
8888
schemaVersion: 1.0
@@ -103,7 +103,7 @@ Most developer-friendly approach using objects:
103103

104104
```ts
105105
const component = new imagebuilder.Component(this, 'JsonComponent', {
106-
platform: imagebuilder.OSVersion.LINUX,
106+
platform: imagebuilder.Platform.LINUX,
107107
data: imagebuilder.ComponentData.fromJsonObject({
108108
schemaVersion: imagebuilder.ComponentSchemaVersion.V1_0,
109109
phases: [
@@ -131,7 +131,7 @@ For type-safe, CDK-native definitions with enhanced properties like `timeout` an
131131

132132
```ts
133133
const component = new imagebuilder.Component(this, 'StructuredComponent', {
134-
platform: imagebuilder.OSVersion.LINUX,
134+
platform: imagebuilder.Platform.LINUX,
135135
data: imagebuilder.ComponentData.fromComponentDocumentJsonObject({
136136
schemaVersion: imagebuilder.ComponentSchemaVersion.V1_0,
137137
phases: [
@@ -161,23 +161,26 @@ For those components you want to upload or have uploaded to S3:
161161
```ts
162162
// Upload a local file
163163
const componentFromAsset = new imagebuilder.Component(this, 'AssetComponent', {
164-
platform: imagebuilder.OSVersion.LINUX,
164+
platform: imagebuilder.Platform.LINUX,
165165
data: imagebuilder.ComponentData.fromAsset(this, 'ComponentAsset', './my-component.yml'),
166166
});
167167

168168
// Reference an existing S3 object
169169
const bucket = s3.Bucket.fromBucketName(this, 'ComponentBucket', 'my-components-bucket');
170170
const componentFromS3 = new imagebuilder.Component(this, 'S3Component', {
171-
platform: imagebuilder.OSVersion.LINUX,
171+
platform: imagebuilder.Platform.LINUX,
172172
data: imagebuilder.ComponentData.fromS3(bucket, 'components/my-component.yml'),
173173
});
174174
```
175175

176176
#### Encrypt component data with a KMS key
177177

178+
You can encrypt component data with a KMS key, so that only principals with access to decrypt with the key are able to
179+
access the component data.
180+
178181
```ts
179182
const component = new imagebuilder.Component(this, 'EncryptedComponent', {
180-
platform: imagebuilder.OSVersion.LINUX,
183+
platform: imagebuilder.Platform.LINUX,
181184
kmsKey: new kms.Key(this, 'ComponentKey'),
182185
data: imagebuilder.ComponentData.fromJsonObject({
183186
schemaVersion: imagebuilder.ComponentSchemaVersion.V1_0,
@@ -206,12 +209,12 @@ AWS provides a collection of managed components for common tasks:
206209
```ts
207210
// Install AWS CLI v2
208211
const awsCliComponent = imagebuilder.AwsManagedComponent.awsCliV2(this, 'AwsCli', {
209-
platform: imagebuilder.OSVersion.LINUX,
212+
platform: imagebuilder.Platform.LINUX
210213
});
211214

212215
// Update the operating system
213216
const updateComponent = imagebuilder.AwsManagedComponent.updateOS(this, 'UpdateOS', {
214-
platform: imagebuilder.OSVersion.LINUX,
217+
platform: imagebuilder.Platform.LINUX
215218
});
216219

217220
// Reference any AWS-managed component by name

packages/@aws-cdk/aws-imagebuilder-alpha/lib/component.ts

Lines changed: 84 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export interface ComponentProps {
6767
/**
6868
* The operating system platform of the component.
6969
*/
70-
readonly platform: OSVersion;
70+
readonly platform: Platform;
7171

7272
/**
7373
* The name of the component.
@@ -143,7 +143,7 @@ export interface ComponentAttributes {
143143
/**
144144
* The version of the component
145145
*
146-
* @default the latest version of the component, x.x.x
146+
* @default - the latest version of the component, x.x.x
147147
*/
148148
readonly componentVersion?: string;
149149
}
@@ -168,7 +168,7 @@ export interface AwsManagedComponentAttributes {
168168
/**
169169
* The version of the AWS-managed component
170170
*
171-
* @default the latest version of the component, x.x.x
171+
* @default - the latest version of the component, x.x.x
172172
*/
173173
readonly componentVersion?: string;
174174

@@ -180,7 +180,7 @@ export interface AwsManagedComponentAttributes {
180180
* @default - none if using `this.fromAwsManagedComponentAttributes()`, otherwise a platform is
181181
* required when using the pre-defined managed component methods
182182
*/
183-
readonly platform?: OSVersion;
183+
readonly platform?: Platform;
184184
}
185185

186186
/**
@@ -200,7 +200,7 @@ export interface AwsMarketplaceComponentAttributes {
200200
/**
201201
* The version of the AWS Marketplace component
202202
*
203-
* @default The latest version of the component, x.x.x
203+
* @default - the latest version of the component, x.x.x
204204
*/
205205
readonly componentVersion?: string;
206206
}
@@ -273,7 +273,7 @@ export interface ComponentDocumentStep {
273273
/**
274274
* The condition to apply to the step. If the condition is false, then the step is skipped
275275
*
276-
* @default no condition is applied to the step and it gets executed
276+
* @default - no condition is applied to the step and it gets executed
277277
*/
278278
readonly if?: any;
279279

@@ -282,7 +282,7 @@ export interface ComponentDocumentStep {
282282
*
283283
* @default None
284284
*/
285-
readonly loop?: any;
285+
readonly loop?: ComponentDocumentLoop;
286286

287287
/**
288288
* The timeout of the step
@@ -299,6 +299,53 @@ export interface ComponentDocumentStep {
299299
readonly onFailure?: ComponentOnFailure;
300300
}
301301

302+
/**
303+
* The looping construct of a component defines a repeated sequence of instructions
304+
*/
305+
export interface ComponentDocumentLoop {
306+
/**
307+
* The name of the loop, which can be used to reference
308+
*
309+
* @default loop
310+
*/
311+
readonly name?: string;
312+
313+
/**
314+
* The for loop iterates on a range of integers specified within a boundary outlined by the start and end of the
315+
* variables
316+
*
317+
* @default - none if `forEach` is provided. otherwise, `for` is required.
318+
*/
319+
readonly for?: ComponentDocumentForLoop;
320+
321+
/**
322+
* The forEach loop iterates on an explicit list of values, which can be strings and chained expressions
323+
*
324+
* @default - none if `for` is provided. otherwise, `forEach` is required.
325+
*/
326+
readonly forEach?: string[];
327+
}
328+
329+
/**
330+
* The for loop iterates on a range of integers specified within a boundary outlined by the start and end of the
331+
* variables. The iterating values are in the set [start, end] and includes boundary values.
332+
*/
333+
export interface ComponentDocumentForLoop {
334+
/**
335+
* Starting value of iteration. Does not accept chaining expressions.
336+
*/
337+
readonly start: number;
338+
/**
339+
* Ending value of iteration. Does not accept chaining expressions.
340+
*/
341+
readonly end: number;
342+
/**
343+
* Difference by which an iterating value is updated through addition. It must be a negative or positive non-zero
344+
* value. Does not accept chaining expressions.
345+
*/
346+
readonly updateBy: number;
347+
}
348+
302349
/**
303350
* The action for a step within the component document
304351
*/
@@ -571,9 +618,11 @@ export abstract class ComponentData {
571618
steps: phase.steps.map((step) => ({
572619
name: step.name,
573620
action: step.action,
574-
inputs: step.inputs,
575621
...(step.onFailure !== undefined && { onFailure: step.onFailure }),
576622
...(step.timeout !== undefined && { timeoutSeconds: step.timeout.toSeconds() }),
623+
...(step.if !== undefined && { if: step.if }),
624+
...(step.loop !== undefined && { loop: step.loop }),
625+
inputs: step.inputs,
577626
})),
578627
})),
579628
});
@@ -700,7 +749,7 @@ export abstract class AwsManagedComponent {
700749
allowedPlatforms: [Platform.LINUX, Platform.WINDOWS],
701750
});
702751

703-
if (attrs.platform?.platform === Platform.WINDOWS) {
752+
if (attrs.platform === Platform.WINDOWS) {
704753
return this.fromAwsManagedComponentAttributes(scope, id, {
705754
componentName: 'aws-cli-version-2-windows',
706755
componentVersion: attrs.componentVersion,
@@ -728,7 +777,7 @@ export abstract class AwsManagedComponent {
728777
allowedPlatforms: [Platform.LINUX, Platform.WINDOWS],
729778
});
730779

731-
if (attrs.platform?.platform === Platform.WINDOWS) {
780+
if (attrs.platform === Platform.WINDOWS) {
732781
return this.fromAwsManagedComponentAttributes(scope, id, {
733782
componentName: 'hello-world-windows',
734783
componentVersion: attrs.componentVersion,
@@ -756,7 +805,7 @@ export abstract class AwsManagedComponent {
756805
allowedPlatforms: [Platform.LINUX, Platform.WINDOWS],
757806
});
758807

759-
if (attrs.platform?.platform === Platform.WINDOWS) {
808+
if (attrs.platform === Platform.WINDOWS) {
760809
return this.fromAwsManagedComponentAttributes(scope, id, {
761810
componentName: 'python-3-windows',
762811
componentVersion: attrs.componentVersion,
@@ -784,7 +833,7 @@ export abstract class AwsManagedComponent {
784833
allowedPlatforms: [Platform.LINUX, Platform.WINDOWS],
785834
});
786835

787-
if (attrs.platform?.platform === Platform.WINDOWS) {
836+
if (attrs.platform === Platform.WINDOWS) {
788837
return this.fromAwsManagedComponentAttributes(scope, id, {
789838
componentName: 'reboot-windows',
790839
componentVersion: attrs.componentVersion,
@@ -814,7 +863,7 @@ export abstract class AwsManagedComponent {
814863
allowedPlatforms: [Platform.LINUX, Platform.WINDOWS],
815864
});
816865

817-
if (attrs.platform?.platform === Platform.WINDOWS) {
866+
if (attrs.platform === Platform.WINDOWS) {
818867
return this.fromAwsManagedComponentAttributes(scope, id, {
819868
componentName: 'stig-build-windows',
820869
componentVersion: attrs.componentVersion,
@@ -842,7 +891,7 @@ export abstract class AwsManagedComponent {
842891
allowedPlatforms: [Platform.LINUX, Platform.WINDOWS],
843892
});
844893

845-
if (attrs.platform?.platform === Platform.WINDOWS) {
894+
if (attrs.platform === Platform.WINDOWS) {
846895
return this.fromAwsManagedComponentAttributes(scope, id, {
847896
componentName: 'update-windows',
848897
componentVersion: attrs.componentVersion,
@@ -923,7 +972,7 @@ export abstract class AwsManagedComponent {
923972
throw new cdk.ValidationError(`platform cannot be a token for ${component}`, scope);
924973
}
925974

926-
if (!allowedPlatforms.includes(attrs.platform.platform)) {
975+
if (!allowedPlatforms.includes(attrs.platform)) {
927976
throw new cdk.ValidationError(`${attrs.platform} is not a supported platform for ${component}`, scope);
928977
}
929978
}
@@ -1061,6 +1110,11 @@ export class Component extends ComponentBase {
10611110
).resourceName!;
10621111

10631112
const [componentNameFromArn, componentVersionFromArn] = (() => {
1113+
if (cdk.Token.isUnresolved(componentNameVersion)) {
1114+
const componentNameVersionSplit = cdk.Fn.split('/', componentNameVersion);
1115+
return [cdk.Fn.select(0, componentNameVersionSplit), cdk.Fn.select(1, componentNameVersionSplit)];
1116+
}
1117+
10641118
const componentNameVersionSplit = componentNameVersion.split('/');
10651119
return [componentNameVersionSplit[0], componentNameVersionSplit[1]];
10661120
})();
@@ -1111,6 +1165,8 @@ export class Component extends ComponentBase {
11111165
*/
11121166
public readonly componentType: string;
11131167

1168+
protected readonly kmsKey?: kms.IKey;
1169+
11141170
public constructor(scope: Construct, id: string, props: ComponentProps) {
11151171
super(scope, id, {
11161172
physicalName:
@@ -1130,7 +1186,7 @@ export class Component extends ComponentBase {
11301186
this.validateComponentName();
11311187

11321188
props.supportedOsVersions?.forEach((osVersion) => {
1133-
if (osVersion.platform !== props.platform.platform) {
1189+
if (osVersion.platform !== props.platform) {
11341190
throw new cdk.ValidationError(
11351191
`os version ${osVersion.osVersion} is not compatible with platform ${props.platform}`,
11361192
this,
@@ -1146,7 +1202,7 @@ export class Component extends ComponentBase {
11461202
version: componentVersion,
11471203
changeDescription: props.changeDescription,
11481204
description: props.description,
1149-
platform: props.platform.platform,
1205+
platform: props.platform,
11501206
kmsKeyId: props.kmsKey?.keyArn,
11511207
tags: props.tags,
11521208
...(props.data.isS3Reference ? { uri: props.data.value } : { data: props.data.value }),
@@ -1164,6 +1220,17 @@ export class Component extends ComponentBase {
11641220
this.componentVersion = componentVersion;
11651221
this.encrypted = true; // Components are always encrypted
11661222
this.componentType = component.attrType;
1223+
this.kmsKey = props.kmsKey;
1224+
}
1225+
1226+
/**
1227+
* Grant KMS key decrypt permissions to the given grantee. This applies only if a KMS key was provided to the
1228+
* component.
1229+
*
1230+
* @param grantee The principal
1231+
*/
1232+
public grantDecrypt(grantee: iam.IGrantable): iam.Grant | undefined {
1233+
return this.kmsKey?.grantDecrypt(grantee);
11671234
}
11681235

11691236
private validateComponentName() {

packages/@aws-cdk/aws-imagebuilder-alpha/lib/os-version.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@ export class OSVersion {
5555
/**
5656
* OS version for macOS 14
5757
*/
58-
public static readonly MAC_OS_14 = new OSVersion(Platform.LINUX, 'macOS 14');
58+
public static readonly MAC_OS_14 = new OSVersion(Platform.MAC_OS, 'macOS 14');
5959

6060
/**
6161
* OS version for macOS 15
6262
*/
63-
public static readonly MAC_OS_15 = new OSVersion(Platform.LINUX, 'macOS 15');
63+
public static readonly MAC_OS_15 = new OSVersion(Platform.MAC_OS, 'macOS 15');
6464

6565
/**
6666
* OS version for all Red Hat Enterprise Linux images
@@ -110,24 +110,24 @@ export class OSVersion {
110110
/**
111111
* OS version for all Windows server images
112112
*/
113-
public static readonly WINDOWS_SERVER = new OSVersion(Platform.LINUX, 'Microsoft Windows Server');
113+
public static readonly WINDOWS_SERVER = new OSVersion(Platform.WINDOWS, 'Microsoft Windows Server');
114114

115115
/**
116116
* OS version for Windows Server 2016
117117
*/
118-
public static readonly WINDOWS_SERVER_2016 = new OSVersion(Platform.LINUX, 'Microsoft Windows Server 2016');
118+
public static readonly WINDOWS_SERVER_2016 = new OSVersion(Platform.WINDOWS, 'Microsoft Windows Server 2016');
119119
/**
120120
* OS version for Windows Server 2019
121121
*/
122-
public static readonly WINDOWS_SERVER_2019 = new OSVersion(Platform.LINUX, 'Microsoft Windows Server 2019');
122+
public static readonly WINDOWS_SERVER_2019 = new OSVersion(Platform.WINDOWS, 'Microsoft Windows Server 2019');
123123
/**
124124
* OS version for Windows Server 2022
125125
*/
126-
public static readonly WINDOWS_SERVER_2022 = new OSVersion(Platform.LINUX, 'Microsoft Windows Server 2022');
126+
public static readonly WINDOWS_SERVER_2022 = new OSVersion(Platform.WINDOWS, 'Microsoft Windows Server 2022');
127127
/**
128128
* OS version for Windows Server 2025
129129
*/
130-
public static readonly WINDOWS_SERVER_2025 = new OSVersion(Platform.LINUX, 'Microsoft Windows Server 2025');
130+
public static readonly WINDOWS_SERVER_2025 = new OSVersion(Platform.WINDOWS, 'Microsoft Windows Server 2025');
131131

132132
/**
133133
* Constructs an OS version with a custom name

0 commit comments

Comments
 (0)