• 45.paramiko python操控远程主机


    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
    
  • 相关阅读:
    MATLAB 模板匹配
    ACDSee15 教你如何轻松在图片上画圈圈、画箭头、写注释
    Qt 显示一个窗体,show()函数和exec()函数有什么区别?
    Qt 将窗体变为顶层窗体(activateWindow(); 和 raise() )
    Qt QSS样式化 菜单Qmenu&QAction
    Qt 获取文件夹中的文件夹名字
    Qt 删除文件夹或者文件
    欧洲终于承认“工业4.0”失败,互联网经济严重落后中美
    深入浅出数据结构
    浅谈城市大脑与智慧城市发展趋势
  • 原文地址:https://www.cnblogs.com/liuzhanghao/p/12974559.html
Copyright © 2020-2023  润新知