pulumi/cmd/lumi/deploy.go
joeduffy 25c52a04c5 Tidy up some loose ends
This removes some loose ends and reimplements `lumi pack eval`.
2017-06-13 07:10:13 -07:00

190 lines
6.9 KiB
Go

// Licensed to Pulumi Corporation ("Pulumi") under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// Pulumi licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"bytes"
"fmt"
"github.com/spf13/cobra"
"github.com/pulumi/lumi/pkg/compiler/errors"
"github.com/pulumi/lumi/pkg/diag/colors"
"github.com/pulumi/lumi/pkg/resource"
"github.com/pulumi/lumi/pkg/resource/deploy"
"github.com/pulumi/lumi/pkg/tokens"
"github.com/pulumi/lumi/pkg/util/cmdutil"
"github.com/pulumi/lumi/pkg/util/contract"
)
func newDeployCmd() *cobra.Command {
var analyzers []string
var dryRun bool
var env string
var showConfig bool
var showReplaceSteps bool
var showSames bool
var summary bool
var output string
var cmd = &cobra.Command{
Use: "deploy [<package>] [-- [<args>]]",
Aliases: []string{"up", "update"},
Short: "Deploy resource updates, creations, and deletions to an environment",
Long: "Deploy resource updates, creations, and deletions to an environment\n" +
"\n" +
"This command updates an existing environment whose state is represented by the\n" +
"existing snapshot file. The new desired state is computed by compiling and evaluating an\n" +
"executable package, and extracting all resource allocations from its resulting object graph.\n" +
"This graph is compared against the existing state to determine what operations must take\n" +
"place to achieve the desired state. This command results in a full snapshot of the\n" +
"environment's new resource state, so that it may be updated incrementally again later.\n" +
"\n" +
"By default, the package to execute is loaded from the current directory. Optionally, an\n" +
"explicit path can be provided using the [package] argument.",
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
info, err := initEnvCmdName(tokens.QName(env), args)
if err != nil {
return err
}
planAndDeploy(cmd, info, deployOptions{
Delete: false,
DryRun: dryRun,
Analyzers: analyzers,
ShowConfig: showConfig,
ShowReplaceSteps: showReplaceSteps,
ShowSames: showSames,
Summary: summary,
Output: output,
})
return nil
}),
}
cmd.PersistentFlags().StringSliceVar(
&analyzers, "analyzer", []string{},
"Run one or more analyzers as part of this deployment")
cmd.PersistentFlags().BoolVarP(
&dryRun, "dry-run", "n", false,
"Don't actually update resources, just print out the planned updates (synonym for plan)")
cmd.PersistentFlags().StringVarP(
&env, "env", "e", "",
"Choose an environment other than the currently selected one")
cmd.PersistentFlags().BoolVar(
&showConfig, "show-config", false,
"Show configuration keys and variables")
cmd.PersistentFlags().BoolVar(
&showReplaceSteps, "show-replace-steps", false,
"Show detailed resource replacement creates and deletes; normally shows as a single step")
cmd.PersistentFlags().BoolVar(
&showSames, "show-sames", false,
"Show resources that needn't be updated because they haven't changed, alongside those that do")
cmd.PersistentFlags().BoolVarP(
&summary, "summary", "s", false,
"Only display summarization of resources and plan operations")
cmd.PersistentFlags().StringVarP(
&output, "output", "o", "",
"Serialize the resulting checkpoint to a specific file, instead of overwriting the existing one")
return cmd
}
type deployOptions struct {
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.
Analyzers []string // an optional set of analyzers to run as part of this deployment.
ShowConfig bool // true to show the configuration variables being used.
ShowReplaceSteps bool // true to show the replacement steps in the plan.
ShowSames 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.
DOT bool // true if we should print the DOT file for this plan.
Output string // the place to store the output, if any.
}
// deployProgress pretty-prints the plan application process as it goes.
type deployProgress struct {
Steps int
Ops map[deploy.StepOp]int
MaybeCorrupt bool
Summary bool
}
func newProgress(summary bool) *deployProgress {
return &deployProgress{
Steps: 0,
Ops: make(map[deploy.StepOp]int),
Summary: summary,
}
}
func (prog *deployProgress) Before(step *deploy.Step) {
stepop := step.Op()
if stepop == deploy.OpSame {
return
}
// Print the step.
stepnum := prog.Steps + 1
var extra string
if stepop == deploy.OpReplaceCreate || stepop == deploy.OpReplaceDelete {
extra = " (part of a replacement change)"
}
var b bytes.Buffer
b.WriteString(fmt.Sprintf("Applying step #%v [%v]%v\n", stepnum, stepop, extra))
printStep(&b, step, prog.Summary, false, "")
fmt.Printf(colors.Colorize(&b))
}
func (prog *deployProgress) After(step *deploy.Step, status resource.Status, err error) {
stepop := step.Op()
if err != nil {
// Issue a true, bonafide error.
cmdutil.Diag().Errorf(errors.ErrorPlanApplyFailed, err)
// Print the state of the resource; we don't issue the error, because the deploy above will do that.
var b bytes.Buffer
stepnum := prog.Steps + 1
b.WriteString(fmt.Sprintf("Step #%v failed [%v]: ", stepnum, stepop))
switch status {
case resource.StatusOK:
b.WriteString(colors.SpecNote)
b.WriteString("provider successfully recovered from this failure")
case resource.StatusUnknown:
b.WriteString(colors.SpecAttention)
b.WriteString("this failure was catastrophic and the provider cannot guarantee recovery")
prog.MaybeCorrupt = true
default:
contract.Failf("Unrecognized resource state: %v", status)
}
b.WriteString(colors.Reset)
b.WriteString("\n")
fmt.Printf(colors.Colorize(&b))
} else if stepop != deploy.OpSame {
// Increment the counters.
prog.Steps++
prog.Ops[stepop]++
// Print out any output properties that got created as a result of this operation.
if step.Op() == deploy.OpCreate {
var b bytes.Buffer
printResourceOutputProperties(&b, step, "")
fmt.Printf(colors.Colorize(&b))
}
}
}