aws / aws-cdk

The AWS Cloud Development Kit is a framework for defining cloud infrastructure in code
https://aws.amazon.com/cdk
Apache License 2.0
11.58k stars 3.87k forks source link

CLI: Using the CDK programmatically #15851

Open mikestopcontinues opened 3 years ago

mikestopcontinues commented 3 years ago

The CDK makes it really easy to deploy infrastructure as code, but using the CDK itself is limited to the command line. We should have easy access to boostrap, diff, deploy, and destroy functionality within code.

Use Case

I'm developing a multi-tenant app with custom domains, which hits a lot of AWS quota limits, so I have to spread my user accounts across an arbitrary number of sub-accounts.

When a user signs up, I have to assign them to an account with space and deploy a customized stack with their config details. I have to retrigger deploys when those details change. I also need to update all of these stacks across all of the subaccounts when I make infrastructure updates.

Similarly, I have to monitor account usage. When a threshold is met, I have to create a new account and deploy a shared infrastructure stack for when the new users start getting assigned to it. As above, I occasionally have to update all of them at once.

It seems the best solution is to use CDK from lambdas which are either triggered on change or scheduled, depending on use case. But I find myself having to navigate around calls to the CDK, where what I really want to do is weave my new App() construction with calls like cdk.deploy(stack) or some such.

If the point of the CDK is to make Infrastructure-as-Code easy, then shouldn't the CDK commands be as easy to program as the infrastructure itself?

Proposed Solution

I think the ideal solution would be simply make the full functionality of the CLI command available programmatically. I hesitate to suggest specifics beyond the idea that the real ideal would be to pass your stacks as arguments directly, as well being able to entirely configure the command in code, rather than environment vars and settings files.

I've dug a little into the codebase, and it looks like the commands are in a strange in-between space. It's almost possible to call a few of them, but only with a lot of manual wiring (if at all). If I'm mistaken, and there's already an easy way to do this, I'd love to hear it. I've yet to find a good solution googling.

Thanks!


This is a :rocket: Feature Request

rix0rrr commented 3 years ago

Duplicate of https://github.com/aws/aws-cdk-rfcs/issues/300

github-actions[bot] commented 3 years ago

⚠️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.

NGL321 commented 2 years ago

I have decided to reopen this issue due to continued frustration with this feature-gap, as seen here:

The frustration is significant enough for there to be published overly complex workarounds (ie. this, this, and this)

I believe it is harder to get traction and gague community interest/need from the RFC alone (due to only appearing in a separate repo).

asquithea commented 2 years ago

Adding my voice here:

For v1, I built a serverless application that provides templates that can populate a cdk.Stack. A lambda then uses CloudFormationDeployments to setup the CloudFormation changeset (i.e. without executing). Combined with the SNS notifications and a client request token, this can then execute asynchronously and we can monitor the deployment progress from another lambda.

As with some of the other requests linked above, I found there's a bit of a gap between the obvious "call .synth()" and being able to pass control to the standard CloudFormation SDK client - and that's only really covered by CloudFormationDeployments. An official API would be great, and the bulk of the logic is really just in that one class.

Since CloudFormation can take quite a long time, it would be great if this can continue to support generating change-sets, specifying the notification arns and passing a client request token - as these three options combine to make it fairly easy to build a solution that runs asynchronously.

github-actions[bot] commented 2 years ago

This issue has received a significant amount of attention so we are automatically upgrading its priority. A member of the community will see the re-prioritization and provide an update on the issue.

mrgrain commented 1 year ago

Thanks all for the feedback so far. We have now released a first iteration of this: @aws-cdk/cli-lib-alpha

Please let me know what you're thinking and keep posting feature ideas. We are well aware this isn't a complete and ready solution yet (hence the experimental state), but it's an important stepping stone to gather interest and feedback.

madeline-k commented 1 year ago

Related: https://github.com/aws/aws-cdk/issues/679

AntonioAngelino commented 1 year ago

Hi @mrgrain,

I built our own wrapper to use CDK v1 programmatically and it keeps working after 2 years.

Since the "cli-lib-alpha" module is available, I built something similar w/ CDK v2 and the new lib. I tried to deploy a simple app, but I cannot bootstrap it because the bootstrap method is not exported. How can I deploy a CDK v2 app programmatically w/o bootstrapping the stack?

AntonioAngelino commented 1 year ago

@mrgrain Ehm, the thumbs-up reaction is not so helpful 😅

Do you plan to add the bootstrap command to the library? Otherwise I'll try to patch the cli-lib-alpha module or roll back to CDK V1.

mikestopcontinues commented 1 year ago

