Emit richer events for resource steps

The engine now emits events with richer metadata during the
ResourceOutputs and ResourcePre callbacks. The CLI can then use this
information to decide if it should display the event or not and how
much of the event to display.

Options dealing with what to display and how to display it have moved
into the CLI and the engine now emits all information for each event.
This commit is contained in:
Matt Ellis 2018-02-04 01:18:06 -08:00
parent 55383c46ba
commit db079b1b0a
10 changed files with 290 additions and 186 deletions

View file

@ -65,16 +65,16 @@ func newDestroyCmd() *cobra.Command {
}
return s.Destroy(proj, root, debug, m, engine.UpdateOptions{
Analyzers: analyzers,
DryRun: preview,
Parallel: parallel,
Analyzers: analyzers,
DryRun: preview,
Parallel: parallel,
Debug: debug,
}, backend.DisplayOptions{
Color: color.Colorization(),
ShowConfig: showConfig,
ShowReplacementSteps: showReplacementSteps,
ShowSames: showSames,
Summary: summary,
Debug: debug,
}, backend.DisplayOptions{
Color: color.Colorization(),
ShowConfig: showConfig,
})
}),
}

View file

@ -53,16 +53,16 @@ func newPreviewCmd() *cobra.Command {
}
return s.Preview(proj, root, debug, engine.UpdateOptions{
Analyzers: analyzers,
DryRun: true,
Parallel: parallel,
Analyzers: analyzers,
DryRun: true,
Parallel: parallel,
Debug: debug,
}, backend.DisplayOptions{
Color: color.Colorization(),
ShowConfig: showConfig,
ShowReplacementSteps: showReplacementSteps,
ShowSames: showSames,
Summary: summary,
Debug: debug,
}, backend.DisplayOptions{
Color: color.Colorization(),
ShowConfig: showConfig,
})
}),
}

View file

@ -61,16 +61,16 @@ func newUpdateCmd() *cobra.Command {
}
return s.Update(proj, root, debug, m, engine.UpdateOptions{
Analyzers: analyzers,
DryRun: preview,
Parallel: parallel,
Analyzers: analyzers,
DryRun: preview,
Parallel: parallel,
Debug: debug,
}, backend.DisplayOptions{
Color: color.Colorization(),
ShowConfig: showConfig,
ShowReplacementSteps: showReplacementSteps,
ShowSames: showSames,
Summary: summary,
Debug: debug,
}, backend.DisplayOptions{
Color: color.Colorization(),
ShowConfig: showConfig,
})
}),
}

View file

