Skip to content

Commit

Permalink
Merge pull request #3 from gruntwork-io/error-messages
Browse files Browse the repository at this point in the history
Terraform error handling
  • Loading branch information
denis256 authored Aug 30, 2024
2 parents d86c62c + e2d8a65 commit 76c20b5
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 18 deletions.
30 changes: 15 additions & 15 deletions engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ import (
)

const (
wgSize = 2
iacCommand = "terraform"
wgSize = 2
iacCommand = "terraform"
errorResultCode = 1
)

type TerraformEngine struct {
Expand Down Expand Up @@ -49,10 +50,12 @@ func (c *TerraformEngine) Run(req *tgengine.RunRequest, stream tgengine.Engine_R

stdoutPipe, err := cmd.StdoutPipe()
if err != nil {
sendError(stream, err)
return err
}
stderrPipe, err := cmd.StderrPipe()
if err != nil {
sendError(stream, err)
return err
}

Expand All @@ -78,6 +81,7 @@ func (c *TerraformEngine) Run(req *tgengine.RunRequest, stream tgengine.Engine_R
}

if err := cmd.Start(); err != nil {
sendError(stream, err)
return err
}

Expand All @@ -99,10 +103,7 @@ func (c *TerraformEngine) Run(req *tgengine.RunRequest, stream tgengine.Engine_R
}
break
}
err = stream.Send(&tgengine.RunResponse{
Stdout: string(char),
})
if err != nil {
if err = stream.Send(&tgengine.RunResponse{Stdout: string(char)}); err != nil {
log.Errorf("Error sending stdout: %v", err)
return
}
Expand All @@ -122,10 +123,7 @@ func (c *TerraformEngine) Run(req *tgengine.RunRequest, stream tgengine.Engine_R
}
break
}
err = stream.Send(&tgengine.RunResponse{
Stderr: string(char),
})
if err != nil {
if err = stream.Send(&tgengine.RunResponse{Stderr: string(char)}); err != nil {
log.Errorf("Error sending stderr: %v", err)
return
}
Expand All @@ -141,16 +139,18 @@ func (c *TerraformEngine) Run(req *tgengine.RunRequest, stream tgengine.Engine_R
resultCode = 1
}
}

err = stream.Send(&tgengine.RunResponse{
ResultCode: int32(resultCode),
})
if err != nil {
if err := stream.Send(&tgengine.RunResponse{ResultCode: int32(resultCode)}); err != nil {
return err
}
return nil
}

func sendError(stream tgengine.Engine_RunServer, err error) {
if err = stream.Send(&tgengine.RunResponse{Stderr: fmt.Sprintf("%v", err), ResultCode: errorResultCode}); err != nil {
log.Warnf("Error sending response: %v", err)
}
}

func (c *TerraformEngine) Shutdown(req *tgengine.ShutdownRequest, stream tgengine.Engine_ShutdownServer) error {
log.Info("Shutdown Terraform engine")

Expand Down
38 changes: 35 additions & 3 deletions engine/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"
"testing"

"github.com/stretchr/testify/require"

"os"
"os/exec"

Expand Down Expand Up @@ -120,12 +122,13 @@ func TestTerraformEngine_Init(t *testing.T) {
mockStream := &MockInitServer{}

err := engine.Init(&tgengine.InitRequest{}, mockStream)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, 1, len(mockStream.Responses))
assert.Equal(t, "Terraform Initialization completed\n", mockStream.Responses[0].Stdout)
}

func TestTerraformEngine_Run(t *testing.T) {
t.Parallel()
engine := &TerraformEngine{}
mockStream := &MockRunServer{}

Expand All @@ -137,7 +140,7 @@ func TestTerraformEngine_Run(t *testing.T) {
EnvVars: map[string]string{"FOO": "bar"},
}
err := engine.Run(req, mockStream)
assert.NoError(t, err)
require.NoError(t, err)
assert.True(t, len(mockStream.Responses) > 0)
// merge stdout from all responses to a string
var output string
Expand All @@ -149,12 +152,41 @@ func TestTerraformEngine_Run(t *testing.T) {
assert.Contains(t, output, "Usage: terraform [global options] <subcommand> [args]")
}

func TestTerraformEngineError(t *testing.T) {
t.Parallel()
engine := &TerraformEngine{}
mockStream := &MockRunServer{}

cmd := "terraform"
args := []string{"not-a-valid-command"}
req := &tgengine.RunRequest{
Command: cmd,
Args: args,
}
err := engine.Run(req, mockStream)
require.NoError(t, err)
assert.True(t, len(mockStream.Responses) > 0)
// merge stdout from all responses to a string
var output string

for _, response := range mockStream.Responses {
if response.Stderr != "" {
output += response.Stderr
}
}
// get status code from last response
code := mockStream.Responses[len(mockStream.Responses)-1].ResultCode
assert.Contains(t, output, "Terraform has no command named \"not-a-valid-command\"")
assert.NotEqual(t, 0, code)
}

func TestTerraformEngine_Shutdown(t *testing.T) {
t.Parallel()
engine := &TerraformEngine{}
mockStream := &MockShutdownServer{}

err := engine.Shutdown(&tgengine.ShutdownRequest{}, mockStream)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, 1, len(mockStream.Responses))
assert.Equal(t, "Terraform Shutdown completed\n", mockStream.Responses[0].Stdout)
}
Expand Down

0 comments on commit 76c20b5

Please sign in to comment.