Describe the bug
I am facing an issue while working with the service catalog. Specifically, I am trying to deploy two service catalog products within the same portfolio, both of which have custom assets (lambdas in this case). However, I am encountering an error during the synth process.
Error: There is already a Construct with name 'AssetsBucketDeployment' in PortfolioStack [ServiceCatalogProductsStack]
at Node.addChild (.../node_modules/constructs/src/construct.ts:403:13)
at new Node (.../node_modules/constructs/src/construct.ts:71:17)
at new Construct (.../node_modules/constructs/src/construct.ts:463:17)
at new BucketDeployment (.../node_modules/aws-cdk-lib/aws-s3-deployment/lib/bucket-deployment.ts:261:5)
at ProductStackSynthesizer.addFileAsset (.../node_modules/aws-cdk-lib/aws-servicecatalog/lib/private/product-stack-synthesizer.ts:33:31)
at new Asset (.../node_modules/aws-cdk-lib/aws-s3-assets/lib/asset.ts:146:40)
When I am using custom assets only for one product, then everything works fine.
Expected Behavior
I expect to be able to deploy two or more products within the same portfolio which can have the custom assets.
Current Behavior
I am able to use custom assets in every product within the same portfolio.
Reproduction Steps
cdk app with which bug can be easily reproduced:
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as servicecatalog from 'aws-cdk-lib/aws-servicecatalog';
import * as nodejs from 'aws-cdk-lib/aws-lambda-nodejs';
import * as logs from 'aws-cdk-lib/aws-logs';
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
export const handler = async () => {};
class ProductAWithCustomAsset extends servicecatalog.ProductStack {
constructor(scope: Construct, id: string, props?: servicecatalog.ProductStackProps) {
super(scope, id, props);
new nodejs.NodejsFunction(this, 'LambdaA', {
entry: 'lib/cdk-stack.ts',
handler: 'handler',
timeout: cdk.Duration.minutes(3),
logRetention: logs.RetentionDays.TWO_WEEKS,
});
}
}
class ProductBWithCustomAsset extends servicecatalog.ProductStack {
constructor(scope: Construct, id: string, props?: servicecatalog.ProductStackProps) {
super(scope, id, props);
// if you comment this out then cdk synth will work
new nodejs.NodejsFunction(this, 'LambdaB', {
entry: 'lib/cdk-stack.ts',
handler: 'handler',
timeout: cdk.Duration.minutes(3),
logRetention: logs.RetentionDays.TWO_WEEKS,
});
}
}
export class ExamplePortfolioStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const portfolio = new servicecatalog.Portfolio(this, 'Portfolio', {
displayName: 'MyPortfolio',
providerName: 'MyProvider',
});
const assetBucket = new s3.Bucket(this, 'ProductAssetBucket', {
bucketName: 'products-asset-bucket',
encryption: s3.BucketEncryption.S3_MANAGED,
enforceSSL: true,
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
});
const productAStackHistory = new servicecatalog.ProductStackHistory(this, 'ProductAStackHistory', {
productStack: new ProductAWithCustomAsset(this, 'ProductAWithCustomAsset', { assetBucket }),
currentVersionName: 'v1',
currentVersionLocked: false,
});
const productA = new servicecatalog.CloudFormationProduct(this, 'ProductAId', {
productName: 'Product A',
owner: 'Owner A',
productVersions: [
productAStackHistory.currentVersion(),
],
});
portfolio.addProduct(productA);
const productBStackHistory = new servicecatalog.ProductStackHistory(this, 'ProductBStackHistory', {
productStack: new ProductBWithCustomAsset(this, 'ProductBWithCustomAsset', { assetBucket }),
currentVersionName: 'v1',
currentVersionLocked: false,
});
const productB = new servicecatalog.CloudFormationProduct(this, 'ProductBId', {
productName: 'Product B',
owner: 'Owner B',
productVersions: [
productBStackHistory.currentVersion(),
],
});
portfolio.addProduct(productB);
}
}
const app = new cdk.App();
new ExamplePortfolioStack(app, 'ExamplePortfolioStackId');
app.synth();
Possible Solution
If I am right, then in the ProductStackSynthesizer.js file in addFileAsset method the name of the assets bucket deployment (marked with bold in the code snippet below) should be generated dynamically (now it is static):
addFileAsset(asset) {
if (!this.assetBucket) {
throw new Error('An Asset Bucket must be provided to use Assets');
}
const outdir = cdk.App.of(this.boundStack)?.outdir ?? 'cdk.out';
const assetPath = `${outdir}/${asset.fileName}`;
if (!this.bucketDeployment) {
const parentStack = this.boundStack._getParentStack();
if (!cdk.Resource.isOwnedResource(this.assetBucket)) {
cdk.Annotations.of(parentStack).addWarning('[WARNING] Bucket Policy Permissions cannot be added to' +
' referenced Bucket. Please make sure your bucket has the correct permissions');
}
this.bucketDeployment = new aws_s3_deployment_1.BucketDeployment(parentStack, '**AssetsBucketDeployment**', {
sources: [aws_s3_deployment_1.Source.asset(assetPath)],
destinationBucket: this.assetBucket,
extract: false,
prune: false,
});
}
Additional Information/Context
No response
CDK CLI Version
2.75.1
Framework Version
No response
Node.js Version
16.17.0
OS
MacOS
Language
Typescript
Language Version
4.8.4
Other information
No response
Describe the bug
I am facing an issue while working with the service catalog. Specifically, I am trying to deploy two service catalog products within the same portfolio, both of which have custom assets (lambdas in this case). However, I am encountering an error during the
synthprocess.When I am using custom assets only for one product, then everything works fine.
Expected Behavior
I expect to be able to deploy two or more products within the same portfolio which can have the custom assets.
Current Behavior
I am able to use custom assets in every product within the same portfolio.
Reproduction Steps
cdk app with which bug can be easily reproduced:
Possible Solution
If I am right, then in the
ProductStackSynthesizer.jsfile inaddFileAssetmethod the name of the assets bucket deployment (marked with bold in the code snippet below) should be generated dynamically (now it is static):Additional Information/Context
No response
CDK CLI Version
2.75.1
Framework Version
No response
Node.js Version
16.17.0
OS
MacOS
Language
Typescript
Language Version
4.8.4
Other information
No response