下面是一个脚本,它登录到远程主机(一个Cisco IOS-XR路由器)并通过SSH运行一个命令。这样做的目的是获取命令的结果(一个整数),以便由Cacti绘制它。仙人掌运行此脚本时每5分钟运行一次,这是正常的投票例程:
#!/bin/bash
if [[ -z $1 ]]
then
exit 1
fi
HOST="$1"
USER="cact-ssh-user"
TIMEOUT=10s
export SSHPASS="aaaaaaaaaaaaa"
CMD="show controllers np struct IPV4-LEAF-FAST-P np0 | in Entries"
RAW_OUTPUT=$(timeout $TIMEOUT sshpass -e ssh -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null $USER@$HOST "$CMD" 2>/dev/null)
GRT_UCASTV4_USED=$(echo -n "$RAW_OUTPUT" | grep "Entries" | awk '{print $6}' | tr -d "," | tr -d " ")
echo -n "ucastv4_used:$GRT_UCASTV4_USED"
该命令通过交互式shell (当我使用/path/to/script/script.sh 10.0.0.1
在Cacti服务器上运行脚本时)运行良好。但是,当Cacti cronjob运行时,输出只是空的。因此,在我对Cacti服务器的SSH会话中,输出是:
$ ./script 10.0.0.1
ucastv4_used:1234
在Cacti日志中,输出是:05/22/2017 03:35:21 PM - SPINE: Poller[0] Host[69] TH[1] DS[6837] SCRIPT: /opt/scripts/cacti-scripts/asr9001-get-tcam-ucast-usage.sh 10.0.0.1, output: ucastv4_used:
我已经将su
编辑给了Cacti用户,脚本运行得很好。因此,这似乎是特定于它作为一个cronjob运行的,SSH命令的输出正在被神奇地重定向到某个地方,我不知道在哪里或者为什么。
为了尝试和调试这一点,我在脚本中添加了以下行(直接在#!/bin/bash
下),并等待Cacti 5分钟轮询间隔运行(当脚本每5分钟调用一次时,我可以在Cacti日志中看到);
exec >/tmp/stdout.log 2>/tmp/stderr.log
set -x
stdout.log
只包含与cacti.log
相同的ucastv4_used:
,stderr.log
文件包含远程SSH主机的登录横幅,没有其他任何内容。SSH输出到哪里去了?
我已经厌倦了将脚本中的SSH行更改为输出文件,然后从那里读取:
timeout $TIMEOUT sshpass -e ssh -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null $USER@$HOST "$CMD" > /tmp/output 2>/dev/null
GRT_UCASTV4_USED=$(grep "Entries" /tmp/output | awk '{print $6}' | tr -d "," | tr -d " ")
文件/tmp/output
是空的,所以GRT_UCASTV4_USED
变量也是空的。最后,stdout.log
和以前一样:ucastv4_used:
我还尝试将#!/bin/bash
更改为#!/bin/bash -i
,以强制进行交互式会话。如果我将-i
添加到脚本中,我可以在stdout.log
文件中看到设置了$PS1
,如果没有-i
,则不会打印任何内容。但是,仍然没有来自SSH命令的输出。SSH输出的命令在哪里?
我还尝试使用ssh ..... | tee /tmp/output
,以便输出应该显示在/tmp/output
和/tmp/stdout.log
中,但两者都是空的。
我可以在远程路由器上看到SSH会话正在启动并运行命令。这是来自debug ssh server
的
RP/0/RSP0/CPU0:May 22 14:52:57.976 UTC: SSHD_[65909]: (open_master_file) command added show controllers np struct IPV4-LEAF-FAST-P np0 | in Entries
而且,由于这是通过我与Cacti服务器的交互会话来实现的,我猜问题就在那里,而不是路由器上。我还确信,Cacti本身并不是问题所在,我可以触发脊柱从我的交互式SSH会话中轮询这个路由器主机,并且脚本工作得很好(进一步指出了在非交互外壳中SSH输出是如何蒸发的问题):
$ cd /usr/local/spine/bin
$ ./spine -V 7 69 69
...
05/22/2017 04:06:56 PM - SPINE: Poller[0] Host[69] TH[1] DS[6837] SCRIPT: /opt/scripts/cacti-scripts/asr9001-get-tcam-ucast-usage.sh 10.0.0.1, output: ucastv4_used:658809
因此,似乎SSH输出被重定向到某个地方,我无法“得到”它,或者路由器不知何故知道这是一个非交互式SSH客户端,并且没有返回任何东西。否则,我如何调试它?
使用思科路由器上的更新1当我通过交互式SSH会话运行脚本到Cacti服务器时,以及当它通过Cacti的轮询间隔/cron作业运行时,我捕获了调试日志。我已经编写了diff
输出,我能找到的唯一有趣的不同之处(除了SSH更改和Cacti服务器更改的临时源端口等)如下:
*** 132,145 ****
(sshd_interactive_shell) *** removing alarm
sshd_interactive_shell - ptyfd = 46
event_contex_init done
! sshd_ptytonet - Channel 1 Received EOT (bytes:1)
! sshd_ptytonet - Channel 1 exec command executed sending CHANNEL_CLOSE
! (close_channel), pid:182260085, sig rcvd:1, state:10 chan_id:1
! addrem_ssh_info_tuple: REMOVE Inside the critical Section %pid:182260085
! Cleanup sshd process 182260085, session id 1, channel_id 1
! addrem_ssh_info_tuple: REMOVE exiting the Critical Section %pid:182260085
close_channel: Accounting stopped: scriptaccount
! In delete channel code, pid:182260085, sig rcvd:1, state:10 chan_id:1
Sending Exit Status: 0 sig: 1
Sending Channel EOF msg
Sending Channel close msg for remote_chan_id = 0 chan_id = 1
--- 134,147 ----
(sshd_interactive_shell) *** removing alarm
sshd_interactive_shell - ptyfd = 46
event_contex_init done
! Pad_len = 6, Packlen = 12
! sshd_nettopty: EOF received. Disconnecting session
! (close_channel), pid:182329717, sig rcvd:1, state:10 chan_id:1
! addrem_ssh_info_tuple: REMOVE Inside the critical Section %pid:182329717
! Cleanup sshd process 182329717, session id 1, channel_id 1
! addrem_ssh_info_tuple: REMOVE exiting the Critical Section %pid:182329717
close_channel: Accounting stopped: scriptaccount
! In delete channel code, pid:182329717, sig rcvd:1, state:10 chan_id:1
Sending Exit Status: 0 sig: 1
Sending Channel EOF msg
Sending Channel close msg for remote_chan_id = 0 chan_id = 1
上半部分是我与Cacti服务器的交互会话。我注意到在上半部分的sshd_ptytonet - Channel 1 Received EOT (bytes:1)
中,而通过cronjob调试显示了sshd_nettopty: EOF received. Disconnecting session
。非交互式会话是否只是将我的SSH命令传递给远程主机并尽可能快地退出(因此它没有等待SSH服务器使用命令输出进行响应)?
发布于 2017-09-12 12:20:04
RAW_OUTPUT=$(timeout $TIMEOUT sshpass -e ssh -T -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null $USER@$HOST "$CMD" </dev/zero 2>/dev/null)
https://stackoverflow.com/questions/44116461
复制相似问题