关于使用python批量操作网络设备(交换机,路由器)的知识点小结

关于使用python批量操作网络设备,这里本人目前只接触了两个模块,netmiko和pratmiko,后面的脚本也都将基于这两个模块。

一、netmiko模块

1、使用netmiko模块连接操作设备


import netmiko          #导入netmiko模块
import time             #导入time模块


#使用with语句打开用于ssh连接所需要的相关信息(用户名,密码,ip地址,需要配置的命令),这个打开了两个文件用户信息文件,命令文件,分别命名为devices_file,cmd_file
with open("ip_user_pass.txt", "r") as devices_file, open("cmdlist.txt", "r") as cmd_file:
    #将用户信息文件按行读取赋值给devices
    devices = devices_file.readlines()
    #将命令文件按行读取赋值给cmdlist
    cmdlist = cmd_file.readlines()
    #使用循环将用户名,密码,IP地址,分别赋值给username,password,ip_address变量,并依次登陆
    for line in devices:
        line = line.strip("\n")
        ip_address = line.split(",")[0]   #split() 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则分隔 num+1 个子字符串
        username = line.split(",")[1]
        password = line.split(",")[2]
        

        #创建一个名为SW2的字典,该字典包含“device_type”“ip”“username”和“password”4个必选的键,如果设备类型是netmiko不支持的类型,不清楚还能不能连接
        SW2 = {
            'device_type': 'huawei',
            'ip': ip_address,
            'username': username,
            'password': password,
            }


        connect = netmiko.ConnectHandler(**SW2)     #函数ConnectHandler()。该函数用来实现SSH登录网络设备,是Netmiko最重要的函数。
        print("Successfully connect to" + SW2['ip'])
        #config_commands = ['dis arp']
        #output = connect.send_config_set(config_commands)
        #rint(output)


        #使用循环将cmdlist中的命令依次输入
        for cmd in cmdlist:
            output2 = connect.send_config_set(cmd)    #send_config_set()则可向设备一次输入多个命令
            print(output2)
            time.sleep(1)
        print("*" * 50 + "分割线" + "*" * 50)


        #result = connect.send_command('dis int LoopBack 0')
        #print(result)

脚本运行结果如下:

2、ssh_netmiko_多线程

使用netmiko实现多线程操作网络设备

#coding=utf-8
import threading        #Python 3已经内置了threading模块来实现多线程,这里引入
from queue import Queue   #多线程中需要用的队列,这里引入,多线程中需要用的队列,这里引入,通过队列传递数据,安全,不会造成多个线程访问时混乱
import netmiko
import time


#定义连接函数,使用netmiko连接设备,并输入预定义命令
def ssh_session(ip, username, password,cmdlist, output_q):
    SW2 = {
        'device_type': 'huawei',
        'ip': ip_address,
        'username': username,
        'password': password,
        }


    connect = netmiko.ConnectHandler(**SW2)
    print("Successfully connect to" + SW2['ip'])
    '''
    config_commands = ['dis arp', 'dis ip routing-table', 'dis int brief']
    output = connect.send_config_set(config_commands)
    print(output)
    print("*" * 50 + "分割线" + "*" * 50)
    '''

    for cmd in cmdlist:
        output = connect.send_config_set(cmd)
        print(output)
        time.sleep(1)
        print("*" * 50 + "分割线" + "*" * 50)

    #result = connect.send_command('dis int LoopBack 0')
    #print(result)



print("程序于 {} 开始执行\n".format(time.strftime("%X")))
threads = []
with open("ip_user_pass.txt", "r") as devices_file, open("cmdlist.txt", "r") as cmd_file:
    devices = devices_file.readlines()
    cmdlist = cmd_file.readlines()
    for line in devices:
        line = line.strip("\n")
        ip_address = line.split(",")[0]   #split() 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则分隔 num+1 个子字符串
        username = line.split(",")[1]
        password = line.split(",")[2]
        #使用threading的Thread()函数为ssh_session函数创建一个线程并将它赋值给变量t,注意Thread()函数的target参数对应的是函数名称(即ssh_session)
        #args对应的是该ssh_session函数的参数
        t = threading.Thread(target=ssh_session, args=(ip_address, username, password, cmdlist, Queue()))
        t.start()
        threads.append(t)

    
for i in threads:
    i.join()    #threading的join()方法的作用是强制阻塞调用它的线程,直到该线程运行完毕或者终止(类似单线程同步)

print("程序于 {} 执行结束\n".format(time.strftime("%X")))

脚本缺少错误控制加入try语句,可以更好的应用脚本,不会因为地址和用户名密码错误导致脚本中断,另外关于脚本里的使用了队列实现线程控制,但是为什么要写成这个形式

t = threading.Thread(target=ssh_session, args=(ip_address, username, password, cmdlist, Queue())),目前我还不太了解。希望知道原理的大大能告诉我一下~

二、prarmiko模块

1、使用prarmiko模块连接网络设备操作(连接协议ssh)

'''
需在命令行运行程序,并给四个文件参数,存放ip的文件在前,存放命令的文件在后,例如:python lab3_1.py ip.txt cmdlist.txt username.txt password.txt
'''


