From 74fa8af913c00dba4c3ef0281211a4b76eba0659 Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Wed, 3 Jun 2020 09:34:37 +0100 Subject: [PATCH] Make Terraform exec timeout configurable --- commands/serve_command.go | 13 +++++++++++++ internal/context/context.go | 11 +++++++++++ internal/terraform/exec/exec.go | 4 +++- langserver/handlers/service.go | 6 ++++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/commands/serve_command.go b/commands/serve_command.go index dc30e0a71..455d31ee7 100644 --- a/commands/serve_command.go +++ b/commands/serve_command.go @@ -9,6 +9,7 @@ import ( "path/filepath" "strings" "syscall" + "time" lsctx "github.com/hashicorp/terraform-ls/internal/context" "github.com/hashicorp/terraform-ls/langserver" @@ -25,6 +26,7 @@ type ServeCommand struct { logFilePath string tfExecPath string tfExecLogPath string + tfExecTimeout string } func (c *ServeCommand) flags() *flag.FlagSet { @@ -34,6 +36,7 @@ func (c *ServeCommand) flags() *flag.FlagSet { fs.StringVar(&c.logFilePath, "log-file", "", "path to a file to log into with support "+ "for variables (e.g. Timestamp, Pid, Ppid) via Go template syntax {{.VarName}}") fs.StringVar(&c.tfExecPath, "tf-exec", "", "path to Terraform binary") + fs.StringVar(&c.tfExecTimeout, "tf-exec-timeout", "", "Overrides Terraform execution timeout (e.g. 30s)") fs.StringVar(&c.tfExecLogPath, "tf-log-file", "", "path to a file for Terraform executions"+ " to be logged into with support for variables (e.g. Timestamp, Pid, Ppid) via Go template"+ " syntax {{.VarName}}") @@ -79,6 +82,16 @@ func (c *ServeCommand) Run(args []string) int { "(interpolated at the time of execution)", c.tfExecLogPath) } + if c.tfExecTimeout != "" { + d, err := time.ParseDuration(c.tfExecTimeout) + if err != nil { + c.Ui.Error(fmt.Sprintf("Failed to parse Terraform timeout: %s", err)) + return 1 + } + ctx = lsctx.WithTerraformExecTimeout(d, ctx) + logger.Printf("Terraform execution timeout set to %s", d) + } + srv := langserver.NewLangServer(ctx, handlers.NewSession) srv.SetLogger(logger) diff --git a/internal/context/context.go b/internal/context/context.go index 2714f4b31..bb8572a07 100644 --- a/internal/context/context.go +++ b/internal/context/context.go @@ -2,6 +2,7 @@ package context import ( "context" + "time" "github.com/hashicorp/terraform-ls/internal/filesystem" "github.com/hashicorp/terraform-ls/internal/terraform/exec" @@ -27,6 +28,7 @@ var ( ctxTfVersion = &contextKey{"terraform version"} ctxTfVersionSetter = &contextKey{"terraform version setter"} ctxTfExecLogPath = &contextKey{"terraform executor log path"} + ctxTfExecTimeout = &contextKey{"terraform execution timeout"} ) func missingContextErr(ctxKey *contextKey) *MissingContextErr { @@ -147,3 +149,12 @@ func TerraformExecLogPath(ctx context.Context) (string, bool) { path, ok := ctx.Value(ctxTfExecLogPath).(string) return path, ok } + +func WithTerraformExecTimeout(timeout time.Duration, ctx context.Context) context.Context { + return context.WithValue(ctx, ctxTfExecTimeout, timeout) +} + +func TerraformExecTimeout(ctx context.Context) (time.Duration, bool) { + path, ok := ctx.Value(ctxTfExecTimeout).(time.Duration) + return path, ok +} diff --git a/internal/terraform/exec/exec.go b/internal/terraform/exec/exec.go index 932d2831c..27b491d6a 100644 --- a/internal/terraform/exec/exec.go +++ b/internal/terraform/exec/exec.go @@ -19,6 +19,8 @@ import ( "github.com/hashicorp/terraform-ls/logging" ) +var defaultExecTimeout = 30 * time.Second + // Environment variables to pass through to Terraform var passthroughEnvVars = []string{ // This allows Terraform to find custom-built providers @@ -56,7 +58,7 @@ type command struct { func NewExecutor(ctx context.Context, path string) *Executor { return &Executor{ ctx: ctx, - timeout: 10 * time.Second, + timeout: defaultExecTimeout, execPath: path, logger: log.New(ioutil.Discard, "", 0), cmdCtxFunc: func(ctx context.Context, path string, arg ...string) *exec.Cmd { diff --git a/langserver/handlers/service.go b/langserver/handlers/service.go index 1195213eb..00194e94f 100644 --- a/langserver/handlers/service.go +++ b/langserver/handlers/service.go @@ -99,6 +99,12 @@ func (svc *service) Assigner() (jrpc2.Assigner, error) { if path, ok := lsctx.TerraformExecLogPath(svc.srvCtx); ok { tf.SetExecLogPath(path) } + + // Timeout is set via CLI flag, hence in the server context + if timeout, ok := lsctx.TerraformExecTimeout(svc.srvCtx); ok { + tf.SetTimeout(timeout) + } + tf.SetLogger(svc.logger) ctx = lsctx.WithTerraformExecutor(tf, ctx)