command/apply: show add/remove/change count for apply

This commit is contained in:
Mitchell Hashimoto 2014-07-17 15:14:26 -07:00
parent 3077800252
commit ba4435f99c
4 changed files with 121 additions and 8 deletions

View File

@ -50,6 +50,10 @@ func (c *ApplyCommand) Run(args []string) int {
} }
} }
// Prepare the extra hooks to count resources
countHook := new(CountHook)
c.Meta.extraHooks = []terraform.Hook{countHook}
// If we don't specify an output path, default to out normal state // If we don't specify an output path, default to out normal state
// path. // path.
if stateOutPath == "" { if stateOutPath == "" {
@ -124,13 +128,21 @@ func (c *ApplyCommand) Run(args []string) int {
c.Ui.Output(c.Colorize().Color(fmt.Sprintf( c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
"[reset][bold][green]\n"+ "[reset][bold][green]\n"+
"Apply succeeded! Infrastructure created and/or updated.\n"+ "Apply complete! Resources: %d added, %d changed, %d destroyed.",
"The state of your infrastructure has been saved to the path\n"+ countHook.Added,
"below. This state is required to modify and destroy your\n"+ countHook.Changed,
"infrastructure, so keep it safe. To inspect the complete state\n"+ countHook.Removed)))
"use the `terraform show` command.\n\n"+
"State path: %s", if countHook.Added > 0 || countHook.Changed > 0 {
stateOutPath))) c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
"[reset]\n"+
"The state of your infrastructure has been saved to the path\n"+
"below. This state is required to modify and destroy your\n"+
"infrastructure, so keep it safe. To inspect the complete state\n"+
"use the `terraform show` command.\n\n"+
"State path: %s",
stateOutPath)))
}
// If we have outputs, then output those at the end. // If we have outputs, then output those at the end.
if len(state.Outputs) > 0 { if len(state.Outputs) > 0 {

83
command/hook_count.go Normal file
View File

@ -0,0 +1,83 @@
package command
import (
"sync"
"github.com/hashicorp/terraform/terraform"
)
// CountHook is a hook that counts the number of resources
// added, removed, changed during the course of an apply.
type CountHook struct {
Added int
Changed int
Removed int
pending map[string]countHookAction
sync.Mutex
terraform.NilHook
}
type countHookAction byte
const (
countHookActionAdd countHookAction = iota
countHookActionChange
countHookActionRemove
)
func (h *CountHook) Reset() {
h.Lock()
defer h.Unlock()
h.pending = nil
h.Added = 0
h.Changed = 0
h.Removed = 0
}
func (h *CountHook) PreApply(
id string,
s *terraform.ResourceState,
d *terraform.ResourceDiff) (terraform.HookAction, error) {
h.Lock()
defer h.Unlock()
if h.pending == nil {
h.pending = make(map[string]countHookAction)
}
action := countHookActionChange
if d.Destroy {
action = countHookActionRemove
} else if s.ID == "" {
action = countHookActionAdd
}
h.pending[id] = action
return terraform.HookActionContinue, nil
}
func (h *CountHook) PostApply(
id string,
s *terraform.ResourceState) (terraform.HookAction, error) {
h.Lock()
defer h.Unlock()
if h.pending != nil {
if a, ok := h.pending[id]; ok {
switch a {
case countHookActionAdd:
h.Added += 1
case countHookActionChange:
h.Changed += 1
case countHookActionRemove:
h.Removed += 1
}
}
}
return terraform.HookActionContinue, nil
}

View File

@ -0,0 +1,11 @@
package command
import (
"testing"
"github.com/hashicorp/terraform/terraform"
)
func TestCountHook_impl(t *testing.T) {
var _ terraform.Hook = new(CountHook)
}

View File

@ -16,6 +16,9 @@ type Meta struct {
ContextOpts *terraform.ContextOpts ContextOpts *terraform.ContextOpts
Ui cli.Ui Ui cli.Ui
// This can be set by the command itself to provide extra hooks.
extraHooks []terraform.Hook
color bool color bool
oldUi cli.Ui oldUi cli.Ui
} }
@ -99,9 +102,13 @@ func (m *Meta) Context(path, statePath string, doPlan bool) (*terraform.Context,
// context with the settings from this Meta. // context with the settings from this Meta.
func (m *Meta) contextOpts() *terraform.ContextOpts { func (m *Meta) contextOpts() *terraform.ContextOpts {
var opts terraform.ContextOpts = *m.ContextOpts var opts terraform.ContextOpts = *m.ContextOpts
opts.Hooks = make([]terraform.Hook, len(m.ContextOpts.Hooks)+1) opts.Hooks = make(
[]terraform.Hook,
len(m.ContextOpts.Hooks)+len(m.extraHooks)+1)
opts.Hooks[0] = m.uiHook() opts.Hooks[0] = m.uiHook()
copy(opts.Hooks[1:], m.ContextOpts.Hooks) copy(opts.Hooks[1:], m.ContextOpts.Hooks)
copy(opts.Hooks[len(m.ContextOpts.Hooks)+1:], m.extraHooks)
println(fmt.Sprintf("%#v", opts.Hooks))
return &opts return &opts
} }