I'm writing an SSH client in Go that connects to a switch and runs a list of configuration commands. So far, I am able to successfully connect to a switch, run the desired commands, and print the output of the session. The problem comes when the switch is expecting a
, space, or "q" to be entered when a command's output is too long. For example:
switch#show int status
Port Name Status Vlan Duplex Speed Type
Gi1/0/1 notconnect 100 auto auto 10/100/1000BaseTX
Gi1/0/2 connected 915 a-full a-100 10/100/1000BaseTX
Gi1/0/3 notconnect 100 auto auto 10/100/1000BaseTX
Gi1/0/4 notconnect 100 auto auto 10/100/1000BaseTX
Gi1/0/5 notconnect 230 auto auto 10/100/1000BaseTX
...
Po1 sw-sww-100-sww-0-0 connected trunk a-full 10G
--More-- # Program hangs here; expecting a new line, space, or 'q'
The --More--
prompt is not actually printed to the screen, so simply checking if the current line of Stdout
contains --More--
and sending a
, space, or "q" does not work.
In addition to fixing this problem, I'd like to filter Stdout
of the session so that the only thing printed is the output of each command. In other words, I don't want the switch's prompt to be printed to the terminal.
To sum up:
- How to capture and print only the output of each command?
- How to send a new line, space, or letter "q" when prompted?
Any help is appreciated. Here is my code:
package main
import (
"bufio"
"fmt"
"golang.org/x/crypto/ssh"
"io"
"log"
"os"
"time"
)
type Device struct {
Config *ssh.ClientConfig
Client *ssh.Client
Session *ssh.Session
Stdin io.WriteCloser
Stdout io.Reader
Stderr io.Reader
}
func (d *Device) Connect() error {
client, err := ssh.Dial("tcp", os.Args[1]+":22", d.Config)
if err != nil {
return err
}
session, err := client.NewSession()
if err != nil {
return err
}
sshIn, err := session.StdinPipe()
if err != nil {
return err
}
sshOut, err := session.StdoutPipe()
if err != nil {
return err
}
sshErr, err := session.StderrPipe()
if err != nil {
return err
}
d.Client = client
d.Session = session
d.Stdin = sshIn
d.Stdout = sshOut
d.Stderr = sshErr
return nil
}
func (d *Device) SendCommand(cmd string) error {
if _, err := io.WriteString(d.Stdin, cmd+"
"); err != nil {
return err
}
return nil
}
func (d *Device) SendConfigSet(cmds []string) error {
for _, cmd := range cmds {
if _, err := io.WriteString(d.Stdin, cmd+"
"); err != nil {
return err
}
time.Sleep(time.Second)
}
return nil
}
func (d *Device) PrintOutput() {
r := bufio.NewReader(d.Stdout)
for {
text, err := r.ReadString('
')
fmt.Printf("%s", text)
if err == io.EOF {
break
}
}
}
func (d *Device) PrintErr() {
r := bufio.NewReader(d.Stderr)
for {
text, err := r.ReadString('
')
fmt.Printf("%s", text)
if err == io.EOF {
break
}
}
}
func main() {
sshConf := ssh.Config{}
sshConf.Ciphers = append(sshConf.Ciphers, "aes128-cbc", "3des-cbc", "blowfish-cbc", "arcfour")
config := &ssh.ClientConfig{
Config: sshConf,
User: "mwalto7",
Auth: []ssh.AuthMethod{
ssh.Password("Lion$Tiger$Bear$"),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Timeout: time.Second * 5,
}
sw := &Device{Config: config}
fmt.Println("Connecting to ", os.Args[1])
if err := sw.Connect(); err != nil {
log.Fatal(err)
}
defer sw.Client.Close()
defer sw.Session.Close()
defer sw.Stdin.Close()
if err := sw.Session.Shell(); err != nil {
log.Fatal(err)
}
commands := []string{"show int status", "exit"}
if err := sw.SendConfigSet(commands); err != nil {
log.Fatal(err)
}
sw.Session.Wait()
sw.PrintOutput()
sw.PrintErr()
}