Implement plan -out with cloud integration#33418
Implement plan -out with cloud integration#33418nfagerlund merged 9 commits intocli-team/saved-cloud-plansfrom
plan -out with cloud integration#33418Conversation
da67c2e to
e2aae10
Compare
brandonc
left a comment
There was a problem hiding this comment.
So exciting to get rid of that error
| if op.PlanOutPath != "" { | ||
| diags = diags.Append(tfdiags.Sourceless( | ||
| tfdiags.Error, | ||
| "Saving a generated plan is currently not supported", |
There was a problem hiding this comment.
I love it when "currently" becomes the past 😆
|
@Uk1288 That IS odd! I also expected it to not show that... But this relates to what @sebasslash brought up, too, so let's talk tomorrow and see if we actually want to skip saving the plan at all. (If so, I figure the way to suppress the message will come out of that.) |
bf55cfe to
989a704
Compare
so we don't have to remember the format version number
This displays the footer that explains what happens if you saved a plan file (or neglected to). We never used to show it, because we didn't support -out.
This was wrong when err != nil and saveErr == nil.
On further consideration, this is a nonsensical thing to do, and it doesn't match the behavior of plain CLI! Additionally, skip next steps message on failure.
989a704 to
fecb608
Compare
sebasslash
left a comment
There was a problem hiding this comment.
Code-wise this looks awesome to me 👍. I have not smoke tested yet so I won't directly approve.
One minor thing: would it be possible to unit test instances where the run errors but the plan should be saved? I imagine with the mock API that might not be trivial to create. Or perhaps this might be better suited for an integration test.
brandonc
left a comment
There was a problem hiding this comment.
Just some minor feedback on return values
internal/cloud/backend_plan.go
Outdated
| // If the run errored, exit before checking whether to save a plan file | ||
| run, err := b.plan(stopCtx, cancelCtx, op, w) | ||
| if err != nil { | ||
| return run, err |
There was a problem hiding this comment.
If we return an error, we should be make it clear that we are returning nil, err, I think.
internal/cloud/backend_plan.go
Outdated
| op.View.PlanNextStep(op.PlanOutPath, "") | ||
| } | ||
|
|
||
| return run, err |
There was a problem hiding this comment.
Same suggestion here. I think we want to be clear about returning nil if we are also returning an error.
sebasslash
left a comment
There was a problem hiding this comment.
Smoke tested and most things are looking good. I've got some concerns (and are mostly on the TFC side of things):
What worked:
- Specifying
-outcreates a JSON artifact representing the remote plan in my root dir - Specifying the created artifact in
terraform applyindeed triggers a run - Can't re-apply a saved plan
- Error is handled when specified plan file doesn't exist, and when the artifact is modified in some way with an incorrect value.
What did not work:
- The state version was not processed correctly (no workspace resources/outputs showing). If I try to run a regular apply afterwards, I get some 'drift detected (delete)', and Terraform taints the resources in my config.
- I might be wrong here, but I expected the run to show up on the UI upon running
terraform plan -out. It only appeared once the plan was applied. This was quite confusing if the run is the first on a workspace. - I expected the plan file to be deleted once applied since it can no longer be used.
| if err != nil { | ||
| return nil, err | ||
| } |
There was a problem hiding this comment.
If we reach this block, run should not be nil. Wondering if there might be unintended consequences with not returning the run at this point.
There was a problem hiding this comment.
I think it's okay — the caller really needs to assume that the primary value is NOT safe to mess with if they got an err, and that's kind of just a limitation of having exactly two return values for failure handling.
There was a problem hiding this comment.
I've discussed with @nfagerlund internally and several of the TFC-related issues I ran into turned out to be issues with my local dev or already planned work. ![]()
On the matter of removing the remote plan artifact on your FS upon applying the saved plan, it is expected to match the existing OSS behavior which does not delete the plan binary.
|
(For posterity: the issue with the plan not appearing in the runs list is a pure UI bug in TFC: some slapstick around the run list taking its ball and going home if there's no "current" run, which is the case if you've never done an eager run or fully confirmed a saved plan run. Addressed in the UI PR!) |
|
Reminder for the merging maintainer: if this is a user-visible change, please update the changelog on the appropriate release branch. |
|
I'm going to lock this pull request because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active contributions. |

This is it! We can use
terraform plan -out my.tfplanin cloud mode to create an arbitrary number of saved plan runs, and thenterraform apply my.tfplanone of the resulting plans to make it the workspace's next apply.Because
save-planis a new attribute in the runs API, it requires an update to go-tfe — hashicorp/go-tfe#724To smoke test this: Make sure your TFC org has been added to the saved-cloud-plans feature flag.