2017-02-25 16:25:33 +01:00
|
|
|
// Copyright 2016 Pulumi, Inc. All rights reserved.
|
2017-02-13 23:26:46 +01:00
|
|
|
|
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
2017-03-01 18:57:14 +01:00
|
|
|
"bufio"
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2017-02-13 23:26:46 +01:00
|
|
|
"path/filepath"
|
2017-02-28 19:32:24 +01:00
|
|
|
"sort"
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
"strconv"
|
|
|
|
"time"
|
2017-02-13 23:26:46 +01:00
|
|
|
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
|
2017-02-25 16:25:33 +01:00
|
|
|
"github.com/pulumi/coconut/pkg/compiler"
|
|
|
|
"github.com/pulumi/coconut/pkg/compiler/core"
|
|
|
|
"github.com/pulumi/coconut/pkg/compiler/errors"
|
2017-02-26 20:20:14 +01:00
|
|
|
"github.com/pulumi/coconut/pkg/compiler/symbols"
|
2017-02-25 16:25:33 +01:00
|
|
|
"github.com/pulumi/coconut/pkg/diag"
|
|
|
|
"github.com/pulumi/coconut/pkg/diag/colors"
|
|
|
|
"github.com/pulumi/coconut/pkg/encoding"
|
|
|
|
"github.com/pulumi/coconut/pkg/eval/heapstate"
|
2017-02-28 19:32:24 +01:00
|
|
|
"github.com/pulumi/coconut/pkg/eval/rt"
|
2017-02-28 21:31:50 +01:00
|
|
|
"github.com/pulumi/coconut/pkg/pack"
|
2017-02-25 16:25:33 +01:00
|
|
|
"github.com/pulumi/coconut/pkg/resource"
|
|
|
|
"github.com/pulumi/coconut/pkg/tokens"
|
|
|
|
"github.com/pulumi/coconut/pkg/util/cmdutil"
|
|
|
|
"github.com/pulumi/coconut/pkg/util/contract"
|
|
|
|
"github.com/pulumi/coconut/pkg/util/mapper"
|
|
|
|
"github.com/pulumi/coconut/pkg/workspace"
|
2017-02-13 23:26:46 +01:00
|
|
|
)
|
|
|
|
|
2017-03-06 15:32:39 +01:00
|
|
|
func newEnvCmd() *cobra.Command {
|
2017-02-26 20:20:14 +01:00
|
|
|
cmd := &cobra.Command{
|
2017-03-06 15:32:39 +01:00
|
|
|
Use: "env",
|
|
|
|
Short: "Manage or deploy into a target environment",
|
|
|
|
Long: "Manage or deploy into a target environment\n" +
|
2017-02-26 20:20:14 +01:00
|
|
|
"\n" +
|
2017-03-06 15:32:39 +01:00
|
|
|
"An environment is a named deployment target, and a single nut have many of them. Each\n" +
|
|
|
|
"environment has a configuration and deployment history associated with it, stored in the\n" +
|
|
|
|
"workspace, in addition to a full checkpoint of the last known good deployment.\n",
|
2017-02-26 20:20:14 +01:00
|
|
|
}
|
|
|
|
|
2017-03-06 16:07:24 +01:00
|
|
|
cmd.AddCommand(newEnvConfigCmd())
|
2017-03-06 15:32:39 +01:00
|
|
|
cmd.AddCommand(newEnvDeployCmd())
|
|
|
|
cmd.AddCommand(newEnvDestroyCmd())
|
|
|
|
cmd.AddCommand(newEnvInitCmd())
|
|
|
|
cmd.AddCommand(newEnvLsCmd())
|
|
|
|
cmd.AddCommand(newEnvRmCmd())
|
2017-02-26 20:20:14 +01:00
|
|
|
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
2017-03-07 14:47:42 +01:00
|
|
|
func initEnvCmd(cmd *cobra.Command, args []string) (*envCmdInfo, error) {
|
2017-03-06 15:32:39 +01:00
|
|
|
// Read in the name of the environment to use.
|
2017-02-27 23:13:27 +01:00
|
|
|
if len(args) == 0 {
|
2017-03-07 14:47:42 +01:00
|
|
|
return nil, fmt.Errorf("missing required environment name")
|
2017-02-27 23:13:27 +01:00
|
|
|
}
|
2017-03-09 16:52:50 +01:00
|
|
|
return initEnvCmdName(tokens.QName(args[0]), args[1:])
|
|
|
|
}
|
2017-02-27 23:13:27 +01:00
|
|
|
|
2017-03-09 16:52:50 +01:00
|
|
|
func initEnvCmdName(name tokens.QName, args []string) (*envCmdInfo, error) {
|
2017-02-27 23:13:27 +01:00
|
|
|
// Read in the deployment information, bailing if an IO error occurs.
|
2017-03-07 14:47:42 +01:00
|
|
|
ctx := resource.NewContext(sink())
|
2017-03-06 15:32:39 +01:00
|
|
|
envfile, env, old := readEnv(ctx, name)
|
|
|
|
if env == nil {
|
2017-02-27 23:13:27 +01:00
|
|
|
contract.Assert(!ctx.Diag.Success())
|
2017-03-07 14:47:42 +01:00
|
|
|
ctx.Close() // close now, since we are exiting.
|
|
|
|
return nil, fmt.Errorf("could not read envfile required to proceed") // failure reading the env information.
|
2017-02-27 23:13:27 +01:00
|
|
|
}
|
2017-03-06 15:32:39 +01:00
|
|
|
return &envCmdInfo{
|
|
|
|
Ctx: ctx,
|
|
|
|
Env: env,
|
|
|
|
Envfile: envfile,
|
|
|
|
Old: old,
|
2017-03-09 16:52:50 +01:00
|
|
|
Args: args,
|
2017-03-07 14:47:42 +01:00
|
|
|
}, nil
|
2017-02-27 23:13:27 +01:00
|
|
|
}
|
|
|
|
|
2017-03-06 15:32:39 +01:00
|
|
|
type envCmdInfo struct {
|
|
|
|
Ctx *resource.Context // the resulting context
|
|
|
|
Env *resource.Env // the environment information
|
|
|
|
Envfile *resource.Envfile // the full serialized envfile from which this came.
|
|
|
|
Old resource.Snapshot // the environment's latest deployment snapshot
|
2017-03-09 16:52:50 +01:00
|
|
|
Args []string // the args after extracting the environment name
|
2017-02-27 23:13:27 +01:00
|
|
|
}
|
|
|
|
|
2017-03-07 14:47:42 +01:00
|
|
|
func (eci *envCmdInfo) Close() error {
|
|
|
|
return eci.Ctx.Close()
|
|
|
|
}
|
|
|
|
|
2017-03-01 18:57:14 +01:00
|
|
|
func confirmPrompt(msg string, args ...interface{}) bool {
|
|
|
|
prompt := fmt.Sprintf(msg, args...)
|
|
|
|
fmt.Printf(
|
|
|
|
colors.ColorizeText(fmt.Sprintf("%v%v%v\n", colors.SpecAttention, prompt, colors.Reset)))
|
|
|
|
fmt.Printf("Please confirm that this is what you'd like to do by typing (\"yes\"): ")
|
|
|
|
reader := bufio.NewReader(os.Stdin)
|
|
|
|
if line, _ := reader.ReadString('\n'); line != "yes\n" {
|
|
|
|
fmt.Fprintf(os.Stderr, "Confirmation declined -- exiting without doing anything\n")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2017-03-06 15:32:39 +01:00
|
|
|
// create just creates a new empty environment without deploying anything into it.
|
|
|
|
// TODO: add the ability to configure the environment at the command line.
|
2017-03-01 00:43:46 +01:00
|
|
|
func create(name tokens.QName) {
|
2017-03-06 15:32:39 +01:00
|
|
|
env := &resource.Env{Name: name}
|
|
|
|
if success := saveEnv(env, nil, "", false); success {
|
|
|
|
fmt.Printf("Environment '%v' initialized; see `coco env deploy` to deploy into it\n", name)
|
2017-02-26 20:20:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-06 15:32:39 +01:00
|
|
|
// remove permanently deletes the environment's information from the local workstation.
|
|
|
|
func remove(env *resource.Env) {
|
|
|
|
deleteEnv(env)
|
|
|
|
msg := fmt.Sprintf("%sEnvironment '%s' has been removed!%s\n",
|
|
|
|
colors.SpecAttention, env.Name, colors.Reset)
|
2017-03-01 18:57:14 +01:00
|
|
|
fmt.Printf(colors.ColorizeText(msg))
|
|
|
|
}
|
|
|
|
|
2017-02-28 21:31:50 +01:00
|
|
|
func prepareCompiler(cmd *cobra.Command, args []string) (compiler.Compiler, *pack.Package) {
|
2017-02-13 23:26:46 +01:00
|
|
|
// If there's a --, we need to separate out the command args from the stack args.
|
|
|
|
flags := cmd.Flags()
|
|
|
|
dashdash := flags.ArgsLenAtDash()
|
|
|
|
var packArgs []string
|
|
|
|
if dashdash != -1 {
|
|
|
|
packArgs = args[dashdash:]
|
|
|
|
args = args[0:dashdash]
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a compiler options object and map any flags and arguments to settings on it.
|
|
|
|
opts := core.DefaultOptions()
|
|
|
|
opts.Args = dashdashArgsToMap(packArgs)
|
|
|
|
|
|
|
|
// In the case of an argument, load that specific package and new up a compiler based on its base path.
|
|
|
|
// Otherwise, use the default workspace and package logic (which consults the current working directory).
|
2017-02-19 20:41:05 +01:00
|
|
|
var comp compiler.Compiler
|
2017-02-28 21:31:50 +01:00
|
|
|
var pkg *pack.Package
|
2017-02-13 23:26:46 +01:00
|
|
|
if len(args) == 0 {
|
2017-02-19 20:41:05 +01:00
|
|
|
var err error
|
|
|
|
comp, err = compiler.Newwd(opts)
|
2017-02-13 23:26:46 +01:00
|
|
|
if err != nil {
|
2017-02-19 20:41:05 +01:00
|
|
|
// Create a temporary diagnostics sink so that we can issue an error and bail out.
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
sink().Errorf(errors.ErrorCantCreateCompiler, err)
|
2017-02-13 23:26:46 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fn := args[0]
|
2017-02-28 21:31:50 +01:00
|
|
|
if pkg = cmdutil.ReadPackageFromArg(fn); pkg != nil {
|
2017-02-13 23:26:46 +01:00
|
|
|
var err error
|
|
|
|
if fn == "-" {
|
|
|
|
comp, err = compiler.Newwd(opts)
|
|
|
|
} else {
|
|
|
|
comp, err = compiler.New(filepath.Dir(fn), opts)
|
|
|
|
}
|
|
|
|
if err != nil {
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
sink().Errorf(errors.ErrorCantReadPackage, fn, err)
|
2017-02-13 23:26:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-02-28 21:31:50 +01:00
|
|
|
|
|
|
|
return comp, pkg
|
|
|
|
}
|
|
|
|
|
|
|
|
// compile just uses the standard logic to parse arguments, options, and to locate/compile a package. It returns the
|
|
|
|
// CocoGL graph that is produced, or nil if an error occurred (in which case, we would expect non-0 errors).
|
2017-03-01 00:43:46 +01:00
|
|
|
func compile(cmd *cobra.Command, args []string, config resource.ConfigMap) *compileResult {
|
2017-02-28 21:31:50 +01:00
|
|
|
// Prepare the compiler info and, provided it succeeds, perform the compilation.
|
|
|
|
if comp, pkg := prepareCompiler(cmd, args); comp != nil {
|
|
|
|
// Create the preexec hook if the config map is non-nil.
|
|
|
|
var preexec compiler.Preexec
|
|
|
|
configVars := make(map[tokens.Token]*rt.Object)
|
|
|
|
if config != nil {
|
|
|
|
preexec = config.ConfigApplier(configVars)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now perform the compilation and extract the heap snapshot.
|
|
|
|
var heap *heapstate.Heap
|
|
|
|
var pkgsym *symbols.Package
|
|
|
|
if pkg == nil {
|
|
|
|
pkgsym, heap = comp.Compile(preexec)
|
|
|
|
} else {
|
|
|
|
pkgsym, heap = comp.CompilePackage(pkg, preexec)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &compileResult{
|
|
|
|
C: comp,
|
|
|
|
Pkg: pkgsym,
|
|
|
|
Heap: heap,
|
|
|
|
ConfigVars: configVars,
|
|
|
|
}
|
2017-02-28 19:32:24 +01:00
|
|
|
}
|
2017-02-28 21:31:50 +01:00
|
|
|
|
|
|
|
return nil
|
2017-02-19 20:41:05 +01:00
|
|
|
}
|
|
|
|
|
2017-02-22 03:31:43 +01:00
|
|
|
type compileResult struct {
|
2017-02-28 19:32:24 +01:00
|
|
|
C compiler.Compiler
|
|
|
|
Pkg *symbols.Package
|
|
|
|
Heap *heapstate.Heap
|
|
|
|
ConfigVars map[tokens.Token]*rt.Object
|
2017-02-22 03:31:43 +01:00
|
|
|
}
|
|
|
|
|
2017-02-28 21:31:50 +01:00
|
|
|
// verify creates a compiler, much like compile, but only performs binding and verification on it. If verification
|
|
|
|
// succeeds, the return value is true; if verification fails, errors will have been output, and the return is false.
|
|
|
|
func verify(cmd *cobra.Command, args []string) bool {
|
|
|
|
// Prepare the compiler info and, provided it succeeds, perform the verification.
|
|
|
|
if comp, pkg := prepareCompiler(cmd, args); comp != nil {
|
|
|
|
// Now perform the compilation and extract the heap snapshot.
|
|
|
|
if pkg == nil {
|
|
|
|
return comp.Verify()
|
|
|
|
}
|
|
|
|
return comp.VerifyPackage(pkg)
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2017-02-22 03:31:43 +01:00
|
|
|
// plan just uses the standard logic to parse arguments, options, and to create a snapshot and plan.
|
2017-03-06 15:32:39 +01:00
|
|
|
func plan(cmd *cobra.Command, info *envCmdInfo, delete bool) *planResult {
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
// If deleting, there is no need to create a new snapshot; otherwise, we will need to compile the package.
|
2017-02-26 20:20:14 +01:00
|
|
|
var new resource.Snapshot
|
|
|
|
var result *compileResult
|
|
|
|
if !delete {
|
|
|
|
// First, compile; if that yields errors or an empty heap, exit early.
|
2017-03-06 15:32:39 +01:00
|
|
|
if result = compile(cmd, info.Args, info.Env.Config); result == nil || result.Heap == nil {
|
2017-02-26 20:20:14 +01:00
|
|
|
return nil
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
2017-02-26 20:20:14 +01:00
|
|
|
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
// Create a resource snapshot from the compiled/evaluated object graph.
|
2017-02-26 20:20:14 +01:00
|
|
|
var err error
|
2017-02-27 23:13:27 +01:00
|
|
|
new, err = resource.NewGraphSnapshot(
|
2017-03-06 15:32:39 +01:00
|
|
|
info.Ctx, info.Env.Name, result.Pkg.Tok, result.C.Ctx().Opts.Args, result.Heap, info.Old)
|
2017-02-19 20:41:05 +01:00
|
|
|
if err != nil {
|
2017-02-22 03:31:43 +01:00
|
|
|
result.C.Diag().Errorf(errors.ErrorCantCreateSnapshot, err)
|
|
|
|
return nil
|
2017-03-01 00:43:46 +01:00
|
|
|
} else if !info.Ctx.Diag.Success() {
|
2017-02-25 01:03:06 +01:00
|
|
|
return nil
|
2017-02-19 20:41:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-26 20:20:14 +01:00
|
|
|
// Generate a plan; this API handles all interesting cases (create, update, delete).
|
Support replacement IDs
This change introduces a new RPC function to the provider interface;
in pseudo-code:
UpdateImpact(id ID, t Type, olds PropertyMap, news PropertyMap)
(bool, PropertyMap, error)
Essentially, during the planning phase, we will consult each provider
about the nature of a proposed update. This update includes a set of
old properties and the new ones and, if the resource provider will need
to replace the property as a result of the update, it will return true;
in general, the PropertyMap will eventually contain a list of all
properties that will be modified as a result of the operation (see below).
The planning phase reacts to this by propagating the change to dependent
resources, so that they know that the ID will change (and so that they
can recalculate their own state accordingly, possibly leading to a ripple
effect). This ensures the overall DAG / schedule is ordered correctly.
This change is most of pulumi/coconut#105. The only missing piece
is to generalize replacing the "ID" property with replacing arbitrary
properties; there are hooks in here for this, but until pulumi/coconut#90
is addressed, it doesn't make sense to make much progress on this.
2017-03-01 18:08:53 +01:00
|
|
|
plan, err := resource.NewPlan(info.Ctx, info.Old, new)
|
|
|
|
if err != nil {
|
|
|
|
result.C.Diag().Errorf(errors.ErrorCantCreateSnapshot, err)
|
|
|
|
return nil
|
|
|
|
}
|
2017-03-03 03:15:38 +01:00
|
|
|
if !info.Ctx.Diag.Success() {
|
|
|
|
return nil
|
|
|
|
}
|
2017-02-26 20:20:14 +01:00
|
|
|
return &planResult{
|
|
|
|
compileResult: result,
|
2017-03-01 00:43:46 +01:00
|
|
|
Info: info,
|
2017-02-26 20:20:14 +01:00
|
|
|
New: new,
|
|
|
|
Plan: plan,
|
|
|
|
}
|
2017-02-22 03:31:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
type planResult struct {
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
*compileResult
|
2017-03-06 15:32:39 +01:00
|
|
|
Info *envCmdInfo // plan command information.
|
Add basic targeting capability
This change partially implements pulumi/coconut#94, by adding the
ability to name targets during creation and reuse those names during
deletion and update. This simplifies the management of deployment
records, checkpoints, and snapshots.
I've opted to call these things "husks" (perhaps going overboard with
joy after our recent renaming). The basic idea is that for any
executable Nut that will be deployed, you have a nutpack/ directory
whose layout looks roughly as follows:
nutpack/
bin/
Nutpack.json
... any other compiled artifacts ...
husks/
... one snapshot per husk ...
For example, if we had a stage and prod husk, we would have:
nutpack/
bin/...
husks/
prod.json
stage.json
In the prod.json and stage.json files, we'd have the most recent
deployment record for that environment. These would presumably get
checked in and versioned along with the overall Nut, so that we
can use Git history for rollbacks, etc.
The create, update, and delete commands look in the right place for
these files automatically, so you don't need to manually supply them.
2017-02-25 18:24:52 +01:00
|
|
|
Old resource.Snapshot // the existing snapshot (if any).
|
|
|
|
New resource.Snapshot // the new snapshot for this plan (if any).
|
2017-03-01 00:43:46 +01:00
|
|
|
Plan resource.Plan // the plan created by this command.
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
|
2017-03-06 15:32:39 +01:00
|
|
|
func apply(cmd *cobra.Command, info *envCmdInfo, opts applyOptions) {
|
2017-02-27 23:13:27 +01:00
|
|
|
if result := plan(cmd, info, opts.Delete); result != nil {
|
2017-02-26 20:20:14 +01:00
|
|
|
// Now based on whether a dry run was specified, or not, either print or perform the planned operations.
|
|
|
|
if opts.DryRun {
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
// If no output file was requested, or "-", print to stdout; else write to that file.
|
|
|
|
if opts.Output == "" || opts.Output == "-" {
|
2017-03-01 18:57:14 +01:00
|
|
|
printPlan(info.Ctx.Diag, result, opts)
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
} else {
|
2017-03-06 15:32:39 +01:00
|
|
|
saveEnv(info.Env, result.New, opts.Output, true /*overwrite*/)
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
} else {
|
2017-02-28 19:32:24 +01:00
|
|
|
// If show unchanged was requested, print them first, along with a header.
|
|
|
|
var header bytes.Buffer
|
|
|
|
printPrelude(&header, result, opts)
|
|
|
|
header.WriteString(fmt.Sprintf("%vDeploying changes:%v\n", colors.SpecUnimportant, colors.Reset))
|
|
|
|
fmt.Printf(colors.Colorize(&header))
|
2017-02-27 19:58:24 +01:00
|
|
|
|
Support replacement IDs
This change introduces a new RPC function to the provider interface;
in pseudo-code:
UpdateImpact(id ID, t Type, olds PropertyMap, news PropertyMap)
(bool, PropertyMap, error)
Essentially, during the planning phase, we will consult each provider
about the nature of a proposed update. This update includes a set of
old properties and the new ones and, if the resource provider will need
to replace the property as a result of the update, it will return true;
in general, the PropertyMap will eventually contain a list of all
properties that will be modified as a result of the operation (see below).
The planning phase reacts to this by propagating the change to dependent
resources, so that they know that the ID will change (and so that they
can recalculate their own state accordingly, possibly leading to a ripple
effect). This ensures the overall DAG / schedule is ordered correctly.
This change is most of pulumi/coconut#105. The only missing piece
is to generalize replacing the "ID" property with replacing arbitrary
properties; there are hooks in here for this, but until pulumi/coconut#90
is addressed, it doesn't make sense to make much progress on this.
2017-03-01 18:08:53 +01:00
|
|
|
// Print a nice message if the update is an empty one.
|
2017-03-01 18:57:14 +01:00
|
|
|
empty := checkEmpty(info.Ctx.Diag, result.Plan)
|
Support replacement IDs
This change introduces a new RPC function to the provider interface;
in pseudo-code:
UpdateImpact(id ID, t Type, olds PropertyMap, news PropertyMap)
(bool, PropertyMap, error)
Essentially, during the planning phase, we will consult each provider
about the nature of a proposed update. This update includes a set of
old properties and the new ones and, if the resource provider will need
to replace the property as a result of the update, it will return true;
in general, the PropertyMap will eventually contain a list of all
properties that will be modified as a result of the operation (see below).
The planning phase reacts to this by propagating the change to dependent
resources, so that they know that the ID will change (and so that they
can recalculate their own state accordingly, possibly leading to a ripple
effect). This ensures the overall DAG / schedule is ordered correctly.
This change is most of pulumi/coconut#105. The only missing piece
is to generalize replacing the "ID" property with replacing arbitrary
properties; there are hooks in here for this, but until pulumi/coconut#90
is addressed, it doesn't make sense to make much progress on this.
2017-03-01 18:08:53 +01:00
|
|
|
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
// Create an object to track progress and perform the actual operations.
|
|
|
|
start := time.Now()
|
2017-03-03 00:46:14 +01:00
|
|
|
progress := newProgress(info.Ctx, opts.Summary)
|
2017-02-27 19:26:44 +01:00
|
|
|
checkpoint, err, _, _ := result.Plan.Apply(progress)
|
|
|
|
if err != nil {
|
2017-03-03 00:46:14 +01:00
|
|
|
contract.Assert(!info.Ctx.Diag.Success()) // an error should have been emitted.
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
|
2017-02-28 19:32:24 +01:00
|
|
|
var summary bytes.Buffer
|
Support replacement IDs
This change introduces a new RPC function to the provider interface;
in pseudo-code:
UpdateImpact(id ID, t Type, olds PropertyMap, news PropertyMap)
(bool, PropertyMap, error)
Essentially, during the planning phase, we will consult each provider
about the nature of a proposed update. This update includes a set of
old properties and the new ones and, if the resource provider will need
to replace the property as a result of the update, it will return true;
in general, the PropertyMap will eventually contain a list of all
properties that will be modified as a result of the operation (see below).
The planning phase reacts to this by propagating the change to dependent
resources, so that they know that the ID will change (and so that they
can recalculate their own state accordingly, possibly leading to a ripple
effect). This ensures the overall DAG / schedule is ordered correctly.
This change is most of pulumi/coconut#105. The only missing piece
is to generalize replacing the "ID" property with replacing arbitrary
properties; there are hooks in here for this, but until pulumi/coconut#90
is addressed, it doesn't make sense to make much progress on this.
2017-03-01 18:08:53 +01:00
|
|
|
if !empty {
|
|
|
|
// Print out the total number of steps performed (and their kinds), the duration, and any summary info.
|
2017-03-02 18:52:08 +01:00
|
|
|
printSummary(&summary, progress.Ops, opts.ShowReplaceSteps, false)
|
Support replacement IDs
This change introduces a new RPC function to the provider interface;
in pseudo-code:
UpdateImpact(id ID, t Type, olds PropertyMap, news PropertyMap)
(bool, PropertyMap, error)
Essentially, during the planning phase, we will consult each provider
about the nature of a proposed update. This update includes a set of
old properties and the new ones and, if the resource provider will need
to replace the property as a result of the update, it will return true;
in general, the PropertyMap will eventually contain a list of all
properties that will be modified as a result of the operation (see below).
The planning phase reacts to this by propagating the change to dependent
resources, so that they know that the ID will change (and so that they
can recalculate their own state accordingly, possibly leading to a ripple
effect). This ensures the overall DAG / schedule is ordered correctly.
This change is most of pulumi/coconut#105. The only missing piece
is to generalize replacing the "ID" property with replacing arbitrary
properties; there are hooks in here for this, but until pulumi/coconut#90
is addressed, it doesn't make sense to make much progress on this.
2017-03-01 18:08:53 +01:00
|
|
|
summary.WriteString(fmt.Sprintf("%vDeployment duration: %v%v\n",
|
|
|
|
colors.SpecUnimportant, time.Since(start), colors.Reset))
|
|
|
|
}
|
|
|
|
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
if progress.MaybeCorrupt {
|
2017-02-28 19:32:24 +01:00
|
|
|
summary.WriteString(fmt.Sprintf(
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
"%vfatal: A catastrophic error occurred; resources states may be unknown%v\n",
|
2017-03-01 01:09:56 +01:00
|
|
|
colors.SpecAttention, colors.Reset))
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now save the updated snapshot to the specified output file, if any, or the standard location otherwise.
|
2017-02-27 19:26:44 +01:00
|
|
|
// Note that if a failure has occurred, the Apply routine above will have returned a safe checkpoint.
|
2017-03-06 15:32:39 +01:00
|
|
|
env := result.Info.Env
|
|
|
|
saveEnv(env, checkpoint, opts.Output, true /*overwrite*/)
|
2017-02-27 19:26:44 +01:00
|
|
|
|
2017-03-01 01:09:56 +01:00
|
|
|
fmt.Printf(colors.Colorize(&summary))
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-01 18:57:14 +01:00
|
|
|
func checkEmpty(d diag.Sink, plan resource.Plan) bool {
|
|
|
|
// If we are doing an empty update, say so.
|
|
|
|
if plan.Empty() {
|
|
|
|
d.Infof(diag.Message("no resources need to be updated"))
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2017-03-06 15:32:39 +01:00
|
|
|
// backupEnv makes a backup of an existing file, in preparation for writing a new one. Instead of a copy, it
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
// simply renames the file, which is simpler, more efficient, etc.
|
2017-03-06 15:32:39 +01:00
|
|
|
func backupEnv(file string) {
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
contract.Require(file != "", "file")
|
|
|
|
os.Rename(file, file+".bak") // ignore errors.
|
Add basic targeting capability
This change partially implements pulumi/coconut#94, by adding the
ability to name targets during creation and reuse those names during
deletion and update. This simplifies the management of deployment
records, checkpoints, and snapshots.
I've opted to call these things "husks" (perhaps going overboard with
joy after our recent renaming). The basic idea is that for any
executable Nut that will be deployed, you have a nutpack/ directory
whose layout looks roughly as follows:
nutpack/
bin/
Nutpack.json
... any other compiled artifacts ...
husks/
... one snapshot per husk ...
For example, if we had a stage and prod husk, we would have:
nutpack/
bin/...
husks/
prod.json
stage.json
In the prod.json and stage.json files, we'd have the most recent
deployment record for that environment. These would presumably get
checked in and versioned along with the overall Nut, so that we
can use Git history for rollbacks, etc.
The create, update, and delete commands look in the right place for
these files automatically, so you don't need to manually supply them.
2017-02-25 18:24:52 +01:00
|
|
|
// TODO: consider multiple backups (.bak.bak.bak...etc).
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
|
2017-03-06 15:32:39 +01:00
|
|
|
// deleteEnv removes an existing snapshot file, leaving behind a backup.
|
|
|
|
func deleteEnv(env *resource.Env) {
|
|
|
|
contract.Require(env != nil, "env")
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
// Just make a backup of the file and don't write out anything new.
|
2017-03-06 15:32:39 +01:00
|
|
|
file := workspace.EnvPath(env.Name)
|
|
|
|
backupEnv(file)
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
|
2017-03-06 15:32:39 +01:00
|
|
|
// readEnv reads in an existing snapshot file, issuing an error and returning nil if something goes awry.
|
|
|
|
func readEnv(ctx *resource.Context, name tokens.QName) (*resource.Envfile, *resource.Env, resource.Snapshot) {
|
2017-03-01 00:43:46 +01:00
|
|
|
contract.Require(name != "", "name")
|
2017-03-06 15:32:39 +01:00
|
|
|
file := workspace.EnvPath(name)
|
Add basic targeting capability
This change partially implements pulumi/coconut#94, by adding the
ability to name targets during creation and reuse those names during
deletion and update. This simplifies the management of deployment
records, checkpoints, and snapshots.
I've opted to call these things "husks" (perhaps going overboard with
joy after our recent renaming). The basic idea is that for any
executable Nut that will be deployed, you have a nutpack/ directory
whose layout looks roughly as follows:
nutpack/
bin/
Nutpack.json
... any other compiled artifacts ...
husks/
... one snapshot per husk ...
For example, if we had a stage and prod husk, we would have:
nutpack/
bin/...
husks/
prod.json
stage.json
In the prod.json and stage.json files, we'd have the most recent
deployment record for that environment. These would presumably get
checked in and versioned along with the overall Nut, so that we
can use Git history for rollbacks, etc.
The create, update, and delete commands look in the right place for
these files automatically, so you don't need to manually supply them.
2017-02-25 18:24:52 +01:00
|
|
|
|
2017-02-25 01:44:46 +01:00
|
|
|
// Detect the encoding of the file so we can do our initial unmarshaling.
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
m, ext := encoding.Detect(file)
|
|
|
|
if m == nil {
|
2017-02-27 19:26:44 +01:00
|
|
|
ctx.Diag.Errorf(errors.ErrorIllegalMarkupExtension, ext)
|
2017-03-01 00:43:46 +01:00
|
|
|
return nil, nil, nil
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
|
2017-02-26 20:52:44 +01:00
|
|
|
// Now read the whole file into a byte blob.
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
b, err := ioutil.ReadFile(file)
|
|
|
|
if err != nil {
|
2017-02-26 20:52:44 +01:00
|
|
|
if os.IsNotExist(err) {
|
2017-03-06 15:32:39 +01:00
|
|
|
ctx.Diag.Errorf(errors.ErrorInvalidEnvName, name)
|
2017-02-26 20:52:44 +01:00
|
|
|
} else {
|
2017-02-27 19:26:44 +01:00
|
|
|
ctx.Diag.Errorf(errors.ErrorIO, err)
|
2017-02-26 20:52:44 +01:00
|
|
|
}
|
2017-03-01 00:43:46 +01:00
|
|
|
return nil, nil, nil
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
|
2017-03-06 15:32:39 +01:00
|
|
|
// Unmarshal the contents into a envfile deployment structure.
|
|
|
|
var envfile resource.Envfile
|
|
|
|
if err = m.Unmarshal(b, &envfile); err != nil {
|
2017-02-27 19:26:44 +01:00
|
|
|
ctx.Diag.Errorf(errors.ErrorCantReadDeployment, file, err)
|
2017-03-01 00:43:46 +01:00
|
|
|
return nil, nil, nil
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
2017-02-25 01:44:46 +01:00
|
|
|
|
|
|
|
// Next, use the mapping infrastructure to validate the contents.
|
2017-02-26 21:00:00 +01:00
|
|
|
// TODO: we can eliminate this redundant unmarshaling once Go supports strict unmarshaling.
|
2017-02-25 01:44:46 +01:00
|
|
|
var obj mapper.Object
|
|
|
|
if err = m.Unmarshal(b, &obj); err != nil {
|
2017-02-27 19:26:44 +01:00
|
|
|
ctx.Diag.Errorf(errors.ErrorCantReadDeployment, file, err)
|
2017-03-01 00:43:46 +01:00
|
|
|
return nil, nil, nil
|
2017-02-25 01:44:46 +01:00
|
|
|
} else {
|
2017-02-26 20:20:14 +01:00
|
|
|
if obj["latest"] != nil {
|
|
|
|
if latest, islatest := obj["latest"].(map[string]interface{}); islatest {
|
|
|
|
delete(latest, "resources") // remove the resources, since they require custom marshaling.
|
|
|
|
}
|
|
|
|
}
|
2017-02-25 01:44:46 +01:00
|
|
|
md := mapper.New(nil)
|
2017-03-06 15:32:39 +01:00
|
|
|
var ignore resource.Envfile // just for errors.
|
2017-02-26 21:00:00 +01:00
|
|
|
if err = md.Decode(obj, &ignore); err != nil {
|
2017-02-27 19:26:44 +01:00
|
|
|
ctx.Diag.Errorf(errors.ErrorCantReadDeployment, file, err)
|
2017-03-01 00:43:46 +01:00
|
|
|
return nil, nil, nil
|
2017-02-25 01:44:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-06 15:32:39 +01:00
|
|
|
env, snap := resource.DeserializeEnvfile(ctx, &envfile)
|
|
|
|
contract.Assert(env != nil)
|
|
|
|
return &envfile, env, snap
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
|
2017-03-06 15:32:39 +01:00
|
|
|
// saveEnv saves a new snapshot at the given location, backing up any existing ones.
|
|
|
|
func saveEnv(env *resource.Env, snap resource.Snapshot, file string, existok bool) bool {
|
|
|
|
contract.Require(env != nil, "env")
|
Add basic targeting capability
This change partially implements pulumi/coconut#94, by adding the
ability to name targets during creation and reuse those names during
deletion and update. This simplifies the management of deployment
records, checkpoints, and snapshots.
I've opted to call these things "husks" (perhaps going overboard with
joy after our recent renaming). The basic idea is that for any
executable Nut that will be deployed, you have a nutpack/ directory
whose layout looks roughly as follows:
nutpack/
bin/
Nutpack.json
... any other compiled artifacts ...
husks/
... one snapshot per husk ...
For example, if we had a stage and prod husk, we would have:
nutpack/
bin/...
husks/
prod.json
stage.json
In the prod.json and stage.json files, we'd have the most recent
deployment record for that environment. These would presumably get
checked in and versioned along with the overall Nut, so that we
can use Git history for rollbacks, etc.
The create, update, and delete commands look in the right place for
these files automatically, so you don't need to manually supply them.
2017-02-25 18:24:52 +01:00
|
|
|
if file == "" {
|
2017-03-06 15:32:39 +01:00
|
|
|
file = workspace.EnvPath(env.Name)
|
Add basic targeting capability
This change partially implements pulumi/coconut#94, by adding the
ability to name targets during creation and reuse those names during
deletion and update. This simplifies the management of deployment
records, checkpoints, and snapshots.
I've opted to call these things "husks" (perhaps going overboard with
joy after our recent renaming). The basic idea is that for any
executable Nut that will be deployed, you have a nutpack/ directory
whose layout looks roughly as follows:
nutpack/
bin/
Nutpack.json
... any other compiled artifacts ...
husks/
... one snapshot per husk ...
For example, if we had a stage and prod husk, we would have:
nutpack/
bin/...
husks/
prod.json
stage.json
In the prod.json and stage.json files, we'd have the most recent
deployment record for that environment. These would presumably get
checked in and versioned along with the overall Nut, so that we
can use Git history for rollbacks, etc.
The create, update, and delete commands look in the right place for
these files automatically, so you don't need to manually supply them.
2017-02-25 18:24:52 +01:00
|
|
|
}
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
|
2017-02-25 16:25:33 +01:00
|
|
|
// Make a serializable CocoGL data structure and then use the encoder to encode it.
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
m, ext := encoding.Detect(file)
|
|
|
|
if m == nil {
|
|
|
|
sink().Errorf(errors.ErrorIllegalMarkupExtension, ext)
|
2017-02-26 20:20:14 +01:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
if filepath.Ext(file) == "" {
|
|
|
|
file = file + ext
|
|
|
|
}
|
2017-03-06 15:32:39 +01:00
|
|
|
dep := resource.SerializeEnvfile(env, snap, "")
|
2017-02-26 20:20:14 +01:00
|
|
|
b, err := m.Marshal(dep)
|
|
|
|
if err != nil {
|
|
|
|
sink().Errorf(errors.ErrorIO, err)
|
|
|
|
return false
|
|
|
|
}
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
|
2017-02-26 20:20:14 +01:00
|
|
|
// If it's not ok for the file to already exist, ensure that it doesn't.
|
|
|
|
if !existok {
|
|
|
|
if _, err := os.Stat(file); err == nil {
|
|
|
|
sink().Errorf(errors.ErrorIO, fmt.Errorf("file '%v' already exists", file))
|
|
|
|
return false
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
}
|
2017-02-26 20:20:14 +01:00
|
|
|
|
|
|
|
// Back up the existing file if it already exists.
|
2017-03-06 15:32:39 +01:00
|
|
|
backupEnv(file)
|
2017-02-26 20:20:14 +01:00
|
|
|
|
|
|
|
// Ensure the directory exists.
|
|
|
|
if err = os.MkdirAll(filepath.Dir(file), 0755); err != nil {
|
|
|
|
sink().Errorf(errors.ErrorIO, err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// And now write out the new snapshot file, overwriting that location.
|
|
|
|
if err = ioutil.WriteFile(file, b, 0644); err != nil {
|
|
|
|
sink().Errorf(errors.ErrorIO, err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
type applyOptions struct {
|
2017-03-02 18:52:08 +01:00
|
|
|
Create bool // true if we are creating resources.
|
|
|
|
Delete bool // true if we are deleting resources.
|
|
|
|
DryRun bool // true if we should just print the plan without performing it.
|
|
|
|
ShowConfig bool // true to show the configuration variables being used.
|
|
|
|
ShowReplaceSteps bool // true to show the replacement steps in the plan.
|
|
|
|
ShowUnchanged bool // true to show the resources that aren't updated, in addition to those that are.
|
|
|
|
Summary bool // true if we should only summarize resources and operations.
|
|
|
|
Output string // the place to store the output, if any.
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// applyProgress pretty-prints the plan application process as it goes.
|
|
|
|
type applyProgress struct {
|
2017-03-03 00:46:14 +01:00
|
|
|
Ctx *resource.Context
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
Steps int
|
|
|
|
Ops map[resource.StepOp]int
|
|
|
|
MaybeCorrupt bool
|
2017-02-25 16:55:22 +01:00
|
|
|
Summary bool
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
|
2017-03-03 00:46:14 +01:00
|
|
|
func newProgress(ctx *resource.Context, summary bool) *applyProgress {
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
return &applyProgress{
|
2017-03-03 00:46:14 +01:00
|
|
|
Ctx: ctx,
|
2017-02-25 16:55:22 +01:00
|
|
|
Steps: 0,
|
|
|
|
Ops: make(map[resource.StepOp]int),
|
|
|
|
Summary: summary,
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (prog *applyProgress) Before(step resource.Step) {
|
|
|
|
// Print the step.
|
2017-03-02 18:52:08 +01:00
|
|
|
stepop := step.Op()
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
stepnum := prog.Steps + 1
|
2017-03-02 18:52:08 +01:00
|
|
|
|
|
|
|
var extra string
|
|
|
|
if stepop == resource.OpReplaceCreate || stepop == resource.OpReplaceDelete {
|
|
|
|
extra = " (part of a replacement step)"
|
|
|
|
}
|
|
|
|
|
|
|
|
var b bytes.Buffer
|
|
|
|
b.WriteString(fmt.Sprintf("Applying step #%v [%v]%v\n", stepnum, stepop, extra))
|
2017-02-25 16:55:22 +01:00
|
|
|
printStep(&b, step, prog.Summary, " ")
|
2017-02-28 19:32:24 +01:00
|
|
|
fmt.Printf(colors.Colorize(&b))
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (prog *applyProgress) After(step resource.Step, err error, state resource.ResourceState) {
|
|
|
|
if err == nil {
|
|
|
|
// Increment the counters.
|
|
|
|
prog.Steps++
|
|
|
|
prog.Ops[step.Op()]++
|
|
|
|
} else {
|
2017-03-03 00:46:14 +01:00
|
|
|
// Issue a true, bonafide error.
|
|
|
|
prog.Ctx.Diag.Errorf(errors.ErrorPlanApplyFailed, err)
|
|
|
|
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
// Print the state of the resource; we don't issue the error, because the apply above will do that.
|
2017-03-03 00:46:14 +01:00
|
|
|
var b bytes.Buffer
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
stepnum := prog.Steps + 1
|
2017-02-25 02:44:54 +01:00
|
|
|
b.WriteString(fmt.Sprintf("Step #%v failed [%v]: ", stepnum, step.Op()))
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
switch state {
|
|
|
|
case resource.StateOK:
|
|
|
|
b.WriteString(colors.SpecNote)
|
|
|
|
b.WriteString("provider successfully recovered from this failure")
|
|
|
|
case resource.StateUnknown:
|
2017-03-01 01:09:56 +01:00
|
|
|
b.WriteString(colors.SpecAttention)
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
b.WriteString("this failure was catastrophic and the provider cannot guarantee recovery")
|
|
|
|
prog.MaybeCorrupt = true
|
|
|
|
default:
|
|
|
|
contract.Failf("Unrecognized resource state: %v", state)
|
|
|
|
}
|
|
|
|
b.WriteString(colors.Reset)
|
|
|
|
b.WriteString("\n")
|
2017-02-28 19:32:24 +01:00
|
|
|
fmt.Printf(colors.Colorize(&b))
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-01 18:57:14 +01:00
|
|
|
func printPlan(d diag.Sink, result *planResult, opts applyOptions) {
|
2017-02-28 19:32:24 +01:00
|
|
|
// First print config/unchanged/etc. if necessary.
|
2017-03-01 18:57:14 +01:00
|
|
|
var prelude bytes.Buffer
|
|
|
|
printPrelude(&prelude, result, opts)
|
2017-02-27 19:58:24 +01:00
|
|
|
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
// Now walk the plan's steps and and pretty-print them out.
|
2017-03-01 18:57:14 +01:00
|
|
|
prelude.WriteString(fmt.Sprintf("%vPlanned changes:%v\n", colors.SpecUnimportant, colors.Reset))
|
|
|
|
fmt.Printf(colors.Colorize(&prelude))
|
|
|
|
|
|
|
|
// Print a nice message if the update is an empty one.
|
|
|
|
if empty := checkEmpty(d, result.Plan); !empty {
|
|
|
|
var summary bytes.Buffer
|
|
|
|
step := result.Plan.Steps()
|
|
|
|
counts := make(map[resource.StepOp]int)
|
|
|
|
for step != nil {
|
2017-03-02 18:52:08 +01:00
|
|
|
op := step.Op()
|
2017-03-01 18:57:14 +01:00
|
|
|
// Print this step information (resource and all its properties).
|
|
|
|
// TODO: it would be nice if, in the output, we showed the dependencies a la `git log --graph`.
|
2017-03-02 18:52:08 +01:00
|
|
|
if opts.ShowReplaceSteps || (op != resource.OpReplaceCreate && op != resource.OpReplaceDelete) {
|
|
|
|
printStep(&summary, step, opts.Summary, "")
|
|
|
|
}
|
2017-03-01 18:57:14 +01:00
|
|
|
counts[step.Op()]++
|
|
|
|
step = step.Next()
|
|
|
|
}
|
2017-02-28 19:32:24 +01:00
|
|
|
|
2017-03-01 18:57:14 +01:00
|
|
|
// Print a summary of operation counts.
|
2017-03-02 18:52:08 +01:00
|
|
|
printSummary(&summary, counts, opts.ShowReplaceSteps, true)
|
2017-03-01 18:57:14 +01:00
|
|
|
fmt.Printf(colors.Colorize(&summary))
|
|
|
|
}
|
2017-02-28 19:32:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func printPrelude(b *bytes.Buffer, result *planResult, opts applyOptions) {
|
|
|
|
// If there are configuration variables, show them.
|
|
|
|
if opts.ShowConfig {
|
|
|
|
printConfig(b, result.compileResult)
|
|
|
|
}
|
|
|
|
|
|
|
|
// If show-sames was requested, walk the sames and print them.
|
|
|
|
if opts.ShowUnchanged {
|
|
|
|
printUnchanged(b, result.Plan, opts.Summary)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func printConfig(b *bytes.Buffer, result *compileResult) {
|
|
|
|
b.WriteString(fmt.Sprintf("%vConfiguration:%v\n", colors.SpecUnimportant, colors.Reset))
|
|
|
|
if result != nil && result.ConfigVars != nil {
|
|
|
|
var toks []string
|
|
|
|
for tok := range result.ConfigVars {
|
|
|
|
toks = append(toks, string(tok))
|
|
|
|
}
|
|
|
|
sort.Strings(toks)
|
|
|
|
for _, tok := range toks {
|
|
|
|
b.WriteString(fmt.Sprintf("%v%v: %v\n", detailsIndent, tok, result.ConfigVars[tokens.Token(tok)]))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-02 18:52:08 +01:00
|
|
|
func printSummary(b *bytes.Buffer, counts map[resource.StepOp]int, showReplaceSteps bool, plan bool) {
|
2017-02-28 19:32:24 +01:00
|
|
|
total := 0
|
|
|
|
for _, c := range counts {
|
|
|
|
total += c
|
|
|
|
}
|
|
|
|
|
|
|
|
var planned string
|
|
|
|
if plan {
|
|
|
|
planned = "planned "
|
|
|
|
}
|
2017-03-01 01:09:56 +01:00
|
|
|
var colon string
|
|
|
|
if total != 0 {
|
|
|
|
colon = ":"
|
|
|
|
}
|
2017-03-01 22:34:29 +01:00
|
|
|
b.WriteString(fmt.Sprintf("%v total %v%v%v\n", total, planned, plural("change", total), colon))
|
2017-02-28 19:32:24 +01:00
|
|
|
|
|
|
|
var planTo string
|
|
|
|
var pastTense string
|
|
|
|
if plan {
|
|
|
|
planTo = "to "
|
|
|
|
} else {
|
|
|
|
pastTense = "d"
|
|
|
|
}
|
|
|
|
|
2017-03-01 22:34:29 +01:00
|
|
|
for _, op := range resource.StepOps() {
|
2017-03-02 18:52:08 +01:00
|
|
|
if !showReplaceSteps && (op == resource.OpReplaceCreate || op == resource.OpReplaceDelete) {
|
|
|
|
// Unless the user requested it, don't show the fine-grained replacement steps; just the logical ones.
|
|
|
|
continue
|
|
|
|
}
|
2017-03-01 22:34:29 +01:00
|
|
|
if c := counts[op]; c > 0 {
|
|
|
|
b.WriteString(fmt.Sprintf(" %v%v %v %v%v%v%v\n",
|
|
|
|
op.Prefix(), c, plural("resource", c), planTo, op, pastTense, colors.Reset))
|
|
|
|
}
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-01 22:34:29 +01:00
|
|
|
func plural(s string, c int) string {
|
|
|
|
if c != 1 {
|
|
|
|
s += "s"
|
2017-02-24 04:03:22 +01:00
|
|
|
}
|
2017-03-01 22:34:29 +01:00
|
|
|
return s
|
2017-02-24 04:03:22 +01:00
|
|
|
}
|
|
|
|
|
2017-02-28 19:32:24 +01:00
|
|
|
const detailsIndent = " " // 4 spaces, plus 2 for "+ ", "- ", and " " leaders
|
2017-02-24 04:03:22 +01:00
|
|
|
|
2017-02-27 20:08:14 +01:00
|
|
|
func printUnchanged(b *bytes.Buffer, plan resource.Plan, summary bool) {
|
2017-02-28 19:32:24 +01:00
|
|
|
b.WriteString(fmt.Sprintf("%vUnchanged resources:%v\n", colors.SpecUnimportant, colors.Reset))
|
2017-02-27 20:08:14 +01:00
|
|
|
for _, res := range plan.Unchanged() {
|
2017-02-28 19:32:24 +01:00
|
|
|
b.WriteString(" ") // simulate the 2 spaces for +, -, etc.
|
2017-02-27 20:08:14 +01:00
|
|
|
printResourceHeader(b, res, nil, "")
|
2017-03-03 00:24:39 +01:00
|
|
|
printResourceProperties(b, res, nil, nil, nil, summary, "")
|
2017-02-27 19:58:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-25 16:55:22 +01:00
|
|
|
func printStep(b *bytes.Buffer, step resource.Step, summary bool, indent string) {
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
// First print out the operation's prefix.
|
2017-03-01 22:34:29 +01:00
|
|
|
b.WriteString(step.Op().Prefix())
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
|
2017-03-03 02:10:10 +01:00
|
|
|
// Next print the resource URN, properties, etc.
|
2017-02-24 04:03:22 +01:00
|
|
|
printResourceHeader(b, step.Old(), step.New(), indent)
|
2017-03-01 22:34:29 +01:00
|
|
|
b.WriteString(step.Op().Suffix())
|
2017-03-03 00:24:39 +01:00
|
|
|
var replaces []resource.PropertyKey
|
|
|
|
if step.Old() != nil {
|
2017-03-03 02:10:10 +01:00
|
|
|
m := step.Old().URN()
|
2017-03-03 00:24:39 +01:00
|
|
|
replaceMap := step.Plan().Replaces()
|
|
|
|
replaces = replaceMap[m]
|
|
|
|
}
|
|
|
|
printResourceProperties(b, step.Old(), step.New(), step.NewProps(), replaces, summary, indent)
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
|
|
|
|
// Finally make sure to reset the color.
|
|
|
|
b.WriteString(colors.Reset)
|
|
|
|
}
|
|
|
|
|
2017-02-24 04:03:22 +01:00
|
|
|
func printResourceHeader(b *bytes.Buffer, old resource.Resource, new resource.Resource, indent string) {
|
|
|
|
var t tokens.Type
|
|
|
|
if old == nil {
|
|
|
|
t = new.Type()
|
|
|
|
} else {
|
|
|
|
t = old.Type()
|
|
|
|
}
|
|
|
|
|
|
|
|
// The primary header is the resource type (since it is easy on the eyes).
|
|
|
|
b.WriteString(fmt.Sprintf("%s:\n", string(t)))
|
|
|
|
}
|
|
|
|
|
|
|
|
func printResourceProperties(b *bytes.Buffer, old resource.Resource, new resource.Resource,
|
2017-03-03 00:24:39 +01:00
|
|
|
computed resource.PropertyMap, replaces []resource.PropertyKey, summary bool, indent string) {
|
2017-02-28 19:32:24 +01:00
|
|
|
indent += detailsIndent
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
|
2017-03-03 02:10:10 +01:00
|
|
|
// Print out the URN and, if present, the ID, as "pseudo-properties".
|
2017-02-24 04:03:22 +01:00
|
|
|
var id resource.ID
|
2017-03-03 02:10:10 +01:00
|
|
|
var URN resource.URN
|
2017-02-24 04:03:22 +01:00
|
|
|
if old == nil {
|
|
|
|
id = new.ID()
|
2017-03-03 02:10:10 +01:00
|
|
|
URN = new.URN()
|
2017-02-24 04:03:22 +01:00
|
|
|
} else {
|
|
|
|
id = old.ID()
|
2017-03-03 02:10:10 +01:00
|
|
|
URN = old.URN()
|
2017-02-24 04:03:22 +01:00
|
|
|
}
|
|
|
|
if id != "" {
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
b.WriteString(fmt.Sprintf("%s[id=%s]\n", indent, string(id)))
|
|
|
|
}
|
2017-03-03 02:10:10 +01:00
|
|
|
b.WriteString(fmt.Sprintf("%s[urn=%s]\n", indent, URN.Name()))
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
|
2017-02-25 16:55:22 +01:00
|
|
|
if !summary {
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
// Print all of the properties associated with this resource.
|
2017-02-24 04:03:22 +01:00
|
|
|
if old == nil && new != nil {
|
|
|
|
printObject(b, new.Properties(), indent)
|
|
|
|
} else if new == nil && old != nil {
|
|
|
|
printObject(b, old.Properties(), indent)
|
|
|
|
} else {
|
2017-03-01 22:34:29 +01:00
|
|
|
contract.Assert(computed != nil) // use computed properties for diffs.
|
2017-03-03 00:24:39 +01:00
|
|
|
printOldNewDiffs(b, old.Properties(), computed, replaces, indent)
|
2017-02-24 04:03:22 +01:00
|
|
|
}
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func printObject(b *bytes.Buffer, props resource.PropertyMap, indent string) {
|
|
|
|
// Compute the maximum with of property keys so we can justify everything.
|
|
|
|
keys := resource.StablePropertyKeys(props)
|
|
|
|
maxkey := 0
|
|
|
|
for _, k := range keys {
|
|
|
|
if len(k) > maxkey {
|
|
|
|
maxkey = len(k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now print out the values intelligently based on the type.
|
|
|
|
for _, k := range keys {
|
2017-02-25 01:44:46 +01:00
|
|
|
if v := props[k]; shouldPrintPropertyValue(v) {
|
|
|
|
printPropertyTitle(b, k, maxkey, indent)
|
|
|
|
printPropertyValue(b, v, indent)
|
|
|
|
}
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-25 01:44:46 +01:00
|
|
|
func shouldPrintPropertyValue(v resource.PropertyValue) bool {
|
|
|
|
return !v.IsNull() // by default, don't print nulls (they just clutter up the output)
|
|
|
|
}
|
|
|
|
|
2017-02-24 04:03:22 +01:00
|
|
|
func printPropertyTitle(b *bytes.Buffer, k resource.PropertyKey, align int, indent string) {
|
|
|
|
b.WriteString(fmt.Sprintf("%s%-"+strconv.Itoa(align)+"s: ", indent, k))
|
|
|
|
}
|
|
|
|
|
|
|
|
func printPropertyValue(b *bytes.Buffer, v resource.PropertyValue, indent string) {
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
if v.IsNull() {
|
2017-02-25 01:44:46 +01:00
|
|
|
b.WriteString("<null>")
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
} else if v.IsBool() {
|
|
|
|
b.WriteString(fmt.Sprintf("%t", v.BoolValue()))
|
|
|
|
} else if v.IsNumber() {
|
|
|
|
b.WriteString(fmt.Sprintf("%v", v.NumberValue()))
|
|
|
|
} else if v.IsString() {
|
|
|
|
b.WriteString(fmt.Sprintf("\"%s\"", v.StringValue()))
|
|
|
|
} else if v.IsResource() {
|
|
|
|
b.WriteString(fmt.Sprintf("-> *%s", v.ResourceValue()))
|
|
|
|
} else if v.IsArray() {
|
|
|
|
b.WriteString(fmt.Sprintf("[\n"))
|
|
|
|
for i, elem := range v.ArrayValue() {
|
2017-02-24 04:03:22 +01:00
|
|
|
newIndent := printArrayElemHeader(b, i, indent)
|
|
|
|
printPropertyValue(b, elem, newIndent)
|
Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly. This is largely
in preparation for performing deletes and updates of existing environments.
The old way was slightly confusing and made things appear more "magical"
than they actually are. Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.
The new way is to offer three commands: create, update, and delete. Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely. The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.
Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands. This will print out the plan without
actually performing any opterations.
All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 20:21:26 +01:00
|
|
|
}
|
|
|
|
b.WriteString(fmt.Sprintf("%s]", indent))
|
|
|
|
} else {
|
|
|
|
contract.Assert(v.IsObject())
|
|
|
|
b.WriteString("{\n")
|
|
|
|
printObject(b, v.ObjectValue(), indent+" ")
|
|
|
|
b.WriteString(fmt.Sprintf("%s}", indent))
|
|
|
|
}
|
|
|
|
b.WriteString("\n")
|
|
|
|
}
|
|
|
|
|
2017-02-24 04:03:22 +01:00
|
|
|
func getArrayElemHeader(b *bytes.Buffer, i int, indent string) (string, string) {
|
2017-02-27 20:27:36 +01:00
|
|
|
prefix := fmt.Sprintf(" %s[%d]: ", indent, i)
|
2017-02-24 04:03:22 +01:00
|
|
|
return prefix, fmt.Sprintf("%-"+strconv.Itoa(len(prefix))+"s", "")
|
2017-02-13 23:26:46 +01:00
|
|
|
}
|
2017-02-24 04:03:22 +01:00
|
|
|
|
|
|
|
func printArrayElemHeader(b *bytes.Buffer, i int, indent string) string {
|
|
|
|
prefix, newIndent := getArrayElemHeader(b, i, indent)
|
|
|
|
b.WriteString(prefix)
|
|
|
|
return newIndent
|
|
|
|
}
|
|
|
|
|
2017-03-03 00:24:39 +01:00
|
|
|
func printOldNewDiffs(b *bytes.Buffer, olds resource.PropertyMap, news resource.PropertyMap,
|
|
|
|
replaces []resource.PropertyKey, indent string) {
|
2017-02-24 04:03:22 +01:00
|
|
|
// Get the full diff structure between the two, and print it (recursively).
|
|
|
|
if diff := olds.Diff(news); diff != nil {
|
2017-03-03 00:24:39 +01:00
|
|
|
printObjectDiff(b, *diff, replaces, false, indent)
|
2017-02-24 04:03:22 +01:00
|
|
|
} else {
|
|
|
|
printObject(b, news, indent)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-03 00:24:39 +01:00
|
|
|
func printObjectDiff(b *bytes.Buffer, diff resource.ObjectDiff,
|
|
|
|
replaces []resource.PropertyKey, causedReplace bool, indent string) {
|
2017-02-24 04:03:22 +01:00
|
|
|
contract.Assert(len(indent) > 2)
|
|
|
|
|
|
|
|
// Compute the maximum with of property keys so we can justify everything.
|
|
|
|
keys := diff.Keys()
|
|
|
|
maxkey := 0
|
|
|
|
for _, k := range keys {
|
|
|
|
if len(k) > maxkey {
|
|
|
|
maxkey = len(k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-03 00:24:39 +01:00
|
|
|
// If a list of what causes a resource to get replaced exist, create a handy map.
|
|
|
|
var replaceMap map[resource.PropertyKey]bool
|
|
|
|
if len(replaces) > 0 {
|
|
|
|
replaceMap = make(map[resource.PropertyKey]bool)
|
|
|
|
for _, k := range replaces {
|
|
|
|
replaceMap[k] = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-24 04:03:22 +01:00
|
|
|
// To print an object diff, enumerate the keys in stable order, and print each property independently.
|
|
|
|
for _, k := range keys {
|
|
|
|
title := func(id string) { printPropertyTitle(b, k, maxkey, id) }
|
|
|
|
if add, isadd := diff.Adds[k]; isadd {
|
2017-02-25 01:44:46 +01:00
|
|
|
if shouldPrintPropertyValue(add) {
|
|
|
|
b.WriteString(colors.SpecAdded)
|
|
|
|
title(addIndent(indent))
|
|
|
|
printPropertyValue(b, add, addIndent(indent))
|
|
|
|
b.WriteString(colors.Reset)
|
|
|
|
}
|
2017-02-24 04:03:22 +01:00
|
|
|
} else if delete, isdelete := diff.Deletes[k]; isdelete {
|
2017-02-25 01:44:46 +01:00
|
|
|
if shouldPrintPropertyValue(delete) {
|
|
|
|
b.WriteString(colors.SpecDeleted)
|
|
|
|
title(deleteIndent(indent))
|
|
|
|
printPropertyValue(b, delete, deleteIndent(indent))
|
|
|
|
b.WriteString(colors.Reset)
|
|
|
|
}
|
2017-02-24 04:03:22 +01:00
|
|
|
} else if update, isupdate := diff.Updates[k]; isupdate {
|
2017-03-03 00:24:39 +01:00
|
|
|
if !causedReplace && replaceMap != nil {
|
|
|
|
causedReplace = replaceMap[k]
|
|
|
|
}
|
|
|
|
printPropertyValueDiff(b, title, update, causedReplace, indent)
|
2017-02-25 01:44:46 +01:00
|
|
|
} else if same := diff.Sames[k]; shouldPrintPropertyValue(same) {
|
2017-02-24 04:03:22 +01:00
|
|
|
title(indent)
|
|
|
|
printPropertyValue(b, diff.Sames[k], indent)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-03 00:24:39 +01:00
|
|
|
func printPropertyValueDiff(b *bytes.Buffer, title func(string), diff resource.ValueDiff,
|
|
|
|
causedReplace bool, indent string) {
|
2017-02-24 04:03:22 +01:00
|
|
|
contract.Assert(len(indent) > 2)
|
|
|
|
|
|
|
|
if diff.Array != nil {
|
|
|
|
title(indent)
|
|
|
|
b.WriteString("[\n")
|
2017-03-03 00:24:39 +01:00
|
|
|
|
|
|
|
a := diff.Array
|
2017-02-24 04:03:22 +01:00
|
|
|
for i := 0; i < a.Len(); i++ {
|
|
|
|
_, newIndent := getArrayElemHeader(b, i, indent)
|
2017-02-27 20:27:36 +01:00
|
|
|
title := func(id string) { printArrayElemHeader(b, i, id) }
|
2017-02-24 04:03:22 +01:00
|
|
|
if add, isadd := a.Adds[i]; isadd {
|
2017-03-02 18:52:08 +01:00
|
|
|
b.WriteString(resource.OpCreate.Color())
|
2017-02-27 20:27:36 +01:00
|
|
|
title(addIndent(indent))
|
2017-02-24 04:03:22 +01:00
|
|
|
printPropertyValue(b, add, addIndent(newIndent))
|
|
|
|
b.WriteString(colors.Reset)
|
|
|
|
} else if delete, isdelete := a.Deletes[i]; isdelete {
|
2017-03-02 18:52:08 +01:00
|
|
|
b.WriteString(resource.OpDelete.Color())
|
2017-02-27 20:27:36 +01:00
|
|
|
title(deleteIndent(indent))
|
|
|
|
printPropertyValue(b, delete, deleteIndent(newIndent))
|
2017-02-24 04:03:22 +01:00
|
|
|
b.WriteString(colors.Reset)
|
|
|
|
} else if update, isupdate := a.Updates[i]; isupdate {
|
2017-03-03 00:24:39 +01:00
|
|
|
printPropertyValueDiff(b, title, update, causedReplace, indent)
|
2017-02-24 04:03:22 +01:00
|
|
|
} else {
|
2017-02-27 20:27:36 +01:00
|
|
|
title(indent)
|
2017-02-24 04:03:22 +01:00
|
|
|
printPropertyValue(b, a.Sames[i], newIndent)
|
|
|
|
}
|
|
|
|
}
|
2017-02-25 01:44:46 +01:00
|
|
|
b.WriteString(fmt.Sprintf("%s]\n", indent))
|
2017-02-24 04:03:22 +01:00
|
|
|
} else if diff.Object != nil {
|
|
|
|
title(indent)
|
|
|
|
b.WriteString("{\n")
|
2017-03-03 00:24:39 +01:00
|
|
|
printObjectDiff(b, *diff.Object, nil, causedReplace, indent+" ")
|
2017-02-25 01:44:46 +01:00
|
|
|
b.WriteString(fmt.Sprintf("%s}\n", indent))
|
2017-03-02 18:52:08 +01:00
|
|
|
} else if diff.Old.IsResource() && diff.New.IsResource() && diff.New.ResourceValue().Replacement() {
|
|
|
|
// If the old and new are both resources, and the new is a replacement, show this in a special way (+-).
|
|
|
|
b.WriteString(resource.OpReplace.Color())
|
|
|
|
title(updateIndent(indent))
|
|
|
|
printPropertyValue(b, diff.Old, updateIndent(indent))
|
|
|
|
b.WriteString(colors.Reset)
|
2017-02-24 04:03:22 +01:00
|
|
|
} else {
|
|
|
|
// If we ended up here, the two values either differ by type, or they have different primitive values. We will
|
|
|
|
// simply emit a deletion line followed by an addition line.
|
2017-02-25 01:44:46 +01:00
|
|
|
if shouldPrintPropertyValue(diff.Old) {
|
2017-03-03 00:24:39 +01:00
|
|
|
var color string
|
|
|
|
if causedReplace {
|
|
|
|
color = resource.OpDelete.Color() // this property triggered replacement; color as a delete
|
|
|
|
} else {
|
|
|
|
color = resource.OpUpdate.Color()
|
|
|
|
}
|
|
|
|
b.WriteString(color)
|
2017-02-25 01:44:46 +01:00
|
|
|
title(deleteIndent(indent))
|
|
|
|
printPropertyValue(b, diff.Old, deleteIndent(indent))
|
2017-03-02 18:52:08 +01:00
|
|
|
b.WriteString(colors.Reset)
|
2017-02-25 01:44:46 +01:00
|
|
|
}
|
|
|
|
if shouldPrintPropertyValue(diff.New) {
|
2017-03-03 00:24:39 +01:00
|
|
|
var color string
|
|
|
|
if causedReplace {
|
|
|
|
color = resource.OpCreate.Color() // this property triggered replacement; color as a create
|
|
|
|
} else {
|
|
|
|
color = resource.OpUpdate.Color()
|
|
|
|
}
|
|
|
|
b.WriteString(color)
|
2017-02-25 01:44:46 +01:00
|
|
|
title(addIndent(indent))
|
|
|
|
printPropertyValue(b, diff.New, addIndent(indent))
|
2017-03-02 18:52:08 +01:00
|
|
|
b.WriteString(colors.Reset)
|
2017-02-25 01:44:46 +01:00
|
|
|
}
|
2017-02-24 04:03:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func addIndent(indent string) string { return indent[:len(indent)-2] + "+ " }
|
|
|
|
func deleteIndent(indent string) string { return indent[:len(indent)-2] + "- " }
|
2017-03-02 18:52:08 +01:00
|
|
|
func updateIndent(indent string) string { return indent[:len(indent)-2] + "+-" }
|