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保持连接的对象

常用方法:

  1. 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) 类型):一个文件名或文件名的列表,用于私钥的身份验证
timeoutfloat类型):一个可选TCP连接的超时时间
allow_agent(bool类型):设置False时用于禁用连接到ssh代理
look_for_keys(bool类型):设置False时用来禁用在~/.ssh中搜索私钥文件
compress(bool类型):设置True时打开压缩
  1. exec_command()方法
  • 远程命令的执行方法,该方法将以元组的形式返回远程命令的标准输入输出为stdin、stdout、stderr的文件对象
  • 该方法执行完毕后通道就被关闭,不能再使用。如要执行另一条命令,需打开一个新的通道
exec_command(self,command,bufsize=-1)

	- 参数说明:
command(str类型):执行命令字符串
get_pty(bool类型):设置是否从目标主机请求一个伪终端,默认值:False
environment(dict[str,str]类型):以字典数据类型定义环境变量,这些环境变量将被并入执行远程命令的默认环境变量中
bufsize(int类型):文件缓冲区大小,默认为-1(不限制)
  1. load_system_host_keys()方法
  • 加载本地公钥校验文件,默认~/.ssh/know_hosts,非默认需手工指定
load_system_host_keys(self,filename=None)

	- 参数说明:
filename(str类型):指定远程主机公钥校验文件路径,未指定默认找路径: ~/.ssh/known_hosts
  1. 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)
  1. 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连接
  1. 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连接
posted @   逃离这世界~  阅读(29)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示

目录导航