Print PolicyPacks run as part of update summary

Fixes pulumi/pulumi-policy#69.
This commit is contained in:
Alex Clemmer 2019-09-25 18:42:30 -07:00
parent 80504bf0bc
commit 429bde332b
9 changed files with 92 additions and 29 deletions

View file

@ -74,6 +74,8 @@ type SummaryEvent struct {
// ResourceChanges contains the count for resource change by type. The keys are deploy.StepOp,
// which is not exported in this package.
ResourceChanges map[string]int `json:"resourceChanges"`
// PolicyPacks run during update. Maps PolicyPackName -> version.
PolicyPacks map[string]string
}
// DiffKind describes the kind of a particular property diff.

View file

@ -182,6 +182,31 @@ func renderSummaryEvent(action apitype.UpdateKind, event engine.SummaryEventPayl
}
}
// Print policy packs loaded. Data is rendered as a table of {policy-pack-name, version}.
if len(event.PolicyPacks) > 0 {
fprintIgnoreError(out, opts.Color.Colorize(fmt.Sprintf("\n%sPolicy Packs run:%s\n",
colors.SpecHeadline, colors.Reset)))
// Calculate column width for the `name` column
const nameColHeader = "Name"
maxNameLen := len(nameColHeader)
for pp := range event.PolicyPacks {
if l := len(pp); l > maxNameLen {
maxNameLen = l
}
}
// Print the column headers and the policy packs.
fprintIgnoreError(out, opts.Color.Colorize(
fmt.Sprintf(" %s%s%s\n",
columnHeader(nameColHeader), messagePadding(nameColHeader, maxNameLen, 2),
columnHeader("Version"))))
for pp, ver := range event.PolicyPacks {
fprintIgnoreError(out, opts.Color.Colorize(
fmt.Sprintf(" %s%s%s\n", pp, messagePadding(pp, maxNameLen, 2), ver)))
}
}
summaryPieces := []string{}
if changeKindCount >= 2 {
// Only if we made multiple types of changes do we need to print out the total number of

View file

@ -88,6 +88,7 @@ func ConvertEngineEvent(e engine.Event) (apitype.EngineEvent, error) {
MaybeCorrupt: p.MaybeCorrupt,
DurationSeconds: int(p.Duration.Seconds()),
ResourceChanges: changes,
PolicyPacks: p.PolicyPacks,
}
case engine.ResourcePreEvent:

View file

@ -296,25 +296,14 @@ func ShowProgressEvents(op string, action apitype.UpdateKind, stack tokens.QName
func (display *ProgressDisplay) getMessagePadding(
uncolorizedColumns []string, columnIndex int, maxColumnLengths []int) string {
extraWhitespace := 1
// In the terminal we try to align the status messages for each resource.
// do not bother with this in the non-terminal case.
extraWhitespace := " "
if columnIndex >= 0 && display.isTerminal {
column := uncolorizedColumns[columnIndex]
maxLength := maxColumnLengths[columnIndex]
extraWhitespace = maxLength - utf8.RuneCountInString(column)
contract.Assertf(extraWhitespace >= 0, "Neg whitespace. %v %s", maxLength, column)
// Place two spaces between all columns (except after the first column). The first
// column already has a ": " so it doesn't need the extra space.
if columnIndex >= 0 {
extraWhitespace += 2
}
extraWhitespace = messagePadding(column, maxLength, 2)
}
return strings.Repeat(" ", extraWhitespace)
return extraWhitespace
}
// Gets the fully padded message to be shown. The message will always include the ID of the

View file

@ -86,12 +86,8 @@ func (data *headerRowData) SetDisplayOrderIndex(time int) {
func (data *headerRowData) ColorizedColumns() []string {
if len(data.columns) == 0 {
blue := func(msg string) string {
return colors.Underline + colors.BrightBlue + msg + colors.Reset
}
header := func(msg string) string {
return blue(msg)
return columnHeader(msg)
}
var statusColumn string

View file

@ -0,0 +1,38 @@
// Copyright 2016-2018, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package display
import (
"strings"
"unicode/utf8"
"github.com/pulumi/pulumi/pkg/diag/colors"
"github.com/pulumi/pulumi/pkg/util/contract"
)
func columnHeader(msg string) string {
return colors.Underline + colors.BrightBlue + msg + colors.Reset
}
func messagePadding(uncolorizedColumn string, maxLength, extraPadding int) string {
extraWhitespace := maxLength - utf8.RuneCountInString(uncolorizedColumn)
contract.Assertf(extraWhitespace >= 0, "Neg whitespace. %v %s", maxLength, uncolorizedColumn)
// Place two spaces between all columns (except after the first column). The first
// column already has a ": " so it doesn't need the extra space.
extraWhitespace += extraPadding
return strings.Repeat(" ", extraWhitespace)
}

View file

@ -91,10 +91,11 @@ type PreludeEventPayload struct {
}
type SummaryEventPayload struct {
IsPreview bool // true if this summary is for a plan operation
MaybeCorrupt bool // true if one or more resources may be corrupt
Duration time.Duration // the duration of the entire update operation (zero values for previews)
ResourceChanges ResourceChanges // count of changed resources, useful for reporting
IsPreview bool // true if this summary is for a plan operation
MaybeCorrupt bool // true if one or more resources may be corrupt
Duration time.Duration // the duration of the entire update operation (zero values for previews)
ResourceChanges ResourceChanges // count of changed resources, useful for reporting
PolicyPacks map[string]string // {policy-pack: version} for each policy pack applied
}
type ResourceOperationFailedPayload struct {
@ -424,7 +425,7 @@ func (e *eventEmitter) preludeEvent(isPreview bool, cfg config.Map) {
}
}
func (e *eventEmitter) previewSummaryEvent(resourceChanges ResourceChanges) {
func (e *eventEmitter) previewSummaryEvent(resourceChanges ResourceChanges, policyPacks map[string]string) {
contract.Requiref(e != nil, "e", "!= nil")
e.Chan <- Event{
@ -434,12 +435,13 @@ func (e *eventEmitter) previewSummaryEvent(resourceChanges ResourceChanges) {
MaybeCorrupt: false,
Duration: 0,
ResourceChanges: resourceChanges,
PolicyPacks: policyPacks,
},
}
}
func (e *eventEmitter) updateSummaryEvent(maybeCorrupt bool,
duration time.Duration, resourceChanges ResourceChanges) {
duration time.Duration, resourceChanges ResourceChanges, policyPacks map[string]string) {
contract.Requiref(e != nil, "e", "!= nil")
e.Chan <- Event{
@ -449,6 +451,7 @@ func (e *eventEmitter) updateSummaryEvent(maybeCorrupt bool,
MaybeCorrupt: maybeCorrupt,
Duration: duration,
ResourceChanges: resourceChanges,
PolicyPacks: policyPacks,
},
}
}

View file

@ -215,7 +215,9 @@ func (planResult *planResult) Close() error {
}
// printPlan prints the plan's result to the plan's Options.Events stream.
func printPlan(ctx *Context, planResult *planResult, dryRun bool) (ResourceChanges, result.Result) {
func printPlan(ctx *Context, planResult *planResult, dryRun bool, policies map[string]string,
) (ResourceChanges, result.Result) {
planResult.Options.Events.preludeEvent(dryRun, planResult.Ctx.Update.GetTarget().Config)
// Walk the plan's steps and and pretty-print them out.
@ -230,7 +232,7 @@ func printPlan(ctx *Context, planResult *planResult, dryRun bool) (ResourceChang
// Emit an event with a summary of operation counts.
changes := ResourceChanges(actions.Ops)
planResult.Options.Events.previewSummaryEvent(changes)
planResult.Options.Events.previewSummaryEvent(changes, policies)
return changes, nil
}

View file

@ -227,6 +227,11 @@ func update(ctx *Context, info *planContext, opts planOptions, dryRun bool) (Res
return nil, result.FromError(err)
}
policies := map[string]string{}
for _, p := range opts.RequiredPolicies {
policies[p.Name()] = p.Version()
}
var resourceChanges ResourceChanges
var res result.Result
if planResult != nil {
@ -241,7 +246,7 @@ func update(ctx *Context, info *planContext, opts planOptions, dryRun bool) (Res
if dryRun {
// If a dry run, just print the plan, don't actually carry out the deployment.
resourceChanges, res = printPlan(ctx, planResult, dryRun)
resourceChanges, res = printPlan(ctx, planResult, dryRun, policies)
} else {
// Otherwise, we will actually deploy the latest bits.
opts.Events.preludeEvent(dryRun, planResult.Ctx.Update.GetTarget().Config)
@ -254,8 +259,10 @@ func update(ctx *Context, info *planContext, opts planOptions, dryRun bool) (Res
resourceChanges = ResourceChanges(actions.Ops)
if len(resourceChanges) != 0 {
// Print out the total number of steps performed (and their kinds), the duration, and any summary info.
opts.Events.updateSummaryEvent(actions.MaybeCorrupt, time.Since(start), resourceChanges)
opts.Events.updateSummaryEvent(actions.MaybeCorrupt, time.Since(start),
resourceChanges, policies)
}
}
}