Plannable import: Make the streamed logs more consistent during a plan operation (#33155)

This commit is contained in:
Liam Cervante 2023-05-10 08:27:15 +02:00 committed by GitHub
parent 27f87ff70e
commit 3c20f7b340
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 82 additions and 37 deletions

View File

@ -193,7 +193,7 @@ func (c *ImportCommand) Run(args []string) int {
c.showDiagnostics(diags)
return 1
}
opReq.Hooks = []terraform.Hook{c.uiHook()}
opReq.Hooks = []terraform.Hook{c.uiHook(views.TerraformOperationImport)}
{
var moreDiags tfdiags.Diagnostics
opReq.Variables, moreDiags = c.collectVariableValues()

View File

@ -605,8 +605,8 @@ func (m *Meta) process(args []string) []string {
}
// uiHook returns the UiHook to use with the context.
func (m *Meta) uiHook() *views.UiHook {
return views.NewUiHook(m.View)
func (m *Meta) uiHook(operation views.TerraformOperation) *views.UiHook {
return views.NewUiHook(m.View, operation)
}
// confirm asks a yes/no confirmation.

View File

@ -94,7 +94,7 @@ func (v *ApplyHuman) Operation() Operation {
func (v *ApplyHuman) Hooks() []terraform.Hook {
return []terraform.Hook{
v.countHook,
NewUiHook(v.view),
NewUiHook(v.view, TerraformOperationApply),
}
}

View File

@ -25,11 +25,12 @@ import (
const defaultPeriodicUiTimer = 10 * time.Second
const maxIdLen = 80
func NewUiHook(view *View) *UiHook {
func NewUiHook(view *View, operation TerraformOperation) *UiHook {
return &UiHook{
view: view,
periodicUiTimer: defaultPeriodicUiTimer,
resources: make(map[string]uiResourceState),
operation: operation,
}
}
@ -43,6 +44,8 @@ type UiHook struct {
resources map[string]uiResourceState
resourcesLock sync.Mutex
operation TerraformOperation
}
var _ terraform.Hook = (*UiHook)(nil)
@ -71,6 +74,15 @@ const (
uiResourceNoOp
)
type TerraformOperation byte
const (
TerraformOperationApply TerraformOperation = iota
TerraformOperationPlan
TerraformOperationImport
TerraformOperationRefresh
)
func (h *UiHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) {
dispAddr := addr.String()
if gen != states.CurrentGen {
@ -282,25 +294,36 @@ func (h *UiHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generatio
}
func (h *UiHook) PreImportState(addr addrs.AbsResourceInstance, importID string) (terraform.HookAction, error) {
h.println(fmt.Sprintf(
h.view.colorize.Color("[reset][bold]%s: Importing from ID %q..."),
addr, importID,
))
if h.operation == TerraformOperationImport {
h.println(fmt.Sprintf(
h.view.colorize.Color("[reset][bold]%s: Importing from ID %q..."),
addr, importID,
))
} else {
h.println(fmt.Sprintf(
h.view.colorize.Color("[reset][bold]%s: Importing state... [id=%s]"),
addr, importID,
))
}
return terraform.HookActionContinue, nil
}
func (h *UiHook) PostImportState(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (terraform.HookAction, error) {
h.println(fmt.Sprintf(
h.view.colorize.Color("[reset][bold][green]%s: Import prepared!"),
addr,
))
for _, s := range imported {
h.println(fmt.Sprintf(
h.view.colorize.Color("[reset][green] Prepared %s for import"),
s.TypeName,
))
}
if h.operation == TerraformOperationImport {
// We only print PostImportState during an Import operation, for a real
// plan operation the maic doesn't happen until an Apply anyway.
h.println(fmt.Sprintf(
h.view.colorize.Color("[reset][bold][green]%s: Import prepared!"),
addr,
))
for _, s := range imported {
h.println(fmt.Sprintf(
h.view.colorize.Color("[reset][green] Prepared %s for import"),
s.TypeName,
))
}
}
return terraform.HookActionContinue, nil
}

View File

@ -26,7 +26,7 @@ import (
func TestUiHookPreApply_create(t *testing.T) {
streams, done := terminal.StreamsForTesting(t)
view := NewView(streams)
h := NewUiHook(view)
h := NewUiHook(view, TerraformOperationApply)
h.resources = map[string]uiResourceState{
"test_instance.foo": {
Op: uiResourceCreate,
@ -83,7 +83,7 @@ func TestUiHookPreApply_create(t *testing.T) {
func TestUiHookPreApply_periodicTimer(t *testing.T) {
streams, done := terminal.StreamsForTesting(t)
view := NewView(streams)
h := NewUiHook(view)
h := NewUiHook(view, TerraformOperationApply)
h.periodicUiTimer = 1 * time.Second
h.resources = map[string]uiResourceState{
"test_instance.foo": {
@ -147,7 +147,7 @@ test_instance.foo: Still modifying... [id=test, 3s elapsed]
func TestUiHookPreApply_destroy(t *testing.T) {
streams, done := terminal.StreamsForTesting(t)
view := NewView(streams)
h := NewUiHook(view)
h := NewUiHook(view, TerraformOperationApply)
h.resources = map[string]uiResourceState{
"test_instance.foo": {
Op: uiResourceDestroy,
@ -206,7 +206,7 @@ func TestUiHookPostApply_colorInterpolation(t *testing.T) {
streams, done := terminal.StreamsForTesting(t)
view := NewView(streams)
view.Configure(&arguments.View{NoColor: false})
h := NewUiHook(view)
h := NewUiHook(view, TerraformOperationApply)
h.resources = map[string]uiResourceState{
"test_instance.foo[\"[red]\"]": {
Op: uiResourceCreate,
@ -258,7 +258,7 @@ func TestUiHookPostApply_colorInterpolation(t *testing.T) {
func TestUiHookPostApply_emptyState(t *testing.T) {
streams, done := terminal.StreamsForTesting(t)
view := NewView(streams)
h := NewUiHook(view)
h := NewUiHook(view, TerraformOperationApply)
h.resources = map[string]uiResourceState{
"data.google_compute_zones.available": {
Op: uiResourceDestroy,
@ -302,7 +302,7 @@ func TestUiHookPostApply_emptyState(t *testing.T) {
func TestPreProvisionInstanceStep(t *testing.T) {
streams, done := terminal.StreamsForTesting(t)
view := NewView(streams)
h := NewUiHook(view)
h := NewUiHook(view, TerraformOperationApply)
addr := addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -395,7 +395,7 @@ test_instance.foo (winrm): bar
t.Run(name, func(t *testing.T) {
streams, done := terminal.StreamsForTesting(t)
view := NewView(streams)
h := NewUiHook(view)
h := NewUiHook(view, TerraformOperationApply)
h.ProvisionOutput(addr, tc.provisioner, tc.input)
result := done(t)
@ -412,7 +412,7 @@ test_instance.foo (winrm): bar
func TestPreRefresh(t *testing.T) {
streams, done := terminal.StreamsForTesting(t)
view := NewView(streams)
h := NewUiHook(view)
h := NewUiHook(view, TerraformOperationApply)
addr := addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -445,7 +445,7 @@ func TestPreRefresh(t *testing.T) {
func TestPreRefresh_noID(t *testing.T) {
streams, done := terminal.StreamsForTesting(t)
view := NewView(streams)
h := NewUiHook(view)
h := NewUiHook(view, TerraformOperationApply)
addr := addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -473,10 +473,10 @@ func TestPreRefresh_noID(t *testing.T) {
}
// Test the very simple PreImportState hook.
func TestPreImportState(t *testing.T) {
func TestPreImportState_Import(t *testing.T) {
streams, done := terminal.StreamsForTesting(t)
view := NewView(streams)
h := NewUiHook(view)
h := NewUiHook(view, TerraformOperationImport)
addr := addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -499,13 +499,39 @@ func TestPreImportState(t *testing.T) {
}
}
func TestPreImportState_Plan(t *testing.T) {
streams, done := terminal.StreamsForTesting(t)
view := NewView(streams)
h := NewUiHook(view, TerraformOperationPlan)
addr := addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_instance",
Name: "foo",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
action, err := h.PreImportState(addr, "test")
if err != nil {
t.Fatal(err)
}
if action != terraform.HookActionContinue {
t.Fatalf("Expected hook to continue, given: %#v", action)
}
result := done(t)
if got, want := result.Stdout(), "test_instance.foo: Importing state... [id=test]\n"; got != want {
t.Fatalf("unexpected output\n got: %q\nwant: %q", got, want)
}
}
// Test the PostImportState UI hook. Again, this hook behaviour seems odd to
// me (see below), so please don't consider these tests as justification for
// keeping this behaviour.
func TestPostImportState(t *testing.T) {
streams, done := terminal.StreamsForTesting(t)
view := NewView(streams)
h := NewUiHook(view)
h := NewUiHook(view, TerraformOperationImport)
addr := addrs.Resource{
Mode: addrs.ManagedResourceMode,

View File

@ -53,7 +53,7 @@ func (v *PlanHuman) Operation() Operation {
func (v *PlanHuman) Hooks() []terraform.Hook {
return []terraform.Hook{
NewUiHook(v.view),
NewUiHook(v.view, TerraformOperationPlan),
}
}

View File

@ -35,7 +35,6 @@ func NewRefresh(vt arguments.ViewType, view *View) Refresh {
return &RefreshHuman{
view: view,
inAutomation: view.RunningInAutomation(),
countHook: &countHook{},
}
default:
panic(fmt.Sprintf("unknown view type %v", vt))
@ -48,8 +47,6 @@ type RefreshHuman struct {
view *View
inAutomation bool
countHook *countHook
}
var _ Refresh = (*RefreshHuman)(nil)
@ -67,8 +64,7 @@ func (v *RefreshHuman) Operation() Operation {
func (v *RefreshHuman) Hooks() []terraform.Hook {
return []terraform.Hook{
v.countHook,
NewUiHook(v.view),
NewUiHook(v.view, TerraformOperationRefresh),
}
}