Python之paramiko模块
一、paramiko介绍
1、 用于帮助开发者通过代码远程连接服务器,并对服务器进行操作。
pip3 install paramiko
二、通过用户名密码方式远程执行命令
1、用户名密码
import paramiko
# 创建SSH对象
ssh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接服务器
ssh.connect(hostname='192.168.200.132', port=22, username='root', password='5740##', look_for_keys=False, allow_agent=False)
# 执行命令
stdin, stdout, stderr = ssh.exec_command('df -Th')
# 获取命令结果
result = stdout.read().decode().strip()
# 获取命令执行结果状态,0 表示命令成功执行;
exit_status = stdout.channel.recv_exit_status()
# 关闭连接
ssh.close()
补充:批量执行命令
import paramiko
import sys
def Ssh_exec_linux(ip, port, usernamme, password):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect(hostname=ip, port=port, username=usernamme, password=password)
except Exception as e:
print("服务器%s连接失败!" % ip)
print(e)
sys.exit(1)
stdin, stdout, stderr = ssh.exec_command('df -Th')
print("服务器%s的磁盘使用率如下:" % ip)
print(stdout.read().decode('utf-8')) # stdout.read()的结果是bytes,需要解码一下
ssh.close()
if __name__ == '__main__':
servers = {
'192.168.200.133': {
'port': '22',
'username': 'root',
'password': '5740##'
},
'192.168.200.134': {
'port': '22',
'username': 'root',
'password': '5740##'
},
'192.168.200.135': {
'port': '22',
'username': 'root',
'password': '5740##'
},
}
for ip, info in servers.items():
Ssh_exec_linux(ip,
info.get('port'),
info.get('username'),
info.get('password'))
三、通过用户名密码方式上传下载文件
1、上传下载文件
import paramiko
def sshFile():
try:
ssh_conn = paramiko.Transport(('192.168.200.133', 22))
ssh_conn.connect(username='root', password='5740##')
# 连接sftp客户端
ftp_client = ssh_conn.open_sftp_client()
# 下载
source_path = "/root/calico.yaml"
destination_path = "/Users/sanpangdan/Desktop/zjz_BBS/calico.yaml" # 指定完整的目标路径,包括文件名
ftp_client.get(source_path, destination_path)
# 上传
source_path = "/Users/sanpangdan/Desktop/zjz_BBS/Thumbs.db"
destination_path = "/root/Thumbs.db" # 指定完整的目标路径,包括文件名
ftp_client.put(source_path, destination_path)
except Exception as e:
print(f"发生错误:{str(e)}")
finally:
if 'ftp_client' in locals():
ftp_client.close()
if 'ssh_conn' in locals():
ssh_conn.close()
if __name__ == '__main__':
sshFile()
2、通过用户名批量上传文件
import paramiko
import os
def sshPutFile(ip, port, username, password, localfile, remotedir):
try:
# 创建SSH连接
ssh_conn = paramiko.Transport((ip, port))
ssh_conn.connect(username=username, password=password)
# 连接SFTP客户端
ftp_client = ssh_conn.open_sftp_client()
remotedir_file = os.path.join(remotedir, localfile)
# 上传本地文件到远程服务器
ftp_client.put(localfile, remotedir_file)
ssh_conn.close()
except Exception as e:
print(f"上传文件到 {ip} 时发生错误: {str(e)}")
if __name__ == '__main__':
servers = {
'192.168.200.133': {
'port': 22,
'username': 'root',
'password': '5740##',
'localfile': 'pi_put.py',
'remotedir': '/root/'
},
'192.168.200.134': {
'port': 22,
'username': 'root',
'password': '5740##',
'localfile': 'pi_put.py',
'remotedir': '/root/'
},
'192.168.200.135': {
'port': 22,
'username': 'root',
'password': '5740##',
'localfile': 'pi_put.py',
'remotedir': '/root/'
},
}
for ip, info in servers.items():
sshPutFile(
ip=ip,
port=info.get('port'),
username=info.get('username'),
password=info.get('password'),
localfile=info.get('localfile'),
remotedir=info.get('remotedir'))
四、通过公钥私钥远程执行命令
1、代码
import paramiko
private_key = paramiko.RSAKey.from_private_key_file('/root/.ssh/id_rsa')
# 创建SSH对象
ssh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接服务器
ssh.connect(hostname='192.168.200.132', port=22, username='root', pkey=private_key)
# 执行命令
stdin, stdout, stderr = ssh.exec_command('df -Th')
# 获取命令结果
result = stdout.read()
# 关闭连接
ssh.close()
print(result)
注:
在 Paramiko 中,pkey 选项用于指定用于身份验证的私钥。具体来说,这个选项允许你提供一个 paramiko.RSAKey 或 paramiko.DSSKey 对象,这些对象表示了你的私钥文件
如果你使用 RSA 密钥作为私钥,你可以按照以下方式设置 pkey 选项:
private_key = paramiko.RSAKey.from_private_key_file('/path/to/private/key')
如果你使用 DSA 密钥,可以这样设置:
private_key = paramiko.DSSKey.from_private_key_file('/path/to/private/key')
在连接服务器时,你可以将 private_key 对象传递给 pkey 参数,
五、通过公钥私钥远程上传下载文件
1、sftp.put
import paramiko
private_key = paramiko.RSAKey.from_private_key_file(r'/root/.ssh/id_rsa')
transport = paramiko.Transport(('192.168.200.132', 22))
transport.connect(username='root', pkey=private_key)
sftp = paramiko.SFTPClient.from_transport(transport)
# 将location.py 上传至服务器 /tmp/test.py
sftp.put('/data/123.py', '/root/123.py')
# 将remove_path 下载到本地 local_path
# sftp.get('123.py', '123.py')
transport.close()
六、通过私钥字符串远程连接服务器
# 也可以是存在于数据库中
key = """-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----"""
import paramiko
from io import StringIO
private_key = paramiko.RSAKey(file_obj=StringIO(key))
# 创建SSH对象
ssh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接服务器
ssh.connect(hostname='192.168.16.85', port=22, username='root', pkey=private_key)
# 执行命令
stdin, stdout, stderr = ssh.exec_command('df')
# 获取命令结果
result = stdout.read()
# 关闭连接
ssh.close()
print(result)
七、实际案例
1、代码
def query_mysql_error_log_count(host_ip):
"""通过ssh远程到主机,在MySQL容器中执行过滤mysql.err的Slave SQL错误日志,返回错误日志行数"""
datetime.datetime.strftime((datetime.datetime.now() + datetime.timedelta(-0)), '%Y-%m-%d')
date_list = [datetime.datetime.strftime((datetime.datetime.now() + datetime.timedelta(-i)),
'%Y-%m-%d') for i in range(2)]
date_list_str = r'\|'.join(date_list)
try:
with paramiko.SSHClient() as ssh:
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname=host_ip, port=port, username=username, password=password)
cmd_str = "docker ps --format='{{.Names}}' | egrep 'mysql.*([standby|slave|master])'"
_, stdout, stderr = ssh.exec_command(cmd_str)
out_lines, err_lines = stdout.readlines(), "".join(stderr.readlines())
if len(out_lines) < 1:
print('Can\'t find mysql container by name regrex mysql.*([standby|slave|master])')
return -1
container_name = out_lines[0].strip()
cmd_str = f"docker exec -i {container_name} tail -10000 /var/log/mysql/mysql.err" \
f" | grep -e '{date_list_str}' | egrep 'Slave SQL for.*Error_code:' | wc -l"
_, stdout, stderr = ssh.exec_command(cmd_str)
out_line, err_lines = stdout.readline(), "".join(stderr.readlines())
number_re = re.compile(r'[0-9]{1,}')
if number_re.match(out_line):
return int(out_line)
elif len(err_lines) > 1:
print(f'Can\'t get mysql err info, err:{err_lines}')
else:
print(f'Error output:{out_lines}')
except Exception as e:
print(f'SSH login host:{host_ip} error:{e}')
return -1
2、 使用 with 上下文管理器(如 with paramiko.SSHClient() as ssh:)的优点包括:
-
自动关闭连接:在执行完所有 SSH 命令后,即使发生异常,
SSHClient实例也会自动关闭。这防止了未关闭的连接堆积,这些未关闭的连接可能会导致端口耗尽或远程服务器上的资源泄露。 -
代码清晰性:使用
with语句使得代码更加清晰易读,因为读者不需要在代码中寻找SSHClient实例的关闭调用。 -
错误处理:如果在执行 SSH 命令时发生异常,上下文管理器会保证在退出
with块之前执行清理工作。这简化了错误处理,因为你只需要处理异常情况,而不需要担心资源的清理。

浙公网安备 33010602011771号