内容给接上篇:Python ssh、telnet协议连接网络设备或者服务器,输入命令返回的结果是多页内容,获取完整的结果方法
2、ssh协议访问远程设备的实现
ssh协议远程访问,用到的是jumpssh第三方包。登陆设备分了2类:
1、不经过跳板机直接登陆目标设备
2、通过跳板机(可能多层)再登陆目标设备
实现逻辑就是构造一个字典,字典key是屏幕上出现的目标字符串的正则表达式,当出现时就输入value。 所以可以匹配多页输出的–More–关键字符,匹配成功输入空格(如果是linux服务器可以直接输入数字,例如1000或者10000,将余下的所有行显示出来
def run_cmd(
self,
cmd,
username=None,
raise_if_error=True,
continuous_output=False,
silent=False,
timeout=None,
input_data=None,
success_exit_code=0,
retry=0,
retry_interval=5,
keep_retry_history=False
):
""" Run command on the remote host and return result locally
:param cmd: command to execute on remote host
cmd can be a str or a list of str
:param username: user used to execute the command (sudo privilege needed)
:param raise_if_error:
if True, raise SSHException when exit code of the command is different from 0
else just return exit code and command output
:param continuous_output: if True, print output all along the command is running
:param silent:
if True, does not log the command run (useful if sensitive information are used in command)
if parameter is a list, all strings of the command matching an item of the list will be concealed
in logs (regexp supported)
:param timeout: length in seconds after what a TimeoutError exception is raised
:param input_data:
key/value dictionary used when remote command expects input from user
when key is matching command output, value is sent
---远程命令需要用户输入时使用的键/值字典
当键与命令输出匹配时,发送值
:param success_exit_code: integer or list of integer considered as a success exit code for command run
:param retry: number of retry until exit code is part of successful exit code list (-1 for infinite retry) or
RunCmdError exception is raised
:param retry_interval: number of seconds between each retry
:param keep_retry_history: if True, all retries results are kept and accessible in return result
default is False as we don't want to save by default all output for all retries especially for big output
:raises TimeoutError: if command run longer than the specified timeout
:raises TypeError: if `cmd` parameter is neither a string neither a list of string
:raises SSHException: if current SSHSession is already closed
:raises RunCmdError: if exit code of the command is different from 0 and raise_if_error is True
:return: a class inheriting from collections.namedtuple containing mainly `exit_code` and `output`
of the remotely executed command
:rtype: RunCmdResult
Usage::
>>> from jumpssh import SSHSession
>>> with SSHSession('gateway.example.com', 'my_user', password='my_password') as ssh_session:
>>> ... ssh_session.run_cmd('hostname')
RunSSHCmdResult(exit_code=0, output=u'gateway.example.com')
"""
内部实现是:
if input_data and channel.send_ready():
# We received a potential prompt.
# 遍历input_data字典的所有key
for pattern in input_data.keys():
# pattern text matching current output => send input data
# re匹配成功就输入对应的value值
if re.search(pattern, data):
channel.send(input_data[pattern] + '\n')
实现的脚本代码:
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from jumpssh import SSHSession
import json,time
from concurrent.futures import ThreadPoolExecutor,as_completed
def ssh_inspection(jump=None,target=None,cmd_list=None):
"""
ssh协议单台设备执行指令函数
:param jump: 跳板服务器ip,port,username,password 字典
:param target: 目标服务器ip,port,username,password 字典
:param cmd_list: 命令列表
:return: 命令执行结果列表
"""
assert isinstance(jump,dict) and isinstance(target,dict)
hostname = target.get('hostname') or target.get('ip')
ip = target.get('ip')
result_content = [format('%s-%s-Results of '%(hostname,ip),'#^99s')+'\n'] # 返回结果列表
# 没有跳板机情况
if not jump:
if not all([target.get('ip'),target.get('port'),target.get('username'),target.get('password'),cmd_list]):
result_content.append('设备信息缺失,无法连接--Device information is missing, unable to connect.\n')
return result_content
else:
try:
switch_session = SSHSession(target.get('ip'), target.get('username'),
port=target.get('port'), password=target.get('password'),
auth_timeout=3,timeout=4).open() #timeout 设置tcp连接超时时间
except Exception as e:
result_content.append(str(e) +'\n')
return result_content
else:
command_list = cmd_list
for command in command_list:
try:
# 结果是多頁返回的情况,比如more打开文本文件,正则匹配输入里面有'More'字符串,就输入'1000\n'
# 表示往下跳过1000行。设置超时返回 timeout设置值
# result = switch_session.get_cmd_output(command,input_data={'More':'1000\n'},timeout=10)
result = switch_session.get_cmd_output(command,input_data={'More':'1000\n'},timeout=10)
except Exception as e:
result = e
result_content.append('-' * 88 + '\n' + format('命令-command:%s ' % command, ' ^88s') +
'\n' + format('结果-result:', ' ^88s') + '\n%s\n' %
result + '-' * 88 + '\n')
switch_session.close()
return result_content
# 通过跳板机跳转情况
else:
if not all([jump.get('ip'),jump.get('port'),jump.get('username'),jump.get('password'),
target.get('ip'),target.get('port'),target.get('username'),target.get('password'),cmd_list]):
result_content.append('缺失必传参数--Missing required parameters.\n')
try:
server_session = SSHSession(jump.get('ip'), jump.get('username'),
port=jump.get('port'), password=jump.get('password'),
timeout=4,auth_timeout=3).open()
switch_session = server_session.get_remote_session(target.get('ip'),
target.get('username'),
port=target.get('port'),
password=target.get('password'),
timeout=4,auth_timeout=3
)
except Exception as e:
result_content.append(str(e)+'\n')
return result_content
else:
command_list = cmd_list
for command in command_list:
try:
# result = switch_session.get_cmd_output(command)
result = switch_session.get_cmd_output(command, input_data={'More': '1000\n'}, timeout=10)
except Exception as e:
result = str(e)
result_content.append('-' * 88 + '\n' + format('命令-command:%s ' % command, ' ^88s') +
'\n' + format('结果-result:', ' ^88s') + '\n%s\n' %
result + '-' * 88 + '\n')
# print(result_content)
server_session.close()
finally:
# server_session.close() # TODO 2020年6月3日14:35:31
pass
return result_content
def batch_inspection(info_list):
"""
批量设备
:param info_list: 设备信息列表,元素是设备信息字典(包含设备信息,跳板信息,命令集信息)
:return: 所有任务执行结果
"""
assert isinstance(info_list,list) and info_list
executor = ThreadPoolExecutor()
all_task = [executor.submit(
ssh_inspection(jump=item.get('jump'),
target=item.get('target'),
cmd_list=item.get('cmd_list')))for item in info_list]
for future in as_completed(all_task,timeout=60):
result = future.result()
print(result)
yield result
if __name__ == '__main__':
jump = {
# 'ip': '10.12.12.12',
# 'port': 22,
# 'username': 'root',
# 'password': '123456'
}
target = {
'ip': '10.12.12.13',
'port': 22,
'username': 'root',
'password': '123456'
}
cmd_list = ['python -V','hostname','cd /tmp/ \n pwd \n ls \n ','df -h']
result = ssh_inspection(jump,target,cmd_list)
for i in result:
print(i)