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 ...
128 lines
4.1 KiB
Go
128 lines
4.1 KiB
Go
// Copyright 2016-2018, Pulumi Corporation. All rights reserved.
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"bufio"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/golang/glog"
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/pulumi/pulumi/pkg/backend/cloud"
|
|
"github.com/pulumi/pulumi/pkg/backend/local"
|
|
"github.com/pulumi/pulumi/pkg/diag/colors"
|
|
"github.com/pulumi/pulumi/pkg/util/cmdutil"
|
|
"github.com/pulumi/pulumi/pkg/workspace"
|
|
)
|
|
|
|
// NewPulumiCmd creates a new Pulumi Cmd instance.
|
|
func NewPulumiCmd() *cobra.Command {
|
|
var logFlow bool
|
|
var logToStderr bool
|
|
var tracing string
|
|
var verbose int
|
|
var cwd string
|
|
cmd := &cobra.Command{
|
|
Use: "pulumi",
|
|
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
|
if cwd != "" {
|
|
if err := os.Chdir(cwd); err != nil {
|
|
cmdutil.ExitError(err.Error())
|
|
}
|
|
}
|
|
|
|
if err := upgradeConfigurationFiles(); err != nil {
|
|
cmdutil.ExitError(err.Error())
|
|
}
|
|
|
|
cmdutil.InitLogging(logToStderr, verbose, logFlow)
|
|
cmdutil.InitTracing("pulumi-cli", tracing)
|
|
},
|
|
PersistentPostRun: func(cmd *cobra.Command, args []string) {
|
|
glog.Flush()
|
|
cmdutil.CloseTracing()
|
|
},
|
|
}
|
|
|
|
// Add additional help that includes which clouds we are logged into.
|
|
defaultHelp := cmd.HelpFunc()
|
|
cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
|
|
defaultHelp(cmd, args)
|
|
fmt.Println("See documentation at https://docs.pulumi.com")
|
|
|
|
url, err := workspace.GetCurrentCloudURL()
|
|
if err == nil && url != "" && !local.IsLocalBackendURL(url) {
|
|
fmt.Printf("\n")
|
|
suffix := ""
|
|
if url != cloud.PulumiCloudURL {
|
|
suffix = fmt.Sprintf(" (%s)", url)
|
|
}
|
|
|
|
fmt.Printf("Currently logged into the Pulumi Cloud%s%s\n", cmdutil.EmojiOr(" ☁️", ""), suffix)
|
|
}
|
|
})
|
|
|
|
cmd.PersistentFlags().StringVarP(&cwd, "cwd", "C", "", "Run pulumi as if it had been started in another directory")
|
|
cmd.PersistentFlags().BoolVarP(&cmdutil.Emoji, "emoji", "e",
|
|
runtime.GOOS == "darwin", "Enable emojis in the output")
|
|
cmd.PersistentFlags().BoolVar(&local.DisableIntegrityChecking, "disable-integrity-checking", false,
|
|
"Disable integrity checking of checkpoint files")
|
|
cmd.PersistentFlags().BoolVar(&logFlow, "logflow", false, "Flow log settings to child processes (like plugins)")
|
|
cmd.PersistentFlags().BoolVar(&logToStderr, "logtostderr", false, "Log to stderr instead of to files")
|
|
cmd.PersistentFlags().StringVar(&tracing, "tracing", "", "Emit tracing to a Zipkin-compatible tracing endpoint")
|
|
cmd.PersistentFlags().IntVarP(
|
|
&verbose, "verbose", "v", 0, "Enable verbose logging (e.g., v=3); anything >3 is very verbose")
|
|
|
|
cmd.AddCommand(newConfigCmd())
|
|
cmd.AddCommand(newDestroyCmd())
|
|
cmd.AddCommand(newHistoryCmd())
|
|
cmd.AddCommand(newInitCmd())
|
|
cmd.AddCommand(newLogsCmd())
|
|
cmd.AddCommand(newNewCmd())
|
|
cmd.AddCommand(newPluginCmd())
|
|
cmd.AddCommand(newPreviewCmd())
|
|
cmd.AddCommand(newRefreshCmd())
|
|
cmd.AddCommand(newStackCmd())
|
|
cmd.AddCommand(newUpdateCmd())
|
|
cmd.AddCommand(newVersionCmd())
|
|
|
|
// Commands specific to the Pulumi Cloud Management Console.
|
|
cmd.AddCommand(newLoginCmd())
|
|
cmd.AddCommand(newLogoutCmd())
|
|
|
|
// We have a set of commands that are useful for developers of pulumi that we add when PULUMI_DEBUG_COMMANDS is
|
|
// set to true.
|
|
if cmdutil.IsTruthy(os.Getenv("PULUMI_DEBUG_COMMANDS")) {
|
|
cmd.AddCommand(newArchiveCommand())
|
|
}
|
|
|
|
// Tell flag about -C, so someone can do pulumi -C <working-directory> stack and the call to cmdutil.InitLogging
|
|
// which calls flag.Parse under the hood doesn't yell at you.
|
|
//
|
|
// TODO[pulumi/pulumi#301]: when we move away from using glog, it should be safe to remove this.
|
|
flag.StringVar(&cwd, "C", "", "Run pulumi as if it had been started in another directory")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func confirmPrompt(prompt string, name string) bool {
|
|
if prompt != "" {
|
|
fmt.Print(
|
|
colors.ColorizeText(
|
|
fmt.Sprintf("%s%s%s\n", colors.SpecAttention, prompt, colors.Reset)))
|
|
}
|
|
|
|
fmt.Print(
|
|
colors.ColorizeText(
|
|
fmt.Sprintf("%sPlease confirm that this is what you'd like to do by typing (%s\"%s\"%s):%s ",
|
|
colors.SpecAttention, colors.BrightWhite, name, colors.SpecAttention, colors.Reset)))
|
|
|
|
reader := bufio.NewReader(os.Stdin)
|
|
line, _ := reader.ReadString('\n')
|
|
return strings.TrimSpace(line) == name
|
|
}
|