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

initial draft of breakpoint debugging blog post #11900

Merged
merged 9 commits into from
May 31, 2024

Conversation

thoward
Copy link
Contributor

@thoward thoward commented May 24, 2024

Proposed changes

Initial draft of blog post on breakpoint debugging.

Related issues (optional)

Closes https://github.com/pulumi/devrel-team/issues/977

@thoward thoward added the area/blog Content issues on blog posts. label May 24, 2024
@thoward thoward added this to the 0.105 milestone May 24, 2024
@pulumi-bot
Copy link
Collaborator

@pulumi-bot
Copy link
Collaborator

@pulumi-bot
Copy link
Collaborator

Copy link
Contributor

@aaronkao aaronkao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looking good. I think its missing a good example of using a debugger to fix a Pulumi program

content/blog/next-level-iac-breakpoint-debugging/index.md Outdated Show resolved Hide resolved
content/blog/next-level-iac-breakpoint-debugging/index.md Outdated Show resolved Hide resolved
```shell {hl_lines=[3]}
#!/bin/bash

export NODE_OPTIONS='--inspect-brk=127.0.0.1:9292'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i believe we need to do a python version of this since all our blog posts should have both typescript and python code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, the blog post is already so complex, and the differences between Python and Node/TS here are significant enough that I think it warrants a separate follow up post. Similarly w/ Go and C#...


* **Inputs and Outputs are asynchronous futures:** If you've used Pulumi before you will have encountered [`Input<T>`][input-docs] and [`Output<T>`][output-docs] values, which are a core function of the tool. However, at the time that the debugger hits a breakpoint on those values, they are likely not populated with their final value. That means you won't be able to inspect them in the debugger very well. Instead, you will need to add an [`apply(...)`][apply-docs] or [`all(..)`][all-docs] block to the code, and place the breakpoint on the materialized value within that block. This follows all the same rules as accessing those variables in code in a Pulumi program.

* **Limited integration with VS Code:** Unfortunately our technique of running Pulumi in wrapper script as a backgrounded pre-launch task in VS Code leaves some things to be desired. It is different enough from the use case that VS Code had in mind for these features that making things "just work" is a little difficult. For example, we can't easily report on errors in the "Problems" tab. Sometimes VS Code can't tell that the program finished and so you'll have to manually stop the debugging session after Pulumi has completed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you rephrase this to be more clear. i don't really understand what is being said here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes VS Code can't tell that the program finished and so you'll have to manually stop the debugging session after Pulumi has completed.

This happens 100% of the time for me, yeah. I figured this was the expected behavior, but I guess not?

It does sound like this is worth explaining in more detail, though. Like how is it "different from the use case VS Code had in mind"? Does it have something to do with the fact that the Node process is spawned by Pulumi?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's more about the difference between a "launch" and "attach" foreground task. Launch will run a program, attach will wait to attach to a program... So to launch the pulumi CLI we run it as a preLaunchTask (because you can't launch and then attach in the same launch config, so it needs to run it "preLaunch"), but if you don't say it's a background task, it will then have two wait conditions... waiting to attach and waiting for prelaunchtask to complete. that means you have to run as a background task (e.g. indicating that it runs forever like a service and not wait on it). Then, once it's running, the launch config will wait to attach to a debugger. but since that's a background task that can start/stop multiple times, instead of attaching then exiting once the thing it attaches to is complete, it attaches, and then goes into a wait/retry loop to try to reconnect with another background process. if it hits that timeout it will exit on its own. otherwise you have to manually exit the debug mode. Other programs behave in a way that is consistent with this model (like tsc-watch), which is what VS Code's implementation is designed for.

Frankly, this is all too complicated for this post which is already fairly long. I wanted to call it out without diving into the details and distracting from the "hero narrative" of Pulumi being debuggable by talking about all the ways the VS Code's debugging implementation makes it not fit perfectly into that model.

Maybe I should just remove this bullet point entirely?


* **Limited integration with VS Code:** Unfortunately our technique of running Pulumi in wrapper script as a backgrounded pre-launch task in VS Code leaves some things to be desired. It is different enough from the use case that VS Code had in mind for these features that making things "just work" is a little difficult. For example, we can't easily report on errors in the "Problems" tab. Sometimes VS Code can't tell that the program finished and so you'll have to manually stop the debugging session after Pulumi has completed.

Despite these limitations, Pulumi with VS Code as your IDE provides a rich experience compared to trawlling through unstructured logs, or adding in `console.log(...)` calls to echo out ad-hoc debugging information (aka. [`printf` debugging][printf-debugging]). Also, you can enable this for any language that Pulumi supports. Python, Go, and C# all have popular debuggers and IDEs that can be used in the same manner.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are there other methods to debug Pulumi programs? Are there other IDEs or other systems that you can do this? Probably should mention all the capabilities you have here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also add this to our own docs, as our coverage of interactive debugging seems to cover only debugging providers (rather than your own IAC).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you can do this with any sophisticated IDE with an extension for CDP (Chrome DevTools Protocol). That would include most IDEs that are designed to work with Node (e.g. Visual Studio, Webstorm, even neovim). I added a note about that.


Ok now let's setup VS Code to run that in debug mode when we hit `F5`!

### Step 3: Configure VS Code `launch.json` and `task.json`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what is missing in all of this is we show "how to set up and use a debuguger", but we don't show a sample of something that is broken and using a debugger to help us fix it. I think the thinking here is like people always code errors into their programs, it will end up executing and failing at provisioning. for something like CloudFormation its a long roll back process. for TF, I don't know what happens. But in Pulumi you can debug the program with a debugger and isolate the error.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Showing a simple error that will normally creep up and how to find it is probably the piece that is missing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! I originally wanted to write it this way but felt the complexity and length of the post would be too much. I went ahead and added that in anyway, in the current revision.

Copy link
Member

@cnunciato cnunciato left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great! A few bits of initial feedback for ya.

content/blog/next-level-iac-breakpoint-debugging/index.md Outdated Show resolved Hide resolved
content/blog/next-level-iac-breakpoint-debugging/index.md Outdated Show resolved Hide resolved
content/blog/next-level-iac-breakpoint-debugging/index.md Outdated Show resolved Hide resolved
Comment on lines +165 to +171
{{% notes type="info" %}}
Let's walk through these lines to explain what's going on here:

* `pulumi login` to set up credentials for the pulumi backend
* `pulumi stack select dev` to run this against our `dev` stack
* `pulumi up -f` to run our program udpate. The -f flag skips the preview phase and also skips the need to interactively confirm that we want to run the update.
{{% /notes %}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like it should just be part of the content, rather than a callout, as it explains what the lines in the script are actually doing.

Suggested change
{{% notes type="info" %}}
Let's walk through these lines to explain what's going on here:
* `pulumi login` to set up credentials for the pulumi backend
* `pulumi stack select dev` to run this against our `dev` stack
* `pulumi up -f` to run our program udpate. The -f flag skips the preview phase and also skips the need to interactively confirm that we want to run the update.
{{% /notes %}}
Let's walk through these lines to explain what's going on here:
* `pulumi login` to set up credentials for the pulumi backend
* `pulumi stack select dev` to run this against our `dev` stack
* `pulumi up -f` to run our program update. The -f flag skips the preview phase and also skips the need to interactively confirm that we want to run the update.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this callout is for "advanced" understanding and can be skipped if you don't care about digging into the details of what this does. Leaving it in sort of railroads the reader into reading this content even if they don't care, so putting in a callout makes it easy for them to skip past it if they want to.


### Step 4: Setting a debugging breakpoint

Now we can try [setting a breakpoint][vs-code-breakpoints] in our code. Navigate to a line within the code and hit the `F9` key. You'll see a small red dot appear next to the line indicating the breakpoint. You can then run the program again using `F5`. When the execution of the code reaches the line it will pause there.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing to note is that the debugging happens in a different terminal session/window, so if your Pulumi program relies on environment variables (e.g., your AWS creds), you'll need some way to pass them to that session. For example, I kept hitting this error (even after ensuring my AWS creds were current in the embedded terminal) until I realized the debugger wasn't actually using that terminal:

Diagnostics:
  pulumi:providers:aws (default_6_37_1):
    error: pulumi:providers:aws resource 'default_6_37_1' has a problem: unable to validate AWS credentials.
    Details: validating provider credentials: retrieving caller identity from STS: operation error STS: GetCallerIdentity, https response error StatusCode: 403, RequestID: 8e37f328-dfa8-4234-8234-5cca32d6ea48, api error ExpiredToken: The security token included in the request is expired

There's an env property you can set in launch.json to help with this -- e.g., if you use a named AWS_PROFILE (as you probably wouldn't want to hack your actual AWS_* creds into that file). For me, since I use AWS SSO through ESC, adding this line to the shell script before pulumi up did the trick:

eval "$(pulumi env open pulumi/dev-sandbox --format shell)"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this configuration will vary so much by the user's local config (e.g. Windows vs Mac, how they have creds set-up for AWS, etc), I've chosen to just leave this part unexplained rather than to try to figure out a way to explain it in a way that is exhaustive enough to cover all the likely scenarios.


* **Inputs and Outputs are asynchronous futures:** If you've used Pulumi before you will have encountered [`Input<T>`][input-docs] and [`Output<T>`][output-docs] values, which are a core function of the tool. However, at the time that the debugger hits a breakpoint on those values, they are likely not populated with their final value. That means you won't be able to inspect them in the debugger very well. Instead, you will need to add an [`apply(...)`][apply-docs] or [`all(..)`][all-docs] block to the code, and place the breakpoint on the materialized value within that block. This follows all the same rules as accessing those variables in code in a Pulumi program.

* **Limited integration with VS Code:** Unfortunately our technique of running Pulumi in wrapper script as a backgrounded pre-launch task in VS Code leaves some things to be desired. It is different enough from the use case that VS Code had in mind for these features that making things "just work" is a little difficult. For example, we can't easily report on errors in the "Problems" tab. Sometimes VS Code can't tell that the program finished and so you'll have to manually stop the debugging session after Pulumi has completed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes VS Code can't tell that the program finished and so you'll have to manually stop the debugging session after Pulumi has completed.

This happens 100% of the time for me, yeah. I figured this was the expected behavior, but I guess not?

It does sound like this is worth explaining in more detail, though. Like how is it "different from the use case VS Code had in mind"? Does it have something to do with the fact that the Node process is spawned by Pulumi?


* **Limited integration with VS Code:** Unfortunately our technique of running Pulumi in wrapper script as a backgrounded pre-launch task in VS Code leaves some things to be desired. It is different enough from the use case that VS Code had in mind for these features that making things "just work" is a little difficult. For example, we can't easily report on errors in the "Problems" tab. Sometimes VS Code can't tell that the program finished and so you'll have to manually stop the debugging session after Pulumi has completed.

Despite these limitations, Pulumi with VS Code as your IDE provides a rich experience compared to trawlling through unstructured logs, or adding in `console.log(...)` calls to echo out ad-hoc debugging information (aka. [`printf` debugging][printf-debugging]). Also, you can enable this for any language that Pulumi supports. Python, Go, and C# all have popular debuggers and IDEs that can be used in the same manner.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also add this to our own docs, as our coverage of interactive debugging seems to cover only debugging providers (rather than your own IAC).

content/blog/next-level-iac-breakpoint-debugging/index.md Outdated Show resolved Hide resolved
@thoward thoward requested a review from cnunciato May 30, 2024 20:15
@pulumi-bot
Copy link
Collaborator

@pulumi-bot
Copy link
Collaborator

@thoward thoward requested a review from aaronkao May 30, 2024 21:25
Copy link
Contributor

@aaronkao aaronkao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good. Lets ship it


Pulumi gives you a rich IaC debugging experience by enabling breakpoint debugging in your favorite IDE. Let's walk through an example of how to enable a full-featured debugging workflow in [VS Code][vs-code] for TypeScript.

## How Breakpoint Debugging Works
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this section be put in one of these

{{% notes type="info" %}}

And then hidden behind a expander? @cnunciato what do you think?

$ pulumi up
```

Everything runs successfully... but if we navigate to the website, we don't see our updated content?! Oh no! What went wrong? Why isn't there an error message?! Time to put on our debugging hats and figure out what is going on. First, let's set up VS Code to enable breakpoint debugging right in the IDE.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice way to introduce the problem example

@pulumi-bot
Copy link
Collaborator

@thoward thoward merged commit b13c6dc into master May 31, 2024
5 checks passed
@thoward thoward deleted the thoward/next-level-iac-breakpoint-debugging-blog-post branch May 31, 2024 17:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/blog Content issues on blog posts.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants