| 149 | var execCommand = exec.Command |
| 150 | |
| 151 | func (r *CmdReporter) runCommand() (stdout, stderr string, retcode int, err error) { |
| 152 | retcode = -1 // default retcode to -1 |
| 153 | |
| 154 | baseCmd := r.cmd[0] |
| 155 | fullArgs := append(r.cmd[1:], r.args...) |
| 156 | |
| 157 | var capturedStdout bytes.Buffer |
| 158 | var capturedStderr bytes.Buffer |
| 159 | |
| 160 | // Capture stdout and stderr, and also send both to the container stdout/stderr, similar to the |
| 161 | // 'tee' command |
| 162 | stdoutTee := io.MultiWriter(&capturedStdout, os.Stdout) |
| 163 | stderrTee := io.MultiWriter(&capturedStderr, os.Stdout) |
| 164 | |
| 165 | c := execCommand(baseCmd, fullArgs...) |
| 166 | c.Stdout = stdoutTee |
| 167 | c.Stderr = stderrTee |
| 168 | |
| 169 | cmdStr := fmt.Sprintf("%s %s", c.Path, strings.Join(c.Args, " ")) |
| 170 | logger.Infof("running command: %s", cmdStr) |
| 171 | |
| 172 | if err := c.Run(); err != nil { |
| 173 | if exitError, ok := err.(*exec.ExitError); ok { |
| 174 | // c.ProcessState.ExitCode is available with Go 1.12 and could replace if block below |
| 175 | if stat, ok := exitError.Sys().(syscall.WaitStatus); ok { |
| 176 | retcode = stat.ExitStatus() |
| 177 | } |
| 178 | // it's possible the above failed to parse the return code, so report the whole error |
| 179 | logger.Warningf("command finished unsuccessfully but return code could not be parsed. %+v", err) |
| 180 | } else { |
| 181 | return "", "", -1, fmt.Errorf("failed to run command [%s]. %+v", cmdStr, err) |
| 182 | } |
| 183 | } else { |
| 184 | retcode = 0 |
| 185 | } |
| 186 | |
| 187 | return capturedStdout.String(), capturedStderr.String(), retcode, nil |
| 188 | } |
| 189 | |
| 190 | func (r *CmdReporter) saveToConfigMap(stdout, stderr string, retcode int) error { |
| 191 | retcodeStr := fmt.Sprintf("%d", retcode) |