Expose change summaries from the backend.

This is a smallish refactoring that exposes the resource change
summaries reported by the engine from the relevant backend methods.
This commit is contained in:
Pat Gavlin 2018-05-15 17:14:53 -07:00
parent 016ae4acba
commit e3020e820b
10 changed files with 64 additions and 54 deletions

View file

@ -84,7 +84,7 @@ func newDestroyCmd() *cobra.Command {
Debug: debug,
}
err = s.Destroy(commandContext(), proj, root, m, opts, cancellationScopes)
_, err = s.Destroy(commandContext(), proj, root, m, opts, cancellationScopes)
if err == context.Canceled {
return errors.New("destroy cancelled")
}

View file

@ -75,7 +75,8 @@ func newPreviewCmd() *cobra.Command {
Debug: debug,
},
}
return s.Preview(commandContext(), proj, root, m, opts, cancellationScopes)
_, err = s.Preview(commandContext(), proj, root, m, opts, cancellationScopes)
return err
}),
}

View file

@ -84,7 +84,7 @@ func newRefreshCmd() *cobra.Command {
Debug: debug,
}
err = s.Refresh(commandContext(), proj, root, m, opts, cancellationScopes)
_, err = s.Refresh(commandContext(), proj, root, m, opts, cancellationScopes)
if err == context.Canceled {
return errors.New("refresh cancelled")
}

View file

@ -88,7 +88,7 @@ func newUpdateCmd() *cobra.Command {
Debug: debug,
}
err = s.Update(commandContext(), proj, root, m, opts, cancellationScopes)
_, err = s.Update(commandContext(), proj, root, m, opts, cancellationScopes)
if err == context.Canceled {
return errors.New("update cancelled")
}

View file

@ -64,16 +64,16 @@ type Backend interface {
// Preview shows what would be updated given the current workspace's contents.
Preview(ctx context.Context, stackRef StackReference, proj *workspace.Project, root string,
m UpdateMetadata, opts UpdateOptions, scopes CancellationScopeSource) error
m UpdateMetadata, opts UpdateOptions, scopes CancellationScopeSource) (engine.ResourceChanges, error)
// Update updates the target stack with the current workspace's contents (config and code).
Update(ctx context.Context, stackRef StackReference, proj *workspace.Project, root string,
m UpdateMetadata, opts UpdateOptions, scopes CancellationScopeSource) error
m UpdateMetadata, opts UpdateOptions, scopes CancellationScopeSource) (engine.ResourceChanges, error)
// Refresh refreshes the stack's state from the cloud provider.
Refresh(ctx context.Context, stackRef StackReference, proj *workspace.Project, root string,
m UpdateMetadata, opts UpdateOptions, scopes CancellationScopeSource) error
m UpdateMetadata, opts UpdateOptions, scopes CancellationScopeSource) (engine.ResourceChanges, error)
// Destroy destroys all of this stack's resources.
Destroy(ctx context.Context, stackRef StackReference, proj *workspace.Project, root string,
m UpdateMetadata, opts UpdateOptions, scopes CancellationScopeSource) error
m UpdateMetadata, opts UpdateOptions, scopes CancellationScopeSource) (engine.ResourceChanges, error)
// GetHistory returns all updates for the stack. The returned UpdateInfo slice will be in
// descending order (newest first).

View file

