This changes the CLI interface in a few ways: * `pulumi preview` is back! The alternative of saying `pulumi update --preview` just felt awkward, and it's a common operation to want to perform. Let's just make it work. * There are two flags consistent across all update commands, `update`, `refresh`, and `destroy`: - `--skip-preview` will skip the preview step. Note that this does *not* skip the prompt to confirm that you'd like to proceed. Indeed, it will still prompt, with a little warning text about the fact that the preview has been skipped. * `--yes` will auto-approve the updates. This lands us in a simpler and more intuitive spot for common scenarios.
102 lines
2.5 KiB
Go
102 lines
2.5 KiB
Go
// Copyright 2018, Pulumi Corporation. All rights reserved.
|
|
|
|
package engine
|
|
|
|
import (
|
|
"github.com/pulumi/pulumi/pkg/diag"
|
|
"github.com/pulumi/pulumi/pkg/resource"
|
|
"github.com/pulumi/pulumi/pkg/resource/deploy"
|
|
"github.com/pulumi/pulumi/pkg/util/contract"
|
|
)
|
|
|
|
func Preview(u UpdateInfo, ctx *Context, opts UpdateOptions) (ResourceChanges, error) {
|
|
contract.Require(u != nil, "u")
|
|
contract.Require(ctx != nil, "ctx")
|
|
|
|
defer func() { ctx.Events <- cancelEvent() }()
|
|
|
|
info, err := newPlanContext(u, "preview", ctx.ParentSpan)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer info.Close()
|
|
|
|
emitter := makeEventEmitter(ctx.Events, u)
|
|
return preview(ctx, info, planOptions{
|
|
UpdateOptions: opts,
|
|
SourceFunc: newUpdateSource,
|
|
Events: emitter,
|
|
Diag: newEventSink(emitter),
|
|
})
|
|
}
|
|
|
|
func preview(ctx *Context, info *planContext, opts planOptions) (ResourceChanges, error) {
|
|
result, err := plan(info, opts, true /*dryRun*/)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if result != nil {
|
|
defer contract.IgnoreClose(result)
|
|
|
|
// Make the current working directory the same as the program's, and restore it upon exit.
|
|
done, err := result.Chdir()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer done()
|
|
|
|
return printPlan(ctx, result, true /*dryRun*/)
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
type previewActions struct {
|
|
Refresh bool
|
|
Ops map[deploy.StepOp]int
|
|
Opts planOptions
|
|
Seen map[resource.URN]deploy.Step
|
|
}
|
|
|
|
func newPreviewActions(opts planOptions) *previewActions {
|
|
return &previewActions{
|
|
Ops: make(map[deploy.StepOp]int),
|
|
Opts: opts,
|
|
Seen: make(map[resource.URN]deploy.Step),
|
|
}
|
|
}
|
|
|
|
func (acts *previewActions) OnResourceStepPre(step deploy.Step) (interface{}, error) {
|
|
acts.Seen[step.URN()] = step
|
|
acts.Opts.Events.resourcePreEvent(step, true /*planning*/, acts.Opts.Debug)
|
|
return nil, nil
|
|
}
|
|
|
|
func (acts *previewActions) OnResourceStepPost(ctx interface{},
|
|
step deploy.Step, status resource.Status, err error) error {
|
|
assertSeen(acts.Seen, step)
|
|
|
|
if err != nil {
|
|
acts.Opts.Diag.Errorf(diag.GetPreviewFailedError(step.URN()), err)
|
|
} else {
|
|
// Track the operation if shown and/or if it is a logically meaningful operation.
|
|
if step.Logical() {
|
|
acts.Ops[step.Op()]++
|
|
}
|
|
|
|
_ = acts.OnResourceOutputs(step)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (acts *previewActions) OnResourceOutputs(step deploy.Step) error {
|
|
assertSeen(acts.Seen, step)
|
|
|
|
// Print the resource outputs separately, unless this is a refresh in which case they are already printed.
|
|
if !acts.Opts.SkipOutputs {
|
|
acts.Opts.Events.resourceOutputsEvent(step, true /*planning*/, acts.Opts.Debug)
|
|
}
|
|
|
|
return nil
|
|
}
|