import paramiko
import time
import getpass
import sys
import socket


#username = input("username:")
#password = getpass.getpass("password:")
ip_file = sys.argv[1]       #sys.argv[]就是一个从程序外部获取参数的桥梁,外部取得的参数可以是多个,所以获得的是一个列表(list),其第一个元素是程序本身,随后才依次是外部给予的参数,                  
cmd_file = sys.argv[2]      #这里使用sys.argv(),即将保存的ip和命令的文件作为参数赋值给变量
user_file = sys.argv[3]
pass_file = sys.argv[4]


switch_with_authentication_issue = []   #认证失败的列表,用于存放用户认证失败的IP地址
switch_not_reachable = []               #连接失败的列表,用于存放连接失败的ip地址


#打开文件用户信息文件,IP地址文件
iplist = open(ip_file, "r")
userlist = open(user_file, "r")
passlist = open(pass_file, "r")


#使用循环按行读取,文件内容,这个用zip() 函数将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象
#例如:    192.168.1.1    admin    123
for line1, line2, line3  in zip(iplist.readlines(), userlist.readlines(), passlist.readlines()):
    try:
        ip = line1.strip()
        username = line2.strip()
        password = line3.strip()
        ssh_client = paramiko.SSHClient()   #调用paramiko的SSHClient方法连接网络设备,及本地设备为客户端
        '''
        默认情况下,Paramiko会拒绝任何未知的SSH公钥(publickey),这里我们需要使用ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        来让Paramiko接受SSH服务端(也就是SW3)提供的公钥,这是任何时候使用Paramiko都要用到的标准配置。
        '''
        ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())    
        ssh_client.connect(hostname=ip, username=username, password=password)   #调用connect()方法,输入连接设备所需的ip,用户名,密码
        print("登录成功", ip)
        command = ssh_client.invoke_shell() #调用Paramiko.SSHClient()的invoke_shell()方法来唤醒shell
        cmdlist = open(cmd_file, "r")   #读入命令文件
        cmdlist.seek(0)      #seek() 方法用于移动文件读取指针到指定位置,参数为0代表从文件开头开始算起。
        for line in cmdlist.readlines():
            command.send(line + "\n")
        time.sleep(5)
        cmdlist.close()
        output = command.recv(65535)
        print(output.decode("ascii"))
    except paramiko.ssh_exception.AuthenticationException:
        print("用户认证失败:" + ip)
        switch_with_authentication_issue.append(ip)
    except socket.error:
        print(ip + "连接失败")
        switch_not_reachable.append(ip)


iplist.close()
userlist.close()
passlist.close()
ssh_client.close


print("*" * 50 + "分割线" + "*" * 50)
print("\n用户认证失败的交换机:\n")
for i in switch_with_authentication_issue:
    print(i)

print("\n网络连接失败交换机:\n")
for i in switch_not_reachable:
    print(i)

三、配置文件备份

1、使用netmiko备份,用于备份netmiko支持的设备,使用h3c设备测试此脚本,备份失败

import netmiko
import time


with open("devices.txt") as devices_file:
    devices = devices_file.readlines()
    for line in devices:
        line = line.strip("\n")
        ipaddr = line.split(",")[0]   #split() 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则分隔 num+1 个子字符串
        username = line.split(",")[1]
        password = line.split(",")[2]
        vendor = line.split(",")[3]


SW2 = {
    'device_type': vendor,
    'ip': ipaddr,
    'username': username,
    'password': password,
    }



now = time.strftime("%Y-%m-%d", time.localtime())

connect = netmiko.ConnectHandler(**SW2)
print("Successfully connect to" + SW2['ip'])
backup_cfg = connect.send_command("dis cur")    #将命令内容赋值给变量
print(backup_cfg)
#将变量的值写入文件,文件命名按时间划分
with open( "C:\\ftp\\交换机_"  + str(now) + "_{}.txt".format(ipaddr), "w") as f:
    f.write(backup_cfg)