@ -590,8 +590,8 @@ func (b *cloudBackend) makeProgramUpdateRequest(stackName tokens.QName, proj *wo
DryRun: opts.DryRun,
Parallel: opts.Parallel,
ShowConfig: false, // This is a legacy option now, the engine will always emit config information
ShowReplacementSteps: opts.ShowReplacementSteps,
ShowSames: opts.ShowSames,
ShowReplacementSteps: false, // This is a legacy option now, the engine will always emit this information
ShowSames: false, // This is a legacy option now, the engine will always emit this information
},
Metadata: apitype.UpdateMetadata{
Message: m.Message,

View file

@ -6,6 +6,9 @@ import "github.com/pulumi/pulumi/pkg/diag/colors"
// DisplayOptions controls how the output of events are rendered
type DisplayOptions struct {
Color colors.Colorization // colorization to apply to events
ShowConfig bool // true if we should show configuration information before updating or previewing
Color colors.Colorization // colorization to apply to events.
ShowConfig bool // true if we should show configuration information.
ShowReplacementSteps bool // true to show the replacement steps in the plan.
ShowSames bool // true to show the resources that aren't updated in addition to updates.
Summary bool // true if we should only summarize resources and operations.
}

View file

@ -13,6 +13,7 @@ import (
"github.com/pulumi/pulumi/pkg/diag"
"github.com/pulumi/pulumi/pkg/diag/colors"
"github.com/pulumi/pulumi/pkg/engine"
"github.com/pulumi/pulumi/pkg/resource"
"github.com/pulumi/pulumi/pkg/resource/deploy"
"github.com/pulumi/pulumi/pkg/util/cmdutil"
"github.com/pulumi/pulumi/pkg/util/contract"
@ -46,6 +47,13 @@ func displayEvents(action string,
displayPreludeEvent(os.Stdout, event.Payload.(engine.PreludeEventPayload), opts)
case engine.SummaryEvent:
displaySummaryEvent(os.Stdout, event.Payload.(engine.SummaryEventPayload), opts)
case engine.ResourceOperationFailed:
displayResourceOperationFailedEvent(os.Stdout,
event.Payload.(engine.ResourceOperationFailedPayload), opts)
case engine.ResourceOutputsEvent:
displayResourceOutputsEvent(os.Stdout, event.Payload.(engine.ResourceOutputsEventPayload), opts)
case engine.ResourcePreEvent:
displayResourcePreEvent(os.Stdout, event.Payload.(engine.ResourcePreEventPayload), opts)
case engine.StdoutColorEvent:
payload := event.Payload.(engine.StdoutEventPayload)
out = os.Stdout
@ -163,6 +171,67 @@ func displayPreludeEvent(out io.Writer, event engine.PreludeEventPayload, opts b
fmt.Fprint(out, opts.Color.Colorize(fmt.Sprintf("%v%v changes:%v\n", colors.SpecUnimportant, action, colors.Reset)))
}
//nolint: gas
func displayResourceOperationFailedEvent(out io.Writer,
event engine.ResourceOperationFailedPayload, opts backend.DisplayOptions) {
fmt.Fprintf(out, "Step #%v failed [%v]: ", event.Steps+1, event.Metadata.Op)
switch event.Status {
case resource.StatusOK:
fmt.Fprint(out, opts.Color.Colorize(
fmt.Sprintf("%vprovider successfully recovered from this failure%v", colors.SpecNote, colors.Reset)))
case resource.StatusUnknown:
fmt.Fprint(out, opts.Color.Colorize(
fmt.Sprintf("%vthis failure was catastrophic and the provider cannot guarantee recovery%v",
colors.SpecAttention, colors.Reset)))
default:
contract.Failf("Unrecognized resource state: %v", event.Status)
}
fmt.Fprint(out, "\n")
}
// nolint: gas
func displayResourcePreEvent(out io.Writer, event engine.ResourcePreEventPayload, opts backend.DisplayOptions) {
if shouldShow(event.Metadata, opts) || isRootStack(event.Metadata) {
fmt.Fprint(out, opts.Color.Colorize(event.Summary))
if !opts.Summary {
fmt.Fprint(out, event.Details)
}
fmt.Fprint(out, opts.Color.Colorize(colors.Reset))
}
}
// nolint: gas
func displayResourceOutputsEvent(out io.Writer, event engine.ResourceOutputsEventPayload, opts backend.DisplayOptions) {
if (shouldShow(event.Metadata, opts) || isRootStack(event.Metadata)) && !opts.Summary {
fmt.Fprint(out, opts.Color.Colorize(event.Text))
}
}
// isRootStack returns true if the step pertains to the rootmost stack component.
func isRootStack(step engine.StepEventMetdata) bool {
return step.URN.Type() == resource.RootStackType
}
// shouldShow returns true if a step should show in the output.
func shouldShow(step engine.StepEventMetdata, opts backend.DisplayOptions) bool {
// For certain operations, whether they are tracked is controlled by flags (to cut down on superfluous output).
if step.Op == deploy.OpSame {
// If the op is the same, it is possible that the resource's metadata changed. In that case, still show it.
if step.Old.Protect != step.New.Protect {
return true
}
return opts.ShowSames
} else if step.Op == deploy.OpCreateReplacement || step.Op == deploy.OpDeleteReplaced {
return opts.ShowReplacementSteps
} else if step.Op == deploy.OpReplace {
return !opts.ShowReplacementSteps
}
return true
}
func plural(s string, c int) string {
if c != 1 {
s += "s"

View file

@ -3,14 +3,11 @@
package engine
import (
"bytes"
"fmt"
"time"
"github.com/pkg/errors"
"github.com/pulumi/pulumi/pkg/diag"
"github.com/pulumi/pulumi/pkg/diag/colors"
"github.com/pulumi/pulumi/pkg/resource"
"github.com/pulumi/pulumi/pkg/resource/deploy"
"github.com/pulumi/pulumi/pkg/util/contract"
@ -18,13 +15,10 @@ import (
// UpdateOptions contains all the settings for customizing how an update (deploy, preview, or destroy) is performed.
type UpdateOptions struct {
Analyzers []string // an optional set of analyzers to run as part of this deployment.
DryRun bool // true if we should just print the plan without performing it.
Parallel int // the degree of parallelism for resource operations (<=1 for serial).
ShowReplacementSteps bool // true to show the replacement steps in the plan.
ShowSames bool // true to show the resources that aren't updated in addition to updates.
Summary bool // true if we should only summarize resources and operations.
Debug bool // true if debugging output it enabled
Analyzers []string // an optional set of analyzers to run as part of this deployment.
DryRun bool // true if we should just print the plan without performing it.
Parallel int // the degree of parallelism for resource operations (<=1 for serial).
Debug bool // true if debugging output it enabled
}
// ResourceChanges contains the aggregate resource changes by operation type.
@ -139,12 +133,10 @@ func (acts *deployActions) OnResourceStepPre(step deploy.Step) (interface{}, err
// Ensure we've marked this step as observed.
acts.Seen[step.URN()] = step
// Report the beginning of the step if appropriate.
if shouldShow(acts.Seen, step, acts.Opts) || isRootStack(step) {
var b bytes.Buffer
printStep(&b, step, acts.Seen, acts.Opts.Summary, false, acts.Opts.Debug)
acts.Opts.Events <- stdOutEventWithColor(&b)
}
indent := stepParentIndent(step, acts.Seen)
summary := getResourcePropertiesSummary(step, indent)
details := getResourcePropertiesDetails(step, indent, false, acts.Opts.Debug)
acts.Opts.Events <- resourcePreEvent(step, indent, summary, details)
// Inform the snapshot service that we are about to perform a step.
return acts.Update.BeginMutation()
@ -154,30 +146,16 @@ func (acts *deployActions) OnResourceStepPost(ctx interface{},
step deploy.Step, status resource.Status, err error) error {
assertSeen(acts.Seen, step)
var b bytes.Buffer
// Report the result of the step.
stepop := step.Op()
if err != nil {
if status == resource.StatusUnknown {
acts.MaybeCorrupt = true
}
// Issue a true, bonafide error.
acts.Opts.Diag.Errorf(diag.ErrorPlanApplyFailed, err)
// Print the state of the resource; we don't issue the error, because the deploy above will do that.
stepnum := acts.Steps + 1
b.WriteString(fmt.Sprintf("Step #%v failed [%v]: ", stepnum, stepop))
switch status {
case resource.StatusOK:
b.WriteString(colors.SpecNote)
b.WriteString("provider successfully recovered from this failure")
case resource.StatusUnknown:
b.WriteString(colors.SpecAttention)
b.WriteString("this failure was catastrophic and the provider cannot guarantee recovery")
acts.MaybeCorrupt = true
default:
contract.Failf("Unrecognized resource state: %v", status)
}
b.WriteString(colors.Reset)
b.WriteString("\n")
acts.Opts.Events <- resourceOperationFailedEvent(step, status, acts.Steps)
} else {
if step.Logical() {
// Increment the counters.
@ -186,13 +164,11 @@ func (acts *deployActions) OnResourceStepPost(ctx interface{},
}
// Also show outputs here, since there might be some from the initial registration.
if shouldShow(acts.Seen, step, acts.Opts) && !acts.Opts.Summary {
printResourceOutputProperties(&b, step, acts.Seen, false, acts.Opts.Debug)
}
indent := stepParentIndent(step, acts.Seen)
text := getResourceOutputsPropertiesString(step, indent, false, acts.Opts.Debug)
acts.Opts.Events <- resourceOutputsEvent(step, indent, text)
}
acts.Opts.Events <- stdOutEventWithColor(&b)
// Write out the current snapshot. Note that even if a failure has occurred, we should still have a
// safe checkpoint. Note that any error that occurs when writing the checkpoint trumps the error reported above.
return ctx.(SnapshotMutation).End(step.Iterator().Snap())
@ -201,12 +177,9 @@ func (acts *deployActions) OnResourceStepPost(ctx interface{},
func (acts *deployActions) OnResourceOutputs(step deploy.Step) error {
assertSeen(acts.Seen, step)
// Print this step's output properties.
if (shouldShow(acts.Seen, step, acts.Opts) || isRootStack(step)) && !acts.Opts.Summary {
var b bytes.Buffer
printResourceOutputProperties(&b, step, acts.Seen, false, acts.Opts.Debug)
acts.Opts.Events <- stdOutEventWithColor(&b)
}
indent := stepParentIndent(step, acts.Seen)
text := getResourceOutputsPropertiesString(step, indent, false, acts.Opts.Debug)
acts.Opts.Events <- resourceOutputsEvent(step, indent, text)
// There's a chance there are new outputs that weren't written out last time.
// We need to perform another snapshot write to ensure they get written out.

View file

@ -3,12 +3,14 @@
package engine
import (
"fmt"
"time"
"github.com/pulumi/pulumi/pkg/diag"
"github.com/pulumi/pulumi/pkg/diag/colors"
"github.com/pulumi/pulumi/pkg/resource"
"github.com/pulumi/pulumi/pkg/resource/config"
"github.com/pulumi/pulumi/pkg/resource/deploy"
"github.com/pulumi/pulumi/pkg/tokens"
"github.com/pulumi/pulumi/pkg/util/contract"
)
@ -23,11 +25,14 @@ type Event struct {
type EventType string
const (
CancelEvent EventType = "cancel"
StdoutColorEvent EventType = "stdoutcolor"
DiagEvent EventType = "diag"
PreludeEvent EventType = "prelude"
SummaryEvent EventType = "summary"
CancelEvent EventType = "cancel"
StdoutColorEvent EventType = "stdoutcolor"
DiagEvent EventType = "diag"
PreludeEvent EventType = "prelude"
SummaryEvent EventType = "summary"
ResourcePreEvent EventType = "resourcepre"
ResourceOutputsEvent EventType = "resourceoutputs"
ResourceOperationFailed EventType = "resourceoperationfailed"
)
func cancelEvent() Event {
@ -58,6 +63,107 @@ type SummaryEventPayload struct {
ResourceChanges ResourceChanges // count of changed resources, useful for reporting
}
type ResourceOperationFailedPayload struct {
Metadata StepEventMetdata
Status resource.Status
Steps int
}
type ResourceOutputsEventPayload struct {
Metadata StepEventMetdata
Indent int
Text string
}
type ResourcePreEventPayload struct {
Metadata StepEventMetdata
Indent int
Summary string
Details string
}
type StepEventMetdata struct {
Op deploy.StepOp // the operation performed by this step.
URN resource.URN // the resource URN (for before and after).
Type tokens.Type // the type affected by this step.
Old *StepEventStateMetadata // the state of the resource before performing this step.
New *StepEventStateMetadata // the state of the resource after performing this step.
Res *StepEventStateMetadata // the latest state for the resource that is known (worst case, old).
Logical bool // true if this step represents a logical operation in the program.
}
type StepEventStateMetadata struct {
Type tokens.Type // the resource's type.
URN resource.URN // the resource's object urn, a human-friendly, unique name for the resource.
Custom bool // true if the resource is custom, managed by a plugin.
Delete bool // true if this resource is pending deletion due to a replacement.
ID resource.ID // the resource's unique ID, assigned by the resource provider (or blank if none/uncreated).
Parent resource.URN // an optional parent URN that this resource belongs to.
Protect bool // true to "protect" this resource (protected resources cannot be deleted).
}
func makeStepEventMetadata(step deploy.Step) StepEventMetdata {
return StepEventMetdata{
Op: step.Op(),
URN: step.URN(),
Type: step.Type(),
Old: makeStepEventStateMetadata(step.Old()),
New: makeStepEventStateMetadata(step.New()),
Res: makeStepEventStateMetadata(step.Res()),
Logical: step.Logical(),
}
}
func makeStepEventStateMetadata(state *resource.State) *StepEventStateMetadata {
if state == nil {
return nil
}
return &StepEventStateMetadata{
Type: state.Type,
URN: state.URN,
Custom: state.Custom,
Delete: state.Delete,
ID: state.ID,
Parent: state.Parent,
Protect: state.Protect,
}
}
func resourceOperationFailedEvent(step deploy.Step, status resource.Status, steps int) Event {
return Event{
Type: ResourceOperationFailed,
Payload: ResourceOperationFailedPayload{
Metadata: makeStepEventMetadata(step),
Status: status,
Steps: steps,
},
}
}
func resourceOutputsEvent(step deploy.Step, indent int, text string) Event {
return Event{
Type: ResourceOutputsEvent,
Payload: ResourceOutputsEventPayload{
Metadata: makeStepEventMetadata(step),
Indent: indent,
Text: text,
},
}
}
func resourcePreEvent(step deploy.Step, indent int, summary string, details string) Event {
return Event{
Type: ResourcePreEvent,
Payload: ResourcePreEventPayload{
Metadata: makeStepEventMetadata(step),
Indent: indent,
Summary: summary,
Details: details,
},
}
}
func preludeEvent(isPreview bool, cfg config.Map) Event {
configStringMap := make(map[string]string, len(cfg))
for k, v := range cfg {
@ -100,16 +206,6 @@ func updateSummaryEvent(maybeCorrupt bool, duration time.Duration, resourceChang
}
}
func stdOutEventWithColor(s fmt.Stringer) Event {
return Event{
Type: StdoutColorEvent,
Payload: StdoutEventPayload{
Message: s.String(),
Color: colors.Raw,
},
}
}
func diagDebugEvent(msg string) Event {
return Event{
Type: DiagEvent,

View file

@ -209,29 +209,6 @@ func assertSeen(seen map[resource.URN]deploy.Step, step deploy.Step) {
contract.Assertf(has, "URN '%v' had not been marked as seen", step.URN())
}
// shouldShow returns true if a step should show in the output.
func shouldShow(seen map[resource.URN]deploy.Step, step deploy.Step, opts deployOptions) bool {
// For certain operations, whether they are tracked is controlled by flags (to cut down on superfluous output).
if step.Op() == deploy.OpSame {
// If the op is the same, it is possible that the resource's metadata changed. In that case, still show it.
if step.Old().Protect != step.New().Protect {
return true
}
return opts.ShowSames
} else if step.Op() == deploy.OpCreateReplacement || step.Op() == deploy.OpDeleteReplaced {
return opts.ShowReplacementSteps
} else if step.Op() == deploy.OpReplace {
return !opts.ShowReplacementSteps
}
return true
}
// isRootStack returns true if the step pertains to the rootmost stack component.
func isRootStack(step deploy.Step) bool {
return step.URN().Type() == resource.RootStackType
}
// stepParentIndent computes a step's parent indentation. If print is true, it also prints parents as it goes.
func stepParentIndent(step deploy.Step, seen map[resource.URN]deploy.Step) int {
indent := 0
@ -249,39 +226,6 @@ func stepParentIndent(step deploy.Step, seen map[resource.URN]deploy.Step) int {
return indent
}
func printStep(b *bytes.Buffer, step deploy.Step, seen map[resource.URN]deploy.Step,
summary bool, planning bool, debug bool) {
op := step.Op()
// First, indent to the same level as this resource has parents, and toggle the level of detail accordingly.
// TODO[pulumi/pulumi#340]: this isn't entirely correct. Conventionally, all children are created adjacent to
// their parents, so this often does the right thing, but not always. For instance, we can have interleaved
// infrastructure that gets emitted in the middle of the flow, making things look like they are parented
// incorrectly. The real solution here is to have a more first class way of structuring the output.
indent := stepParentIndent(step, seen)
// Print the indentation.
b.WriteString(getIndentationString(indent, op, false))
// First, print out the operation's prefix.
b.WriteString(op.Prefix())
// Next, print the resource type (since it is easy on the eyes and can be quickly identified).
printStepHeader(b, step)
// Next print the resource URN, properties, etc.
var replaces []resource.PropertyKey
if step.Op() == deploy.OpCreateReplacement {
replaces = step.(*deploy.CreateStep).Keys()
} else if step.Op() == deploy.OpReplace {
replaces = step.(*deploy.ReplaceStep).Keys()
}
printResourceProperties(b, step.URN(), step.Old(), step.New(), replaces, summary, planning, indent, op, debug)
// Reset the color -- we're done.
b.WriteString(colors.Reset)
}
func printStepHeader(b *bytes.Buffer, step deploy.Step) {
var extra string
old := step.Old()
@ -337,16 +281,26 @@ func writeVerbatim(b *bytes.Buffer, op deploy.StepOp, value string) {
writeWithIndentNoPrefix(b, 0, op, "%s", value)
}
func printResourceProperties(
b *bytes.Buffer, urn resource.URN, old *resource.State, new *resource.State,
replaces []resource.PropertyKey, summary bool, planning bool, indent int, op deploy.StepOp, debug bool) {
func getResourcePropertiesSummary(step deploy.Step, indent int) string {
var b bytes.Buffer
indent++
op := step.Op()
urn := step.URN()
old := step.Old()
// Print the indentation.
b.WriteString(getIndentationString(indent, op, false))
// First, print out the operation's prefix.
b.WriteString(op.Prefix())
// Next, print the resource type (since it is easy on the eyes and can be quickly identified).
printStepHeader(&b, step)
// For these simple properties, print them as 'same' if they're just an update or replace.
simplePropOp := considerSameIfNotCreateOrDelete(op)
// Print out the URN and, if present, the ID, as "pseudo-properties".
// Print out the URN and, if present, the ID, as "pseudo-properties" and indent them.
var id resource.ID
if old != nil {
id = old.ID
@ -354,22 +308,40 @@ func printResourceProperties(
// Always print the ID and URN.
if id != "" {
writeWithIndentNoPrefix(b, indent, simplePropOp, "[id=%s]\n", string(id))
writeWithIndentNoPrefix(&b, indent+1, simplePropOp, "[id=%s]\n", string(id))
}
if urn != "" {
writeWithIndentNoPrefix(b, indent, simplePropOp, "[urn=%s]\n", urn)
writeWithIndentNoPrefix(&b, indent+1, simplePropOp, "[urn=%s]\n", urn)
}
// If not summarizing, print all of the properties associated with this resource.
if !summary {
if old == nil && new != nil {
printObject(b, new.Inputs, planning, indent, op, false, debug)
} else if new == nil && old != nil {
printObject(b, old.Inputs, planning, indent, op, false, debug)
} else {
printOldNewDiffs(b, old.Inputs, new.Inputs, replaces, planning, indent, op, debug)
}
return b.String()
}
func getResourcePropertiesDetails(step deploy.Step, indent int, planning bool, debug bool) string {
var b bytes.Buffer
// indent everything an additional level, like other properties.
indent++
var replaces []resource.PropertyKey
if step.Op() == deploy.OpCreateReplacement {
replaces = step.(*deploy.CreateStep).Keys()
} else if step.Op() == deploy.OpReplace {
replaces = step.(*deploy.ReplaceStep).Keys()
}
old := step.Old()
new := step.New()
if old == nil && new != nil {
printObject(&b, new.Inputs, planning, indent, step.Op(), false, debug)
} else if new == nil && old != nil {
printObject(&b, old.Inputs, planning, indent, step.Op(), false, debug)
} else {
printOldNewDiffs(&b, old.Inputs, new.Inputs, replaces, planning, indent, step.Op(), debug)
}
return b.String()
}
func maxKey(keys []resource.PropertyKey) int {
@ -401,18 +373,16 @@ func printObject(
// printResourceOutputProperties prints only those properties that either differ from the input properties or, if
// there is an old snapshot of the resource, differ from the prior old snapshot's output properties.
func printResourceOutputProperties(b *bytes.Buffer, step deploy.Step,
seen map[resource.URN]deploy.Step, planning bool, debug bool) {
func getResourceOutputsPropertiesString(step deploy.Step, indent int, planning bool, debug bool) string {
var b bytes.Buffer
// Only certain kinds of steps have output properties associated with them.
new := step.New()
if new == nil || new.Outputs == nil {
return
return ""
}
op := considerSameIfNotCreateOrDelete(step.Op())
// Now compute the indentation level, in part based on the parents.
indent := stepParentIndent(step, seen)
// First fetch all the relevant property maps that we may consult.
ins := new.Inputs
outs := new.Outputs
@ -434,14 +404,16 @@ func printResourceOutputProperties(b *bytes.Buffer, step deploy.Step,
if print {
if firstout {
writeWithIndentNoPrefix(b, indent, op, "---outputs:---\n")
writeWithIndentNoPrefix(&b, indent, op, "---outputs:---\n")
firstout = false
}
printPropertyTitle(b, string(k), maxkey, indent, op, false)
printPropertyValue(b, out, planning, indent, op, false, debug)
printPropertyTitle(&b, string(k), maxkey, indent, op, false)
printPropertyValue(&b, out, planning, indent, op, false, debug)
}
}
}
return b.String()
}
func considerSameIfNotCreateOrDelete(op deploy.StepOp) deploy.StepOp {

View file

@ -3,8 +3,6 @@
package engine
import (
"bytes"
"github.com/pkg/errors"
"github.com/pulumi/pulumi/pkg/resource"
"github.com/pulumi/pulumi/pkg/resource/deploy"
@ -81,12 +79,11 @@ func newPreviewActions(opts deployOptions) *previewActions {
func (acts *previewActions) OnResourceStepPre(step deploy.Step) (interface{}, error) {
acts.Seen[step.URN()] = step
// Print this step information (resource and all its properties).
if shouldShow(acts.Seen, step, acts.Opts) || isRootStack(step) {
var b bytes.Buffer
printStep(&b, step, acts.Seen, acts.Opts.Summary, true, acts.Opts.Debug)
acts.Opts.Events <- stdOutEventWithColor(&b)
}
indent := stepParentIndent(step, acts.Seen)
summary := getResourcePropertiesSummary(step, indent)
details := getResourcePropertiesDetails(step, indent, true, acts.Opts.Debug)
acts.Opts.Events <- resourcePreEvent(step, indent, summary, details)
return nil, nil
}
@ -101,10 +98,7 @@ func (acts *previewActions) OnResourceStepPost(ctx interface{},
acts.Ops[step.Op()]++
}
// Also show outputs here, since there might be some from the initial registration.
if shouldShow(acts.Seen, step, acts.Opts) && !acts.Opts.Summary {
_ = acts.OnResourceOutputs(step)
}
_ = acts.OnResourceOutputs(step)
}
return nil
}
@ -112,11 +106,8 @@ func (acts *previewActions) OnResourceStepPost(ctx interface{},
func (acts *previewActions) OnResourceOutputs(step deploy.Step) error {
assertSeen(acts.Seen, step)
// Print this step's output properties.
if (shouldShow(acts.Seen, step, acts.Opts) || isRootStack(step)) && !acts.Opts.Summary {
var b bytes.Buffer
printResourceOutputProperties(&b, step, acts.Seen, true, acts.Opts.Debug)
acts.Opts.Events <- stdOutEventWithColor(&b)
}
indent := stepParentIndent(step, acts.Seen)
text := getResourceOutputsPropertiesString(step, indent, true, acts.Opts.Debug)
acts.Opts.Events <- resourceOutputsEvent(step, indent, text)
return nil
}