Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ServiceCatalog: Not possible to deploy two products within the same portfolio both of which have custom assets (lambdas) #25189

Closed
ViktarKhomich opened this issue Apr 19, 2023 · 7 comments · Fixed by #26885
Assignees
Labels
@aws-cdk/aws-servicecatalog Related to AWS Service Catalog bug This issue is a bug. effort/medium Medium work item – several days of effort p2

Comments

@ViktarKhomich
Copy link

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

@ViktarKhomich ViktarKhomich added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Apr 19, 2023
@github-actions github-actions bot added the @aws-cdk/aws-servicecatalog Related to AWS Service Catalog label Apr 19, 2023
@khushail khushail self-assigned this Apr 19, 2023
@khushail khushail added investigating This issue is being investigated and/or work is in progress to resolve the issue. needs-reproduction This issue needs reproduction. and removed needs-triage This issue or PR still needs to be triaged. labels Apr 19, 2023
@khushail
Copy link
Contributor

thanks for reporting this bug @ViktarKhomich. I am able to reproduce the issue and see that this id is static in the code.

I am marking this bug as P2 which means our team won't be able to work on it immediately. However we welcome community PRs. If you would also like to contribute , here is the contributing guide to get started.

@khushail khushail added p2 effort/small Small work item – less than a day of effort and removed investigating This issue is being investigated and/or work is in progress to resolve the issue. needs-reproduction This issue needs reproduction. labels Apr 19, 2023
@khushail khushail removed their assignment Apr 19, 2023
@khushail khushail added effort/large Large work item – several weeks of effort p1 and removed effort/small Small work item – less than a day of effort p2 labels Apr 19, 2023
@ViktarKhomich
Copy link
Author

@khushail thank you for your reply! In meanwhile, I noticed that you changed the current status of the issue to P1 and expected efforts for fixing are large. Does it mean you will fix it? Otherwise, I would like to contribute, because for us this issue is kind of blocker.

@khushail
Copy link
Contributor

Hi @ViktarKhomich , I marked it as P1 to bring it to the notice of Core team so it could be prioritised. But I understand they have a lot on their plate and might not work on a fix as soon as needed by you. So it sounds great if you are contributing. Please feel free to create a PR and our team would be happy to review it.

@ViktarKhomich
Copy link
Author

Hi @khushail,
could you please take a look on PR for this issue? It was opened for a while now (once it was automatically closed because no actions were taken). We would need your assistance with it.
Thank you in advance!

@schnipseljagd
Copy link

I think the problem also applies to products in different portfolios in the same stack.
As a workaround I am creating a separate stack for each product which seems to work fine.

@gbvanrenswoude
Copy link

Please discuss amongs the cdk team if you want to go for the proposed code change, or want to explore the suggestion proposed. I feel the suggested fix is accurate, so I would disagree with closing this and leaving it unattended: https://github.com/aws/aws-cdk/pull/26039/files/51c6272831ff7a82e06de5a0a9db44b055d7626a#r1243504435

@kaizencc kaizencc added p2 effort/medium Medium work item – several days of effort and removed p1 effort/large Large work item – several weeks of effort labels Jul 26, 2023
ViktarKhomich pushed a commit to ViktarKhomich/aws-cdk that referenced this issue Aug 8, 2023
… in the same portfolio (aws#25189)

Check for the existing AssetDeploymentBucket and if it is, use it otherwise create a new one
@colifran colifran assigned colifran and unassigned colifran Aug 9, 2023
@rix0rrr rix0rrr self-assigned this Aug 23, 2023
@mergify mergify bot closed this as completed in #26885 Aug 25, 2023
mergify bot pushed a commit that referenced this issue Aug 25, 2023
…ts (#26885)

To move the assets into the target bucket, a `BucketDeployment` was created for every `ProductStack`. Instead, we will now share the same `BucketDeployment` for all `ProductStacks`.

This moves the custom resource around in the construct tree (leading to replacement), but that is a safe operation. Nothing will be destroyed by this move.

Closes #25189.

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
@github-actions
Copy link

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment