写部署脚本时,难免涉及到一些远程执行命令或者传输文件。
之前一直使用sh库,调用sh.ssh远程执行一些命令,sh.scp传输文件,但是实际使用中还是比较麻烦的,光是模拟用户登陆这一点,还需要单独定义方法模拟输入。
感受一下:
from sh import ssh PASS = 'xxxx' def ssh_interact(line, stdin): line = line.strip() print(line) if line.endswith('password:'): stdin.put(PASS) ssh('x.x.x.x', _out=ssh_interact)
来自官方文档
后来发现paramiko库更加优雅、便捷,所以准备用pramiko替换掉sh。
之前通过同事了解到,paramiko在远程执行python脚本时,脚本中的输出内容可能会通过stderr这个管道输出出来,所以直接用paramiko的SSHClient类中的exec_command方法执行,通过读stderr管道中有无输出来判断命令是否成功执行的方式是行不通的。所以用更底层一些的Channel类的recv_exit_status方法判断执行退出码更好一些。
安装
可以通过使用pip install paramiko安装,细节这里不再赘述。
封装
# coding: utf-8 import os.path from paramiko import SSHClient, AutoAddPolicy, AuthenticationException class ConnectError(Exception): """ 连接错误时抛出的异常 """ pass class RemoteExecError(Exception): """ 远程执行命令,失败时抛出的异常 """ pass class SCPError(Exception): """ 远程下发文件时抛出的异常 """ pass
... class Remote(object): def __init__(self, host, username, password=None, port=22, key_filename=None): self.host = host self.username = username self.password = password self.port = port self.key_filename = key_filename self._ssh = None def _connect(self): self._ssh = SSHClient() self._ssh.set_missing_host_key_policy(AutoAddPolicy()) try: if self.key_filename: self._ssh.connect(self.host, username=self.username, port=self.port, key_filename=self.key_filename) else: self._ssh.connect(self.host, username=self.username, password=self.password, port=self.port) except AuthenticationException: self._ssh = None raise ConnectionError('连接失败,请确认用户名、密码、端口或密钥文件是否有效') except Exception as e: self._ssh = None raise ConnectionError('连接时出现意料外的错误:%s' % e) def get_ssh(self): if not self._ssh: self._connect() return self._ssh
实例化SSHClient类,通过它的connect()方法获取SSH连接。
需要注意的是,远程访问的主机若是第一次连接,属于未知设备需要认证,通过set_missing_host_key_policy()方法设置一种策略,这里使用的是AutoAddPolicy()。
这里的_connect支持两种方式登录,一种是提供主机的用户名密码,另一种是通过密钥文件。在连接时检查如果指定了密钥文件则使用这种方式登录,否则通过用户名密码登录。
_connect()虽然是实际的建立连接的方法,但实际对外接口是get_ssh(),如果已经有建立好的SSH连接直接返回,避免重复建立连接。
class Remote(object): ... def ssh(self, cmd, root_password=None, get_pty=False, super=False): cmd = self._prepare_cmd(cmd, root_password, super) stdout = self._exec(cmd, get_pty) return stdout def _prepare_cmd(self, cmd, root_password=None, super=False): if self.username != 'root' and super: if root_password: cmd = "echo '{}'|su - root -c '{}'".format(root_password, cmd) else: cmd = "echo '{}'|sudo -p '' -S su - root -c '{}'".format(self.password, cmd) return cmd def _exec(self, cmd, gty_pty=False): channel = self.get_ssh().get_transport().open_session() if get_pty: channel.get_pty() channel.exec_command(cmd) stdout = channel.makefile('r', -1).readlines() stderr = channel.makefile_stderr('r', -1).readlines() ret_code = channel.recv_exit_status() if ret_code: msg = ''.join(stderr) if stderr else ''.join(stdout) raise RemoteExecError(msg) return stdout
在远程执行某些命令时,可能需要管理员权限,这种时候需要做一些判断,首先判断登录提供的用户名如果不是root,则需要对命令做一些修改。这里的修改有两种情况,一是,该普通用户本身就有sudo权限,只需要把执行的命令加到sudo之后执行就可以,还有一种是普通用户没有sudo权限,需要通过su先切换到root身份之后再执行,这种情况下需要提供root密码。
还有一点要注意的是get_pty这个参数,实际在远程执行sudo命令时,一般主机都会需要通过tty才能执行,通过把get_pty值设置为True,可以模拟tty,但是随之而来也会有一个问题,如果是远程执行一个需要长期运行的进程,例如启动nginx服务,当远程命令执行后SSH退出之后,此次运行的所有程序也会随之结束,所以在需要通过远程命令运行某些服务或程序时,是不能指定get_pty参数的;但同时,如果是普通用户远程登录,是没有权限执行service命令的。建议的一种方式是修改/etc/sudoers配置文件,注释掉Defaults requiretty这行。
class Remote(object): ... def scp(self, local_file, remote_path): if not os.path.exists(local_file): raise SCPError("Local %s isn't exists" % local_file) if not os.path.isfile(local_file): raise SCPError("%s is not a File" % local_file) sftp = self.get_ssh().open_sftp() try: sftp.put(local_file, remote_path) except Exception as e: raise SCPError(e)
先确认要下发的文件存在,并且是文件不是目录,如果不是则抛出异常。同时,remote_path需要是远程主机的文件绝对目录,例如/tmp/xxx.xxx,而不能是/tmp。
使用
# coding: utf-8 from remote_client import RemoteClient rc = RemoteClient('10.1.100.1', 'test', 'test_pass') rc.ssh('whoami') # [u'test\n'] rc.scp('/tmp/test.out', '/tmp/test.out')
总结
相较于sh,paramiko好用的不是一星半点,这里只是提供了一个简单的封装,paramiko本身还有很多其他用法,欢迎大家积极讨论。
以上只是本人的一点理解,如果有错误之处,欢迎指正。
以上这篇使用paramiko远程执行命令、下发文件的实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持小牛知识库。
本文向大家介绍Python使用paramiko连接远程服务器执行Shell命令的实现,包括了Python使用paramiko连接远程服务器执行Shell命令的实现的使用技巧和注意事项,需要的朋友参考一下 需求 在自动化测试场景里, 有时需要在代码里获取远程服务器的某些数据, 或执行一些查询命令,如获取Linux系统版本号 \ 获取CPU及内存的占用等, 本章记录一下使用paramiko模块SSH连
本文向大家介绍基于使用paramiko执行远程linux主机命令(详解),包括了基于使用paramiko执行远程linux主机命令(详解)的使用技巧和注意事项,需要的朋友参考一下 paramiko是python的SSH库,可用来连接远程linux主机,然后执行linux命令或者通过SFTP传输文件。 关于使用paramiko执行远程主机命令可以找到很多参考资料了,本文在此基础上做一些封装,便于扩展
本文向大家介绍python 采用paramiko 远程执行命令及报错解决,包括了python 采用paramiko 远程执行命令及报错解决的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了python 采用paramiko 远程执行命令及报错解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 报错1: 是由于 没有设置 报错2: 会卡死
问题内容: 所以我正在与paramiko一起进行一些基本的SSH测试,并且没有将任何输出输出到stdout中。这是我的代码。 因此,每当我运行此命令时,都会执行该命令(如执行cp之类的操作所看到的那样,文件将被复制),但是我始终会收到“此命令无输出”的信息。当输出stdout = stdout.readlines()时,输出为[]。另外,如果我将打印语句添加到for循环中,它将永远不会运行。有人可
问题内容: 如何在远程Linux机器上执行命令/脚本?说我想从框a的框b开始服务tomcat。 问题答案: 我想这是最好的安全方式,例如: 必须根据您的特定需求(例如,仅绑定到ipv4)部署OPTIONS的地方,并且您的远程命令可能正在启动您的tomcat守护程序。 注意 : 如果不想在每次运行ssh时都提示您,也请查看ssh- agent,以及系统允许的情况。关键是…了解ssh密钥交换过程。请仔
本文向大家介绍python利用paramiko连接远程服务器执行命令的方法,包括了python利用paramiko连接远程服务器执行命令的方法的使用技巧和注意事项,需要的朋友参考一下 python中的paramiko模块是用来实现ssh连接到远程服务器上的库,在进行连接的时候,可以用来执行命令,也可以用来上传文件。 1、得到一个连接的对象 在进行连接的时候,可以使用如下的代码: 在connect函