Skip to content

Commit b4a6120

Browse files
authored
fix(servicecatalog): incorrect objectkey produced from asset relative… (#23580)
Currently when assets are nested in a directory, ProductStack is unable to parse the fileName and produces an incorrect template. Since `asset.fileName` is the relative to the root of the cloud assembly, in which this asset source resides, we need to call `path.basename` in order to get the actual name of the file before parsing it to generate the `s3Filename` More details found in #23560 ---- ### All Submissions: * [X] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 7cbe8ac commit b4a6120

File tree

2 files changed

+67
-4
lines changed

2 files changed

+67
-4
lines changed

packages/@aws-cdk/aws-servicecatalog/lib/private/product-stack-synthesizer.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as path from 'path';
12
import { CfnBucket, IBucket } from '@aws-cdk/aws-s3';
23
import { BucketDeployment, Source } from '@aws-cdk/aws-s3-deployment';
34
import * as cdk from '@aws-cdk/core';
@@ -42,7 +43,11 @@ export class ProductStackSynthesizer extends cdk.StackSynthesizer {
4243
const physicalName = this.physicalNameOfBucket(this.assetBucket);
4344

4445
const bucketName = physicalName;
45-
const s3Filename = asset.fileName?.split('.')[1] + '.zip';
46+
if (!asset.fileName) {
47+
throw new Error('Asset file name is undefined');
48+
}
49+
const assetFileBaseName = path.basename(asset.fileName);
50+
const s3Filename = assetFileBaseName.split('.')[1] + '.zip';
4651
const objectKey = `${s3Filename}`;
4752
const s3ObjectUrl = `s3://${bucketName}/${objectKey}`;
4853
const httpUrl = `https://s3.${bucketName}/${objectKey}`;

packages/@aws-cdk/aws-servicecatalog/test/product-stack.test.ts

+61-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import * as fs from 'fs';
22
import * as path from 'path';
3+
import { Template } from '@aws-cdk/assertions';
4+
import * as lambda from '@aws-cdk/aws-lambda';
35
import * as s3 from '@aws-cdk/aws-s3';
46
import * as s3_assets from '@aws-cdk/aws-s3-assets';
57
import * as sns from '@aws-cdk/aws-sns';
@@ -32,13 +34,69 @@ describe('ProductStack', () => {
3234
assetBucket: testAssetBucket,
3335
});
3436

35-
// WHEN
36-
new s3_assets.Asset(productStack, 'testAsset', {
37-
path: path.join(__dirname, 'assets'),
37+
new lambda.Function(productStack, 'HelloHandler', {
38+
runtime: lambda.Runtime.PYTHON_3_9,
39+
code: lambda.Code.fromAsset(path.join(__dirname, 'assets')),
40+
handler: 'index.handler',
3841
});
3942

43+
// WHEN
44+
const assembly = app.synth();
45+
4046
// THEN
4147
expect(productStack._getAssetBucket()).toBeDefined();
48+
const template = JSON.parse(fs.readFileSync(path.join(assembly.directory, productStack.templateFile), 'utf-8'));
49+
Template.fromJSON(template).hasResourceProperties('AWS::Lambda::Function', {
50+
Code: {
51+
S3Bucket: 'test-asset-bucket',
52+
S3Key: 'd3833f63e813b3a96ea04c8c50ca98209330867f5f6ac358efca11f85a3476c2.zip',
53+
},
54+
});
55+
});
56+
57+
test('Used defined Asset bucket in product stack with nested assets', () => {
58+
// GIVEN
59+
const app = new cdk.App(
60+
{ outdir: 'cdk.out' },
61+
);
62+
const mainStack = new cdk.Stack(app, 'MyStack');
63+
let templateFileUrl = '';
64+
class PortfolioStage extends cdk.Stage {
65+
constructor(scope: Construct, id: string) {
66+
super(scope, id);
67+
68+
const portfolioStack: cdk.Stack = new cdk.Stack(this, 'NestedStack');
69+
70+
const testAssetBucket = new s3.Bucket(portfolioStack, 'TestAssetBucket', {
71+
bucketName: 'test-asset-bucket',
72+
});
73+
const productStack = new servicecatalog.ProductStack(portfolioStack, 'MyProductStack', {
74+
assetBucket: testAssetBucket,
75+
});
76+
77+
new lambda.Function(productStack, 'HelloHandler', {
78+
runtime: lambda.Runtime.PYTHON_3_9,
79+
code: lambda.Code.fromAsset(path.join(__dirname, 'assets')),
80+
handler: 'index.handler',
81+
});
82+
83+
expect(productStack._getAssetBucket()).toBeDefined();
84+
templateFileUrl = productStack.templateFile;
85+
}
86+
}
87+
const portfolioStage = new PortfolioStage(mainStack, 'PortfolioStage');
88+
89+
// WHEN
90+
app.synth();
91+
92+
//THEN
93+
const template = JSON.parse(fs.readFileSync(path.join(portfolioStage.outdir, templateFileUrl), 'utf-8'));
94+
Template.fromJSON(template).hasResourceProperties('AWS::Lambda::Function', {
95+
Code: {
96+
S3Bucket: 'test-asset-bucket',
97+
S3Key: 'd3833f63e813b3a96ea04c8c50ca98209330867f5f6ac358efca11f85a3476c2.zip',
98+
},
99+
});
42100
});
43101

44102
test('fails if bucketName is not specified in product stack with assets', () => {

0 commit comments

Comments
 (0)