https://www.jianshu.com/p/944674f44b24

paramiko 是 Python 中的一个用来连接远程主机的第三方工具,通过使用 paramiko 可以用来代替以 ssh 连接到远程主机执行命令。

paramiko 模块提供了两个核心组件,分别是 SSHClient 和 SFTPClient。前者用于在远程主机上执行命令,是对于 ssh 会话的封装;后者用于对资源上传下载等操作,是对 sftp 的封装。

paramiko 模块提供了一些SSH核心组件

  • Channel: 建立 ssh 连接后,paramiko会调用底层的 channel 类来打开一个socket连接,后续发送的命令会通过 channel 进行发送,当接收到命令的返回结果(标准输出或标准错误)后,结果又将通过 channel 发送到连接的客户端。
  • Client: 建立的 ssh 会话的客户端。通过客户端可以去连接多个远程主机,并将执行的命令通过 client.exec_command() 方法发送到远程主机。
  • Message: 一个用来将传输过程中的字符、整形、布尔及长类型的字符组合进行编码组成的字节流信息。
  • PacketizerImplementation of the base SSH packet protocol.
  • Transport: 封装了一个加密的会话,调用该会话时会创建一个流式隧道(通常称为 channel)

封装的具体逻辑,为了保持功能的纯粹性,仅通过 paramiko 实现客户端的的建立及命令的发送。

以下为实现逻辑

#!/usr/bin/env python3
# coding=utf-8 import sys
import socket
import paramiko
from paramiko.ssh_exception import NoValidConnectionsError, AuthenticationException class Connect(object): def __init__(self, username: str,
password: str,
port: int = 22,
hostname: str,
pkey: str = None,
look_for_keys: bool = True,
allow_agent: bool = True,
timeout: float = None
):
self.hostname = hostname
self.username = suername
self.port = port
self.password = password
self.pkey = pkey
self.allow_agent = allow_agent
self.look_for_keys = look_for_keys
self.timeout = timeout def _connect(self):
self.client = SSHClient()
self.client.load_system_host_keys()
self.client.set_missing_host_key_policy(paramiko.AutoAddpolicy())
try:
self.client.connect(hostname=self.hostname,
port=self.port,
username=self.username,
password=self.password,
pkey=self.pkey,
allow_agent=self.allow_agent,
look_for_keys=self.look_for_keys
)
except BadHostKeyException as badKey:
msg = "Receive a bad key"
sys.exit()
except AuthenticationException as auth:
msg = "Invalid username or password"
sys.exit()
except SSHExpection as ssh:
msg = "Establish ssh session error"
sys.exit()
exception scoket.error as sock:
msg = "Connecting has a socket error"
sys.exit() def run(self, command: str):
stdin, stdout, stderr = self.client.exec_command(command, timeout=self.timeout)
stdin.close()
stdout.flush() try:
output = stdout.read()
err_msg = stderr.read() output = output.decode("utf-8") if isinstance(output, bytes) else output
err_msg = err_msg.decode("utf-8") if isinstance(err_msg, bytes) else err_msg
return output, err_msg except socket.timeout:
raise(f"Exec Command {command} timeout") def close(self):
self.client.close()

将ssh会话保存到会话池中

