Skip to content
This repository has been archived by the owner on Jan 30, 2020. It is now read-only.

fix(SSHChannelReader): Read output completely before checking command exit. #260

Merged
merged 1 commit into from
Apr 2, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions fleetctl/journal.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,21 +54,17 @@ func journalAction(c *cli.Context) {
}

// check if the job is running on this machine
var channel *ssh.Channel
var err error
if machine.IsLocalMachineState(js.MachineState) {
channel = runLocalCommand(cmd)
runLocalCommand(cmd)
} else {
channel, err = runRemoteCommand(cmd, js.MachineState.PublicIP)
err := runRemoteCommand(cmd, js.MachineState.PublicIP)
if err != nil {
log.Fatalf("Unable to run command over SSH: %v", err)
}
}

readSSHChannel(channel)
}

func runLocalCommand(cmd string) *ssh.Channel {
func runLocalCommand(cmd string) {
cmdSlice := strings.Split(cmd, " ")
osCmd := exec.Command(cmdSlice[0], cmdSlice[1:]...)
stdout, _ := osCmd.StdoutPipe()
Expand All @@ -86,10 +82,10 @@ func runLocalCommand(cmd string) *ssh.Channel {
channel.Exit <- err
}()

return channel
readSSHChannel(channel)
}

func runRemoteCommand(cmd string, ip string) (*ssh.Channel, error) {
func runRemoteCommand(cmd string, ip string) error {
addr := fmt.Sprintf("%s:22", ip)

var sshClient *ssh.SSHForwardingClient
Expand All @@ -100,14 +96,16 @@ func runRemoteCommand(cmd string, ip string) (*ssh.Channel, error) {
sshClient, err = ssh.NewSSHClient("core", addr, getChecker(), false)
}
if err != nil {
return nil, err
return err
}

defer sshClient.Close()

channel, err := ssh.Execute(sshClient, cmd)
if err != nil {
return nil, err
return err
}
return channel, nil

readSSHChannel(channel)
return nil
}
64 changes: 28 additions & 36 deletions fleetctl/ssh.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package main

import (
"bufio"
"errors"
"fmt"
"io"
"log"
"os"
"os/exec"
Expand Down Expand Up @@ -159,42 +159,34 @@ func findAddressInRunningUnits(lookup string) (string, bool) {
}

func readSSHChannel(channel *ssh.Channel) {
readSSHChannelOutput(channel.Stdout)

exitErr := <-channel.Exit
if exitErr == nil {
return
}

readSSHChannelOutput(channel.Stderr)

exitStatus := -1
switch exitError := exitErr.(type) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, this switch will disappear in the future if this patch is accepted:

https://codereview.appspot.com/81290043/

case *gossh.ExitError:
exitStatus = exitError.ExitStatus()
case *exec.ExitError:
status := exitError.Sys().(syscall.WaitStatus)
exitStatus = status.ExitStatus()
}

os.Exit(exitStatus)
}

func readSSHChannelOutput(o *bufio.Reader) {
for {
select {
case exitErr := <-channel.Exit:
if exitErr == nil {
return
}

for {
bytes, err := channel.Stderr.ReadBytes('\n')
if err != nil {
break
}

fmt.Print(string(bytes))
}

exitStatus := -1
switch exitError := exitErr.(type) {
case *gossh.ExitError:
exitStatus = exitError.ExitStatus()
case *exec.ExitError:
status := exitError.Sys().(syscall.WaitStatus)
exitStatus = status.ExitStatus()
}

os.Exit(exitStatus)
default:
bytes, err := channel.Stdout.ReadBytes('\n')
if err != nil {
if err != io.EOF {
return // unknown error reading stdout, finishing.
}
break // let the exit channel to finish properly.
}

fmt.Print(string(bytes))
bytes, err := o.ReadBytes('\n')
if err != nil {
break
}

fmt.Print(string(bytes))
}
}