pulumi/cmd/refresh.go

135 lines
4.1 KiB
Go
Raw Normal View History

// Copyright 2016-2018, Pulumi Corporation. All rights reserved.
package cmd
import (
"context"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/pulumi/pulumi/pkg/backend"
"github.com/pulumi/pulumi/pkg/engine"
"github.com/pulumi/pulumi/pkg/util/cmdutil"
)
func newRefreshCmd() *cobra.Command {
var debug bool
var message string
var stack string
// Flags for engine.UpdateOptions.
var analyzers []string
var color colorFlag
var diffDisplay bool
var parallel int
var showConfig bool
var showReplacementSteps bool
var showSames bool
var nonInteractive bool
var skipPreview bool
var yes bool
var cmd = &cobra.Command{
Use: "refresh",
Short: "Refresh the resources in a stack",
Long: "Refresh the resources in a stack.\n" +
"\n" +
"This command compares the current stack's resource state with the state known to exist in\n" +
"the actual cloud provider. Any such changes are adopted into the current stack. Note that if\n" +
"the program text isn't updated accordingly, subsequent updates may still appear to be out of\n" +
"synch with respect to the cloud provider's source of truth.\n" +
"\n" +
"The program to run is loaded from the project in the current directory. Use the `-C` or\n" +
"`--cwd` flag to use a different directory.",
Args: cmdutil.NoArgs,
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
interactive := isInteractive(nonInteractive)
if !interactive {
yes = true // auto-approve changes, since we cannot prompt.
}
opts, err := updateFlagsToOptions(interactive, skipPreview, yes)
Revise the way previews are controlled I found the flag --force to be a strange name for skipping a preview, since that name is usually reserved for operations that might be harmful and yet you're coercing a tool to do it anyway, knowing there's a chance you're going to shoot yourself in the foot. I also found that what I almost always want in the situation where --force was being used is to actually just run a preview and have the confirmation auto-accepted. Going straight to --force isn't the right thing in a CI scenario, where you actually want to run a preview first, just to ensure there aren't any issues, before doing the update. In a sense, there are four options here: 1. Run a preview, ask for confirmation, then do an update (the default). 2. Run a preview, auto-accept, and then do an update (the CI scenario). 3. Just run a preview with neither a confirmation nor an update (dry run). 4. Just do an update, without performing a preview beforehand (rare). This change enables all four workflows in our CLI. Rather than have an explosion of flags, we have a single flag, --preview, which can specify the mode that we're operating in. The following are the values which correlate to the above four modes: 1. "": default (no --preview specified) 2. "auto": auto-accept preview confirmation 3. "only": only run a preview, don't confirm or update 4. "skip": skip the preview altogether As part of this change, I redid a bit of how the preview modes were specified. Rather than booleans, which had some illegal combinations, this change introduces a new enum type. Furthermore, because the engine is wholly ignorant of these flags -- and only the backend understands them -- it was confusing to me that engine.UpdateOptions stored this flag, especially given that all interesting engine options _also_ accepted a dryRun boolean. As of this change, the backend.PreviewBehavior controls the preview options.
2018-04-28 23:50:17 +02:00
if err != nil {
return err
}
s, err := requireStack(stack, true)
if err != nil {
return err
}
proj, root, err := readProject()
if err != nil {
return err
}
m, err := getUpdateMetadata(message, root)
if err != nil {
return errors.Wrap(err, "gathering environment metadata")
}
opts.Engine = engine.UpdateOptions{
Analyzers: analyzers,
Parallel: parallel,
Debug: debug,
}
opts.Display = backend.DisplayOptions{
Color: color.Colorization(),
ShowConfig: showConfig,
ShowReplacementSteps: showReplacementSteps,
ShowSameResources: showSames,
IsInteractive: interactive,
DiffDisplay: diffDisplay,
Debug: debug,
}
_, err = s.Refresh(commandContext(), proj, root, m, opts, cancellationScopes)
if err == context.Canceled {
return errors.New("refresh cancelled")
}
return err
}),
}
cmd.PersistentFlags().BoolVarP(
&debug, "debug", "d", false,
"Print detailed debugging output during resource operations")
cmd.PersistentFlags().StringVarP(
&stack, "stack", "s", "",
"Choose a stack other than the currently selected one")
cmd.PersistentFlags().StringVarP(
&message, "message", "m", "",
"Optional message to associate with the update operation")
// Flags for engine.UpdateOptions.
cmd.PersistentFlags().StringSliceVar(
&analyzers, "analyzer", nil,
"Run one or more analyzers as part of this update")
cmd.PersistentFlags().VarP(
&color, "color", "c", "Colorize output. Choices are: always, never, raw, auto")
cmd.PersistentFlags().BoolVar(
&diffDisplay, "diff", false,
"Display operation as a rich diff showing the overall change")
cmd.PersistentFlags().BoolVar(
&nonInteractive, "non-interactive", false, "Disable interactive mode")
cmd.PersistentFlags().IntVarP(
&parallel, "parallel", "p", 0,
"Allow P resource operations to run in parallel at once (<=1 for no parallelism)")
cmd.PersistentFlags().BoolVar(
&showReplacementSteps, "show-replacement-steps", false,
"Show detailed resource replacement creates and deletes instead of a single step")
cmd.PersistentFlags().BoolVar(
&showSames, "show-sames", false,
"Show resources that needn't be updated because they haven't changed, alongside those that do")
cmd.PersistentFlags().BoolVar(
&skipPreview, "skip-preview", false,
"Do not perform a preview before performing the refresh")
cmd.PersistentFlags().BoolVarP(
&yes, "yes", "y", false,
"Automatically approve and perform the refresh after previewing it")
return cmd
}