11. python paramiko系统批量运维管理器
11. paramiko系统批量运维管理器
- paramiko是基于python实现的SSH2远程安全连接,支持认证及密钥方式,可实现远程文件传输、执行命令、中间SSH代理等功能,相对于pexpect,封装层次更高,更贴近于ssh协议的功能。
11.1 paramiko安装:
pip install paramiko
简单实现远程执行命令示例:
#!/usr/bin/python3
#_*_coding:utf-8_*_
import paramiko
import paramiko.util
hostname = '10.0.0.242'
username = 'root'
password = '6'
paramiko.util.log_to_file('syslogin.log') #发送paramiko日志到syslogin.log文件
ssh = paramiko.SSHClient() #创建一个ssh客户端的client对象
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy) #允许连接未在known_hosts中列出的的主机
ssh.connect(hostname=hostname,username=username,password=password) #创建ssh连接
stdin,stdout,stderr = ssh.exec_command('ip a') #调用远程执行命令exec_command()
res,err = stdout.read(),stderr.read() #获取命令的返回结果
result = res if res else err #如果没有返回stdout则报错输出stderr
print(result.decode('utf-8'))
ssh.close() #关闭ssh连接
11.2 paramiko核心组件
- 使用paramiko库连接服务器有两种方式,一种是使用SSHClient类,另一种是使用Transport类。它们都支持密码认证和密钥认证方式。
11.2.1 SSHClient类:
- SSHClient的作用类似于Linux的ssh命令,是对SSH会话的封装,该类封装了传输(Transport),通道(Channel)及SFTPClient建立的方法(open_sftp),通常用于执行远程命令。
- Transport: 是一种加密的会话,使用时会同步创建一个加密通道,这个通道叫做Channel
- Channel: 是一种类Socket,一种安全的ssh传输通道
- Session: 是client和server保持连接的对象
常用方法:
- connect()方法
- 实现了远程ssh连接并校验
connect(self,hostname,port=22,username=None,password=None,pkey=None,key_filename=None,
timeout=None,allow_agent=True,look_for_keys=True,compress=False)
- 参数说明:
hostname(str类型):连接主机的地址
port(int类型):连接端口,默认为22
username(str类型):校验的用户名,默认为当前本地用户名
password(str类型):密码
pkey(Pkey类型):私钥方式身份验证
key_filename(str 或 list(str) 类型):一个文件名或文件名的列表,用于私钥的身份验证
timeout(float类型):一个可选TCP连接的超时时间
allow_agent(bool类型):设置False时用于禁用连接到ssh代理
look_for_keys(bool类型):设置False时用来禁用在~/.ssh中搜索私钥文件
compress(bool类型):设置True时打开压缩
- exec_command()方法
- 远程命令的执行方法,该方法将以元组的形式返回远程命令的标准输入输出为stdin、stdout、stderr的文件对象
- 该方法执行完毕后通道就被关闭,不能再使用。如要执行另一条命令,需打开一个新的通道
exec_command(self,command,bufsize=-1)
- 参数说明:
command(str类型):执行命令字符串
get_pty(bool类型):设置是否从目标主机请求一个伪终端,默认值:False
environment(dict[str,str]类型):以字典数据类型定义环境变量,这些环境变量将被并入执行远程命令的默认环境变量中
bufsize(int类型):文件缓冲区大小,默认为-1(不限制)
- load_system_host_keys()方法
- 加载本地公钥校验文件,默认~/.ssh/know_hosts,非默认需手工指定
load_system_host_keys(self,filename=None)
- 参数说明:
filename(str类型):指定远程主机公钥校验文件路径,未指定默认找路径: ~/.ssh/known_hosts
- set_missing_host_key_policy()方法
- 该方法用于远程主机没有本地主机秘钥或HostKeys对象时的策略,有三种方法:AutoAddPolicy、RejectPolicy(默认)、WarningPolicy仅限于SSHClient方法
- 参数说明:
AutoAddPolicy:自动添加主机名及主机密钥到本地HostKeys对象,并将其保存,不依赖于load_system_host_keys()的配置,即使~/.ssh/known_hosts不存在也不影响;
RejectPolicy(默认):自动拒绝未知的主机名和密钥,依赖于load_system_host_keys()的配置;
WarningPolicy:用于记录一个未知的主机密钥的python告警,并接受它,与AutoAddPolicy相似,但未知主机会告警;
- 示例:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy)
- open_sftp()方法
- 该方法用于在当前SSH会话的基础上创建一个SFTP会话,返回的是一个SFTPClient对象,可以进行文件的上传,下载等操作
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy)
sftp = ssh.open_sftp() # 创建SFTP客户端实例
#权限位 = 0o644 # 例如设置文件权限为644(-rw-r--r--)
sftp.put('/local/path/file.txt', '/remote/path/file.txt',mode=权限位) # 上传文件
#对于下载的文件没有设置权限位的方法,可以使用os.chmod('/local/path/file.txt',0o644)来设置
sftp.get('/remote/path/file.txt', '/local/path/file.txt') # 下载文件
sftp.remove('/remote/path/file.txt') # 删除文件
sftp.close() #关闭sftp会话
ssh.close() #关闭ssh连接
- invoke_shell(term='vt100', width=80, height=24, width_pixels=0, height_pixels=0, environment=None)
- 在远程主机行生成新的交互式shell,通常在此之前需调用get_pyt,利用send函数发送cmd到SSH server,添加做回车来执行shell命令(cmd中需要有\n命令才能执行)。注意不同的情况,如果执行完telnet命令后,telnet的换行符是\r\n,通过recv函数获取回显 recv(bufsize)
11.2.2 Transport类:
- SSHClient类只是简历SSH连接的便捷方式,要更直接、更灵活的控制,应使用Transport类
- Transport类用于将SSH传输附加到流(通常是套接字),协商加密会话进行认证,然后会在会话之间创建流隧道,也就是通道。多个通道可以在单个会话中多路复用(通道复用技术)
#!/usr/bin/python3
#_*_coding:utf-8_*_
import paramiko
import paramiko.util
hostname = '10.0.0.11'
port = 22
username = 'root'
password = '6'
paramiko.util.log_to_file('syslogin.log') #发送paramiko日志到syslogin.log文件
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname=hostname,username=username,password=password)
#创建transport对象
transport = ssh.get_transport()
#创建channel对象
channel = transport.open_session()
#执行第一个命令
channel.exec_command('free -m')
output1 = ''
while True:
data = channel.recv(1024)
if not data:
break
output1 += data.decode()
print(output1)
#同一通道执行第二条命令
channel.exec_command('ip a')
output2 = ''
while True:
data = channel.recv(1024)
if not data:
break
output2 += data.decode()
print(output2)
channel.close()
ssh.close()
>>>输出:
(test-venv) root@supershy:~/test-venv# python3 test.py
total used free shared buff/cache available
Mem: 3875 367 1096 1 2411 3215
Swap: 0 0 0
Traceback (most recent call last):
File "/root/test-venv/test.py", line 38, in <module>
channel.exec_command('ip a')
File "/root/test-venv/lib/python3.10/site-packages/paramiko/channel.py", line 69, in _check
raise SSHException("Channel is not open")
paramiko.ssh_exception.SSHException: Channel is not open
报错:未解决
原因:第一条命令执行完后自动将通道关闭了,导致第二个命令不能使用同一条通道
11.2.3 基于私钥连接
#!/usr/bin/python3
#_*_coding:utf-8_*_
import paramiko
import paramiko.util
hostname = '10.0.0.242'
username = 'root'
paramiko.util.log_to_file('syslogin.log') #发送paramiko日志到syslogin.log文件
#获取私钥
private_key = paramiko.RSAKey.from_private_key_file('/root/.ssh/id_rsa')
ssh = paramiko.SSHClient() #创建一个ssh客户端的client对象
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy) #允许连接未在known_hosts中列出的的主机
ssh.connect(hostname=hostname,username=username,pkey=private_key) #创建ssh连接
stdin,stdout,stderr = ssh.exec_command('ip a') #调用远程执行命令exec_command()
res,err = stdout.read(),stderr.read() #获取命令的返回结果
result = res if res else err #如果没有返回stdout则报错输出stderr
print(result.decode('utf-8'))
ssh.close() #关闭ssh连接
11.2.4 普通用户执行sudo命令
#!/usr/bin/python3
#_*_coding:utf-8_*_
import paramiko
import paramiko.util
hostname = '10.0.0.242'
username = 'supershy'
password = '6'
paramiko.util.log_to_file('syslogin.log') #发送paramiko日志到syslogin.log文件
ssh = paramiko.SSHClient() #创建一个ssh客户端的client对象
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #允许连接未在known_hosts中列出的的主机
ssh.connect(hostname=hostname,username=username,password=password) #创建ssh连接
#执行sudo时加上-S(--stdin)选项,执行sudo时会交互式提示输入密码,通过-S标准输入
stdin,stdout,stderr = ssh.exec_command('sudo -S ip a')
#通过标准输入提供用户密码,\n表示换行
stdin.write('abc123\n')
#刷新标准输入的内部缓冲区,将其中内容立即提供给标准输入
stdin.flush()
res,err = stdout.read(),stderr.read() #获取命令的返回结果
result = res if res else err #如果没有返回stdout则报错输出stderr
print(result.decode('utf-8'))
ssh.close() #关闭ssh连接
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通