Print PolicyPacks run as part of update summary
Fixes pulumi/pulumi-policy#69.
This commit is contained in:
parent
80504bf0bc
commit
429bde332b
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
38
pkg/backend/display/tableutil.go
Normal file
38
pkg/backend/display/tableutil.go
Normal 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)
|
||||
}
|
|
@ -95,6 +95,7 @@ type SummaryEventPayload struct {
|
|||
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,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue