zoukankan      html  css  js  c++  java
  • 4.python 系统批量运维管理器之paramiko模块

    paramiko

    paramiko是ssh服务最经常使用的模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接。

    paramiko实现ssh2不外乎两个角度:SSH客户端与服务端

    • SSHClient:包装了Channel,Transport,SFTPClient。
    • Channel:是一种Socket类,一种安全的SSH传输通道。
    • Transport:是一种加密的会话(但是这样一个对象的Session并未建立),并且创建了一个加密的tunnels,这个tunnels叫做Channel。
    • Session:是Client与Server保持连接的对象,用Connect(),start_client(),start_server()开始会话。

    具体请参考paramiko的库文档:http://docs.paramiko.org/en/2.0/index.html

    使用pip install paramiko安装,失败的话,建议使用yum安装:yum install python-paramiko

    代码实例:

    paramiko远程密码连接:

    import paramiko  

    #实例化SSHClient

    client = paramiko.SSHClient()

    #创建ssh连接日志文件(只保留前一次连接的详细日志,以前的日志会自动被覆盖)
    paramiko.util.log_to_file('paramiko.log')

    #自动添加策略,保存服务器的主机名和密钥信息,如果不添加,不在know_hosts文件中记录的主机将无法连接

    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    #连接SSH服务端,以用户名和密码进行认证

    client.connect(hostname='127.0.0.1', port=22, username='root', password='123456')

    #打开一个Channel并执行命令

    stdin,stdout,stderr = client.exec_command(command)

    #打印执行结果

    result=stdout.read().decode('utf-8')
    print(result)

    #关闭SSHClient连接
    client.close()

    SSHClient()里面有一个transport变量,这个是用于获取连接的,因此我们也可以单独获取到transport变量,然后执行连接操作:

    import paramiko

    #创建一个通道 transport
    = paramiko.Transport(('127.0.0.1', 22))

    #用户名密码连接服务器 transport.connect(username
    ='root', password='123456')

    #实例化SSHClient ssh
    = paramiko.SSHClient()
    ssh._transport
    = transport stdin, stdout, stderr = ssh.exec_command(command) print(stdout.read().decode('utf-8'))

    #关闭连接 transport.close()

    paramiko使用密钥连接

    import paramiko
    
    # 配置私人密钥文件位置
    private = paramiko.RSAKey.from_private_key_file('/Users/zjz/.ssh/id_rsa')
    #实例化SSHClient client
    = paramiko.SSHClient()
    #自动添加策略,保存服务器的主机名和密钥信息,如果不添加,那么不再本地know_hosts文件中记录的主机将无法连接 client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    #连接SSH服务端,以用户名和密码进行认证 client.connect(hostname
    ='127.0.0.1',port=22,username='root',pkey=private)
    # 打开一个Channel并执行命令 stdin, stdout, stderr
    = client.exec_command(command) # stdout 为正确输出,stderr为错误输出,同时是有1个变量有值
    # 打印执行结果 print(stdout.read().decode(
    'utf-8'))
    # 关闭SSHClient client.close()

    使用transport封装使用密钥连接:

    import paramiko
    
    # 配置私人密钥文件位置
    private = paramiko.RSAKey.from_private_key_file('/Users/zjz/.ssh/id_rsa')
    # 创建一个通道 transport
    = paramiko.Transport(('127.0.0.1', 22)) transport.connect(username='root', pkey=private_key)
    #实例化SSHClient client
    = paramiko.SSHClient() client._transport = transport
    # 打开一个Channel并执行命令 stdin, stdout, stderr
    = client.exec_command('df -h ') # stdout 为正确输出,stderr为错误输出,同时是有1个变量有值
    # 打印执行结果 print(stdout.read().decode(
    'utf-8'))
    # 关闭SSHClient transport.close()

    SFTPClient实现上传文件

    import paramiko
    
    # 获取Transport实例 tran
    = paramiko.Transport(('127.0.0.1', 22))
    # 连接SSH服务端,使用password tran.connect(username
    ="root", password='123456')
    # 或使用 # 配置私人密钥文件位置
    private = paramiko.RSAKey.from_private_key_file('/Users/zjz/.ssh/id_rsa')
    # 连接SSH服务端,使用pkey指定私钥 tran.connect(username
    ="root", pkey=private)
    # 获取SFTP实例 sftp
    = paramiko.SFTPClient.from_transport(tran)
    # 设置上传的本地
    /远程文件路径 localpath = "/Users/1.txt" remotepath = "/tmp/1.txt"
    # 执行上传动作 sftp.put(localpath, remotepath)
    #如果远程主机有这个文件则返回一个对象,负责抛出异常
    try:
    sftp.file(remotepath)
    print("上传成功")
    except IOError:
    print("上传失败")
    finally:
    # 关闭连接 tran.close()

    SFTPClinet实现下载文件

    import paramiko
    import os
    # 获取Transport实例 tran
    = paramiko.Transport(('127.0.0.1', 22))
    # 连接SSH服务端,使用password tran.connect(username
    ="root", password='123456')
    # 或使用 # 配置私人密钥文件位置
    private = paramiko.RSAKey.from_private_key_file('/Users/zjz/.ssh/id_rsa')
    # 连接SSH服务端,使用pkey指定私钥 tran.connect(username
    ="root", pkey=private)
    # 获取SFTP实例 sftp
    = paramiko.SFTPClient.from_transport(tran)
    # 设置下载的本地
    /远程文件路径 localpath = "/Users/1.txt" remotepath = "/tmp/1.txt"
    #判断远程服务器是否有这个文件
    try: sftp.file(remotepath)
    #执行下载动作 sftp.
    get(remotepath, localpath) except IOError as e:
    print(remotepath+"remote file no exit!")
    exit()
    finally:
    #关闭连接
    sftp.close()
    if os.path.isfile(localpath):
    print("下载成功")
    else:
    print("下载失败")

    SSHClient也可以实现交互式终端

    核心代码:

    # 打开一个通道 
    channel = trans.open_session() 
    
    # 获取终端 channel.get_pty()
    # 激活终端,这样就可以登录到终端了,就和我们用类似于xshell登录系统一样 channel.invoke_shell()

    重要的是select模块的使用,select会监听socket或者文件描述符的I/O状态变化,并返回变化的socket或者文件描述符的对象

    r_list,w_list,x_list = select.select(rlist, wlist, xlist, timeout])

    参数详解:

    • rlist:list类型,监听其中的socket或者文件描述符是否变为可读状态,返回那些可读的socket或者文件描述符组成的list
    • wlist:list类型,监听其中的socket或者文件描述符是否变为可写状态,返回那些可写的socket或者文件描述符组成的list
    • xlist:list类型,监听其中的socket或者文件描述符是否出错,返回那些出错的socket或者文件描述符组成的list
    • timeout:设置select的超时时间,设置为None代表永远不会超时,即阻塞。

    详细模块用法见:https://blog.csdn.net/weixin_43367828/article/details/84640103

    xshell功能实现

    import paramiko 
    import os
    import select
    import sys

    # 建立一个socket

    trans = paramiko.Transport(('127.0.0.1', 22))

    # 启动一个客户端

    trans.start_client()

    # 如果使用rsa密钥登录的话
    ''' default_key_file = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa') prikey = paramiko.RSAKey.from_private_key_file(default_key_file) trans.auth_publickey(username='super', key=prikey) '''

    # 如果使用用户名和密码登录
    trans.auth_password(username=
    'root', password='123456')

    # 打开一个通道
    channel = trans.open_session()

    # 获取终端
    channel.get_pty()

    # 激活终端,这样就可以登录到终端了,就和我们用类似于xshell登录系统一样
    channel.invoke_shell()

    # 下面就可以执行你所有的操作,用select实现
    # 对输入终端sys.stdin和 通道进行监控,
    # 当用户在终端输入命令后,将命令交给channel通道,这个时候sys.stdin就发生变化,select就可以感知
    # channel的发送命令、获取结果过程其实就是一个socket的发送和接受信息的过程

    while True:
    readlist, writelist, errlist = select.select([channel, sys.stdin,], [], [])
    # 如果是用户输入命令了,sys.stdin发生变化
    if sys.stdin in readlist:
    # 获取输入的内容
    input_cmd = sys.stdin.read(1)
    # 将命令发送给服务器
    channel.sendall(input_cmd)
    # 服务器返回了结果,channel通道接受到结果,发生变化 select感知到
    if channel in readlist:
    # 获取结果
    result = channel.recv(1024)
    # 断开连接后退出
    if len(result) == 0:
    print(" **** EOF **** ")
    break
    # 输出到屏幕
    sys.stdout.write(result.decode())
    sys.stdout.flush()
    # 关闭通道
    channel.close()
    # 关闭链接
    trans.close()

    SSHClient实现堡垒机模式下的命令执行

             堡垒机在一定程度上提升了运营安全级别,但同时也提高了日常运营成本,作为管理的中转设备,任何针对业务服务器的管理请求都会经过此节点,比如SSH协议,首先运维人员在办公电脑通过SSH协议登陆堡垒机,再通过堡垒机SSH跳转到所有的业务服务器进行维护操作。

             可以利用paramiko的invoke_shell机制实现通过堡垒机实现服务器操作,原理是SSHClient.connect到堡垒机后开启一个新的SSH会话(session),通过新的会话运行 "sshuser@IP" 去实现远程命令执行。

    SFTPClient实现堡垒机模式下的远程文件上传

            实现堡垒机模式下的文件上传,原理是通过paramiko的SFTPClient将文件从办公设备上传至堡垒机指定的临时目录,如 /tmp。再通过SSHClient的invoke_shell方法开启ssh会话,执行scp命令,将 /tmp下的指定文件复制到目标业务服务器上。

    具体代码实现请参考:http://www.cnblogs.com/charliedaifu/p/10098848.html

    sftp是安全文件传输协议,提供一种安全的加密方法,sftp是SSH的一部分,SFTPClient类实现了sftp客户端,通过已建立的SSH通道传输文件,与其他的操作,如下:

    方法描述
    sftp.getcwd() 返回当前工作目录
    sftp.chdir(path) 改变工作目录
    sftp.chmod(path, mode) 修改权限
    sftp.chown(path, uid, gid) 设置属主属组
    sftp.close() 关闭sftp
    sftp.file(filename, mode=’r’, bufsize=-1) 读取文件
    sftp.from_transport(s) 创建SFTP客户端通道
    sftp.listdir(path=’.’) 列出目录,返回一个列表
    sftp.listdir_attr(path=’.’) 列出目录,返回一个SFTPAttributes列表
    sftp.mkdir(path, mode=511) 创建目录
    sftp.normalize(path) 返回规范化path
    sftp.open(filename, mode=’r’, bufsize=-1) 在远程服务器打开文件
    sftp.put(localpath, remotepath, callback=None) localpath文件上传到远程服务器remotepath
    sftp.get(remotepath, localpath, callback=None) 从远程服务器remotepath拉文件到本地localpath
    sftp.readlink(path) 返回一个符号链接目标
    sftp.remove(path) 删除文件
    sftp.rename(oldpath, newpath) 重命名文件或目录
    sftp.rmdir(path) 删除目录
    sftp.stat(path) 返回远程服务器文件信息(返回一个对象的属性)
    sftp.truncate(path, size) 截取文件大小
    sftp.symlink(source, dest) 创建一个软链接(快捷方式)
    sftp.unlink(path) 删除软链接

    参考连接:

    https://blog.csdn.net/songfreeman/article/details/50920767

    https://blog.csdn.net/qq_29778641/article/details/82186438

    https://blog.csdn.net/forever_wen/article/details/82556154

  • 相关阅读:
    基于python的socket网络编程
    Python3报错:ModuleNotFoundError: No module named '_bz2'
    机器学习博客网站
    《Linux内核设计与实现》 读书笔记(4)--进程的调度
    k8s 简单入门
    docker 简单入门
    python3 教程
    .toml 文件简介
    编码规范
    python3 基本用法
  • 原文地址:https://www.cnblogs.com/bmjoker/p/10566175.html
Copyright © 2011-2022 走看看