#!/usr/bin/env python3
# encoding=utf-8 import os
import socket
import paramiko
from collections import deque
from paramiko.ssh_exception import SSHException
from paramiko.ssh_exception import NoValidConnectionsError, AuthenticationException
from eventlet import pools class SSHPool(pools.Pool): """创建 SSH 对象池 """
_pool = deque() def __init__(self,
ip: str,
username: str,
password: str = None,
port: int = 22,
privatekey: str = None,
timeout: float = None,
**kwargs
):
self.ip = ip
self.port = port
self.password = password
self.username = username
self.privatekey = privatekey
self.timeout = timeout
super(SSHPool, self).__init__(**kwargs) def create(self):
try:
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) if self.password:
client.connect(self.ip,
port=self.port,
username=self.username,
password=self.password,
timeout=self.timeout
)
elif self.privatekey:
if isinstance(self.privatekey, paramiko.rsakey.RSAKey):
key = self.privatekey
else:
keyfile = os.path.expanduser(self.privatekey)
key = paramiko.RSAKey.from_private_key_file(keyfile)
client.connect(self.ip,
port=self.port,
username=self.username,
look_for_keys=True,
pkey=key,
timeout=self.timeout
)
else:
raise SSHException("Invalid username or password") # Paramiko by default sets the socket timeout to 0.1 seconds,
# ignoring what we set through the sshclient. This doesn't help for
# keeping long lived connections. Hence we have to bypass it, by
# overriding it after the transport is initialized. We are setting
# the sockettimeout to None and setting a keepalive packet so that,
# the server will keep the connection open. All that does is send
# a keepalive packet every ssh_conn_timeout seconds. if self.timeout:
transport = client.get_transport()
transport.sock.settimeout(None)
transport.set_keepalive(self.timeout)
return client except socket.timeout:
raise SSHException("Connect timeout")
except NoValidConnectionsError as novalid:
raise SSHException("Connect valid failed")
except AuthenticationException as auth:
raise SSHException("Invalid username or password")
except Exception as e:
raise SSHException("An exception happened") def get(self):
"""从会话池中获取 SSH 会话
1. 返回一个存活的会话
2. 不存在的会话或已经失效的会话, 会新建一个会话并返回该会话
"""
conn = super(SSHPool, self).get()
print("get: [%s]" % conn)
if conn:
if conn.get_transport().is_active():
return conn
else:
conn.close()
return self.create() #def put(self, ssh):
# """将 SSH 会话添加到会话池中"""
# conn = super(SSHPool, self).get()
# if ssh not in self._pool:
# self._pool.append(ssh) def remove(self, ssh):
"""关闭 SSH 会话,并将其从会话池中移除"""
ssh.close()
ssh = None
print("remove: [%s]" % ','.join(self.free_items))
if ssh in self.free_items:
self.free_items.pop(ssh)
if self.current_size > 0:
self.current -= 1 if __name__ == "__main__":
client = SSHPool(username='root', password='****!', ip='****')
with client.get() as conn:
_, stdout, stderr = conn.exec_command("ls -l")
print(stdout.read().decode()) # 参考自: https://opendev.org/openstack/cinder/commit/75ef446fef63320e9c1ed4a04e59ffbbb62b5cef?style=unified

