Merge pull request #17646 from hashicorp/jbardin/GH-17638

use correct context for communicator.Retry
This commit is contained in:
James Bardin 2018-03-21 08:34:17 -04:00 committed by GitHub
commit 40421c30e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 96 additions and 23 deletions

View File

@ -312,11 +312,11 @@ func applyFn(ctx context.Context) error {
return err return err
} }
ctx, cancel := context.WithTimeout(ctx, comm.Timeout()) retryCtx, cancel := context.WithTimeout(ctx, comm.Timeout())
defer cancel() defer cancel()
// Wait and retry until we establish the connection // Wait and retry until we establish the connection
err = communicator.Retry(ctx, func() error { err = communicator.Retry(retryCtx, func() error {
return comm.Connect(o) return comm.Connect(o)
}) })
if err != nil { if err != nil {

View File

@ -48,9 +48,6 @@ func applyFn(ctx context.Context) error {
return err return err
} }
ctx, cancel := context.WithTimeout(ctx, comm.Timeout())
defer cancel()
// Get the source // Get the source
src, deleteSource, err := getSrc(data) src, deleteSource, err := getSrc(data)
if err != nil { if err != nil {
@ -99,8 +96,11 @@ func getSrc(data *schema.ResourceData) (string, bool, error) {
// copyFiles is used to copy the files from a source to a destination // copyFiles is used to copy the files from a source to a destination
func copyFiles(ctx context.Context, comm communicator.Communicator, src, dst string) error { func copyFiles(ctx context.Context, comm communicator.Communicator, src, dst string) error {
retryCtx, cancel := context.WithTimeout(ctx, comm.Timeout())
defer cancel()
// Wait and retry until we establish the connection // Wait and retry until we establish the connection
err := communicator.Retry(ctx, func() error { err := communicator.Retry(retryCtx, func() error {
return comm.Connect(nil) return comm.Connect(nil)
}) })
if err != nil { if err != nil {

View File

@ -231,10 +231,10 @@ func applyFn(ctx context.Context) error {
return err return err
} }
ctx, cancel := context.WithTimeout(ctx, comm.Timeout()) retryCtx, cancel := context.WithTimeout(ctx, comm.Timeout())
defer cancel() defer cancel()
err = communicator.Retry(ctx, func() error { err = communicator.Retry(retryCtx, func() error {
return comm.Connect(o) return comm.Connect(o)
}) })

View File

@ -157,20 +157,23 @@ func runScripts(
comm communicator.Communicator, comm communicator.Communicator,
scripts []io.ReadCloser) error { scripts []io.ReadCloser) error {
// Wait for the context to end and then disconnect retryCtx, cancel := context.WithTimeout(ctx, comm.Timeout())
go func() { defer cancel()
<-ctx.Done()
comm.Disconnect()
}()
// Wait and retry until we establish the connection // Wait and retry until we establish the connection
err := communicator.Retry(ctx, func() error { err := communicator.Retry(retryCtx, func() error {
return comm.Connect(o) return comm.Connect(o)
}) })
if err != nil { if err != nil {
return err return err
} }
// Wait for the context to end and then disconnect
go func() {
<-ctx.Done()
comm.Disconnect()
}()
for _, script := range scripts { for _, script := range scripts {
var cmd *remote.Cmd var cmd *remote.Cmd

View File

@ -2,11 +2,15 @@ package remoteexec
import ( import (
"bytes" "bytes"
"context"
"io" "io"
"testing" "testing"
"time"
"strings" "strings"
"github.com/hashicorp/terraform/communicator"
"github.com/hashicorp/terraform/communicator/remote"
"github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
@ -206,6 +210,59 @@ func TestResourceProvider_CollectScripts_scriptsEmpty(t *testing.T) {
} }
} }
func TestProvisionerTimeout(t *testing.T) {
o := new(terraform.MockUIOutput)
c := new(communicator.MockCommunicator)
disconnected := make(chan struct{})
c.DisconnectFunc = func() error {
close(disconnected)
return nil
}
completed := make(chan struct{})
c.CommandFunc = func(cmd *remote.Cmd) error {
defer close(completed)
cmd.Init()
time.Sleep(2 * time.Second)
cmd.SetExitStatus(0, nil)
return nil
}
c.ConnTimeout = time.Second
c.UploadScripts = map[string]string{"hello": "echo hello"}
c.RemoteScriptPath = "hello"
p := Provisioner().(*schema.Provisioner)
conf := map[string]interface{}{
"inline": []interface{}{"echo hello"},
}
scripts, err := collectScripts(schema.TestResourceDataRaw(
t, p.Schema, conf))
if err != nil {
t.Fatal(err)
}
ctx := context.Background()
done := make(chan struct{})
go func() {
defer close(done)
if err := runScripts(ctx, o, c, scripts); err != nil {
t.Fatal(err)
}
}()
select {
case <-disconnected:
t.Fatal("communicator disconnected before command completed")
case <-completed:
}
<-done
}
func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfig { func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfig {
r, err := config.NewRawConfig(c) r, err := config.NewRawConfig(c)
if err != nil { if err != nil {

View File

@ -131,17 +131,11 @@ func applyFn(ctx context.Context) error {
return err return err
} }
ctx, cancelFunc := context.WithTimeout(ctx, comm.Timeout()) retryCtx, cancel := context.WithTimeout(ctx, comm.Timeout())
defer cancelFunc() defer cancel()
// Wait for the context to end and then disconnect
go func() {
<-ctx.Done()
comm.Disconnect()
}()
// Wait and retry until we establish the connection // Wait and retry until we establish the connection
err = communicator.Retry(ctx, func() error { err = communicator.Retry(retryCtx, func() error {
return comm.Connect(o) return comm.Connect(o)
}) })
@ -149,6 +143,12 @@ func applyFn(ctx context.Context) error {
return err return err
} }
// Wait for the context to end and then disconnect
go func() {
<-ctx.Done()
comm.Disconnect()
}()
var src, dst string var src, dst string
o.Output("Provisioning with Salt...") o.Output("Provisioning with Salt...")

View File

@ -18,6 +18,9 @@ type MockCommunicator struct {
Uploads map[string]string Uploads map[string]string
UploadScripts map[string]string UploadScripts map[string]string
UploadDirs map[string]string UploadDirs map[string]string
CommandFunc func(*remote.Cmd) error
DisconnectFunc func() error
ConnTimeout time.Duration
} }
// Connect implementation of communicator.Communicator interface // Connect implementation of communicator.Communicator interface
@ -27,11 +30,17 @@ func (c *MockCommunicator) Connect(o terraform.UIOutput) error {
// Disconnect implementation of communicator.Communicator interface // Disconnect implementation of communicator.Communicator interface
func (c *MockCommunicator) Disconnect() error { func (c *MockCommunicator) Disconnect() error {
if c.DisconnectFunc != nil {
return c.DisconnectFunc()
}
return nil return nil
} }
// Timeout implementation of communicator.Communicator interface // Timeout implementation of communicator.Communicator interface
func (c *MockCommunicator) Timeout() time.Duration { func (c *MockCommunicator) Timeout() time.Duration {
if c.ConnTimeout != 0 {
return c.ConnTimeout
}
return time.Duration(5 * time.Second) return time.Duration(5 * time.Second)
} }
@ -44,6 +53,10 @@ func (c *MockCommunicator) ScriptPath() string {
func (c *MockCommunicator) Start(r *remote.Cmd) error { func (c *MockCommunicator) Start(r *remote.Cmd) error {
r.Init() r.Init()
if c.CommandFunc != nil {
return c.CommandFunc(r)
}
if !c.Commands[r.Command] { if !c.Commands[r.Command] {
return fmt.Errorf("Command not found!") return fmt.Errorf("Command not found!")
} }