Implement a refresh command
This change implements a `pulumi refresh` command. It operates a bit
like `pulumi update`, and friends, in that it supports `--preview` and
`--diff`, along with the usual flags, and will update your checkpoint.
It works through substitution of the deploy.Source abstraction, which
generates a sequence of resource registration events. This new
deploy.RefreshSource takes in a prior checkpoint and will walk it,
refreshing the state via the associated resource providers by invoking
Read for each resource encountered, and merging the resulting state with
the prior checkpoint, to yield a new resource.Goal state. This state is
then fed through the engine in the usual ways with a few minor caveats:
namely, although the engine must generate steps for the logical
operations (permitting us to get nice summaries, progress, and diffs),
it mustn't actually carry them out because the state being imported
already reflects reality (a deleted resource has *already* been deleted,
so of course the engine need not perform the deletion). The diffing
logic also needs to know how to treat the case of refresh slightly
differently, because we are going to be diffing outputs and not inputs.
Note that support for managed stacks is not yet complete, since that
requires updates to the service to support a refresh endpoint. That
will be coming soon ...
2018-04-10 20:22:39 +02:00
|
|
|
// Copyright 2016-2018, Pulumi Corporation. All rights reserved.
|
|
|
|
|
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
2018-04-20 03:59:14 +02:00
|
|
|
"context"
|
Implement a refresh command
This change implements a `pulumi refresh` command. It operates a bit
like `pulumi update`, and friends, in that it supports `--preview` and
`--diff`, along with the usual flags, and will update your checkpoint.
It works through substitution of the deploy.Source abstraction, which
generates a sequence of resource registration events. This new
deploy.RefreshSource takes in a prior checkpoint and will walk it,
refreshing the state via the associated resource providers by invoking
Read for each resource encountered, and merging the resulting state with
the prior checkpoint, to yield a new resource.Goal state. This state is
then fed through the engine in the usual ways with a few minor caveats:
namely, although the engine must generate steps for the logical
operations (permitting us to get nice summaries, progress, and diffs),
it mustn't actually carry them out because the state being imported
already reflects reality (a deleted resource has *already* been deleted,
so of course the engine need not perform the deletion). The diffing
logic also needs to know how to treat the case of refresh slightly
differently, because we are going to be diffing outputs and not inputs.
Note that support for managed stacks is not yet complete, since that
requires updates to the service to support a refresh endpoint. That
will be coming soon ...
2018-04-10 20:22:39 +02:00
|
|
|
|
|
|
|
"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
|
2018-05-01 00:27:53 +02:00
|
|
|
var nonInteractive bool
|
2018-05-05 20:57:09 +02:00
|
|
|
var skipPreview bool
|
|
|
|
var yes bool
|
Implement a refresh command
This change implements a `pulumi refresh` command. It operates a bit
like `pulumi update`, and friends, in that it supports `--preview` and
`--diff`, along with the usual flags, and will update your checkpoint.
It works through substitution of the deploy.Source abstraction, which
generates a sequence of resource registration events. This new
deploy.RefreshSource takes in a prior checkpoint and will walk it,
refreshing the state via the associated resource providers by invoking
Read for each resource encountered, and merging the resulting state with
the prior checkpoint, to yield a new resource.Goal state. This state is
then fed through the engine in the usual ways with a few minor caveats:
namely, although the engine must generate steps for the logical
operations (permitting us to get nice summaries, progress, and diffs),
it mustn't actually carry them out because the state being imported
already reflects reality (a deleted resource has *already* been deleted,
so of course the engine need not perform the deletion). The diffing
logic also needs to know how to treat the case of refresh slightly
differently, because we are going to be diffing outputs and not inputs.
Note that support for managed stacks is not yet complete, since that
requires updates to the service to support a refresh endpoint. That
will be coming soon ...
2018-04-10 20:22:39 +02:00
|
|
|
|
|
|
|
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 {
|
2018-05-05 20:57:09 +02:00
|
|
|
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
|
Implement a refresh command
This change implements a `pulumi refresh` command. It operates a bit
like `pulumi update`, and friends, in that it supports `--preview` and
`--diff`, along with the usual flags, and will update your checkpoint.
It works through substitution of the deploy.Source abstraction, which
generates a sequence of resource registration events. This new
deploy.RefreshSource takes in a prior checkpoint and will walk it,
refreshing the state via the associated resource providers by invoking
Read for each resource encountered, and merging the resulting state with
the prior checkpoint, to yield a new resource.Goal state. This state is
then fed through the engine in the usual ways with a few minor caveats:
namely, although the engine must generate steps for the logical
operations (permitting us to get nice summaries, progress, and diffs),
it mustn't actually carry them out because the state being imported
already reflects reality (a deleted resource has *already* been deleted,
so of course the engine need not perform the deletion). The diffing
logic also needs to know how to treat the case of refresh slightly
differently, because we are going to be diffing outputs and not inputs.
Note that support for managed stacks is not yet complete, since that
requires updates to the service to support a refresh endpoint. That
will be coming soon ...
2018-04-10 20:22:39 +02:00
|
|
|
}
|
|
|
|
|
2018-04-20 07:55:52 +02:00
|
|
|
s, err := requireStack(stack, true)
|
Implement a refresh command
This change implements a `pulumi refresh` command. It operates a bit
like `pulumi update`, and friends, in that it supports `--preview` and
`--diff`, along with the usual flags, and will update your checkpoint.
It works through substitution of the deploy.Source abstraction, which
generates a sequence of resource registration events. This new
deploy.RefreshSource takes in a prior checkpoint and will walk it,
refreshing the state via the associated resource providers by invoking
Read for each resource encountered, and merging the resulting state with
the prior checkpoint, to yield a new resource.Goal state. This state is
then fed through the engine in the usual ways with a few minor caveats:
namely, although the engine must generate steps for the logical
operations (permitting us to get nice summaries, progress, and diffs),
it mustn't actually carry them out because the state being imported
already reflects reality (a deleted resource has *already* been deleted,
so of course the engine need not perform the deletion). The diffing
logic also needs to know how to treat the case of refresh slightly
differently, because we are going to be diffing outputs and not inputs.
Note that support for managed stacks is not yet complete, since that
requires updates to the service to support a refresh endpoint. That
will be coming soon ...
2018-04-10 20:22:39 +02:00
|
|
|
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")
|
|
|
|
}
|
|
|
|
|
2018-05-05 20:57:09 +02:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
|
2018-05-08 03:23:03 +02:00
|
|
|
err = s.Refresh(commandContext(), proj, root, m, opts, cancellationScopes)
|
2018-04-20 03:59:14 +02:00
|
|
|
if err == context.Canceled {
|
|
|
|
return errors.New("refresh cancelled")
|
|
|
|
}
|
|
|
|
return err
|
Implement a refresh command
This change implements a `pulumi refresh` command. It operates a bit
like `pulumi update`, and friends, in that it supports `--preview` and
`--diff`, along with the usual flags, and will update your checkpoint.
It works through substitution of the deploy.Source abstraction, which
generates a sequence of resource registration events. This new
deploy.RefreshSource takes in a prior checkpoint and will walk it,
refreshing the state via the associated resource providers by invoking
Read for each resource encountered, and merging the resulting state with
the prior checkpoint, to yield a new resource.Goal state. This state is
then fed through the engine in the usual ways with a few minor caveats:
namely, although the engine must generate steps for the logical
operations (permitting us to get nice summaries, progress, and diffs),
it mustn't actually carry them out because the state being imported
already reflects reality (a deleted resource has *already* been deleted,
so of course the engine need not perform the deletion). The diffing
logic also needs to know how to treat the case of refresh slightly
differently, because we are going to be diffing outputs and not inputs.
Note that support for managed stacks is not yet complete, since that
requires updates to the service to support a refresh endpoint. That
will be coming soon ...
2018-04-10 20:22:39 +02:00
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
|
|
|
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")
|
2018-05-05 20:57:09 +02:00
|
|
|
cmd.PersistentFlags().BoolVar(
|
|
|
|
&nonInteractive, "non-interactive", false, "Disable interactive mode")
|
Implement a refresh command
This change implements a `pulumi refresh` command. It operates a bit
like `pulumi update`, and friends, in that it supports `--preview` and
`--diff`, along with the usual flags, and will update your checkpoint.
It works through substitution of the deploy.Source abstraction, which
generates a sequence of resource registration events. This new
deploy.RefreshSource takes in a prior checkpoint and will walk it,
refreshing the state via the associated resource providers by invoking
Read for each resource encountered, and merging the resulting state with
the prior checkpoint, to yield a new resource.Goal state. This state is
then fed through the engine in the usual ways with a few minor caveats:
namely, although the engine must generate steps for the logical
operations (permitting us to get nice summaries, progress, and diffs),
it mustn't actually carry them out because the state being imported
already reflects reality (a deleted resource has *already* been deleted,
so of course the engine need not perform the deletion). The diffing
logic also needs to know how to treat the case of refresh slightly
differently, because we are going to be diffing outputs and not inputs.
Note that support for managed stacks is not yet complete, since that
requires updates to the service to support a refresh endpoint. That
will be coming soon ...
2018-04-10 20:22:39 +02:00
|
|
|
cmd.PersistentFlags().IntVarP(
|
|
|
|
¶llel, "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")
|
2018-05-05 20:57:09 +02:00
|
|
|
cmd.PersistentFlags().BoolVar(
|
|
|
|
&skipPreview, "skip-preview", false,
|
|
|
|
"Do not perform a preview before performing the refresh")
|
|
|
|
cmd.PersistentFlags().BoolVar(
|
|
|
|
&yes, "yes", false,
|
|
|
|
"Automatically approve and perform the refresh after previewing it")
|
2018-04-24 23:23:08 +02:00
|
|
|
|
Implement a refresh command
This change implements a `pulumi refresh` command. It operates a bit
like `pulumi update`, and friends, in that it supports `--preview` and
`--diff`, along with the usual flags, and will update your checkpoint.
It works through substitution of the deploy.Source abstraction, which
generates a sequence of resource registration events. This new
deploy.RefreshSource takes in a prior checkpoint and will walk it,
refreshing the state via the associated resource providers by invoking
Read for each resource encountered, and merging the resulting state with
the prior checkpoint, to yield a new resource.Goal state. This state is
then fed through the engine in the usual ways with a few minor caveats:
namely, although the engine must generate steps for the logical
operations (permitting us to get nice summaries, progress, and diffs),
it mustn't actually carry them out because the state being imported
already reflects reality (a deleted resource has *already* been deleted,
so of course the engine need not perform the deletion). The diffing
logic also needs to know how to treat the case of refresh slightly
differently, because we are going to be diffing outputs and not inputs.
Note that support for managed stacks is not yet complete, since that
requires updates to the service to support a refresh endpoint. That
will be coming soon ...
2018-04-10 20:22:39 +02:00
|
|
|
return cmd
|
|
|
|
}
|