Skip to content

Commit 789dc9c

Browse files
committed
feat!: dynamic naming and existing component imports
1 parent e30d9a1 commit 789dc9c

File tree

5 files changed

+48
-138
lines changed

5 files changed

+48
-138
lines changed

API.md

Lines changed: 3 additions & 55 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,6 @@ new ImagePipeline(this, "MyImagePipeline", {
5959
version: '0.1.0',
6060
},
6161
],
62-
kmsKeyAlias: 'alias/my-key',
63-
profileName: 'ImagePipelineInstanceProfile',
64-
infraConfigName: 'MyInfrastructureConfiguration',
65-
imageRecipe: 'MyImageRecipe',
66-
pipelineName: 'MyImagePipeline',
6762
parentImage: 'ami-0e1d30f2c40c4c701',
6863
ebsVolumeConfigurations: [
6964
{
@@ -130,11 +125,6 @@ new ImagePipeline(this, "MyImagePipeline", {
130125
version: '0.1.0',
131126
},
132127
],
133-
kmsKeyAlias: 'alias/my-key',
134-
profileName: 'ImagePipelineInstanceProfile',
135-
infraConfigName: 'MyInfrastructureConfiguration',
136-
imageRecipe: 'MyImageRecipe',
137-
pipelineName: 'MyImagePipeline',
138128
parentImage: 'ami-0e1d30f2c40c4c701',
139129
securityGroups: [sg.securityGroupId],
140130
subnetId: private_subnet[0].subnetId,
@@ -164,12 +154,7 @@ image_pipeline = ImagePipeline(
164154
version: '0.1.0',
165155
},
166156
],
167-
kms_key_alias="alias/my-key",
168-
image_recipe="Recipe4",
169-
pipeline_name="Pipeline4",
170-
infra_config_name="InfraConfig4",
171157
parent_image="ami-0e1d30f2c40c4c701",
172-
profile_name="ImagePipelineProfile4",
173158
)
174159
# ...
175160
```
@@ -224,12 +209,7 @@ image_pipeline = ImagePipeline(
224209
version: '0.1.0',
225210
},
226211
],
227-
kms_key_alias="alias/my-key",
228-
image_recipe="Recipe4",
229-
pipeline_name="Pipeline4",
230-
infra_config_name="InfraConfig4",
231212
parent_image="ami-0e1d30f2c40c4c701",
232-
profile_name="ImagePipelineProfile4",
233213
security_groups=[sg.security_group_id],
234214
subnet_id=priv_subnets[0].subnet_id
235215
)

src/index.ts

Lines changed: 43 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { createHash } from 'crypto';
12
import { readFileSync } from 'fs';
23
import * as path from 'path';
34
import {
@@ -7,6 +8,7 @@ import {
78
aws_sns as sns,
89
aws_sns_subscriptions as subscriptions,
910
aws_lambda as lambda,
11+
Names,
1012
} from 'aws-cdk-lib';
1113
import { SnsEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
1214
import { Construct } from 'constructs';
@@ -40,23 +42,11 @@ export interface ImagePipelineProps {
4042
/**
4143
* List of component props
4244
*/
43-
readonly components: ComponentProps[];
44-
/**
45-
* Name of the instance profile that will be associated with the Instance Configuration.
46-
*/
47-
readonly profileName: string;
45+
readonly components: (ComponentProps | string)[];
4846
/**
4947
* Additional policies to add to the instance profile associated with the Instance Configurations
5048
*/
5149
readonly additionalPolicies?: iam.ManagedPolicy[];
52-
/**
53-
* Name of the Infrastructure Configuration for Image Builder
54-
*/
55-
readonly infraConfigName: string;
56-
/**
57-
* Name of the Image Recipe
58-
*/
59-
readonly imageRecipe: string;
6050
/**
6151
* UserData script that will override default one (if specified)
6252
*
@@ -67,10 +57,6 @@ export interface ImagePipelineProps {
6757
* Image recipe version (Default: 0.0.1)
6858
*/
6959
readonly imageRecipeVersion?: string;
70-
/**
71-
* Name of the Image Pipeline
72-
*/
73-
readonly pipelineName: string;
7460
/**
7561
* The source (parent) image that the image recipe uses as its base environment. The value can be the parent image ARN or an Image Builder AMI ID
7662
*/
@@ -150,6 +136,9 @@ export class ImagePipeline extends Construct {
150136
let imageRecipe: imagebuilder.CfnImageRecipe;
151137
this.imageRecipeComponents = [];
152138

139+
const uid = Names.uniqueId(this);
140+
const profileName = `${uid}Profile`;
141+
153142
// Construct code below
154143
const topic = new sns.Topic(this, 'ImageBuilderTopic', {
155144
displayName: 'Image Builder Notify',
@@ -176,21 +165,21 @@ export class ImagePipeline extends Construct {
176165

177166
const profile = new iam.CfnInstanceProfile(this, 'InstanceProfile', {
178167
roles: [role.roleName],
179-
instanceProfileName: props.profileName,
168+
instanceProfileName: profileName,
180169
});
181170

182171
if (props.securityGroups == null || props.subnetId == null) {
183172
infrastructureConfig = new imagebuilder.CfnInfrastructureConfiguration(this, 'InfrastructureConfiguration', {
184-
instanceProfileName: props.profileName,
185-
name: props.infraConfigName,
173+
instanceProfileName: profileName,
174+
name: `${uid}InfraConfig`,
186175
description: 'Example Infrastructure Configuration for Image Builder',
187176
instanceTypes: props.instanceTypes ?? ['t3.medium', 'm5.large', 'm5.xlarge'],
188177
snsTopicArn: topic.topicArn,
189178
});
190179
} else {
191180
infrastructureConfig = new imagebuilder.CfnInfrastructureConfiguration(this, 'InfrastructureConfiguration', {
192-
instanceProfileName: props.profileName,
193-
name: props.infraConfigName,
181+
instanceProfileName: profileName,
182+
name: `${uid}InfraConfig`,
194183
description: 'Example Infrastructure Configuration for Image Builder',
195184
instanceTypes: props.instanceTypes ?? ['t3.medium', 'm5.large', 'm5.xlarge'],
196185
snsTopicArn: topic.topicArn,
@@ -207,7 +196,7 @@ export class ImagePipeline extends Construct {
207196
let imageRecipeProps: imagebuilder.CfnImageRecipeProps;
208197
imageRecipeProps = {
209198
components: [],
210-
name: props.imageRecipe,
199+
name: 'Placeholder',
211200
parentImage: props.parentImage,
212201
version: props.imageRecipeVersion ?? '0.0.1',
213202
};
@@ -228,22 +217,30 @@ export class ImagePipeline extends Construct {
228217
imageRecipe = new imagebuilder.CfnImageRecipe(this, 'ImageRecipe', imageRecipeProps);
229218

230219
props.components.forEach((component) => {
231-
let newComponent = new imagebuilder.CfnComponent(this, component.name, {
232-
name: component.name,
233-
platform: props.platform ? props.platform : 'Linux',
234-
version: component.version,
235-
data: readFileSync(component.document).toString(),
236-
});
220+
if (typeof component === 'string') {
221+
this.imageRecipeComponents.push({ componentArn: component });
222+
} else {
223+
let newComponent = new imagebuilder.CfnComponent(this, component.name, {
224+
name: `${uid}${component.name}`,
225+
platform: props.platform ? props.platform : 'Linux',
226+
version: component.version,
227+
data: readFileSync(component.document).toString(),
228+
});
229+
230+
// add the component to the Image Recipe
231+
this.imageRecipeComponents.push({ componentArn: newComponent.attrArn });
232+
}
237233

238-
// add the component to the Image Recipe
239-
this.imageRecipeComponents.push({ componentArn: newComponent.attrArn });
240234
imageRecipe.components = this.imageRecipeComponents;
241235
});
242236

237+
const hashId = this.hash(props.components);
238+
imageRecipe.name = `${uid}${hashId}`;
239+
243240
let imagePipelineProps: imagebuilder.CfnImagePipelineProps;
244241
imagePipelineProps = {
245242
infrastructureConfigurationArn: infrastructureConfig.attrArn,
246-
name: props.pipelineName,
243+
name: `${uid}ImagePipeline`,
247244
description: 'A sample image pipeline',
248245
imageRecipeArn: imageRecipe.attrArn,
249246
};
@@ -267,8 +264,8 @@ export class ImagePipeline extends Construct {
267264
amiDistributionConfiguration: {
268265
//Capital case here because it's an object of type any, but capital case is what is expected in CloudFormation
269266
//https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-distributionconfiguration-amidistributionconfiguration.html
270-
Name: `${props.imageRecipe}-${distributionRegion}-{{imagebuilder:buildDate}}`,
271-
Description: `copy AMI ${props.imageRecipe} to ${distributionRegion}`,
267+
Name: `${uid}-${distributionRegion}-{{imagebuilder:buildDate}}`,
268+
Description: `copy AMI to ${distributionRegion}`,
272269
TargetAccountIds: props.distributionAccountIDs,
273270
LaunchPermissionConfiguration: {
274271
UserIds: props.distributionAccountIDs,
@@ -279,8 +276,8 @@ export class ImagePipeline extends Construct {
279276
distributionsList.push(distributionConfig);
280277
});
281278
const amiDistributionConfiguration = new imagebuilder.CfnDistributionConfiguration(this, 'amiDistributionConfiguration', {
282-
name: `${props.imageRecipe}-distribution-config`,
283-
description: `Cross account distribution settings for ${props.imageRecipe}`,
279+
name: `${uid}DistributionConfig`,
280+
description: `Cross account distribution settings for ${uid}`,
284281
distributions: distributionsList,
285282
});
286283
imagePipelineProps = {
@@ -308,7 +305,7 @@ export class ImagePipeline extends Construct {
308305
}),
309306
],
310307
});
311-
const amiSsmUpdateLambdaRole = new iam.Role(this, `${props.imageRecipe}UpdateLambdaRole`, {
308+
const amiSsmUpdateLambdaRole = new iam.Role(this, 'UpdateLambdaRole', {
312309
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
313310
managedPolicies: [
314311
iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'),
@@ -317,7 +314,7 @@ export class ImagePipeline extends Construct {
317314
AmiSsmUpdateLambdaPolicy: amiSsmUpdateLambdaPolicy,
318315
},
319316
});
320-
const amiSsmUpdateLambda = new lambda.Function(this, `${props.imageRecipe}UpdateLambda`, {
317+
const amiSsmUpdateLambda = new lambda.Function(this, 'UpdateLambda', {
321318
runtime: lambda.Runtime.PYTHON_3_10,
322319
code: lambda.Code.fromAsset(path.join(__dirname, '../assets/image-builder-update-lambda')),
323320
handler: 'image-builder-lambda-update-ssm.lambda_handler',
@@ -331,4 +328,12 @@ export class ImagePipeline extends Construct {
331328
}
332329
new imagebuilder.CfnImagePipeline(this, 'ImagePipeline', imagePipelineProps);
333330
}
331+
332+
private hash(o: object): string {
333+
return createHash('sha256')
334+
.update(JSON.stringify(o))
335+
.digest('hex')
336+
.toUpperCase()
337+
.slice(0, 6);
338+
}
334339
}

0 commit comments

Comments
 (0)