• python3 远程Linux服务器执行命令和上传下载文件


    一、简介

      paramiko是一个基于SSH用于连接远程服务器并执行相关操作(SSHClient和SFTPClinet,即一个是远程连接,一个是上传下载服务),使用该模块可以对远程服务器进行命令或文件操作,值得一说的是,fabric和ansible内部的远程管理就是使用的paramiko来现实。

    二、使用

    1、下载

    pip3 install paramiko

    2、模块使用

    SSHClient:

      远程连接分为两种:(1)基于用户名密码连接 (2)基于公钥秘钥连接

      通过是用paramiko远程操作,其实本质也分为两种:(1)只用SSHClient (2)自己创建一个transport

    (1)基于用户名和密码的连接

    import paramiko
    
    # 创建SSH对象
    ssh = paramiko.SSHClient()
    # 允许连接不在know_hosts文件中的主机
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    # 连接服务器
    ssh.connect(hostname='c1.salt.com', port=22, username='GSuser', password='123')
    # 执行命令
    stdin, stdout, stderr = ssh.exec_command('ls')
    # 获取命令结果
    result = stdout.read()
    # 关闭连接
    ssh.close()

      SSHClient 封装 Transport

    import paramiko
    
    transport = paramiko.Transport(('hostname', 22))
    transport.connect(username='GSuser', password='123')
    
    ssh = paramiko.SSHClient()
    ssh._transport = transport
    
    stdin, stdout, stderr = ssh.exec_command('df')
    print(stdout.read())
    
    transport.close()

    (2)基于公钥秘钥连接

    import paramiko
    
    # 添加公钥密钥文件
    private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')
    # 创建SSH对象
    ssh = paramiko.SSHClient()
    # 允许连接不在know_hosts文件中的主机
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    # 连接服务器
    ssh.connect(hostname='192.168.1.105', port=22, username='666', key=private_key)
    # 执行命令
    # 执行多条命令时需要将各个命令用‘;’隔开,最后将get_pty设为True;如果是单条命令的则只传入命令即可
    stdin, stdout, stderr = ssh.exec_command('cd dw/2020-06-02/;ls',get_pty=True)
    # 多条命令的话会将执行结果一起返回,所以建议遍历打印。也可以直接打印:print(stdout.read().decode('utf-8'))
    files = stdout.readlines()
    for i in files:
        # 打印执行反馈结果
        print(i.encode().decode('utf-8').split()[0])
    # 打印报错信息
    print(stderr.read().decode('utf-8'))
    # 关闭连接
    ssh.close()

      SSHClient 封装Transport

    import paramiko
    
    private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')
    transport = paramiko.Transport(('192.168.1.105', 22))
    transport.connect(username='666', pkey=private_key)
    ssh = paramiko.SSHClient()
    ssh._transport = transport
    # 执行多条命令时需要将各个命令用‘;’隔开,最后将get_pty设为True;如果是单条命令的则只传入命令即可
    stdin, stdout, stderr = ssh.exec_command('cd dw/2020-06-02/;ls',get_pty=True)
    # 多条命令的话会将执行结果一起返回,所以建议遍历打印。也可以直接打印:print(stdout.read().decode('utf-8'))
    files = stdout.readlines()
    for i in files:
        # 打印执行反馈结果
        print(i.encode().decode('utf-8').split()[0])
    # 打印报错信息
    print(stderr.read().decode('utf-8'))
    transport.close()

    SFTPClient:

      用于连接远程服务器并进行上传下载功能。

    (1)基于用户名密码上传下载

    import paramiko
    
    transport = paramiko.Transport(('192.168.1.105',22))
    transport.connect(username='666',password='123')
    
    sftp = paramiko.SFTPClient.from_transport(transport)
    # 将location.py 上传至服务器 /tmp/test.py
    sftp.put('/tmp/location.py', '/tmp/test.py')
    # 将remove_path 下载到本地 local_path
    sftp.get('remove_path', 'local_path')
    
    transport.close()

    (2)基于公钥秘钥上传下载

    import paramiko
    
    private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')
    
    transport = paramiko.Transport(('192.168.1.105', 22))
    transport.connect(username='666', pkey=private_key )
    
    sftp = paramiko.SFTPClient.from_transport(transport)
    # 将location.py 上传至服务器 /tmp/test.py
    sftp.put('/tmp/location.py', '/tmp/test.py')
    # 将remove_path 下载到本地 local_path
    sftp.get('remove_path', 'local_path')
    
    transport.close()

    Demo: 实现远程命令执行和文件上传

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import paramiko
    
    class SSHConnection(object):
    
        def __init__(self, host='192.168.12.68', port=22, username='locojoy',pwd='123321QQ!'):
            self.host = host
            self.port = port
            self.username = username
            self.pwd = pwd
            self.__k = None
    
        def run(self):
            self.connect()  # 连接远程服务器
            self.upload('db.py','/tmp/1.py')  # 将本地的db.py文件上传到远端服务器的/tmp/目录下并改名为1.py
            self.cmd('df')  # 执行df 命令
            self.close()    # 关闭连接
    
        def connect(self):
            transport = paramiko.Transport((self.host, self.port))
            transport.connect(username=self.username, password=self.pwd)
            self.__transport = transport
    
        def close(self):
            self.__transport.close()
    
        def upload(self,local_path,target_path):
            sftp = paramiko.SFTPClient.from_transport(self.__transport)
            sftp.put(local_path,target_path)
    
        def cmd(self, command):
            ssh = paramiko.SSHClient()
            ssh._transport = self.__transport
            # 执行命令
            stdin, stdout, stderr = ssh.exec_command(command)
            # 获取命令结果
            result = stdout.read()
            print(result)
            return result
    
    obj = SSHConnection()
    obj.run()

    paramiko在堡垒机中的应用

    (1)简单实例:远程连接一台主机,操作命令,linux版本,输入终端为回车则发送命令。不支持tab补全功能。

    import paramiko, sys, os, socket, select, getpass
    from paramiko.py3compat import u   # 在python3中是这样使用的,如果在Python2中则注释这行
    
    # 这个程序依赖于终端,只能在Liunx下运行,windows用其他的方式
    
    tran = paramiko.Transport(('192.168.12.68', 22,))
    tran.start_client()
    tran.auth_password('locojoy', '123321QQ!')
    
    # 打开一个通道
    chan = tran.open_session()
    # 获取一个终端
    chan.get_pty()
    # 激活器
    chan.invoke_shell()
    
    # 原始的方法利用终端进行收发消息
    # 利用sys.stdin,肆意妄为执行操作
    # 用户在终端输入内容,并将内容发送至远程服务器
    # 远程服务器执行命令,并将结果返回
    # 用户终端显示内容
    
    while True:
        # 监视用户输入和服务器返回数据
        # sys.stdin 处理用户输入
        # chan 是之前创建的通道,用于接收服务器返回信息
        # 通过select监听终端(输入输出),一旦变化,就将拿到的数据发送给服务器
        # 通过监听socket句柄,如果有变化表示服务器要给我发消息
        readable, writeable, error = select.select([chan, sys.stdin, ],[],[],1)
        # 通过select.select 监听chan(打开的通道(和远程服务器连接的状态)), sys.stdin(输入),一旦变化就写入readable
        # 当chan变化时,加入到readable,远程服务器发送内容过来
        if chan in readable:
            try:
                x = u(chan.recv(1024))  # Python3用这个
                # x = chan.recv(1024)  Python2使用这个
                if len(x) == 0:
                    print('
    *** EOF
    ')
                    break
                sys.stdout.write(x)   # 写入缓冲区
                sys.stdout.flush()    # 刷新,将缓冲区内容显示出来
            except socket.timeout:
                pass
        # 当sys.stdin 放入readable中时,将获取到的内容发送到远程服务器
        if sys.stdin in readable:
            inp = sys.stdin.readline()
            chan.sendall(inp)
    
    chan.close()
    tran.close()

    (2)每按一个键就发送记录,并支持tab自动补全

    import paramiko, sys, os, socket, select, getpass, termios, tty
    from paramiko.py3compat import u
    
    tran = paramiko.Transport(('10.211.55.4', 22,))
    tran.start_client()
    tran.auth_password('wupeiqi', '123')
    # 打开一个通道
    chan = tran.open_session()
    # 获取一个终端
    chan.get_pty()
    # 激活器
    chan.invoke_shell()
    
    # 获取原tty属性
    oldtty = termios.tcgetattr(sys.stdin)
    try:
        # 为tty设置新属性
        # 默认当前tty设备属性:
        #   输入一行回车,执行
        #   CTRL+C 进程退出,遇到特殊字符,特殊处理。
        # 这是为原始模式,不认识所有特殊符号
        # 放置特殊字符应用在当前终端,如此设置,将所有的用户输入均发送到远程服务器
        tty.setraw(sys.stdin.fileno())  # 恢复终端原始状态,每按一个键就发送
        chan.settimeout(0.0)
    
        while True:
            # 监视 用户输入 和 远程服务器返回数据(socket)
            # 阻塞,直到句柄可读
            r, w, e = select.select([chan, sys.stdin], [], [], 1)
            if chan in r:  # 获取服务返回的内容
                try:
                    x = u(chan.recv(1024))
                    if len(x) == 0:
                        print('
    *** EOF
    ')
                        break
                    sys.stdout.write(x)
                    sys.stdout.flush()
                except socket.timeout:
                    pass
            if sys.stdin in r: # 发送命令
                x = sys.stdin.read(1) # 读取一个字符
                if len(x) == 0:
                    break
                chan.send(x) # 发送一个字符
    
    finally:
        # 重新设置终端属性,将终端状态还原
        termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
    
    chan.close()
    tran.close()
  • 相关阅读:
    静态方法中访问类的实例成员
    Java Interger类,两对整数明明完全一样,为何一个输出true,一个输出false
    使用类的静态字段和构造函数,跟踪某个类所创建对象的个数
    Java基础笔记3
    Java 统计单词频数
    重拾javaweb(假期后第一次web测试)
    人月神话读后感(三)
    人月神话读后感(二)
    人月神话读后感(一)
    七天开发安卓软件(七)
  • 原文地址:https://www.cnblogs.com/xshan/p/13037604.html
Copyright © 2020-2023  润新知