Paramiko执行后台命令报错

1. 报错关键字

  • paramiko
  • Exception ignored in: <function BufferedFile.__del__ at 0x000001E62C28A048>
  • TypeError: ‘NoneType’ object is not callable

2. 代码

1
2
3
4
5
import paramiko
sshc = paramiko.SSHClient()
sshc.set_missing_host_key_policy(paramiko.AutoAddPolicy())
sshc.connect(host, username=username,port=port,pkey=key)
stdin1, stdout1, stderr1 = sshc.exec_command("setsid ...(省略)... &")

setsid是linux系统命令,如果再window下写的代码此处必然无法运行。可以先将setsid相关代码通过sshc.open_sftp()上传到服务端,然后通过sshc.exec_command(“python setsid.py”)运行脚本。

nohup 与 setsid 区别

参考:http://www.tang-lei.com/2019/03/04/linux-nohup-setsid-使用区别/

  • nohup

    nohup命令的功能就是使用当前进程忽略hangup信号,从而继续执行。默认的标准输入输出都会被重定向到当前目录下的nohup.out文件里。一般我们配置在命令的末尾加上 & 来配合使用。

    可以通过 >filename 2>&1 来重定向默认的输入输出, 如:”nohup minio server :9001 /mnt/test/ > /var/log/minio_test.log 2>&1 &”, 通过jobs 可以看到该进程的父进程是当前shell的进程号

    作用说明:进程在后台执行;忽略hangup信号;重定向日志输出

  • &

    & 代表后台运行程序。如果终端退出,则该进程会结束。通常配合nohup和setsid使用

  • setsid

    setsid 就是set session id 的意思。表示该命令运行的进程是一个新的session。因此其父进程不属于当前终端。实际上setsid运行的进程,其父进程id(ppid)为1(init进程的id)。

    如:”setsid minion server :9001 /mnt/test/ > /var/log/minio_test.log &”。注意:setsid输出重定向必须手动指定。

  • 结论

    由于nohup的父进程与当前的worker有关,当我们Ctrl+C的时候,也会把其给kill掉。而setsid的父进程是init,所以当我们退出worker的时候,并不会kill掉该服务

3. 输出

1
2
3
4
5
6
7
8
9
Exception ignored in: <function BufferedFile.__del__ at 0x000001E62C28A048>
Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\site-packages\paramiko\file.py", line 66, in __del__
File "C:\ProgramData\Anaconda3\lib\site-packages\paramiko\channel.py", line 1392, in close
File "C:\ProgramData\Anaconda3\lib\site-packages\paramiko\channel.py", line 991, in shutdown_write
File "C:\ProgramData\Anaconda3\lib\site-packages\paramiko\channel.py", line 963, in shutdown
File "C:\ProgramData\Anaconda3\lib\site-packages\paramiko\channel.py", line 1246, in _send_eof
File "C:\ProgramData\Anaconda3\lib\site-packages\paramiko\message.py", line 232, in add_int
TypeError: 'NoneType' object is not callable

报错原因

  1. windows回车和linux回车存在差异,如下图是windows的回车,二linux不是。

  2. nohup & 命令执行完没有完全退出

  3. shell命令存在错误

4. 解决方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
## main.py
import paramiko
sshc = paramiko.SSHClient()
sshc.set_missing_host_key_policy(paramiko.AutoAddPolicy())
sshc.connect(host, username=username,port=port,pkey=key)

sftp = sshc.open_sftp()
localfile = "cmd.py"
remotepath = "/path/cmd.py"
sftp.put(localfile, remotepath)
stdin, stdout1, stderr = sshc.exec_command("python "+"cmd.py")
sshc.close()

## cmd.py
import os
import sys
SnapID = "snap-096b5af48e45fe262"
datapath = "/mnt/snap/8572302701/hda/data.gz.aes"
opensslcmd = os.popen( # 此处选用os.popen,主要是怀疑paramiko存在问题
"setsid ...(your shell commands)... &"
)
# 此处可以多添加几个无用命令
sys.exit()

将代码最后添加一个sys.exit()程序恢复正常,其实主要ssh返回的结果缓冲释放过快未读完,就产生报错了。也有说,加一个sleep 1秒也可以解决。

也可能是shell脚本问题,需仔细检查;windows于linux 回车差异需要注意。