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,
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