This commit is contained in:
Radek Simko 2017-03-02 18:41:18 +00:00
parent 08283f077b
commit 17c9a403f2
No known key found for this signature in database
GPG Key ID: 6823F3DCCE01BB19
3 changed files with 90 additions and 9 deletions

View File

@ -4,6 +4,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"fmt" "fmt"
"log"
"sort" "sort"
"strings" "strings"
"sync" "sync"
@ -50,6 +51,7 @@ func (h *UiHook) PreApply(
n *terraform.InstanceInfo, n *terraform.InstanceInfo,
s *terraform.InstanceState, s *terraform.InstanceState,
d *terraform.InstanceDiff) (terraform.HookAction, error) { d *terraform.InstanceDiff) (terraform.HookAction, error) {
log.Printf("[DEBUG] PreApply arguments:\n%#v\n%#v\n%#v", n, s, d)
h.once.Do(h.init) h.once.Do(h.init)
id := n.HumanId() id := n.HumanId()
@ -129,9 +131,8 @@ func (h *UiHook) PreApply(
attrString = "\n " + attrString attrString = "\n " + attrString
} }
var stateId, stateIdSuffix string var stateIdSuffix string
if s != nil && s.ID != "" { if s != nil && s.ID != "" {
stateId = s.ID
stateIdSuffix = fmt.Sprintf(" (ID: %s)", truncateId(s.ID, maxIdLen)) stateIdSuffix = fmt.Sprintf(" (ID: %s)", truncateId(s.ID, maxIdLen))
} }
@ -143,12 +144,12 @@ func (h *UiHook) PreApply(
attrString))) attrString)))
// Set a timer to show an operation is still happening // Set a timer to show an operation is still happening
time.AfterFunc(periodicUiTimer, func() { h.stillApplying(id, stateId) }) time.AfterFunc(periodicUiTimer, func() { h.stillApplying(id, s) })
return terraform.HookActionContinue, nil return terraform.HookActionContinue, nil
} }
func (h *UiHook) stillApplying(id, stateId string) { func (h *UiHook) stillApplying(id string, s *terraform.InstanceState) {
// Grab the operation. We defer the lock here to avoid the "still..." // Grab the operation. We defer the lock here to avoid the "still..."
// message showing up after a completion message. // message showing up after a completion message.
h.l.Lock() h.l.Lock()
@ -173,8 +174,8 @@ func (h *UiHook) stillApplying(id, stateId string) {
} }
var stateIdSuffix string var stateIdSuffix string
if stateId != "" { if s != nil && s.ID != "" {
stateIdSuffix = fmt.Sprintf("ID: %s, ", truncateId(stateId, maxIdLen)) stateIdSuffix = fmt.Sprintf("ID: %s, ", truncateId(s.ID, maxIdLen))
} }
h.ui.Output(h.Colorize.Color(fmt.Sprintf( h.ui.Output(h.Colorize.Color(fmt.Sprintf(
@ -186,13 +187,15 @@ func (h *UiHook) stillApplying(id, stateId string) {
))) )))
// Reschedule // Reschedule
time.AfterFunc(periodicUiTimer, func() { h.stillApplying(id, stateId) }) time.AfterFunc(periodicUiTimer, func() { h.stillApplying(id, s) })
} }
func (h *UiHook) PostApply( func (h *UiHook) PostApply(
n *terraform.InstanceInfo, n *terraform.InstanceInfo,
s *terraform.InstanceState, s *terraform.InstanceState,
applyerr error) (terraform.HookAction, error) { applyerr error) (terraform.HookAction, error) {
log.Printf("[DEBUG] PostApply arguments:\n%#v\n%#v\n%#v", n, s, applyerr)
id := n.HumanId() id := n.HumanId()
h.l.Lock() h.l.Lock()
@ -221,10 +224,13 @@ func (h *UiHook) PostApply(
// Errors are collected and printed in ApplyCommand, no need to duplicate // Errors are collected and printed in ApplyCommand, no need to duplicate
return terraform.HookActionContinue, nil return terraform.HookActionContinue, nil
} }
log.Printf("[DEBUG] Printing out output: %#v", msg)
h.ui.Output(h.Colorize.Color(fmt.Sprintf( colorized := h.Colorize.Color(fmt.Sprintf(
"[reset][bold]%s: %s%s[reset]", "[reset][bold]%s: %s%s[reset]",
id, msg, stateIdSuffix))) id, msg, stateIdSuffix))
h.ui.Output(colorized)
return terraform.HookActionContinue, nil return terraform.HookActionContinue, nil
} }

View File

@ -1,10 +1,72 @@
package command package command
import ( import (
"bytes"
"fmt" "fmt"
"testing" "testing"
"time"
"github.com/hashicorp/terraform/terraform"
"github.com/mitchellh/cli"
"github.com/mitchellh/colorstring"
) )
func TestUiHookPostApply_emptyState(t *testing.T) {
colorize := &colorstring.Colorize{
Colors: colorstring.DefaultColors,
Disable: true,
Reset: true,
}
ir := bytes.NewReader([]byte{})
errBuf := bytes.NewBuffer([]byte{})
outBuf := bytes.NewBuffer([]byte{})
ui := cli.MockUi{
InputReader: ir,
ErrorWriter: errBuf,
OutputWriter: outBuf,
}
h := &UiHook{
Colorize: colorize,
Ui: &ui,
}
h.init()
h.resources = map[string]uiResourceState{
"data.google_compute_zones.available": uiResourceState{
Op: uiResourceDestroy,
Start: time.Now(),
},
}
mock := &terraform.MockInstanceInfo{
terraform.InstanceInfo{
Id: "data.google_compute_zones.available",
ModulePath: []string{"root"},
Type: "google_compute_zones",
},
}
n := mock.WithUniqueExtra("destroy")
action, err := h.PostApply(n, nil, nil)
if err != nil {
t.Fatal(err)
}
if action != terraform.HookActionContinue {
t.Fatal("Expected hook to continue, given: %#v", action)
}
expectedOutput := ""
output := outBuf.String()
if output != expectedOutput {
t.Fatalf("Output didn't match.\nExpected: %q\nGiven: %q", expectedOutput, output)
}
expectedErrOutput := ""
errOutput := errBuf.String()
if errOutput != expectedErrOutput {
t.Fatalf("Error output didn't match.\nExpected: %q\nGiven: %q", expectedErrOutput, errOutput)
}
}
func TestTruncateId(t *testing.T) { func TestTruncateId(t *testing.T) {
testCases := []struct { testCases := []struct {
Input string Input string

View File

@ -72,6 +72,19 @@ type InstanceInfo struct {
uniqueExtra string uniqueExtra string
} }
type MockInstanceInfo struct {
InstanceInfo
}
func (m *MockInstanceInfo) WithUniqueExtra(extra string) *InstanceInfo {
return &InstanceInfo{
Id: m.Id,
ModulePath: m.ModulePath,
Type: m.Type,
uniqueExtra: extra,
}
}
// HumanId is a unique Id that is human-friendly and useful for UI elements. // HumanId is a unique Id that is human-friendly and useful for UI elements.
func (i *InstanceInfo) HumanId() string { func (i *InstanceInfo) HumanId() string {
if i == nil { if i == nil {