@ -551,7 +551,8 @@ func createDiff(events []engine.Event, displayOpts backend.DisplayOptions) strin
func (b *cloudBackend) PreviewThenPrompt(
ctx context.Context, updateKind client.UpdateKind, stack backend.Stack, pkg *workspace.Project, root string,
m backend.UpdateMetadata, opts backend.UpdateOptions, scopes backend.CancellationScopeSource) (bool, error) {
m backend.UpdateMetadata, opts backend.UpdateOptions,
scopes backend.CancellationScopeSource) (engine.ResourceChanges, bool, error) {
// create a channel to hear about the update events from the engine. this will be used so that
// we can build up the diff display in case the user asks to see the details of the diff
@ -574,25 +575,25 @@ func (b *cloudBackend) PreviewThenPrompt(
}()
// Perform the update operations, passing true for dryRun, so that we get a preview.
hasChanges := true
changes, hasChanges := engine.ResourceChanges(nil), true
if !opts.SkipPreview {
changes, err := b.updateStack(
c, err := b.updateStack(
ctx, updateKind, stack, pkg, root, m, opts, eventsChannel, true /*dryRun*/, scopes)
if err != nil {
return false, err
return c, false, err
}
// TODO(ellismg)[pulumi/pulumi#1347]: Work around 1347 by forcing a choice when running a preview against a PPC
hasChanges = changes.HasChanges() || !stack.(Stack).RunLocally()
changes, hasChanges = c, c.HasChanges() || !stack.(Stack).RunLocally()
}
// If there are no changes, or we're auto-approving or just previewing, we can skip the confirmation prompt.
if !hasChanges || opts.AutoApprove || updateKind == client.UpdateKindPreview {
return hasChanges, nil
return changes, hasChanges, nil
}
// Otherwise, ensure the user wants to proceed.
return hasChanges, confirmBeforeUpdating(updateKind, stack, events, opts)
return changes, hasChanges, confirmBeforeUpdating(updateKind, stack, events, opts)
}
// confirmBeforeUpdating asks the user whether to proceed. A nil error means yes.
@ -648,12 +649,13 @@ func confirmBeforeUpdating(updateKind client.UpdateKind, stack backend.Stack,
func (b *cloudBackend) PreviewThenPromptThenExecute(
ctx context.Context, updateKind client.UpdateKind, stackRef backend.StackReference, pkg *workspace.Project,
root string, m backend.UpdateMetadata, opts backend.UpdateOptions, scopes backend.CancellationScopeSource) error {
root string, m backend.UpdateMetadata, opts backend.UpdateOptions,
scopes backend.CancellationScopeSource) (engine.ResourceChanges, error) {
// First get the stack.
stack, err := getStack(ctx, b, stackRef)
if err != nil {
return err
return nil, err
}
if !stack.(Stack).RunLocally() && updateKind == client.UpdateKindDestroy {
@ -662,33 +664,36 @@ func (b *cloudBackend) PreviewThenPromptThenExecute(
}
// Preview the operation to the user and ask them if they want to proceed.
hasChanges, err := b.PreviewThenPrompt(ctx, updateKind, stack, pkg, root, m, opts, scopes)
changes, hasChanges, err := b.PreviewThenPrompt(ctx, updateKind, stack, pkg, root, m, opts, scopes)
if err != nil || !hasChanges || updateKind == client.UpdateKindPreview {
return err
return changes, err
}
// Now do the real operation. We don't care about the events it issues, so just pass a nil channel along.
_, err = b.updateStack(ctx, updateKind, stack, pkg, root, m, opts, nil, false /*dryRun*/, scopes)
return err
return b.updateStack(ctx, updateKind, stack, pkg, root, m, opts, nil, false /*dryRun*/, scopes)
}
func (b *cloudBackend) Preview(ctx context.Context, stackRef backend.StackReference, pkg *workspace.Project,
root string, m backend.UpdateMetadata, opts backend.UpdateOptions, scopes backend.CancellationScopeSource) error {
root string, m backend.UpdateMetadata, opts backend.UpdateOptions,
scopes backend.CancellationScopeSource) (engine.ResourceChanges, error) {
return b.PreviewThenPromptThenExecute(ctx, client.UpdateKindPreview, stackRef, pkg, root, m, opts, scopes)
}
func (b *cloudBackend) Update(ctx context.Context, stackRef backend.StackReference, pkg *workspace.Project,
root string, m backend.UpdateMetadata, opts backend.UpdateOptions, scopes backend.CancellationScopeSource) error {
root string, m backend.UpdateMetadata, opts backend.UpdateOptions,
scopes backend.CancellationScopeSource) (engine.ResourceChanges, error) {
return b.PreviewThenPromptThenExecute(ctx, client.UpdateKindUpdate, stackRef, pkg, root, m, opts, scopes)
}
func (b *cloudBackend) Refresh(ctx context.Context, stackRef backend.StackReference, pkg *workspace.Project,
root string, m backend.UpdateMetadata, opts backend.UpdateOptions, scopes backend.CancellationScopeSource) error {
root string, m backend.UpdateMetadata, opts backend.UpdateOptions,
scopes backend.CancellationScopeSource) (engine.ResourceChanges, error) {
return b.PreviewThenPromptThenExecute(ctx, client.UpdateKindRefresh, stackRef, pkg, root, m, opts, scopes)
}
func (b *cloudBackend) Destroy(ctx context.Context, stackRef backend.StackReference, pkg *workspace.Project,
root string, m backend.UpdateMetadata, opts backend.UpdateOptions, scopes backend.CancellationScopeSource) error {
root string, m backend.UpdateMetadata, opts backend.UpdateOptions,
scopes backend.CancellationScopeSource) (engine.ResourceChanges, error) {
return b.PreviewThenPromptThenExecute(ctx, client.UpdateKindDestroy, stackRef, pkg, root, m, opts, scopes)
}

View file

@ -9,6 +9,7 @@ import (
"github.com/pkg/errors"
"github.com/pulumi/pulumi/pkg/apitype"
"github.com/pulumi/pulumi/pkg/backend"
"github.com/pulumi/pulumi/pkg/engine"
"github.com/pulumi/pulumi/pkg/operations"
"github.com/pulumi/pulumi/pkg/resource"
"github.com/pulumi/pulumi/pkg/resource/config"
@ -118,22 +119,22 @@ func (s *cloudStack) Remove(ctx context.Context, force bool) (bool, error) {
}
func (s *cloudStack) Preview(ctx context.Context, proj *workspace.Project, root string, m backend.UpdateMetadata,
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) error {
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) (engine.ResourceChanges, error) {
return backend.PreviewStack(ctx, s, proj, root, m, opts, scopes)
}
func (s *cloudStack) Update(ctx context.Context, proj *workspace.Project, root string, m backend.UpdateMetadata,
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) error {
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) (engine.ResourceChanges, error) {
return backend.UpdateStack(ctx, s, proj, root, m, opts, scopes)
}
func (s *cloudStack) Refresh(ctx context.Context, proj *workspace.Project, root string, m backend.UpdateMetadata,
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) error {
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) (engine.ResourceChanges, error) {
return backend.RefreshStack(ctx, s, proj, root, m, opts, scopes)
}
func (s *cloudStack) Destroy(ctx context.Context, proj *workspace.Project, root string, m backend.UpdateMetadata,
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) error {
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) (engine.ResourceChanges, error) {
return backend.DestroyStack(ctx, s, proj, root, m, opts, scopes)
}

View file

@ -192,8 +192,8 @@ func (b *localBackend) GetLatestConfiguration(ctx context.Context,
}
func (b *localBackend) Preview(
_ context.Context, stackRef backend.StackReference, proj *workspace.Project, root string,
m backend.UpdateMetadata, opts backend.UpdateOptions, scopes backend.CancellationScopeSource) error {
_ context.Context, stackRef backend.StackReference, proj *workspace.Project, root string, m backend.UpdateMetadata,
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) (engine.ResourceChanges, error) {
return b.performEngineOp("previewing", backend.PreviewUpdate,
stackRef.StackName(), proj, root, m, opts, scopes,
@ -207,18 +207,18 @@ func (b *localBackend) Preview(
func (b *localBackend) Update(
_ context.Context, stackRef backend.StackReference, proj *workspace.Project, root string, m backend.UpdateMetadata,
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) error {
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) (engine.ResourceChanges, error) {
// The Pulumi Service will pick up changes to a stack's tags on each update. (e.g. changing the description
// in Pulumi.yaml.) While this isn't necessary for local updates, we do the validation here to keep
// parity with stacks managed by the Pulumi Service.
tags, err := backend.GetStackTags()
if err != nil {
return errors.Wrap(err, "getting stack tags")
return nil, errors.Wrap(err, "getting stack tags")
}
stackName := stackRef.StackName()
if err = backend.ValidateStackProperties(string(stackName), tags); err != nil {
return errors.Wrap(err, "validating stack properties")
return nil, errors.Wrap(err, "validating stack properties")
}
return b.performEngineOp("updating", backend.DeployUpdate,
stackName, proj, root, m, opts, scopes, engine.Update)
@ -226,7 +226,7 @@ func (b *localBackend) Update(
func (b *localBackend) Refresh(
_ context.Context, stackRef backend.StackReference, proj *workspace.Project, root string, m backend.UpdateMetadata,
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) error {
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) (engine.ResourceChanges, error) {
return b.performEngineOp("refreshing", backend.RefreshUpdate,
stackRef.StackName(), proj, root, m, opts, scopes, engine.Refresh)
@ -234,7 +234,7 @@ func (b *localBackend) Refresh(
func (b *localBackend) Destroy(
_ context.Context, stackRef backend.StackReference, proj *workspace.Project, root string, m backend.UpdateMetadata,
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) error {
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) (engine.ResourceChanges, error) {
return b.performEngineOp("destroying", backend.DestroyUpdate,
stackRef.StackName(), proj, root, m, opts, scopes, engine.Destroy)
@ -243,11 +243,12 @@ func (b *localBackend) Destroy(
type engineOpFunc func(engine.UpdateInfo, *engine.Context, engine.UpdateOptions, bool) (engine.ResourceChanges, error)
func (b *localBackend) performEngineOp(op string, kind backend.UpdateKind,
stackName tokens.QName, proj *workspace.Project, root string, m backend.UpdateMetadata,
opts backend.UpdateOptions, scopes backend.CancellationScopeSource, performEngineOp engineOpFunc) error {
stackName tokens.QName, proj *workspace.Project, root string, m backend.UpdateMetadata, opts backend.UpdateOptions,
scopes backend.CancellationScopeSource, performEngineOp engineOpFunc) (engine.ResourceChanges, error) {
update, err := b.newUpdate(stackName, proj, root)
if err != nil {
return err
return nil, err
}
events := make(chan engine.Event)
@ -301,13 +302,13 @@ func (b *localBackend) performEngineOp(op string, kind backend.UpdateKind,
if updateErr != nil {
// We swallow saveErr and backupErr as they are less important than the updateErr.
return updateErr
return changes, updateErr
}
if saveErr != nil {
// We swallow backupErr as it is less important than the saveErr.
return errors.Wrap(saveErr, "saving update info")
return changes, errors.Wrap(saveErr, "saving update info")
}
return errors.Wrap(backupErr, "saving backup")
return changes, errors.Wrap(backupErr, "saving backup")
}
func (b *localBackend) GetHistory(ctx context.Context, stackRef backend.StackReference) ([]backend.UpdateInfo, error) {

View file

@ -7,6 +7,7 @@ import (
"github.com/pulumi/pulumi/pkg/apitype"
"github.com/pulumi/pulumi/pkg/backend"
"github.com/pulumi/pulumi/pkg/engine"
"github.com/pulumi/pulumi/pkg/operations"
"github.com/pulumi/pulumi/pkg/resource/config"
"github.com/pulumi/pulumi/pkg/resource/deploy"
@ -50,22 +51,22 @@ func (s *localStack) Remove(ctx context.Context, force bool) (bool, error) {
}
func (s *localStack) Preview(ctx context.Context, proj *workspace.Project, root string, m backend.UpdateMetadata,
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) error {
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) (engine.ResourceChanges, error) {
return backend.PreviewStack(ctx, s, proj, root, m, opts, scopes)
}
func (s *localStack) Update(ctx context.Context, proj *workspace.Project, root string, m backend.UpdateMetadata,
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) error {
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) (engine.ResourceChanges, error) {
return backend.UpdateStack(ctx, s, proj, root, m, opts, scopes)
}
func (s *localStack) Refresh(ctx context.Context, proj *workspace.Project, root string, m backend.UpdateMetadata,
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) error {
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) (engine.ResourceChanges, error) {
return backend.RefreshStack(ctx, s, proj, root, m, opts, scopes)
}
func (s *localStack) Destroy(ctx context.Context, proj *workspace.Project, root string, m backend.UpdateMetadata,
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) error {
opts backend.UpdateOptions, scopes backend.CancellationScopeSource) (engine.ResourceChanges, error) {
return backend.DestroyStack(ctx, s, proj, root, m, opts, scopes)
}

View file

@ -9,6 +9,7 @@ import (
"github.com/pkg/errors"
"github.com/pulumi/pulumi/pkg/apitype"
"github.com/pulumi/pulumi/pkg/engine"
"github.com/pulumi/pulumi/pkg/operations"
"github.com/pulumi/pulumi/pkg/resource/config"
"github.com/pulumi/pulumi/pkg/resource/deploy"
@ -24,16 +25,16 @@ type Stack interface {
// Preview changes to this stack.
Preview(ctx context.Context, proj *workspace.Project, root string, m UpdateMetadata, opts UpdateOptions,
scopes CancellationScopeSource) error
scopes CancellationScopeSource) (engine.ResourceChanges, error)
// Update this stack.
Update(ctx context.Context, proj *workspace.Project, root string, m UpdateMetadata, opts UpdateOptions,
scopes CancellationScopeSource) error
scopes CancellationScopeSource) (engine.ResourceChanges, error)
// Refresh this stack's state from the cloud provider.
Refresh(ctx context.Context, proj *workspace.Project, root string, m UpdateMetadata, opts UpdateOptions,
scopes CancellationScopeSource) error
scopes CancellationScopeSource) (engine.ResourceChanges, error)
// Destroy this stack's resources.
Destroy(ctx context.Context, proj *workspace.Project, root string, m UpdateMetadata, opts UpdateOptions,
scopes CancellationScopeSource) error
scopes CancellationScopeSource) (engine.ResourceChanges, error)
// remove this stack.
Remove(ctx context.Context, force bool) (bool, error)
@ -52,25 +53,25 @@ func RemoveStack(ctx context.Context, s Stack, force bool) (bool, error) {
// PreviewStack previews changes to this stack.
func PreviewStack(ctx context.Context, s Stack, proj *workspace.Project, root string, m UpdateMetadata,
opts UpdateOptions, scopes CancellationScopeSource) error {
opts UpdateOptions, scopes CancellationScopeSource) (engine.ResourceChanges, error) {
return s.Backend().Preview(ctx, s.Name(), proj, root, m, opts, scopes)
}
// UpdateStack updates the target stack with the current workspace's contents (config and code).
func UpdateStack(ctx context.Context, s Stack, proj *workspace.Project, root string, m UpdateMetadata,
opts UpdateOptions, scopes CancellationScopeSource) error {
opts UpdateOptions, scopes CancellationScopeSource) (engine.ResourceChanges, error) {
return s.Backend().Update(ctx, s.Name(), proj, root, m, opts, scopes)
}
// RefreshStack refresh's the stack's state from the cloud provider.
func RefreshStack(ctx context.Context, s Stack, proj *workspace.Project, root string, m UpdateMetadata,
opts UpdateOptions, scopes CancellationScopeSource) error {
opts UpdateOptions, scopes CancellationScopeSource) (engine.ResourceChanges, error) {
return s.Backend().Refresh(ctx, s.Name(), proj, root, m, opts, scopes)
}
// DestroyStack destroys all of this stack's resources.
func DestroyStack(ctx context.Context, s Stack, proj *workspace.Project, root string, m UpdateMetadata,
opts UpdateOptions, scopes CancellationScopeSource) error {
opts UpdateOptions, scopes CancellationScopeSource) (engine.ResourceChanges, error) {
return s.Backend().Destroy(ctx, s.Name(), proj, root, m, opts, scopes)
}