1.paramiko:
paramiko是一个基于SSH用于连接远程服务器并执行相关操作(SSHClient和SFTPClinet,即一个是远程连接,一个是上传下载服务),使用该模块可以对远程服务器进行命令或文件操作,值得一说的是,fabric和ansible内部的远程管理就是使用的paramiko来现实。
密码连接方式:
pip install paramiko
paramiko有两个模块SSHClient()和SFTPClient()
1.SSHClient()
方式一:
import paramiko, re, time
class Linux(object):
def __init__(self, info, port=22):
self.ip = info['ip']
self.user = info['user']
self.passw = info['passw']
self.port = port
def linuxConnect(self):
# 实例化一个transport对象
try:
# 创建SSH对象
self.ssh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的主机
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 建立ssh对象
self.ssh.connect(hostname=self.ip, port=22, username=self.user, password=self.passw)
# 执行命令
stdin, stdout, stderr = self.ssh.exec_command('ls')
if stdout.read() != '':
print('连接成功')
return self.ssh
else:
self.linuxConnect()
except:
print('连接失败')
return 'fail'
def linuxSend(self, info):
stdin, stdout, stderr = self.ssh.exec_command(info)
if re.search('docker exec', info):
return
result = stdout.read().decode()
return result
def linuxReceive(self, info):
stdin, stdout, stderr = self.ssh.exec_command(info)
result = stdout.readlines()
return result
# 关闭连接
def linuxClose(self):
self.ssh.close()
if __name__ == '__main__':
linux = Linux({"ip": "10.20.70.11", "user": "root", "passw": "1"})
linux.linuxConnect()
rev = linux.linuxReceive('LANG=en_US.UTF-8;sar -u 1 1')
print(rev[-1])
print(float(re.findall('(S+)', rev[-1])[2]))
v_CPU = 100 - float(re.findall('(S+)', rev[-1])[-1])
print(v_CPU)
方式二:
import paramiko, re, time
class Linux(object):
def __init__(self, info):
self.ip = info['ip']
self.user = info['user']
self.passw = info['passw']
def linuxConnect(self):
# 实例化一个transport对象
try:
self.transport = paramiko.Transport((self.ip, 22))
# 建立连接
self.transport.connect(username=self.user, password=self.passw)
# 建立ssh对象
self.ssh = paramiko.SSHClient()
# 绑定transport到ssh对象
self.ssh._transport = self.transport
stdin, stdout, stderr = self.ssh.exec_command('ls')
if stdout.read() != '':
print('连接成功')
return self.ssh
else:
self.linuxConnect()
except:
print('连接失败')
return 'fail'
def linuxSend(self, info):
stdin, stdout, stderr = self.ssh.exec_command(info)
if re.search('docker exec', info):
return
result = stdout.read().decode()
return result
def linuxReceive(self, info):
stdin, stdout, stderr = self.ssh.exec_command(info)
result = stdout.readlines()
return result
def upload(self, local_path, target_path):
# 连接,上传
# file_name = self.create_file()
sftp = paramiko.SFTPClient.from_transport(self.transport)
# 将location.py 上传至服务器 /tmp/test.py
sftp.put(local_path, target_path)
def download(self, remote_path, local_path):
sftp = paramiko.SFTPClient.from_transport(self.transport)
sftp.get(remote_path, local_path)
# 关闭连接
def linuxClose(self):
self.transport.close()
linux = Linux({"ip": "10.20.70.11", "user": "root", "passw": "1"})
linux.linuxConnect()
rev = linux.linuxReceive('LANG=en_US.UTF-8;sar -u 1 1')
print(rev)
v_CPU = 100 - float(re.findall('(S+)', rev[-1])[-1])
print(v_CPU)
SFTPClient()也是使用transport来实现的,因此如果有需求需要执行命令和上传文件糅合在一起的话,那么就需要使用transport的方式来实现。
秘钥连接方式:
方式一:
import paramiko, re, time
class Linux(object):
def __init__(self, info):
self.ip = info['ip']
self.pub_key_file = info["id_rsa"]
self.user = info["user"]
def linuxConnect(self):
# 实例化一个transport对象
try:
private_key = paramiko.RSAKey.from_private_key_file(self.pub_key_file)
self.ssh = paramiko.SSHClient()
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.ssh.connect(hostname=self.ip, port=22, username=self.user, pkey=private_key)
# 绑定transport到ssh对象
stdin, stdout, stderr = self.ssh.exec_command('ls')
if stdout.read() != '':
print('连接成功')
return self.ssh
else:
self.linuxConnect()
except:
print('连接失败')
return 'fail'
def linuxSend(self, info):
stdin, stdout, stderr = self.ssh.exec_command(info)
if re.search('docker exec', info):
return
result = stdout.read().decode()
return result
def linuxReceive(self, info):
stdin, stdout, stderr = self.ssh.exec_command(info)
result = stdout.readlines()
return result
# 关闭连接
def linuxClose(self):
self.ssh.close()
linux = Linux({"ip": "10.20.70.11", "user": "root", "id_rsa": r"C:Usersyzt.sshid_rsa"})
linux.linuxConnect()
rev = linux.linuxReceive('LANG=en_US.UTF-8;sar -u 1 1')
print(rev)
v_CPU = 100 - float(re.findall('(S+)', rev[-1])[-1])
print(v_CPU)
方式二:
import paramiko, re, time
class Linux(object):
def __init__(self, info):
self.ip = info['ip']
self.pub_key_file = info["id_rsa"]
self.user = info["user"]
def linuxConnect(self):
# 实例化一个transport对象
try:
private_key = paramiko.RSAKey.from_private_key_file(self.pub_key_file)
self.transport = paramiko.Transport((self.ip, 22))
self.transport.connect(username=self.user, pkey=private_key)
self.ssh = paramiko.SSHClient()
# self.ssh._transport = self.transport
stdin, stdout, stderr = self.ssh.exec_command('ls')
if stdout.read() != '':
print('连接成功')
return self.ssh
else:
self.linuxConnect()
except:
print('连接失败')
return 'fail'
def linuxSend(self, info):
stdin, stdout, stderr = self.ssh.exec_command(info)
if re.search('docker exec', info):
return
result = stdout.read().decode()
return result
def linuxReceive(self, info):
stdin, stdout, stderr = self.ssh.exec_command(info)
result = stdout.readlines()
return result
def upload(self, local_path, target_path):
# 连接,上传
# file_name = self.create_file()
sftp = paramiko.SFTPClient.from_transport(self.transport)
# 将location.py 上传至服务器 /tmp/test.py
sftp.put(local_path, target_path)
def download(self, remote_path, local_path):
sftp = paramiko.SFTPClient.from_transport(self.transport)
sftp.get(remote_path, local_path)
# 关闭连接
def linuxClose(self):
self.transport.close()
linux = Linux({"ip": "10.20.70.11", "user": "root", "id_rsa": r"C:Usersyzt.sshid_rsa"})
linux.linuxConnect()
# rev = linux.linuxReceive('LANG=en_US.UTF-8;sar -u 1 1')
# print(rev)
# v_CPU = 100 - float(re.findall('(S+)', rev[-1])[-1])
# print(v_CPU)
linux.upload(r"C:UsersyztDesktopworkInfosecTestPlatform
equirements.txt", "/tmp/requirements.txt")
2.关于paramiko上传文件速率问题:
这是paramiko我们操作定义好的类,我直接拿过来了
import paramiko, re, os, time
from PublicMethod.config import BASE_PATH
from InfosecTestPlatform.settings import BASE_DIR
class Linux(object):
def __init__(self, ip,user='XXX',passw='XXXXX'):
self.ip = ip
self.user = user
self.passw = passw
self.num = 6
def SSHConnect(self):
try:
self.transport = paramiko.Transport((self.ip, 22))
# 建立连接
self.transport.connect(username=self.user, password=self.passw)
# 建立ssh对象
self.ssh = paramiko.SSHClient()
# 绑定transport到ssh对象
self.ssh._transport = self.transport
stdin, stdout, stderr = self.ssh.exec_command('ls')
if stdout.read() != '':
print('连接成功')
return self.ssh
else:
if self.num > 0:
self.num -= 1
time.sleep(2)
self.SSHConnect()
except:
print('连接失败')
return False
# SFTP 连接 上传下载文件
def SFTPConnect(self):
try:
# 实例化transport对象,并建立连接
self.transport = paramiko.Transport((self.ip, 22))
self.transport.connect(username=self.user, password=self.passw)
# 实例化sftp对象,指定连接对象
self.sftp = paramiko.SFTPClient.from_transport(self.transport)
return True
except:
if self.num > 0:
print('SFTP第 %s 次连接失败'% (4-self.num))
self.num -= 1
time.sleep(2)
self.SFTPConnect()
else:
return False
# 发送指令
def LinuxSend(self, info):
stdin, stdout, stderr = self.ssh.exec_command(info)
result = stdout.read().decode()
return result
# 发送指令 按行返回信息
def LinuxReceive(self, info):
stdin, stdout, stderr = self.ssh.exec_command(info)
result = stdout.readlines()
return result
# 上传文件
def LinuxPut(self, path, info):
name = path.split('/')[-1]
docker_path = os.path.join(info, name)
self.sftp.put(localpath=path, remotepath=docker_path)
# 下载文件 linux中 只能从/tmp 下载
def LinuxGet(self, remotepath,local):
local_path = os.path.join(BASE_PATH, local)
remote_path='/tmp/%s'%remotepath
self.sftp.get(remotepath=remote_path, localpath=local_path)
# 关闭连接
def LinuxClose(self):
self.transport.close()
3.参数文件源码分析:
# SFTP 连接 上传下载文件
def SFTPConnect(self):
try:
# 实例化transport对象,并建立连接
self.transport = paramiko.Transport((self.ip, 22))
self.transport.connect(username=self.user, password=self.passw)
# 实例化sftp对象,指定连接对象
self.sftp = paramiko.SFTPClient.from_transport(self.transport)
return True
except:
if self.num > 0:
print('SFTP第 %s 次连接失败'% (4-self.num))
self.num -= 1
time.sleep(2)
self.SFTPConnect()
else:
return False
1.首先传输文件需要用这个方式去给self.sftp 赋值,但是你首先得创建一个通道self.transport,这个就是读取文件的船.
Transport:源码
def __init__(
self,
sock,
default_window_size=DEFAULT_WINDOW_SIZE, # 默认的window读取文件size
default_max_packet_size=DEFAULT_MAX_PACKET_SIZE, # 这个是传输的包的大小
gss_kex=False,
gss_deleg_creds=True,
disabled_algorithms=None,
)
由于self.sftp = paramiko.SFTPClient.from_transport(self.transport)将self.transport这个对象放进去了,我们直接去看传输文件时put方法
2.put方法源码
def put(self, localpath, remotepath, callback=None, confirm=True):
file_size = os.stat(localpath).st_size
with open(localpath, "rb") as fl:
return self.putfo(fl, remotepath, file_size, callback, confirm)
3.putfo方法源码
def putfo(self, fl, remotepath, file_size=0, callback=None, confirm=True):
with self.file(remotepath, "wb") as fr:
fr.set_pipelined(True)
size = self._transfer_with_callback(
reader=fl, writer=fr, file_size=file_size, callback=callback
)
if confirm:
s = self.stat(remotepath)
if s.st_size != size:
raise IOError(
"size mismatch in put! {} != {}".format(s.st_size, size)
)
else:
s = SFTPAttributes()
return s
4.继续看_transfer_with_callback
这个方法才是真正获取数据的地方,注释部分是原来的代码,我加了上面的四行if判断部分代码,最大可以改为2M,我从网上看的博客说的.但是我发现改了之后效果并不是多好
def _transfer_with_callback(self, reader, writer, file_size, callback):
size = 0
while True:
if file_size > 10485760:
read_size = 1048576
else:
read_size = 32768
# data = reader.read(32768)
data = reader.read(read_size)
writer.write(data)
size += len(data)
if len(data) == 0:
break
if callback is not None:
callback(size, file_size)
return size
5.默认参数,说实话下面的默认参数不知道啥意思
DEFAULT_WINDOW_SIZE = 64 * 2 ** 15 2M
DEFAULT_MAX_PACKET_SIZE = 2 ** 15 32K
# lower bound on the max packet size we'll accept from the remote host
# Minimum packet size is 32768 bytes according to
# http://www.ietf.org/rfc/rfc4254.txt
MIN_WINDOW_SIZE = 2 ** 15
# However, according to http://www.ietf.org/rfc/rfc4253.txt it is perfectly
# legal to accept a size much smaller, as OpenSSH client does as size 16384.
MIN_PACKET_SIZE = 2 ** 12
# Max windows size according to http://www.ietf.org/rfc/rfc4254.txt
MAX_WINDOW_SIZE = 2 ** 32 - 1
参考:https://www.cnblogs.com/shengulong/p/9018968.html
6.第四步调了每次读取字节的大小,下面在改一个地方吧,在self.transport赋值的时候加上后面两个参数可能有用,反正我的没报错.
def SFTPConnect(self):
try:
# 实例化transport对象,并建立连接
self.transport = paramiko.Transport((self.ip, 22), 2 * 1024 * 1024, 1024 * 1024)
self.transport.connect(username=self.user, password=self.passw)
# 实例化sftp对象,指定连接对象
self.sftp = paramiko.SFTPClient.from_transport(self.transport)
return True
except:
if self.num > 0:
print('SFTP第 %s 次连接失败'% (4-self.num))
self.num -= 1
time.sleep(2)
self.SFTPConnect()
else:
return False