consul/testing/deployer/sprawl/internal/runner/exec.go

124 lines
2.6 KiB
Go
Raw Normal View History

[COMPLIANCE] License changes (#18443) * Adding explicit MPL license for sub-package This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Adding explicit MPL license for sub-package This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Updating the license from MPL to Business Source License Going forward, this project will be licensed under the Business Source License v1.1. Please see our blog post for more details at <Blog URL>, FAQ at www.hashicorp.com/licensing-faq, and details of the license at www.hashicorp.com/bsl. * add missing license headers * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 --------- Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
2023-08-11 13:12:13 +00:00
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package runner
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"os"
"os/exec"
"github.com/hashicorp/go-hclog"
)
type Runner struct {
logger hclog.Logger
tfBin string
dockerBin string
}
func Load(logger hclog.Logger) (*Runner, error) {
r := &Runner{
logger: logger,
}
type item struct {
name string
dest *string
warn string // optional
}
lookup := []item{
{"docker", &r.dockerBin, ""},
{"terraform", &r.tfBin, ""},
}
var (
bins []string
err error
)
for _, i := range lookup {
*i.dest, err = exec.LookPath(i.name)
if err != nil {
if errors.Is(err, exec.ErrNotFound) {
if i.warn != "" {
return nil, fmt.Errorf("Could not find %q on path (%s): %w", i.name, i.warn, err)
} else {
return nil, fmt.Errorf("Could not find %q on path: %w", i.name, err)
}
}
return nil, fmt.Errorf("Unexpected failure looking for %q on path: %w", i.name, err)
}
bins = append(bins, *i.dest)
}
r.logger.Trace("using binaries", "paths", bins)
return r, nil
}
func (r *Runner) DockerExec(ctx context.Context, args []string, stdout io.Writer, stdin io.Reader) error {
return cmdExec(ctx, "docker", r.dockerBin, args, stdout, nil, stdin, "")
}
func (r *Runner) DockerExecWithStderr(ctx context.Context, args []string, stdout, stderr io.Writer, stdin io.Reader) error {
return cmdExec(ctx, "docker", r.dockerBin, args, stdout, stderr, stdin, "")
}
func (r *Runner) TerraformExec(ctx context.Context, args []string, stdout io.Writer, workdir string) error {
return cmdExec(ctx, "terraform", r.tfBin, args, stdout, nil, nil, workdir)
}
func cmdExec(ctx context.Context, name, binary string, args []string, stdout, stderr io.Writer, stdin io.Reader, dir string) error {
if binary == "" {
panic("binary named " + name + " was not detected")
}
var errWriter bytes.Buffer
if stdout == nil {
stdout = os.Stdout // TODO: wrap logs
}
cmd := exec.CommandContext(ctx, binary, args...)
if dir != "" {
cmd.Dir = dir
}
cmd.Stdout = stdout
cmd.Stderr = &errWriter
if stderr != nil {
cmd.Stderr = io.MultiWriter(stderr, cmd.Stderr)
}
cmd.Stdin = stdin
if err := cmd.Run(); err != nil {
return &ExecError{
BinaryName: name,
Err: err,
ErrorOutput: errWriter.String(),
}
}
return nil
}
type ExecError struct {
BinaryName string
ErrorOutput string
Err error
}
func (e *ExecError) Unwrap() error {
return e.Err
}
func (e *ExecError) Error() string {
return fmt.Sprintf(
"could not invoke %q: %v : %s",
e.BinaryName,
e.Err,
e.ErrorOutput,
)
}