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 (cmd *command) StartCommand() (error, *ssh.Session) { var ( session *ssh.Session err error ) z := cmd.zh // open ssh link if z.client == nil { if err = z.dialSSH(); err != nil { return err, nil } } // establish ssh session if session, err = z.client.NewSession(); err != nil { return err, nil } // setup env, stdin, stdout, stderr if err = prepareCommand(session, cmd); err != nil { return err, nil } // start remote command err = session.Start(cmd.Path) if err == nil { return err, session } return err, nil }
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 }
// RunCommandBackground runs a background command in a vagrant node func (n *VagrantNode) RunCommandBackground(cmd string) (string, error) { var ( s *ssh.Session err error ) if s, err = n.client.NewSession(); err != nil { return "", err } defer s.Close() // start and forget about the command as user asked to run in background. // The limitation is we/ won't know if it fails though. Not a worry right // now as the test will fail anyways, but might be good to find a better way. return "", s.Start(newCmdStrWithSource(cmd)) }
func stream(command string, session *ssh.Session) (output chan string, done chan bool, err error) { outReader, err := session.StdoutPipe() Ω(err).ShouldNot(HaveOccurred()) errReader, err := session.StderrPipe() Ω(err).ShouldNot(HaveOccurred()) outputReader := io.MultiReader(outReader, errReader) err = session.Start(command) Ω(err).ShouldNot(HaveOccurred()) scanner := bufio.NewScanner(outputReader) outputChan := make(chan string) done = make(chan bool) go func(scanner *bufio.Scanner, out chan string, done chan bool) { defer close(outputChan) defer close(done) for scanner.Scan() { outputChan <- scanner.Text() } done <- true session.Close() }(scanner, outputChan, done) return outputChan, done, err }
}) }) Context("while a command is running", func() { var stdin io.WriteCloser var stdout io.Reader BeforeEach(func() { var err error stdin, err = session.StdinPipe() Expect(err).NotTo(HaveOccurred()) stdout, err = session.StdoutPipe() Expect(err).NotTo(HaveOccurred()) err = session.Start("trap 'echo Caught SIGUSR1' USR1; echo trapped; cat") 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())
func (s *BotClientT) Start(botId string, botInstance int, cmdline string, cfg *ConfigT, debugLevel int) error { var err error var sshclient *ssh.Client var session *ssh.Session // var wg sync.WaitGroup var cmd string if s.Host[botInstance].Status == BotStatPaused { return nil } if s.Host[botInstance].Status == BotStatRunning { err = s.PingAt(botId, botInstance, cfg) if err == nil { Goose.Ping.Logf(2, "bot %s@%s is alive", botId, s.Host[botInstance].Name) return nil } } Goose.StartStop.Logf(2, "Starting bot %s@%s", botId, s.Host[botInstance].Name) s.Host[botInstance].Status = BotStatUnreachable if s.Host[botInstance].OnStatUpdate != nil { s.Host[botInstance].OnStatUpdate(BotStatUnreachable) } cfg.SshClientConfig.User = s.SysUser sshclient, err = ssh.Dial("tcp", s.Host[botInstance].Name+":22", cfg.SshClientConfig) if err != nil { Goose.StartStop.Logf(1, "%s (%s)", ErrDialingToBot, err) return ErrDialingToBot } defer sshclient.Close() Goose.StartStop.Logf(3, "Dialed to bot %s@%s", botId, s.Host[botInstance].Name) session, err = sshclient.NewSession() if err != nil { Goose.StartStop.Logf(1, "%s (%s)", ErrCreatingSession, err) return ErrCreatingSession } defer session.Close() Goose.StartStop.Logf(3, "Session started at bot %s@%s", botId, s.Host[botInstance].Name) /* wg.Add(1) go func() { defer wg.Done() w, _ := session.StdinPipe() defer w.Close() Goose.StartStop.Logf(2,"Closing stdin for bot %s",botId) //fmt.Fprintf(w, "%s\n", config) }() */ /* // Set up terminal modes modes := ssh.TerminalModes{ ssh.ECHO: 0, // disable echoing ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud } // Request pseudo terminal if err := session.RequestPty("xterm", 80, 40, modes); err != nil { Goose.StartStop.Fatalf(1,"request for pseudo terminal failed: %s", err) } session.Stdout = &bytes.Buffer{} session.Stderr = &bytes.Buffer{} */ cmd = fmt.Sprintf("%s%c%s -v %d %s", s.BinDir, os.PathSeparator, s.BinName, debugLevel, cmdline) Goose.StartStop.Logf(3, "Will run %s@%s using %s", botId, s.Host[botInstance].Name, cmd) err = session.Start(cmd) // err = session.Run(cmd) Goose.StartStop.Logf(2, "Running bot %s", botId) // wg.Wait() if err != nil { session.Signal(ssh.SIGKILL) Goose.StartStop.Logf(1, "%s (%s)", ErrFailedStartingBot, err) return ErrFailedStartingBot } Goose.StartStop.Logf(2, "Started bot %s with cmd:[%s]", botId, cmd) s.Host[botInstance].Status = BotStatRunning if s.Host[botInstance].OnStatUpdate != nil { s.Host[botInstance].OnStatUpdate(BotStatRunning) } return nil }
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 }