func tailFile(session *ssh.Session, file string, sudo bool, linec chan<- string) error { var command string if sudo { command = fmt.Sprintf("sudo /usr/bin/env tail -F %s", file) } else { command = fmt.Sprintf("/usr/bin/env tail -F %s", file) } var wg sync.WaitGroup errc := make(chan error, 3) consumeStream := func(r io.Reader) { defer wg.Done() scan := bufio.NewScanner(r) scan.Split(bufio.ScanLines) for scan.Scan() { linec <- scan.Text() } if err := scan.Err(); err != nil { errc <- err } } stderr, err := session.StderrPipe() if err != nil { return fmt.Errorf("opening stderr: %v", err) } stdout, err := session.StdoutPipe() if err != nil { return fmt.Errorf("opening stdout: %v", err) } wg.Add(1) go consumeStream(stderr) go consumeStream(stdout) if err := session.Start(command); err != nil { return err } wg.Add(1) go func() { if err := session.Wait(); err != nil { errc <- err } }() go func() { wg.Wait() close(errc) }() return <-errc }
func (ssc *SSHConfig) Exec(cmd string, stdout, stderr io.Writer, input chan string) (err tree_lib.TreeError) { var ( session *ssh.Session stdin io.WriteCloser command_ended bool ) err.From = tree_lib.FROM_SSH_EXEC session, err.Err = ssc.conn.NewSession() if !err.IsNull() { return } defer session.Close() session.Stdout = stdout session.Stderr = stderr stdin, err.Err = session.StdinPipe() if !err.IsNull() { return } err.Err = session.Start(cmd) if !err.IsNull() { return } command_ended = false go func() { for !command_ended { io.Copy(stdin, bytes.NewBufferString(<-input)) } }() err.Err = session.Wait() command_ended = true return }
Expect(err).NotTo(HaveOccurred()) reader := bufio.NewReader(stdout) Eventually(reader.ReadLine).Should(ContainSubstring("trapped")) }) It("delivers the signal to the process", func() { err := session.Signal(ssh.SIGUSR1) Expect(err).NotTo(HaveOccurred()) Eventually(runner.SignalCallCount).Should(Equal(1)) err = stdin.Close() Expect(err).NotTo(HaveOccurred()) err = session.Wait() Expect(err).NotTo(HaveOccurred()) stdoutBytes, err := ioutil.ReadAll(stdout) Expect(err).NotTo(HaveOccurred()) Expect(stdoutBytes).To(ContainSubstring("Caught SIGUSR1")) }) It("exits with an exit-signal response", func() { err := session.Signal(ssh.SIGUSR2) Expect(err).NotTo(HaveOccurred()) Eventually(runner.SignalCallCount).Should(Equal(1)) err = stdin.Close() Expect(err).NotTo(HaveOccurred())
func pipe(ch ssh.Channel, client *ssh.Client, session *ssh.Session, command string) (int, error) { targetStderr, err := session.StderrPipe() if err != nil { return -1, errors.New("fail to pipe stderr: " + err.Error()) } targetStdout, err := session.StdoutPipe() if err != nil { return -1, errors.New("fail to pipe stdout: " + err.Error()) } targetStdin, err := session.StdinPipe() if err != nil { return -1, errors.New("fail to pipe stdin: " + err.Error()) } go io.Copy(targetStdin, ch) go io.Copy(ch.Stderr(), targetStderr) go io.Copy(ch, targetStdout) err = session.Start(command) if err != nil { ch.Write([]byte("Error when starting '" + command + "': " + err.Error())) ch.Close() } err = session.Wait() if err != nil { if err, ok := err.(*ssh.ExitError); ok { return err.ExitStatus(), nil } else { return -1, errors.New("failed to wait ssh command: " + err.Error()) } } return 0, nil }