Skip to content

Commit cf795cd

Browse files
author
Tarun Belani
committed
Addressed review comments
1 parent b6c2864 commit cf795cd

File tree

10 files changed

+152
-73
lines changed

10 files changed

+152
-73
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ const advancedSchedulePipeline = new imagebuilder.ImagePipeline(this, 'AdvancedS
133133
autoDisableFailureCount: 3
134134
},
135135
// Start enabled
136-
enabled: true
136+
status: imagebuilder.ImagePipelineStatus.ENABLED
137137
});
138138
```
139139

packages/@aws-cdk/aws-imagebuilder-alpha/lib/image-pipeline.ts

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,9 @@ export interface ImagePipelineProps {
132132
/**
133133
* Indicates whether the pipeline is enabled to be triggered by the provided schedule
134134
*
135-
* @default true
135+
* @default ImagePipelineStatus.ENABLED
136136
*/
137-
readonly enabled?: boolean;
137+
readonly status?: ImagePipelineStatus;
138138

139139
/**
140140
* The infrastructure configuration used for building the image.
@@ -278,6 +278,21 @@ export enum ScheduleStartCondition {
278278
EXPRESSION_MATCH_AND_DEPENDENCY_UPDATES_AVAILABLE = 'EXPRESSION_MATCH_AND_DEPENDENCY_UPDATES_AVAILABLE',
279279
}
280280

281+
/**
282+
* Indicates whether the pipeline is enabled to be triggered by the provided schedule
283+
*/
284+
export enum ImagePipelineStatus {
285+
/**
286+
* Indicates that the pipeline is enabled for scheduling
287+
*/
288+
ENABLED = 'ENABLED',
289+
290+
/**
291+
* Indicates that the pipeline is disabled and will not be triggered on the schedule
292+
*/
293+
DISABLED = 'DISABLED',
294+
}
295+
281296
/**
282297
* A new or imported Image Pipeline
283298
*/
@@ -491,21 +506,35 @@ export class ImagePipeline extends ImagePipelineBase {
491506
this.infrastructureConfiguration._bind({ isContainerBuild: props.recipe._isContainerRecipe() });
492507
}
493508

509+
if (props.recipe._isImageRecipe() && props.recipe._isContainerRecipe()) {
510+
throw new cdk.ValidationError('the recipe must either be an IImageRecipe or IContainerRecipe', this);
511+
}
512+
513+
if (!props.recipe._isImageRecipe() && !props.recipe._isContainerRecipe()) {
514+
throw new cdk.ValidationError('the recipe must either be an IImageRecipe or IContainerRecipe', this);
515+
}
516+
494517
const imagePipeline = new CfnImagePipeline(this, 'Resource', {
495518
name: this.physicalName,
496519
description: props.description,
497520
...(props.recipe._isImageRecipe() && { imageRecipeArn: props.recipe.imageRecipeArn }),
498521
...(props.recipe._isContainerRecipe() && { containerRecipeArn: props.recipe.containerRecipeArn }),
499-
...(props.enabled !== undefined && { status: props.enabled ? 'ENABLED' : 'DISABLED' }),
522+
...(props.status !== undefined && { status: props.status }),
500523
infrastructureConfigurationArn: this.infrastructureConfiguration.infrastructureConfigurationArn,
501524
distributionConfigurationArn: props.distributionConfiguration?.distributionConfigurationArn,
502525
enhancedImageMetadataEnabled: props.enhancedImageMetadataEnabled,
503526
executionRole: this.executionRole?.roleArn,
504527
schedule: this.buildSchedule(props),
505528
loggingConfiguration: this.buildLoggingConfiguration(props),
506-
imageTestsConfiguration: buildImageTestsConfiguration(props),
507-
imageScanningConfiguration: buildImageScanningConfiguration(scope, props),
508-
workflows: buildWorkflows(props),
529+
imageTestsConfiguration: buildImageTestsConfiguration<
530+
ImagePipelineProps,
531+
CfnImagePipeline.ImageTestsConfigurationProperty
532+
>(props),
533+
imageScanningConfiguration: buildImageScanningConfiguration<
534+
ImagePipelineProps,
535+
CfnImagePipeline.ImageScanningConfigurationProperty
536+
>(this, props),
537+
workflows: buildWorkflows<ImagePipelineProps, CfnImagePipeline.WorkflowConfigurationProperty[]>(props),
509538
tags: props.tags,
510539
});
511540

Lines changed: 34 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,77 @@
11
import * as cdk from 'aws-cdk-lib';
2-
import * as ecr from 'aws-cdk-lib/aws-ecr';
3-
import { CfnImagePipeline } from 'aws-cdk-lib/aws-imagebuilder';
2+
import { CfnImage, CfnImagePipeline } from 'aws-cdk-lib/aws-imagebuilder';
43
import { Construct } from 'constructs';
5-
import { IRecipeBase } from '../recipe-base';
6-
import { WorkflowConfiguration, WorkflowOnFailure } from '../workflow';
4+
import { ImagePipelineProps } from '../image-pipeline';
75

86
/**
97
* Generates the image tests configuration property into the `ImageTestsConfiguration` type in the CloudFormation L1
108
* definition.
119
*
12-
* @param imageTestsEnabled Props input for whether image tests are enabled
10+
* @param props Props input for the construct
1311
*/
14-
export const buildImageTestsConfiguration = ({
15-
imageTestsEnabled,
16-
}: {
17-
imageTestsEnabled?: boolean;
18-
}): { imageTestsEnabled: boolean } | undefined => {
19-
if (imageTestsEnabled === undefined) {
12+
export const buildImageTestsConfiguration = <
13+
PropsT extends ImagePipelineProps,
14+
OutputT extends CfnImagePipeline.ImageTestsConfigurationProperty | CfnImage.ImageTestsConfigurationProperty,
15+
>(
16+
props: PropsT,
17+
): OutputT | undefined => {
18+
if (props.imageTestsEnabled === undefined) {
2019
return undefined;
2120
}
2221

23-
return { imageTestsEnabled };
22+
return { imageTestsEnabled: props.imageTestsEnabled } as OutputT;
2423
};
2524

2625
/**
2726
* Generates the image scanning configuration property into the `ImageScanningConfiguration` type in the CloudFormation
2827
* L1 definition.
2928
*
3029
* @param scope The construct scope
31-
* @param imageScanningEnabled Props input for whether image scanning is enabled
32-
* @param imageScanningEcrRepository Props input for the image scanning ECR repository
33-
* @param imageScanningEcrTags Props input for the image scanning ECR tags
34-
* @param recipe Props input for the image or container recipe
30+
* @param props Props input for the construct
3531
*/
36-
export const buildImageScanningConfiguration = (
32+
export const buildImageScanningConfiguration = <
33+
PropsT extends ImagePipelineProps,
34+
OutputT extends CfnImagePipeline.ImageScanningConfigurationProperty | CfnImage.ImageScanningConfigurationProperty,
35+
>(
3736
scope: Construct,
38-
{
39-
imageScanningEnabled,
40-
imageScanningEcrRepository,
41-
imageScanningEcrTags,
42-
recipe,
43-
}: {
44-
imageScanningEnabled?: boolean;
45-
imageScanningEcrRepository?: ecr.IRepository;
46-
imageScanningEcrTags?: string[];
47-
recipe: IRecipeBase;
48-
},
49-
):
50-
| { ecrConfiguration?: { containerTags?: string[]; repositoryName?: string }; imageScanningEnabled?: boolean }
51-
| undefined => {
52-
if (!recipe._isContainerRecipe() && imageScanningEcrRepository !== undefined) {
37+
props: PropsT,
38+
): OutputT | undefined => {
39+
if (!props.recipe._isContainerRecipe() && props.imageScanningEcrRepository !== undefined) {
5340
throw new cdk.ValidationError('imageScanningEcrRepository is only supported for container recipe builds', scope);
5441
}
5542

56-
if (!recipe._isContainerRecipe() && imageScanningEcrTags !== undefined) {
43+
if (!props.recipe._isContainerRecipe() && props.imageScanningEcrTags !== undefined) {
5744
throw new cdk.ValidationError('imageScanningEcrTags is only supported for container recipe builds', scope);
5845
}
5946

6047
const ecrConfiguration: CfnImagePipeline.EcrConfigurationProperty = {
61-
...(imageScanningEcrRepository !== undefined && {
62-
repositoryName: imageScanningEcrRepository.repositoryName,
48+
...(props.imageScanningEcrRepository !== undefined && {
49+
repositoryName: props.imageScanningEcrRepository.repositoryName,
6350
}),
64-
...((imageScanningEcrTags ?? []).length && { containerTags: imageScanningEcrTags }),
51+
...((props.imageScanningEcrTags ?? []).length && { containerTags: props.imageScanningEcrTags }),
6552
};
6653

6754
const imageScanningConfiguration = {
68-
...(imageScanningEnabled !== undefined && { imageScanningEnabled: imageScanningEnabled }),
55+
...(props.imageScanningEnabled !== undefined && { imageScanningEnabled: props.imageScanningEnabled }),
6956
...(Object.keys(ecrConfiguration).length && { ecrConfiguration }),
7057
};
7158

72-
return Object.keys(imageScanningConfiguration).length ? imageScanningConfiguration : undefined;
59+
return Object.keys(imageScanningConfiguration).length ? (imageScanningConfiguration as OutputT) : undefined;
7360
};
7461

7562
/**
7663
* Generates the workflows property into the `WorkflowConfiguration` type in the CloudFormation L1
7764
* definition.
7865
*
79-
* @param workflows Props input for the workflows
66+
* @param props Props input for the construct
8067
*/
81-
export const buildWorkflows = ({
82-
workflows,
83-
}: {
84-
workflows?: WorkflowConfiguration[];
85-
}):
86-
| {
87-
workflowArn: string;
88-
onFailure?: WorkflowOnFailure;
89-
parallelGroup?: string;
90-
parameters?: {
91-
name: string;
92-
value: string[];
93-
}[];
94-
}[]
95-
| undefined => {
96-
const cfnWorkflows = workflows?.map((workflow) => {
68+
export const buildWorkflows = <
69+
PropsT extends ImagePipelineProps,
70+
OutputT extends CfnImagePipeline.WorkflowConfigurationProperty[] | CfnImage.WorkflowConfigurationProperty[],
71+
>(
72+
props: PropsT,
73+
): OutputT | undefined => {
74+
const cfnWorkflows = props.workflows?.map((workflow) => {
9775
const parameters = Object.entries(workflow.parameters ?? {}).map(([name, value]) => ({
9876
name,
9977
value: value.value,
@@ -106,5 +84,5 @@ export const buildWorkflows = ({
10684
};
10785
});
10886

109-
return cfnWorkflows?.length ? cfnWorkflows : undefined;
87+
return cfnWorkflows?.length ? (cfnWorkflows as OutputT) : undefined;
11088
};

packages/@aws-cdk/aws-imagebuilder-alpha/test/image-pipeline.test.ts

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@ import {
88
AwsManagedWorkflow,
99
ContainerRecipe,
1010
DistributionConfiguration,
11+
IContainerRecipe,
12+
IImageRecipe,
1113
ImagePipeline,
14+
ImagePipelineStatus,
1215
ImageRecipe,
1316
InfrastructureConfiguration,
17+
IRecipeBase,
1418
ScheduleStartCondition,
1519
WorkflowOnFailure,
1620
WorkflowParameterValue,
@@ -97,7 +101,7 @@ describe('ImagePipeline', () => {
97101
'DistributionConfiguration',
98102
'imported-distribution-configuration',
99103
),
100-
enabled: true,
104+
status: ImagePipelineStatus.ENABLED,
101105
executionRole: iam.Role.fromRoleName(stack, 'ExecutionRole', 'imagebuilder-execution-role'),
102106
schedule: {
103107
expression: events.Schedule.cron({ minute: '0', hour: '0', weekDay: '0' }),
@@ -217,7 +221,7 @@ describe('ImagePipeline', () => {
217221
'imported-distribution-configuration',
218222
),
219223
executionRole: iam.Role.fromRoleName(stack, 'ExecutionRole', 'imagebuilder-execution-role'),
220-
enabled: false,
224+
status: ImagePipelineStatus.DISABLED,
221225
schedule: {
222226
expression: events.Schedule.rate(cdk.Duration.days(7)),
223227
startCondition: ScheduleStartCondition.EXPRESSION_MATCH_AND_DEPENDENCY_UPDATES_AVAILABLE,
@@ -880,4 +884,62 @@ describe('ImagePipeline', () => {
880884
});
881885
}).toThrow(cdk.ValidationError);
882886
});
887+
888+
test('throws a validation error when the recipe is neither an IImageRecipe or IContainerRecipe', () => {
889+
class BadRecipe extends cdk.Resource implements IRecipeBase {
890+
public grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant {
891+
return iam.Grant.addToPrincipal({
892+
grantee,
893+
actions,
894+
resourceArns: ['*'],
895+
scope: stack,
896+
});
897+
}
898+
899+
public grantRead(grantee: iam.IGrantable): iam.Grant {
900+
return this.grant(grantee, 'imagebuilder:GetBadRecipe');
901+
}
902+
903+
public _isContainerRecipe(): this is IContainerRecipe {
904+
return false;
905+
}
906+
907+
public _isImageRecipe(): this is IImageRecipe {
908+
return false;
909+
}
910+
}
911+
912+
expect(() => new ImagePipeline(stack, 'ImagePipeline', { recipe: new BadRecipe(stack, 'BadRecipe') })).toThrow(
913+
cdk.ValidationError,
914+
);
915+
});
916+
917+
test('throws a validation error when the recipe is both an IImageRecipe and IContainerRecipe', () => {
918+
class BadRecipe extends cdk.Resource implements IRecipeBase {
919+
public grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant {
920+
return iam.Grant.addToPrincipal({
921+
grantee,
922+
actions,
923+
resourceArns: ['*'],
924+
scope: stack,
925+
});
926+
}
927+
928+
public grantRead(grantee: iam.IGrantable): iam.Grant {
929+
return this.grant(grantee, 'imagebuilder:GetBadRecipe');
930+
}
931+
932+
public _isContainerRecipe(): this is IContainerRecipe {
933+
return true;
934+
}
935+
936+
public _isImageRecipe(): this is IImageRecipe {
937+
return true;
938+
}
939+
}
940+
941+
expect(() => new ImagePipeline(stack, 'ImagePipeline', { recipe: new BadRecipe(stack, 'BadRecipe') })).toThrow(
942+
cdk.ValidationError,
943+
);
944+
});
883945
});

packages/@aws-cdk/aws-imagebuilder-alpha/test/integ.all-parameters.image-pipeline.ami.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const imagePipeline = new imagebuilder.ImagePipeline(stack, 'ImagePipeline-AMI',
3232
recipe: imageRecipe,
3333
infrastructureConfiguration,
3434
distributionConfiguration: amiDistributionConfiguration,
35-
enabled: true,
35+
status: imagebuilder.ImagePipelineStatus.ENABLED,
3636
executionRole,
3737
schedule: {
3838
expression: events.Schedule.expression('cron(0 7 ? * mon *)'),

packages/@aws-cdk/aws-imagebuilder-alpha/test/integ.all-parameters.image-pipeline.container.js.snapshot/aws-cdk-imagebuilder-image-pipeline-container-all-parameters.assets.json

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

packages/@aws-cdk/aws-imagebuilder-alpha/test/integ.all-parameters.image-pipeline.container.js.snapshot/aws-cdk-imagebuilder-image-pipeline-container-all-parameters.template.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,7 @@
799799
"PipelineExecutionStartCondition": "EXPRESSION_MATCH_AND_DEPENDENCY_UPDATES_AVAILABLE",
800800
"ScheduleExpression": "rate(7 days)"
801801
},
802-
"Status": "ENABLED",
802+
"Status": "DISABLED",
803803
"Workflows": [
804804
{
805805
"WorkflowArn": {

packages/@aws-cdk/aws-imagebuilder-alpha/test/integ.all-parameters.image-pipeline.container.js.snapshot/manifest.json

Lines changed: 11 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk/aws-imagebuilder-alpha/test/integ.all-parameters.image-pipeline.container.js.snapshot/tree.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk/aws-imagebuilder-alpha/test/integ.all-parameters.image-pipeline.container.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const containerImagePipeline = new imagebuilder.ImagePipeline(stack, 'ImagePipel
3838
recipe: containerRecipe,
3939
infrastructureConfiguration,
4040
distributionConfiguration: containerDistributionConfiguration,
41-
enabled: true,
41+
status: imagebuilder.ImagePipelineStatus.DISABLED,
4242
executionRole,
4343
schedule: {
4444
expression: events.Schedule.rate(cdk.Duration.days(7)),

0 commit comments

Comments
 (0)