package dns import ( "bytes" "io" "os" "os/exec" "sync" "k8s.io/klog/v2" ) // 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 Execute(shell string, arg ...string) (bool, error) { var errStdout, errStderr error crlf := []byte("\r\n") lf := []byte("\n") 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) errb := bytes.TrimSuffix(stderr.Bytes(), crlf) errb = bytes.TrimSuffix(errb, lf) if stderr != nil { klog.Infof("err:\n%s\n", string(errb)) } return true, nil }