Junos PyEZ utilitzant l'exemple de la tasca de cerca de subxarxes ipv4 gratuïtes

Un article sobre el treball amb Junos PyEZ - "Microframework Python que us permet gestionar i automatitzar dispositius que executen Junos OS", automatització i gestió, tot el que ens agrada. L'escriptura de l'script descrit en aquest article tenia diversos objectius: aprendre Python i automatitzar tasques per recopilar informació o canviar configuracions en equips amb el sistema operatiu Junos. L'elecció d'aquesta combinació específica de Python + Junos PyEZ es va fer a causa de la baixa barrera d'entrada al llenguatge de programació Python i la facilitat d'ús de la biblioteca Junos PyEZ, que no requereix coneixements experts del sistema operatiu Junos.

Tasca

Auditoria de les subxarxes ipv4 gratuïtes de l'empresa. El criteri que una subxarxa sigui gratuïta és l'absència d'una entrada sobre aquesta a les rutes de l'interruptor que actua com a encaminador que executa Junos OS.

Implementació

Python + Junos PyEZ, tot i que hi havia la temptació de fer-ho mitjançant paramiko i ssh.exec_command, Com a resultat, haureu de configurar el protocol de gestió de xarxa del dispositiu netconf a l'equip que s'està sondejant. Netconf treballa amb maquinari mitjançant una trucada de procediment remot RPC i utilitza XML, en aquest exemple, per proporcionar la informació que rep.

La instal·lació de la versió actual de Junos PyEZ des de PyPI es fa amb l'ordre següent:

$ pip install junos-eznc

També podeu instal·lar des de la branca principal del projecte a GitHub amb l'ordre següent:

$ pip install git+https://github.com/Juniper/py-junos-eznc.git

I una opció més via

$ pip install -r requirements.txt 

Aquesta ordre instal·larà les biblioteques que falten al sistema i que són necessàries per al funcionament. En la meva versió requisits.txt Només n'hi ha dos, les últimes versions s'indiquen en el moment d'escriure el guió:

junos-eznc
netaddr

De manera predeterminada, l'script pren el nom de l'usuari actual del sistema; podeu iniciar sessió amb el nom d'un altre usuari mitjançant la clau show_route.py -u getpass.getpass pren la contrasenya de stdin de manera que la contrasenya no romandrà al sistema. Per connectar-vos a l'equip, també haureu d'introduir el seu nom d'amfitrió o adreça IP quan se us demani. S'han rebut totes les dades necessàries per a l'autorització al dispositiu.

Junos PyEZ admet la connexió a equips que executen Junos OS mitjançant la consola, telnet o netconf mitjançant ssh. L'article parla d'aquesta darrera opció.

Per connectar-se a l'equip, utilitzeu la classe Device del mòdul jnpr.junos

with jnpr.junos.Device(host=router,
                           user=args.name,
                           passwd=password) as dev:

Es fa una sol·licitud per a totes les rutes conegudes per l'encaminador mitjançant una trucada de procediment remot o una trucada de procediment remot, la que sigui més convenient.

data = dev.rpc.get_route_information()

Comandament similar al sistema operatiu Junos

user@router> show route | display xml

Afegint rpc al final de l'ordre, obtenim una etiqueta de petició i la podem fer coincidir amb el nom del mètode RPC, d'aquesta manera podem trobar altres noms d'interès. Val la pena assenyalar que la sintaxi per escriure l'etiqueta de sol·licitud és diferent del nom del mètode, és a dir, hauríeu de substituir els guions per guions baixos.

user@router> show route | display xml rpc
<rpc-reply >route_list = data.xpath("//rt-destination/text()")

La resta de la part es va embolicar en un bucle while, per no repetir la sol·licitud a l'encaminador si calia registrar una altra subxarxa d'aquelles que l'encaminador ja coneixia. Val la pena esmentar que l'encaminador en el qual estic fent la sol·licitud només coneix rutes a través d'OSPF, de manera que per a un encaminador perifèric és millor canviar una mica la sol·licitud per reduir el temps d'execució de l'script.

data = dev.rpc.get_ospf_route_information()

Ara mirem el contingut del bucle while

Al principi, se li demanarà a l'usuari que introdueixi una subxarxa amb una màscara i no més de tres octets de la xarxa de la mateixa subxarxa, això és necessari per establir el rang de cerca. No m'agrada gaire aquesta implementació d'especificar els criteris i el rang de cerca, però fins ara no he trobat una solució millor. A continuació, de la llista resultant de subxarxes route_list, utilitzant una variable que no contingui més de tres octets, selecciono les subxarxes que m'interessen

tmp = re.search(r'^%sS*' % subnet_search, route_list[i])

A través d'IPNetwork, el mòdul netaddr, rebo subxarxes en forma de llista d'adreces ipv4

range_subnet = netaddr.IPNetwork(tmp.group(0))

Utilitzant IPNetwork, obtinc un rang d'adreces d'una xarxa introduïda per l'usuari amb una màscara i generi una llista de totes les adreces d'aquest rang per comparar-les amb la llista d'adreces ocupades.

for i in set(net_list).difference(set(busyip)):
        freeip.append(i)

Mostra la llista resultant d'adreces lliures en forma de subxarxes

print(netaddr.IPSet(freeip))

A continuació es mostra l'script complet, provat en commutadors utilitzats com a encaminador, models ex4550, ex4600


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
import getpass
import netaddr
import re
import sys

import jnpr.junos

parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user',
                    action='store',
                    dest='name',
                    help='Enter login from tacacs if it differs from the '
                         'username in the system.')
args = parser.parse_args()

if not args.name:
    args.name = getpass.getuser()    # Return the “login name” of the user.
router = input("Full routers name: ")
password = getpass.getpass("Password: ")

try:
    # Authenticates to a device running Junos, for get information about routs
    # into xml format and selects by tag.
    route_list = []
    with jnpr.junos.Device(host=router,
                           user=args.name,
                           passwd=password) as dev:
        data = dev.rpc.get_route_information()
    route_list = data.xpath("//rt-destination/text()")
except (jnpr.junos.exception.ConnectRefusedError,
        jnpr.junos.exception.ConnectUnknownHostError) as err:
    print("Equipment name or password wrong.")
    sys.exit(1)

while True:
    subnet = input("Net with mask: ")
    subnet_search = input("Input no more three octet: ")
    # Gets a list of busy IP addresses from the received subnets.
    busyip = []
    for i in range(len(route_list)):
        tmp = re.search(r'^%sS*' % subnet_search, route_list[i])
        if tmp:
            range_subnet = netaddr.IPNetwork(tmp.group(0))
            for ip in range_subnet:
                busyip.append("%s" % ip)
    range_subnet = netaddr.IPNetwork(subnet)
    # Gets list ip adresses from subnetworks lists.
    net_list = []
    for ip in range_subnet:
        net_list.append("%s" % ip)
    # Сomparing lists.
    freeip = []
    for i in set(net_list).difference(set(busyip)):
        freeip.append(i)
    print(netaddr.IPSet(freeip))

    request = input("To run request again enter yes or y, "
                    "press 'enter', complete request: ")
    if request in ("yes", "y"):
        continue
    else:
        print('Bye')
        break

Font: www.habr.com

Afegeix comentari