H3C备份失败原因:netmiko模块在huawei的连接中有取消分屏显示功能的命令,而H3C设备没有,华为设备的取消分屏显示功能可以针对用户设置,而且是临时。举个例子:一个user用户登录华为设备后执行取消分屏显示命令后对设备中其他用户没影响(其他用户还是分屏显示),当user用户退出ssh的时候该用户的分屏显示功能会自动恢复,就像定义了:进入自己家目录的环境一样方便强大。而H3C网络设备的分屏显示针对的是全局设备,而且并不是进入、退出环境那样临时性生效一样。那么如何解决这种坑呢,经过多次网上查找和多次测试,终于完美实现一次性显示完整的输出大量信息。(转载于https://blog.51cto.com/chier11/2398299?source=dra)

import netmiko
import time


with open("devices.txt") as devices_file:
    devices = devices_file.readlines()
    for line in devices:
        line = line.strip("\n")
        ipaddr = line.split(",")[0]   #split() 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则分隔 num+1 个子字符串
        username = line.split(",")[1]
        password = line.split(",")[2]
        vendor = line.split(",")[3]


SW2 = {
    'device_type': vendor,
    'ip': ipaddr,
    'username': username,
    'password': password,
    }

now = time.strftime("%Y-%m-%d", time.localtime())

connect = netmiko.ConnectHandler(**SW2)
print("Successfully connect to" + SW2['ip'])
backup_cfg = connect.send_command("dis cur")    #将命令内容赋值给变量
if "---- More ----" in backup_cfg:
	backup_cfg += connect.send_command_timing('            \n', strip_prompt=False, strip_command=False, normalize=False)
            #遇到more,就多输入几次个空格,normalize=False表示不取消命令前后空格。
output = backup_cfg.split("\n")
print (output)
#将变量的值写入文件,文件命名按时间划分
with open( "C:\\交换机_"  + str(now) + "_{}.txt".format(ipaddr), "w") as f:
    f.write(backup_cfg)

2、使用prarmiko,基于tftp备份配置文件

首先要搭建一个tftp服务器,使用tftp相关软件即可

其次运行脚本

import paramiko
import time


with open("ip_user_pass.txt") as devices_file:
    devices = devices_file.readlines()
    for line in devices:
        line = line.strip("\n")
        ip_address = line.split(",")[0]   #split() 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则分隔 num+1 个子字符串
        username = line.split(",")[1]
        password = line.split(",")[2]
        now = time.strftime("%Y-%m-%d", time.localtime())
        ssh_client = paramiko.SSHClient()
        ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh_client.connect(hostname=ip_address, username=username, password=password)
        print("登陆成功:",ip_address)
        command = ssh_client.invoke_shell()
        command.send("copy startup.cfg {}_{}.cfg\n".format(now,ip_address))
        command.send("y\n")
        command.send("tftp 192.168.134.222 put {}_{}.cfg\n".format(now,ip_address))
        time.sleep(15)
        command.send("delete  {}_{}.cfg\n".format(now,ip_address))
        command.send("y\n")
        time.sleep(5)
        output = command.recv(65535)
        print(output.decode("ascii"))
    ssh_client.close
 

3、使用prarmiko,基于sftp备份配置文件
首先配置网络设备(H3C)为sftp服务器端

from os import chmod
import paramiko
import time
import socket


switch_with_authentication_issue = []   #认证失败的列表,用于存放用户认证失败的IP地址
switch_not_reachable = []               #连接失败的列表,用于存放连接失败的ip地址
with open("ip_user_pass.txt") as devices_file:
    devices = devices_file.readlines()
    for line in devices:
        try:
            line = line.strip("\n")
            ip_address = line.split(",")[0]   #split() 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则分隔 num+1 个子字符串
            username = line.split(",")[1]
            password = line.split(",")[2]
            ssh_client = paramiko.SSHClient()
            ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            ssh_client.connect(hostname=ip_address, username=username, password=password)
            print("登陆成功:",ip_address)
            command = ssh_client.invoke_shell()
            command.send("sftp server enable\n")
            command.send("local-user client002\n")
            command.send("password simple aabbcc\n")
            command.send("service-type ssh\n")
            command.send("quit\n")
            command.send("ssh user client002 service-type sftp authentication-type password\n")
            command.send("save")
            command.send("y\n")
            time.sleep(5)
            output = command.recv(65535)
            print(output.decode("ascii"))
        except paramiko.ssh_exception.AuthenticationException:
            print("用户认证失败:" + ip_address)
            switch_with_authentication_issue.append(ip_address)
        except socket.error:
            print("连接失败:" + ip_address)
            switch_not_reachable.append(ip_address)
    ssh_client.close

print("*" * 50 + "分割线" + "*" * 50)
print("\n用户认证失败的交换机:\n")
for i in switch_with_authentication_issue:
    print(i)

print("\n网络连接失败交换机:\n")
for i in switch_not_reachable:
    print(i)



其次使用paramiko,连接sftp服务器下载配置文件

import paramiko


def sftp_get(ip, user, pwd, local_file,remote_file, port=22):
    try:
        t = paramiko.Transport(ip, port)
        t.connect(username=user, password=pwd)
        sftp = paramiko.SFTPClient.from_transport(t)
        sftp.get(remote_file, local_file)
        t.close()

    except Exception as e:
        print(e)


def sftp_put(ip, user, pwd, local_file, remote_file, port=22):
    try:
        t = paramiko.Transport(ip, port)
        t.connect(username=user, password=pwd)
        sftp = paramiko.SFTPClient.from_transport(t)
        sftp.put(local_file, remote_file)
        t.close()

    except Exception as e:
        print(e)

if __name__ == '__main__':
    '''
    不要运行的,请注释掉,前面加'#'符号
    '''
    ip = '192.168.0.101'
    user= 'admin'
    pwd= 'Admin@123'
    local_file = r"D:\test\123.txt"
    remote_file = "flash:/vrpcfg.zip"
    sftp_get(ip='192.168.0.200', user=user, pwd=pwd, remote_file=remote_file, local_file=r'D:\test\vrpcfg.zip')
    # sftp_put(ip='192.168.0.200', user=user, pwd=pwd, local_file=local_file, remote_file='flash:/123.txt')
  • 3
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值