Merge pull request #20615 from hashicorp/svh/f-input-context
core: add a context to the UIInput interface
This commit is contained in:
commit
4628fbcc65
|
@ -112,7 +112,7 @@ func (b *Local) opApply(
|
|||
b.CLI.Output("")
|
||||
}
|
||||
|
||||
v, err := op.UIIn.Input(&terraform.InputOpts{
|
||||
v, err := op.UIIn.Input(stopCtx, &terraform.InputOpts{
|
||||
Id: "approve",
|
||||
Query: query,
|
||||
Description: desc,
|
||||
|
|
|
@ -16,7 +16,6 @@ import (
|
|||
version "github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/state"
|
||||
"github.com/hashicorp/terraform/state/remote"
|
||||
"github.com/hashicorp/terraform/svchost"
|
||||
|
@ -73,9 +72,6 @@ type Remote struct {
|
|||
// configuration.
|
||||
prefix string
|
||||
|
||||
// schema defines the configuration for the backend.
|
||||
schema *schema.Backend
|
||||
|
||||
// services is used for service discovery
|
||||
services *disco.Disco
|
||||
|
||||
|
@ -759,13 +755,13 @@ func (b *Remote) Operation(ctx context.Context, op *backend.Operation) (*backend
|
|||
}
|
||||
|
||||
func (b *Remote) cancel(cancelCtx context.Context, op *backend.Operation, r *tfe.Run) error {
|
||||
if r.Status == tfe.RunPending && r.Actions.IsCancelable {
|
||||
if r.Actions.IsCancelable {
|
||||
// Only ask if the remote operation should be canceled
|
||||
// if the auto approve flag is not set.
|
||||
if !op.AutoApprove {
|
||||
v, err := op.UIIn.Input(&terraform.InputOpts{
|
||||
v, err := op.UIIn.Input(cancelCtx, &terraform.InputOpts{
|
||||
Id: "cancel",
|
||||
Query: "\nDo you want to cancel the pending remote operation?",
|
||||
Query: "\nDo you want to cancel the remote operation?",
|
||||
Description: "Only 'yes' will be accepted to cancel.",
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -313,7 +313,7 @@ func (b *Remote) checkPolicy(stopCtx, cancelCtx context.Context, op *backend.Ope
|
|||
}
|
||||
|
||||
func (b *Remote) confirm(stopCtx context.Context, op *backend.Operation, opts *terraform.InputOpts, r *tfe.Run, keyword string) error {
|
||||
v, err := op.UIIn.Input(opts)
|
||||
v, err := op.UIIn.Input(stopCtx, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error asking %s: %v", opts.Id, err)
|
||||
}
|
||||
|
|
|
@ -217,7 +217,7 @@ type mockInput struct {
|
|||
answers map[string]string
|
||||
}
|
||||
|
||||
func (m *mockInput) Input(opts *terraform.InputOpts) (string, error) {
|
||||
func (m *mockInput) Input(ctx context.Context, opts *terraform.InputOpts) (string, error) {
|
||||
v, ok := m.answers[opts.Id]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("unexpected input request in test: %s", opts.Id)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
@ -127,7 +128,7 @@ command and dealing with them before running this command again.
|
|||
if dir != "." {
|
||||
query = fmt.Sprintf("Would you like to upgrade the module in %s?", dir)
|
||||
}
|
||||
v, err := c.UIInput().Input(&terraform.InputOpts{
|
||||
v, err := c.UIInput().Input(context.Background(), &terraform.InputOpts{
|
||||
Id: "approve",
|
||||
Query: query,
|
||||
Description: `Only 'yes' will be accepted to confirm.`,
|
||||
|
|
|
@ -128,7 +128,7 @@ type Meta struct {
|
|||
//
|
||||
// stateOutPath is used to override the output path for the state.
|
||||
// If not provided, the StatePath is used causing the old state to
|
||||
// be overriden.
|
||||
// be overridden.
|
||||
//
|
||||
// backupPath is used to backup the state file before writing a modified
|
||||
// version. It defaults to stateOutPath + DefaultBackupExtension
|
||||
|
@ -470,7 +470,7 @@ func (m *Meta) confirm(opts *terraform.InputOpts) (bool, error) {
|
|||
}
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
v, err := m.UIInput().Input(opts)
|
||||
v, err := m.UIInput().Input(context.Background(), opts)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf(
|
||||
"Error asking for confirmation: %s", err)
|
||||
|
|
|
@ -773,7 +773,7 @@ func (m *Meta) selectWorkspace(b backend.Backend) error {
|
|||
|
||||
// If the selected workspace is not migrated, ask the user to select
|
||||
// a workspace from the list of migrated workspaces.
|
||||
v, err := m.UIInput().Input(&terraform.InputOpts{
|
||||
v, err := m.UIInput().Input(context.Background(), &terraform.InputOpts{
|
||||
Id: "select-workspace",
|
||||
Query: fmt.Sprintf(
|
||||
"\n[reset][bold][yellow]The currently selected workspace (%s) is not migrated.[reset]",
|
||||
|
|
|
@ -242,7 +242,7 @@ func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error {
|
|||
// for a new name and migrate the default state to the given named state.
|
||||
stateTwo, err = func() (statemgr.Full, error) {
|
||||
log.Print("[TRACE] backendMigrateState: target doesn't support a default workspace, so we must prompt for a new name")
|
||||
name, err := m.UIInput().Input(&terraform.InputOpts{
|
||||
name, err := m.UIInput().Input(context.Background(), &terraform.InputOpts{
|
||||
Id: "new-state-name",
|
||||
Query: fmt.Sprintf(
|
||||
"[reset][bold][yellow]The %q backend configuration only allows "+
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/hashicorp/terraform/internal/earlyconfig"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/hashicorp/terraform/configs"
|
||||
"github.com/hashicorp/terraform/configs/configload"
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
"github.com/hashicorp/terraform/internal/earlyconfig"
|
||||
"github.com/hashicorp/terraform/internal/initwd"
|
||||
"github.com/hashicorp/terraform/registry"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
|
@ -285,7 +286,7 @@ func (m *Meta) inputForSchema(given cty.Value, schema *configschema.Block) (cty.
|
|||
attrS := schema.Attributes[name]
|
||||
|
||||
for {
|
||||
strVal, err := input.Input(&terraform.InputOpts{
|
||||
strVal, err := input.Input(context.Background(), &terraform.InputOpts{
|
||||
Id: name,
|
||||
Query: name,
|
||||
Description: attrS.Description,
|
||||
|
|
|
@ -3,6 +3,7 @@ package command
|
|||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -38,7 +39,7 @@ type UIInput struct {
|
|||
once sync.Once
|
||||
}
|
||||
|
||||
func (i *UIInput) Input(opts *terraform.InputOpts) (string, error) {
|
||||
func (i *UIInput) Input(ctx context.Context, opts *terraform.InputOpts) (string, error) {
|
||||
i.once.Do(i.init)
|
||||
|
||||
r := i.Reader
|
||||
|
@ -137,6 +138,12 @@ func (i *UIInput) Input(opts *terraform.InputOpts) (string, error) {
|
|||
}
|
||||
|
||||
return line, nil
|
||||
case <-ctx.Done():
|
||||
// Print a newline so that any further output starts properly
|
||||
// on a new line.
|
||||
fmt.Fprintln(w)
|
||||
|
||||
return "", ctx.Err()
|
||||
case <-sigCh:
|
||||
// Print a newline so that any further output starts properly
|
||||
// on a new line.
|
||||
|
|
|
@ -2,6 +2,7 @@ package command
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
|
@ -17,7 +18,7 @@ func TestUIInputInput(t *testing.T) {
|
|||
Writer: bytes.NewBuffer(nil),
|
||||
}
|
||||
|
||||
v, err := i.Input(&terraform.InputOpts{})
|
||||
v, err := i.Input(context.Background(), &terraform.InputOpts{})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
@ -33,7 +34,7 @@ func TestUIInputInput_spaces(t *testing.T) {
|
|||
Writer: bytes.NewBuffer(nil),
|
||||
}
|
||||
|
||||
v, err := i.Input(&terraform.InputOpts{})
|
||||
v, err := i.Input(context.Background(), &terraform.InputOpts{})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
|
@ -88,7 +89,7 @@ func (c *UnlockCommand) Run(args []string) int {
|
|||
"This will allow local Terraform commands to modify this state, even though it\n" +
|
||||
"may be still be in use. Only 'yes' will be accepted to confirm."
|
||||
|
||||
v, err := c.UIInput().Input(&terraform.InputOpts{
|
||||
v, err := c.UIInput().Input(context.Background(), &terraform.InputOpts{
|
||||
Id: "force-unlock",
|
||||
Query: "Do you really want to force-unlock?",
|
||||
Description: desc,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
package schema
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
|
@ -1255,7 +1256,7 @@ func (m schemaMap) inputString(
|
|||
input terraform.UIInput,
|
||||
k string,
|
||||
schema *Schema) (interface{}, error) {
|
||||
result, err := input.Input(&terraform.InputOpts{
|
||||
result, err := input.Input(context.Background(), &terraform.InputOpts{
|
||||
Id: k,
|
||||
Query: k,
|
||||
Description: schema.Description,
|
||||
|
|
|
@ -170,12 +170,12 @@ func TestVersionListing(t *testing.T) {
|
|||
}
|
||||
|
||||
if len(versions) != len(expected) {
|
||||
t.Fatalf("Received wrong number of versions. expected: %q, got: %q", expected, versions)
|
||||
t.Fatalf("Received wrong number of versions. expected: %#v, got: %#v", expected, versions)
|
||||
}
|
||||
|
||||
for i, v := range versions {
|
||||
if v.Version != expected[i].Version {
|
||||
t.Fatalf("incorrect version: %q, expected %q", v, expected[i])
|
||||
t.Fatalf("incorrect version: %#v, expected %#v", v, expected[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/rpc"
|
||||
|
||||
"github.com/hashicorp/go-plugin"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
// UIInput is an implementatin of terraform.UIInput that communicates
|
||||
// UIInput is an implementation of terraform.UIInput that communicates
|
||||
// over RPC.
|
||||
type UIInput struct {
|
||||
Client *rpc.Client
|
||||
}
|
||||
|
||||
func (i *UIInput) Input(opts *terraform.InputOpts) (string, error) {
|
||||
func (i *UIInput) Input(ctx context.Context, opts *terraform.InputOpts) (string, error) {
|
||||
var resp UIInputInputResponse
|
||||
err := i.Client.Call("Plugin.Input", opts, &resp)
|
||||
if err != nil {
|
||||
|
@ -41,7 +42,7 @@ type UIInputServer struct {
|
|||
func (s *UIInputServer) Input(
|
||||
opts *terraform.InputOpts,
|
||||
reply *UIInputInputResponse) error {
|
||||
value, err := s.UIInput.Input(opts)
|
||||
value, err := s.UIInput.Input(context.Background(), opts)
|
||||
*reply = UIInputInputResponse{
|
||||
Value: value,
|
||||
Error: plugin.NewBasicError(err),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
|
@ -32,7 +33,7 @@ func TestUIInput_input(t *testing.T) {
|
|||
Id: "foo",
|
||||
}
|
||||
|
||||
v, err := input.Input(opts)
|
||||
v, err := input.Input(context.Background(), opts)
|
||||
if !i.InputCalled {
|
||||
t.Fatal("input should be called")
|
||||
}
|
||||
|
|
|
@ -232,7 +232,7 @@ func TestLookupProviderVersions(t *testing.T) {
|
|||
for _, v := range resp.Versions {
|
||||
_, err := version.NewVersion(v.Version)
|
||||
if err != nil {
|
||||
t.Fatalf("invalid version %q: %s", v, err)
|
||||
t.Fatalf("invalid version %#v: %v", v, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package terraform
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
|
@ -26,6 +27,8 @@ func (c *Context) Input(mode InputMode) tfdiags.Diagnostics {
|
|||
return diags
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
if mode&InputModeVar != 0 {
|
||||
log.Printf("[TRACE] Context.Input: Prompting for variables")
|
||||
|
||||
|
@ -60,7 +63,7 @@ func (c *Context) Input(mode InputMode) tfdiags.Diagnostics {
|
|||
retry := 0
|
||||
for {
|
||||
var err error
|
||||
rawValue, err = c.uiInput.Input(&InputOpts{
|
||||
rawValue, err = c.uiInput.Input(ctx, &InputOpts{
|
||||
Id: fmt.Sprintf("var.%s", n),
|
||||
Query: fmt.Sprintf("var.%s", n),
|
||||
Description: v.Description,
|
||||
|
@ -208,7 +211,7 @@ func (c *Context) Input(mode InputMode) tfdiags.Diagnostics {
|
|||
}
|
||||
|
||||
log.Printf("[TRACE] Context.Input: Prompting for %s argument %s", pa, key)
|
||||
rawVal, err := input.Input(&InputOpts{
|
||||
rawVal, err := input.Input(ctx, &InputOpts{
|
||||
Id: key,
|
||||
Query: key,
|
||||
Description: attrS.Description,
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package terraform
|
||||
|
||||
import "context"
|
||||
|
||||
// UIInput is the interface that must be implemented to ask for input
|
||||
// from this user. This should forward the request to wherever the user
|
||||
// inputs things to ask for values.
|
||||
type UIInput interface {
|
||||
Input(*InputOpts) (string, error)
|
||||
Input(context.Context, *InputOpts) (string, error)
|
||||
}
|
||||
|
||||
// InputOpts are options for asking for input.
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package terraform
|
||||
|
||||
import "context"
|
||||
|
||||
// MockUIInput is an implementation of UIInput that can be used for tests.
|
||||
type MockUIInput struct {
|
||||
InputCalled bool
|
||||
|
@ -10,7 +12,7 @@ type MockUIInput struct {
|
|||
InputFn func(*InputOpts) (string, error)
|
||||
}
|
||||
|
||||
func (i *MockUIInput) Input(opts *InputOpts) (string, error) {
|
||||
func (i *MockUIInput) Input(ctx context.Context, opts *InputOpts) (string, error) {
|
||||
i.InputCalled = true
|
||||
i.InputOpts = opts
|
||||
if i.InputFn != nil {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package terraform
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
|
@ -12,8 +13,8 @@ type PrefixUIInput struct {
|
|||
UIInput UIInput
|
||||
}
|
||||
|
||||
func (i *PrefixUIInput) Input(opts *InputOpts) (string, error) {
|
||||
func (i *PrefixUIInput) Input(ctx context.Context, opts *InputOpts) (string, error) {
|
||||
opts.Id = fmt.Sprintf("%s.%s", i.IdPrefix, opts.Id)
|
||||
opts.Query = fmt.Sprintf("%s%s", i.QueryPrefix, opts.Query)
|
||||
return i.UIInput.Input(opts)
|
||||
return i.UIInput.Input(ctx, opts)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package terraform
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -15,7 +16,7 @@ func testPrefixUIInput(t *testing.T) {
|
|||
UIInput: input,
|
||||
}
|
||||
|
||||
_, err := prefix.Input(&InputOpts{Id: "bar"})
|
||||
_, err := prefix.Input(context.Background(), &InputOpts{Id: "bar"})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue