cert-manager-webhook-sthome/pkg/dns/shell.go

121 lines
3.0 KiB
Go

package dns
import (
"bytes"
"fmt"
"io"
"os"
"os/exec"
"strings"
"sync"
"k8s.io/klog/v2"
)
func Execute(shell string, arg ...string) (bool, error) {
var outb, errb bytes.Buffer
cmd := exec.Command(shell, arg...)
cmd.Dir = AcmeDir
cmd.Stdout = &outb
cmd.Stderr = &errb
klog.Infof("cmd: %s\n", cmd.String())
err := cmd.Run()
outstr := strings.TrimSuffix(outb.String(), "\n")
errstr := strings.TrimSuffix(errb.String(), "\n")
klog.Infof("out:\n%s\n", outstr)
if err != nil {
klog.Errorf("Script returned error:\nerr:\n")
klog.Errorf("%s\n============\n", err)
return false, err
}
if errb.String() != "" {
klog.Infof("stderr:\n")
klog.Errorf("%s\n============\n", errstr)
return false, fmt.Errorf("stderr:\n%q", errstr)
}
klog.Infof("Script returned success\n")
return true, nil
}
// https://blog.kowalczyk.info/article/wOYk/advanced-command-execution-in-go-with-osexec.html
func Execute2(shell string, arg ...string) (bool, error) {
var stdoutBuf, stderrBuf bytes.Buffer
cmd := exec.Command(shell, arg...)
cmd.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
cmd.Stderr = io.MultiWriter(os.Stderr, &stderrBuf)
err := cmd.Run()
if err != nil {
klog.Errorf("Script returned error:\nerr:\n")
klog.Errorf("%s\n============\n", err)
return false, err
}
outStr, errStr := string(stdoutBuf.String()), string(stderrBuf.String())
fmt.Printf("\nout:\n%s\nerr:\n%s\n", outStr, errStr)
klog.Infof("Script returned success\n")
return true, nil
}
// CapturingPassThroughWriter is a writer that remembers
// data written to it and passes it to w
type CapturingPassThroughWriter struct {
buf bytes.Buffer
w io.Writer
}
// NewCapturingPassThroughWriter creates new CapturingPassThroughWriter
func NewCapturingPassThroughWriter(w io.Writer) *CapturingPassThroughWriter {
return &CapturingPassThroughWriter{
w: w,
}
}
func (w *CapturingPassThroughWriter) Write(d []byte) (int, error) {
w.buf.Write(d)
return w.w.Write(d)
}
// Bytes returns bytes written to the writer
func (w *CapturingPassThroughWriter) Bytes() []byte {
return w.buf.Bytes()
}
func Execute3(shell string, arg ...string) (bool, error) {
var errStdout, errStderr error
cmd := exec.Command(shell, arg...)
stdoutIn, _ := cmd.StdoutPipe()
stderrIn, _ := cmd.StderrPipe()
stdout := NewCapturingPassThroughWriter(os.Stdout)
stderr := NewCapturingPassThroughWriter(os.Stderr)
err := cmd.Start()
if err != nil {
klog.Fatalf("cmd.Start() failed with '%s'\n", err)
}
var wg sync.WaitGroup
wg.Add(1)
go func() {
_, errStdout = io.Copy(stdout, stdoutIn)
wg.Done()
}()
_, errStderr = io.Copy(stderr, stderrIn)
wg.Wait()
err = cmd.Wait()
if err != nil {
klog.Fatalf("cmd.Run() failed with %s\n", err)
}
if errStdout != nil || errStderr != nil {
klog.Fatalf("failed to capture stdout or stderr\n")
}
//outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes())
//fmt.Printf("\nout:\n%s\nerr:\n%s\n", outStr, errStr)
errStr := string(stderr.Bytes())
if stderr != nil {
klog.Infof("err:\n%s\n", errStr)
}
return true, nil
}