【转帖】基于paramiko的二次封装的更多相关文章

  1. Python实现Paramiko的二次封装

    Paramiko是一个用于执行SSH命令的Python第三方库,使用该库可实现自动化运维的所有任务,如下是一些常用代码的封装方式,多数代码为半成品,只是敲代码时的备份副本防止丢失,仅供参考,目前本人巡 ...

  2. iOS基于MBProgressHUD的二次封装,一行搞定,使用超简单

    MBProgressHUD的使用,临时总结了几款最常用的使用场景: 1.提示消息 用法: [YJProgressHUD showMessage:@"显示文字,1s隐藏" inVie ...

  3. 基于element-ui进行二次封装的表格组件

    <!-- * @description 表格组件 * @fileName TableList.vue * @authorQ * @date 2021/05/15 15:13:45 --> ...

  4. Selenium二次封装-Java版本

    package com.yanfuchang.selenium.utils; import java.awt.AWTException; import java.awt.Robot; import j ...

  5. 基于Dapper二次封装了一个易用的ORM工具类:SqlDapperUtil

    基于Dapper二次封装了一个易用的ORM工具类:SqlDapperUtil,把日常能用到的各种CRUD都进行了简化封装,让普通程序员只需关注业务即可,因为非常简单,故直接贴源代码,大家若需使用可以直 ...

  6. python+selenium十:基于原生selenium的二次封装

    from selenium import webdriverfrom selenium.webdriver.support.wait import WebDriverWaitfrom selenium ...

  7. 使用Vue CLI 3将基于element-ui二次封装的组件发布到npm

    前言:之前在网上找的好多都是基于vue-cli 2.x的,而使用vue-cli 3的文章比较少,Vue CLI 3 中文文档,所以我在自己尝试的时候把几篇文章结合了一下,调出来了我想要的模式,也就是V ...

  8. android基于开源网络框架asychhttpclient,二次封装为通用网络请求组件

    网络请求是全部App都不可缺少的功能,假设每次开发都重写一次网络请求或者将曾经的代码拷贝到新的App中,不是非常合理,出于此目的,我希望将整个网络请求框架独立出来,与业务逻辑分隔开,这样就能够避免每次 ...

  9. 基于bootstrap table配置的二次封装

    准备 jQuery js css 引用完毕 开始 如果对bootstrap table 的方法与事件不熟悉: Bootstrap table方法,Bootstrap table事件 <table ...

  10. Vue.js 自定义组件封装实录——基于现有控件的二次封装(以计时器为例)

    在本人着手开发一个考试系统的过程中,出现了如下一个需求:制作一个倒计时的控件显示在试卷页面上.本文所记录的就是这样的一个过程. 前期工作 对于这个需求,自然我想到的是有没有现成的组件可以直接使用(本着 ...

随机推荐

  1. Blog Statistics Dec 1, 2021 - Dec 1, 2022

    1. Overview Data Date: Dec 1, 2021 - Dec 1, 2022 Number of articles: 51 All Platform Total Visits: 3 ...

  2. 华为云GaussDB两大数据库通过中国信通院多项评测

    摘要:权威认可!华为云GaussDB两大数据库通过中国信通院多项评测. 本文分享自华为云社区<官宣!华为云GaussDB两大数据库通过中国信通院多项评测>,作者: GaussDB 数据库 ...

  3. 使用 Python Poetry 进行依赖管理

    摘要:在本教程中,您探索了如何创建新的 Python Poetry 项目以及如何将 Poetry 添加到现有项目中. 本文分享自华为云社区<使用 Python Poetry 进行依赖管理> ...

  4. PPT 小图标 设计感Max 精修

    https://www.bilibili.com/video/BV1ha411g7f5?p=14 图标用处 信息可视化,快速获取信息 增加内容图示化细节,增强设计感 SVG/PNG 图标使用 SVG ...

  5. Kubernetes(K8S) 配置管理 Secret 介绍

    Secret 作用:加密数据(base64)存在 etcd 里面,让 Pod 容器以挂载 Volume 方式进行访问 场景:凭证 [root@k8smaster ~]# echo -n 'admin' ...

  6. byte[] 数组,创建的时候赋初始值

    C# //创建一个长度为10的byte数组,并且其中每个byte的值为0x08. byte[] myByteArray = Enumerable.Repeat((byte)0x08, 10).ToAr ...

  7. Nacos 服务状态监听四种写发

    监听服务的四种实现方式,以监听 Nacos 服务为例 1. 传统方式 public void subscribe() { try { NamingService namingService = Nam ...

  8. 转载--阿里云ECS自建K8S集群

    一.概述(官方建议) 集群规划 目前在创建Kubernetes集群时,存在着使用很多小规格ECS的现象,这样做有以下弊端: 小规格Woker ECS的网络资源受限. 如果一个容器基本可以占用一个小规格 ...

  9. AtCoder Beginner Contest 167 (A~F,DEF Good)

    比赛链接:https://atcoder.jp/contests/abc167/tasks AB水题, C - Skill Up 题意: 初始时 \(m\) 个算法的能力均为 \(0\),\(n\) ...

  10. Codeforces Round #481 (Div. 3) 经典几道思维题

    A - AAA POJ - 3321 给你一颗树,支持两种操作 1.修改某一节点的权值 2.查询子树的权值(子树中节点的个数) 很显然可以用树状数组/线段树维护 B - BBB CodeForces ...