【转帖】基于paramiko的二次封装
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: 一个用来将传输过程中的字符、整形、布尔及长类型的字符组合进行编码组成的字节流信息。Packetizer:Implementation 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的二次封装的更多相关文章
- Python实现Paramiko的二次封装
Paramiko是一个用于执行SSH命令的Python第三方库,使用该库可实现自动化运维的所有任务,如下是一些常用代码的封装方式,多数代码为半成品,只是敲代码时的备份副本防止丢失,仅供参考,目前本人巡 ...
- iOS基于MBProgressHUD的二次封装,一行搞定,使用超简单
MBProgressHUD的使用,临时总结了几款最常用的使用场景: 1.提示消息 用法: [YJProgressHUD showMessage:@"显示文字,1s隐藏" inVie ...
- 基于element-ui进行二次封装的表格组件
<!-- * @description 表格组件 * @fileName TableList.vue * @authorQ * @date 2021/05/15 15:13:45 --> ...
- Selenium二次封装-Java版本
package com.yanfuchang.selenium.utils; import java.awt.AWTException; import java.awt.Robot; import j ...
- 基于Dapper二次封装了一个易用的ORM工具类:SqlDapperUtil
基于Dapper二次封装了一个易用的ORM工具类:SqlDapperUtil,把日常能用到的各种CRUD都进行了简化封装,让普通程序员只需关注业务即可,因为非常简单,故直接贴源代码,大家若需使用可以直 ...
- python+selenium十:基于原生selenium的二次封装
from selenium import webdriverfrom selenium.webdriver.support.wait import WebDriverWaitfrom selenium ...
- 使用Vue CLI 3将基于element-ui二次封装的组件发布到npm
前言:之前在网上找的好多都是基于vue-cli 2.x的,而使用vue-cli 3的文章比较少,Vue CLI 3 中文文档,所以我在自己尝试的时候把几篇文章结合了一下,调出来了我想要的模式,也就是V ...
- android基于开源网络框架asychhttpclient,二次封装为通用网络请求组件
网络请求是全部App都不可缺少的功能,假设每次开发都重写一次网络请求或者将曾经的代码拷贝到新的App中,不是非常合理,出于此目的,我希望将整个网络请求框架独立出来,与业务逻辑分隔开,这样就能够避免每次 ...
- 基于bootstrap table配置的二次封装
准备 jQuery js css 引用完毕 开始 如果对bootstrap table 的方法与事件不熟悉: Bootstrap table方法,Bootstrap table事件 <table ...
- Vue.js 自定义组件封装实录——基于现有控件的二次封装(以计时器为例)
在本人着手开发一个考试系统的过程中,出现了如下一个需求:制作一个倒计时的控件显示在试卷页面上.本文所记录的就是这样的一个过程. 前期工作 对于这个需求,自然我想到的是有没有现成的组件可以直接使用(本着 ...
随机推荐
- linux中redis下载安装部署启动
下载安装部署 创建一个存放Redis的文件夹,下载安装包 mkdir redis 进入redis文件 cd redis 下载redis安装包 wget http://download.redis.io ...
- linux中mysql下载安装部署
创建mysql文件 mkdir mysql 首先通过yum下载wget命令 yum -y install wget 在mysql文件中通过wget下载MySQL存储库 wget https://dev ...
- linux_文本处理工具详细介绍
文本处理工具 1. grep工具 grep是行过滤工具:用于根据关键字进行行过滤 语法和选项 语法: # grep [选项] '关键字' 文件名 常见选项: OPTIONS: -i: 不区分大小写 - ...
- 如何使用GaussDB(DWS)的本地临时表进行数据处理
本文分享自华为云社区<GaussDB(DWS)临时表系列 - 本地临时表>,作者: acydy . GaussDB(DWS) 从8.2.1版本后支持三种形式的临时表:本地临时表.Volat ...
- 华为云MVP程云:知识化转型,最终要赋能一线
摘要:如今的智能语音助手,可以帮助我们完成日常生活中的一些常规动作.同样,在企业中,智能问答机器人也在扮演着同样的角色. 本文分享自华为云社区<[亿码当先,云聚金陵]华为云MVP程云:知识化转型 ...
- PNG文件解读(1):PNG/APNG格式的前世今生
PNG格式的前世今生 png是一种无损压缩的位图片形格式,其设计目的是试图替代GIF和TIFF文件格式,同时增加一些GIF文件格式所不具备的特性.PNG使用从LZ77派生的无损数据压缩算法--LZW专 ...
- 总结MySQL 的一些知识点:MySQL 插入数据
MySQL 插入数据 MySQL 表中使用INSERT INTOSQL语句来插入数据. 你可以通过 mysql> 命令提示窗口中向数据表中插入数据,或者通过PHP脚本来插入数据. 语法 以下为向 ...
- 火山引擎 DataTester:在广告投放场景下的 A/B 实验实践
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 "我知道在广告上的投资有一半是无用的,但问题是我不知道是哪一半." --零售大亨约翰·沃纳梅克 ...
- Solon 开发进阶
Solon 开发进阶 一.插件扩展机制 二.体外扩展机制 三.常用配置说明 四.启动参数说明 五.全局异常订阅 本系列在内核知识的基础上做进一步延申.主要涉及: 插件扩展体系 体外扩展体系 常用配置 ...
- kubernetes实战(三十一):Prometheus监控Windows主机
1. 基本说明 使用Prometheus监控Windows主机和Linux主机并无太大区别,都是使用社区的Exporter进行采集数据,之后暴露一个接口,可以让Prometheus采集到主机的数据. ...