Un artigo sobre o traballo con Junos PyEZ: "microframework de Python que che permite xestionar e automatizar dispositivos que executan Junos OS", automatización e xestión, todo o que nos encanta. Escribir o script descrito neste artigo tiña varios obxectivos: aprender Python e automatizar tarefas para recoller información ou cambiar as configuracións dos equipos que executaban Junos OS. A elección desta combinación específica de Python + Junos PyEZ realizouse debido á baixa barreira de entrada á linguaxe de programación Python e á facilidade de uso da biblioteca Junos PyEZ, que non require coñecementos expertos sobre Junos OS.
Tarefa
Auditoría de subredes ipv4 gratuítas pertencentes á empresa. O criterio de que unha subrede sexa gratuíta é a ausencia dunha entrada sobre ela nas rutas do switch que actúa como un enrutador que executa Junos OS.
Implantación
Python + Junos PyEZ, aínda que houbo a tentación de facelo a través de paramiko e ssh.exec_command,
A instalación da versión actual de Junos PyEZ desde PyPI faise co seguinte comando:
$ pip install junos-eznc
Tamén podes instalar desde a rama principal do proxecto en GitHub co seguinte comando:
$ pip install git+https://github.com/Juniper/py-junos-eznc.git
E unha opción máis vía
$ pip install -r requirements.txt
Este comando instalará as bibliotecas que faltan no sistema e son necesarias para o seu funcionamento. Na miña versión requisitos.txt Só hai dous deles, as últimas versións están indicadas no momento de escribir o guión:
junos-eznc
netaddr
Por defecto, o script toma o nome do usuario actual no sistema; pode iniciar sesión co nome doutro usuario usando a chave show_route.py -u getpass.getpass acepta o contrasinal de stdin polo que o contrasinal non permanecer no sistema. Para conectarse ao equipo, tamén terá que introducir o seu nome de host ou enderezo IP cando se lle solicite. Recibíronse todos os datos necesarios para a autorización no dispositivo.
Junos PyEZ admite a conexión a equipos que executan Junos OS mediante a consola, telnet ou netconf a través de ssh. O artigo discute esta última opción.
Para conectarse ao equipo, use a clase Dispositivo do módulo jnpr.junos
with jnpr.junos.Device(host=router,
user=args.name,
passwd=password) as dev:
Realízase unha solicitude para todas as rutas coñecidas polo enrutador mediante chamada de procedemento remoto ou chamada de procedemento remoto, o que resulte máis conveniente.
data = dev.rpc.get_route_information()
Comando similar en Junos OS
user@router> show route | display xml
Engadindo rpc ao final do comando, obtemos unha etiqueta de solicitude e podemos asociala co nome do método RPC, deste xeito podemos descubrir outros nomes de interese. Paga a pena notar que a sintaxe para escribir a etiqueta de solicitude é diferente do nome do método, é dicir, debería substituír os guións por guións baixos.
user@router> show route | display xml rpc
<rpc-reply >route_list = data.xpath("//rt-destination/text()")
O resto da parte envolveuse nun bucle while, para non repetir a solicitude ao router se fose necesario comprobar noutra subrede das que o router xa coñece. Cómpre mencionar que o enrutador no que fago a solicitude coñece rutas só a través de OSPF, polo que para un enrutador de borde é mellor cambiar un pouco a solicitude para reducir o tempo de execución do script.
data = dev.rpc.get_ospf_route_information()
Agora vexamos o contido do bucle while
Ao principio, pediráselle ao usuario que introduza unha subrede cunha máscara e non máis de tres octetos da rede da mesma subrede, isto é necesario para establecer o rango de busca. Non me gusta moito esta implementación de especificar os criterios e o intervalo de busca, pero ata agora non atopei unha solución mellor. A continuación, a partir da lista resultante de subredes route_list, usando unha variable que non conteña máis de tres octetos, selecciono as subredes que me interesan
tmp = re.search(r'^%sS*' % subnet_search, route_list[i])
A través de IPNetwork, o módulo netaddr, recibo subredes en forma de lista de enderezos ipv4
range_subnet = netaddr.IPNetwork(tmp.group(0))
Usando IPNetwork, obteño un rango de enderezos dunha rede introducida polo usuario cunha máscara e xero unha lista de todos os enderezos deste rango para comparalos coa lista de enderezos ocupados.
for i in set(net_list).difference(set(busyip)):
freeip.append(i)
Amoso a lista resultante de enderezos libres en forma de subredes
print(netaddr.IPSet(freeip))
Abaixo está o script completo, probado en interruptores usados como enrutador, modelos 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
Fonte: www.habr.com