Python ssh switches control | 交换机SSH管理脚本

目前管理的交换机数量庞大,一些常用功能的配置往往需要多次、逐一登录交换机手动操作。
为提高统一管理、配置的效率,采用Python写了这个小工具,实现了:

  • Python SSH操作,依赖于paramiko库
  • 开启、关闭交换机分页显示功能
  • 开启、关闭交换机特权模式
  • 读取交换机列表文件、命令列表文件,批量执行
  • 多线程并行的多台交换机同时配置
  • 多线程进程数量自定义设置

    paramiko库

    官网:http://www.paramiko.org/

    Paramiko is a Python (2.6+, 3.3+) implementation of the SSHv2 protocol [1], providing both client and server functionality. While it leverages a Python C extension for low level cryptography (PyCrypto), Paramiko itself is a pure Python interface around SSH networking concepts.

简单的SSH连接、执行命令过程:

1
2
3
4
5
6
client = SSHClient()
client.load_system_host_keys()
client.connect('ssh.example.com')
stdin, stdout, stderr = client.exec_command('ls -l')
print stdout.readlines()
client.close()

该脚本在Linux SSH后执行单挑命令操作时,顺利执行,但如果SSH交换机后执行多条命令时,将抛出异常。
这是由于exec_command()命令执行后,Channel会在Channel.settimeout.settimeout时间内关闭。
如果需要多次交互的执行命令、获取返回信息,应使用invoke_shell()函数,代码更改如下:

1
2
3
4
5
6
7
8
9
10
client = SSHClient()
client.load_system_host_keys()
client.connect('ssh.example.com')
ssh_shell = client.invoke_shell()
print ssh_shell.recv(1024)
for cmd in cmd_list:
res = ssh_client.sendall(cmd.strip() + '\n')
time.sleep(float(1))
print ssh_client.recv(1024)
client.close()

netlib库

官网:jtdub/netlib

netlib是pyRouterLib库的升级版,主要来实现对Cisco网络设备的SSH管理

基本满足了对网络设备管理的功能,但由于设备厂商差异,部分交换机指令(paging、enable等)存在差异。


因此在此基础上进一步封装,使得满足:1) 兼容国内主流网络设备(思科、华为、锐捷) 2) 实现自动no_paging, enable, save等管理功能 3) 读取配置文件,支持批量化执行配置命令
主要函数说明:

ssh_control.py
threading_ssh: 多线程入口,ssh执行命令的线程
main: 主函数入口

ssh_client.py
ssh_connect: ssh建立连接
ssh_exec_commands: 执行多条命令
ssh_enable: 进入特权模式
ssh_unpaging: 关闭交换机的分页显示功能
ssh_disable: 退出特权模式
ssh_paging: 开启交换机的分页显示功能
ssh_save: 保存交换机配置
ssh_disconnect: 关闭SSH连接

ssh_control.py源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import time
import threading
import ConfigParser
import ssh_client
from LogFile import Logger
from LogFile import log_file

""" Multi threading ssh function.
"""
def threading_ssh(sw_each, sw_type, cmd_list):
# config logging
logger = log_file(sw_each)

# print "Begin to ssh for switch: ", sw_each["sw_ip"], " in ", threading.current_thread()
msg = "Begin to ssh for switch: ", sw_each["sw_ip"], " in ", threading.current_thread()
logger.log(msg)

ssh = ssh_client.ssh_connect(sw_each, logger)
ssh_client.ssh_enable(ssh, sw_type, logger)
ssh_client.ssh_unpaging(ssh, sw_type, logger)
ssh_client.ssh_exec_commands(ssh, cmd_list, logger)
ssh_client.ssh_paging(ssh, sw_type, logger)
# ssh_client.ssh_disable(ssh, sw_each, sw_type) #no need to change to user mode
ssh_client.ssh_save(ssh, sw_type, logger)
ssh_client.ssh_disconnect(ssh, logger)
print "Success to exec commands for switch: ", sw_each["sw_ip"]
msg = "All comands have been executed for switch: ", sw_each["sw_ip"], " in ", threading.current_thread()
logger.log(msg)

def main():
# config running parameters.
conf = ConfigParser.ConfigParser()
sw_type = "huawei"
sw_list_file = "sw_list"
cmd_list_file = "cmd_list"
thread_count = 1
with open("config", "r") as f:
conf.readfp(f)
sw_type = conf.get("Config", "sw_type")
sw_list_file = conf.get("Config", "sw_list_file")
# print "sw_list_file:", sw_list_file
cmd_list_file = conf.get("Config", "cmd_list_file")
thread_count = conf.get("Config", "thread_count")

# sw_list stored all the switch data(ip,name,pwd)
sw_list = []
with open(sw_list_file, "r") as f:
for line in f:
sw_ip, sw_name, sw_pwd = line.strip().split("\t")
sw_data = {"sw_ip":sw_ip, "sw_name":sw_name, "sw_pwd":sw_pwd}
sw_list.append(sw_data)

# cmd_list store all the cmd which will be exec
cmd_list = []
with open(cmd_list_file, "r") as f:
cmd = f.readline().strip()
cmd_list.append(cmd)

threads = []
# print "sw_list: ", sw_list
for sw_each in sw_list:
t = threading.Thread(target=threading_ssh, args=(sw_each, sw_type, cmd_list))
t.setDaemon(True)
t.start()
threads.append(t)

for t in threads:
t.join()


if __name__ == "__main__":
main()

项目地址:fivezh/netlib

  • 考虑将这些功能规划、封装,打包形成一个开源库
  • 兼容国内各主流交换机厂商(思科、华为、锐捷等)