Since the related discussion #19719 has been marked as resolved, any news on this?

mrgrain commented 1 year ago

@mrgrain Ehm, the thumbs-up reaction is not so helpful 😅

Do you plan to add the bootstrap command to the library? Otherwise I'll try to patch the cli-lib-alpha module or roll back to CDK V1.

It was very late where I am. I'll look into it. cli-lib-alpha is very much open to change. PRs are also welcome 😀

AntonioAngelino commented 1 year ago

@mrgrain Just opened the PR. Looking forward to reading your feedback 🤞

mrgrain commented 1 year ago

Yes, looks great! Thank you so much!

Please do let me know about any other use cases that this lib doesn't currently cover.

AntonioAngelino commented 1 year ago

@mrgrain Sure, I'll let you know if everything will work as expected :)

AntonioAngelino commented 1 year ago

@mrgrain please check https://github.com/aws/aws-cdk/issues/26224 . I'd like to open a PR to fix that ASAP, ty.

mrgrain commented 1 year ago

Fixed and merged. Both should be released this week.

I'll look into setting up proper integration tests for this. 'Cause this would have been an easy catch.

AntonioAngelino commented 1 year ago

I'm able to use CDK programmatically, but I had to build a utility that uses the AWS SDK to fetch the stack outputs once the deployment is completed (I have to deploy multiple stacks and crossRegionReferences is not an option).

I think the next step is having both list() and deploy() returning something meaningful.

mrgrain commented 1 year ago

I think the next step is having both list() and deploy() returning something meaningful.

Yes, I agree. Appreciate the feedback!

My current plan is:

amine-mf commented 1 year ago

Hi, I'm trying to migrate one of our lambdas that deploys a stack using SdkProvider and CloudFormationDeployments to use the cli-lib-alpha. I've been stuck because of the following error :

ERROR   Uncaught Exception  
{
    "errorType": "TypeError",
    "errorMessage": "Cannot read properties of undefined (reading 'replace')",
    "stack": [
        "TypeError: Cannot read properties of undefined (reading 'replace')",
        "    at versionNumber (/var/task/index.js:12339:3425)",
        "    at ../../aws-cdk/lib/version.ts (/var/task/index.js:12339:4612)",
        "    at __init (/var/task/index.js:99:2574)",
        "    at ../../aws-cdk/lib/api/cxapp/cloud-assembly.ts (/var/task/index.js:12339:6140)",
        "    at __init (/var/task/index.js:99:2574)",
        "    at ../../aws-cdk/lib/api/cxapp/cloud-executable.ts (/var/task/index.js:12341:29928)",
        "    at __init (/var/task/index.js:99:2574)",
        "    at ../../aws-cdk/lib/cli.ts (/var/task/index.js:12453:8224)",
        "    at __init (/var/task/index.js:99:2574)",
        "    at ../../aws-cdk/lib/index.js (/var/task/index.js:12453:8967)"
    ]
}

Has anybody faced it, any one has a clue on how to fix it? (I'm using v2.91.0) The way I'm using it, is through AwsCdkCli.fromCloudAssemblyDirectoryProducer(...) but I don't think it helps as the error seems to happen while loading the cxapp lib, before running any of my code.

It seems that packages/aws-cdk/lib/version.ts is not meant to be loaded in a bundled js context (ex: lambda function). Both functions versionNumber() and commit() fail.

[UPDATE] Setting the nodeModules property of the lambda to avoid bundling the lib did the job (But feels more like a workaround than an actual fix, versionNumber() and commit() should be adapted anyway IMHO). Example:

{
   ...
   bundling: {
          ...,
          nodeModules: ["@aws-cdk/cli-lib-alpha"],
        },
   ...
}
mrgrain commented 1 year ago

Thanks @amine-mf for the investigation. Glad you got to the bottom of this. I agree that versionNumber() and commit() could use a better implementation.

ahammond commented 1 year ago

We have (currently internal, but I'm hoping to open-source) https://github.com/time-loop/cdk-log-parser library. This exists specifically to parse the output of cdk-diff, which we run using https://github.com/time-loop/clickup-projen/tree/main/docs/cdk-diff

taabrcr commented 9 months ago

Hi all, this @aws-cdk/cli-lib-alpha looks really promising :), any hints or info on when this will be a bit more mature (beta, first release)?

hanseltime commented 9 months ago

I would like to add my voice here. More than just programmatically calling the cdk commands, I would love to be able to just expose the CDKToolKit class and CloudAssembly classes. They have a lot of good functions that would allow for writing of helper methods and by having a package for that, I could write libraries that are not vulnerable to growing out of date due to copy-paste