From f85c1e2a5e349f58382daec92dd353ab15fefd1d Mon Sep 17 00:00:00 2001 From: Simon Baeumer Date: Fri, 19 Nov 2021 15:55:35 +0100 Subject: [PATCH] Add error handling to executors --- pkg/runtime/docker_executor.go | 18 +++++++++++------- pkg/runtime/executor.go | 2 +- pkg/runtime/local_executor.go | 8 ++++---- pkg/runtime/runner.go | 16 +++++++++++----- pkg/runtime/ssh_executor.go | 16 +++++++++------- 5 files changed, 36 insertions(+), 24 deletions(-) diff --git a/pkg/runtime/docker_executor.go b/pkg/runtime/docker_executor.go index 68591262..b3e00d7e 100644 --- a/pkg/runtime/docker_executor.go +++ b/pkg/runtime/docker_executor.go @@ -28,7 +28,7 @@ type DockerExecutor struct { } // Execute executes the script inside a docker container -func (e DockerExecutor) Execute(test TestCase) TestResult { +func (e DockerExecutor) Execute(test TestCase) (TestResult, error) { log.Printf("DOCKER_HOST: %s \n", os.Getenv("DOCKER_HOST")) log.Printf("DOCKER_CERT_PATH: %s \n", os.Getenv("DOCKER_CERT_PATH")) log.Printf("DOCKER_API_VERSION: %s \n", os.Getenv("DOCKER_API_VERSION")) @@ -39,7 +39,7 @@ func (e DockerExecutor) Execute(test TestCase) TestResult { test.Result.Error = err return TestResult{ TestCase: test, - } + }, nil } authConfig := types.AuthConfig{ @@ -60,10 +60,14 @@ func (e DockerExecutor) Execute(test TestCase) TestResult { test.Result.Error = fmt.Errorf("could not pull image '%s' with error: '%s'", e.Image, err) return TestResult{ TestCase: test, - } + }, nil } buf := bytes.Buffer{} - buf.ReadFrom(reader) + _, err = buf.ReadFrom(reader) + if err != nil { + return TestResult{}, fmt.Errorf("Error reading buffer in docker executor %w", err) + } + log.Printf("Pull log image'%s':\n %s\n", e.Image, buf.String()) var env []string @@ -84,7 +88,7 @@ func (e DockerExecutor) Execute(test TestCase) TestResult { test.Result.Error = fmt.Errorf("could not pull image '%s' with error: '%s'", e.Image, err) return TestResult{ TestCase: test, - } + }, nil } log.Printf("Started container %s %s\n", e.Image, resp.ID) @@ -92,7 +96,7 @@ func (e DockerExecutor) Execute(test TestCase) TestResult { test.Result.Error = fmt.Errorf("could not pull image '%s' with error: '%s'", e.Image, err) return TestResult{ TestCase: test, - } + }, nil } duration := time.Duration(1 * time.Second) defer cli.ContainerStop(ctx, resp.ID, &duration) @@ -130,5 +134,5 @@ func (e DockerExecutor) Execute(test TestCase) TestResult { log.Println("title: '"+test.Title+"'", " Stdout: ", test.Result.Stdout) log.Println("title: '"+test.Title+"'", " Stderr: ", test.Result.Stderr) - return Validate(test) + return Validate(test), nil } diff --git a/pkg/runtime/executor.go b/pkg/runtime/executor.go index c06b58c3..fc469dc9 100644 --- a/pkg/runtime/executor.go +++ b/pkg/runtime/executor.go @@ -2,5 +2,5 @@ package runtime // Executor interface which will be implemented by all available executors, like ssh or local type Executor interface { - Execute(test TestCase) TestResult + Execute(test TestCase) (TestResult, error) } diff --git a/pkg/runtime/local_executor.go b/pkg/runtime/local_executor.go index 9b81d1ee..0f41630e 100644 --- a/pkg/runtime/local_executor.go +++ b/pkg/runtime/local_executor.go @@ -21,13 +21,13 @@ func NewLocalExecutor() Executor { } // Execute will execute the given test on the current node -func (e LocalExecutor) Execute(test TestCase) TestResult { +func (e LocalExecutor) Execute(test TestCase) (TestResult, error) { timeoutOpt, err := createTimeoutOption(test.Command.Timeout) if err != nil { test.Result = CommandResult{Error: err} return TestResult{ TestCase: test, - } + }, nil } envOpt := createEnvVarsOption(test) @@ -47,7 +47,7 @@ func (e LocalExecutor) Execute(test TestCase) TestResult { return TestResult{ TestCase: test, - } + }, nil } log.Println("title: '"+test.Title+"'", " Command: ", test.Command.Cmd) @@ -65,7 +65,7 @@ func (e LocalExecutor) Execute(test TestCase) TestResult { log.Println("title: '"+test.Title+"'", " Stdout: ", test.Result.Stdout) log.Println("title: '"+test.Title+"'", " Stderr: ", test.Result.Stderr) - return Validate(test) + return Validate(test), nil } func createEnvVarsOption(test TestCase) func(c *cmd.Command) { diff --git a/pkg/runtime/runner.go b/pkg/runtime/runner.go index c1edd464..765c4218 100644 --- a/pkg/runtime/runner.go +++ b/pkg/runtime/runner.go @@ -27,6 +27,7 @@ func (r *Runner) Run(tests []TestCase) <-chan TestResult { var wg sync.WaitGroup wg.Add(1) + go func(tests chan TestCase) { defer wg.Done() @@ -36,19 +37,24 @@ func (r *Runner) Run(tests []TestCase) <-chan TestResult { t.Nodes = []string{"local"} } - for _, n := range t.Nodes { + for _, node := range t.Nodes { result := TestResult{} for i := 1; i <= t.Command.GetRetries(); i++ { if t.Skip { - result = TestResult{TestCase: t, Skipped: true, Node: n} + result = TestResult{TestCase: t, Skipped: true, Node: node} break } - e := r.getExecutor(n) - result = e.Execute(t) - result.Node = n + e := r.getExecutor(node) + result, err := e.Execute(t) + if err != nil { + panic(fmt.Sprintf("[FATAL] %s [%s]: %s", t.Title, node, err.Error())) + } + + result.Node = node result.Tries = i + fmt.Println(result) if result.ValidationResult.Success { break diff --git a/pkg/runtime/ssh_executor.go b/pkg/runtime/ssh_executor.go index cde4f8bf..8d073bf4 100644 --- a/pkg/runtime/ssh_executor.go +++ b/pkg/runtime/ssh_executor.go @@ -8,6 +8,7 @@ import ( "log" "net" "strings" + "time" ) var _ Executor = (*SSHExecutor)(nil) @@ -49,7 +50,7 @@ func NewSSHExecutor(host string, user string, opts ...func(e *SSHExecutor)) Exec } // Execute executes a command on a remote host viá SSH -func (e SSHExecutor) Execute(test TestCase) TestResult { +func (e SSHExecutor) Execute(test TestCase) (TestResult, error) { if test.Command.InheritEnv { panic("Inherit env is not supported viá SSH") } @@ -72,19 +73,20 @@ func (e SSHExecutor) Execute(test TestCase) TestResult { HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil }, + Timeout: 10*time.Second, } // create ssh connection conn, err := ssh.Dial("tcp", e.Host, sshConf) if err != nil { - log.Fatal(err) + return TestResult{}, fmt.Errorf("Failed to connect to ssh %w", err) } // start session session, err := conn.NewSession() defer session.Close() if err != nil { - log.Fatal(err) + return TestResult{}, fmt.Errorf("Failed to create a new ssh session %w", err) } var stdoutBuffer bytes.Buffer @@ -96,11 +98,11 @@ func (e SSHExecutor) Execute(test TestCase) TestResult { err := session.Setenv(k, v) if err != nil { test.Result = CommandResult{ - Error: fmt.Errorf("Failed setting env variables, maybe ssh server is configured to only accept LC_ prefixed env variables. Error: %s", err), + Error: fmt.Errorf("Failed setting env variables, maybe ssh server is configured to only accept LC_ prefixed env variables. %w", err), } return TestResult{ TestCase: test, - } + }, nil } } @@ -125,7 +127,7 @@ func (e SSHExecutor) Execute(test TestCase) TestResult { return TestResult{ TestCase: test, - } + }, nil } test.Result = CommandResult{ @@ -138,7 +140,7 @@ func (e SSHExecutor) Execute(test TestCase) TestResult { log.Println("title: '"+test.Title+"'", " Stdout: ", test.Result.Stdout) log.Println("title: '"+test.Title+"'", " Stderr: ", test.Result.Stderr) - return Validate(test) + return Validate(test), nil } func (e SSHExecutor) createSigner() ssh.Signer {