使用go ssh库与Cisco设备进行通信

huangapple go评论107阅读模式
英文:

Talking to Cisco equipment using go ssh library

问题

我正在尝试通过SSH连接到路由器并使用show命令来监控各种Cisco ASR参数。以下是工作流程的一部分(省略了错误处理):

client, err := ssh.Dial("tcp", "172.16.32.95:22", config)
session, err := client.NewSession()
sshOut, err := session.StdoutPipe()
sshIn, err := session.StdinPipe()
err := session.RequestPty("xterm", 80, 40, modes)
err := session.Shell()

在这一点上,我可以向sshIn写入内容并从sshOut读取内容。
由于Cisco(和其他厂商的)路由器不支持执行命令(如果我理解有误,请纠正),我只能将命令传递给shell并读取输入,直到找到命令提示符。

好的。这是我用来跳过第一个命令提示符之前的初始路由器问候的部分:

buf := make([]byte, 1000)
n, err := sshOut.Read(buf) //读取SSH终端的欢迎消息
loadStr := ""
if err == nil {
    loadStr = string(buf[:n])
}
for (err == nil) && (!strings.Contains(loadStr, "[local]")) {
    n, err = sshOut.Read(buf)
    loadStr += string(buf[:n])
}
fmt.Println(loadStr)

输出结果如下:

Last login: Tue Jan 14 17:29:06 -0500 2014 on pts/1 from 172.16.35.101.
Cisco Systems SSI
[local]ewag# 

要运行命令,我向sshIn写入内容:

if _, err := sshIn.Write([]byte("show clock\r")); err != nil {
    panic("Failed to run: " + err.Error())
}

然后以与读取初始问候相同的方式读取响应,输出结果如下(包括问候):

Last login: Tue Jan 14 18:06:14 -0500 2014 on pts/2 from 10.7.7.14.
Cisco Systems SSI
[local]ewag# 
show clock
Tuesday January 14 18:09:19 EST 2014
[local]ewag# 

一切都还好。但是当我尝试发送较长的命令时,例如:

if _, err := sshIn.Write([]byte("show session progress ipsg-service ipsg-gprs-svc\r")); err != nil {
    panic("Failed to run: " + err.Error())
}

输出结果出现了断裂:

Last login: Tue Jan 14 18:09:19 -0500 2014 on pts/2 from 10.7.7.14.
Cisco Systems SSI
[local]ewag# 
show session progress ipsg
-service ipsg-gprs-svc
Unknown command - "ipsg-service", unrecognized keyword
[local]ewag# 

我发送的命令在某个地方被分割了,但命令结果的输出是正确的,没有分割。

所以问题是如何修复这个分割问题?目前我没有更多的想法。谢谢关注!

英文:

I'm trying to implement monitoring various Cisco ASR parameters doing ssh to router and using show commands to get results. Here is part of the workflow (error handling omitted):
<!-- language: lang-go -->

client, err := ssh.Dial(&quot;tcp&quot;, &quot;172.16.32.95:22&quot;, config)
session, err := client.NewSession()
sshOut, err := session.StdoutPipe()
sshIn, err := session.StdinPipe()
err := session.RequestPty(&quot;xterm&quot;, 80, 40, modes)
err := session.Shell()

At this point I can write to sshIn and read from sshOut.
Since Cisco's (and other vendor's) routers don't support exec'ing commands (correct me if I'm wrong) all I can do is to pass commands to shell and read input until I find command prompt.

Ok. Here is part I use to skip initial router greetings before the first command prompt:

buf := make([]byte, 1000)
n, err := sshOut.Read(buf) //this reads the ssh terminal welcome message
loadStr := &quot;&quot;
if err == nil {
	loadStr = string(buf[:n])
}
for (err == nil) &amp;&amp; (!strings.Contains(loadStr, &quot;[local]&quot;)) {
	n, err = sshOut.Read(buf)
	loadStr += string(buf[:n])
}
fmt.Println(loadStr)

which yields:

Last login: Tue Jan 14 17:29:06 -0500 2014 on pts/1 from 172.16.35.101.
Cisco Systems SSI
[local]ewag# 

To run command I write to sshIn:

if _, err := sshIn.Write([]byte(&quot;show clock\r&quot;)); err != nil {
	panic(&quot;Failed to run: &quot; + err.Error())
}

And read response the same way I read initial greeting, which yields (with greetings):

Last login: Tue Jan 14 18:06:14 -0500 2014 on pts/2 from 10.7.7.14.
Cisco Systems SSI
[local]ewag# 
show clock
Tuesday January 14 18:09:19 EST 2014
[local]ewag# 

Still everything ok. But when I try to send somewhat longer command, f.e.:

if _, err := sshIn.Write([]byte(&quot;show session progress ipsg-service ipsg-gprs-svc\r&quot;)); err != nil {
	panic(&quot;Failed to run: &quot; + err.Error())
}

Output breaks:

Last login: Tue Jan 14 18:09:19 -0500 2014 on pts/2 from 10.7.7.14.
Cisco Systems SSI
[local]ewag# 
show session progress ipsg
-service ipsg-gprs-svc
Unknown command - &quot;ipsg-service&quot;, unrecognized keyword
[local]ewag# 

The command I've sent got split at some point, but output for command result is passed correctly without splits.

So question is how this split can be fixed? For now I'm out of ideas.
Thanks for attention!

答案1

得分: 1

愚蠢的错误。我以这种方式请求pty:

session.RequestPty("vt100", 80, 40, modes)

这给了我宽度为40个字符,高度为80个字符。
在我的情况下,正确的调用应该是:

session.RequestPty("vt100", 0, 200, modes)

这样一切都按预期工作。而且不需要显式更改终端宽度。

英文:

Stupid mistake. I was requesting pty this way:

session.RequestPty(&quot;vt100&quot;, 80, 40, modes)

which gives me width 40 chars, and height 80 chars.
In my case the correct call should be:

session.RequestPty(&quot;vt100&quot;, 0, 200, modes)

This way everything works as expected. And there is no need to change terminal width explicitly.

答案2

得分: 0

问题通过在Cisco上设置终端宽度来解决。
因此,在建立会话后,我发送以下命令:

terminal width 200

给路由器。

现在,长命令在回复中正确显示。

英文:

Problem was resolved by setting terminal width on Cisco.
So, after session is established, I send command:

terminal width 200

to router.

Now long commands are displayed correctly in replies.

huangapple
  • 本文由 发表于 2014年1月15日 07:24:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/21126195.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定