Junos PyEZ usando el ejemplo de la tarea de buscar subredes ipv4 gratuitas

Un artículo sobre cómo trabajar con Junos PyEZ: automatización y administración “Microframework de Python que le permite administrar y automatizar dispositivos que ejecutan Junos OS”, todo lo que nos encanta. Escribir el script descrito en este artículo tenía varios objetivos: aprender Python y automatizar tareas para recopilar información o cambiar configuraciones en equipos que ejecutan Junos OS. La elección de esta combinación específica de Python + Junos PyEZ se realizó debido a la baja barrera de entrada al lenguaje de programación Python y la facilidad de uso de la biblioteca Junos PyEZ, que no requiere conocimientos expertos de Junos OS.

Tarea

Auditoría de subredes ipv4 libres pertenecientes a la empresa. El criterio de que una subred está libre es la ausencia de una entrada sobre ella en las rutas del conmutador que actúa como enrutador que ejecuta Junos OS.

implementación

Python + Junos PyEZ, aunque hubo la tentación de hacerlo mediante paramiko y ssh.exec_command, Como resultado, deberá configurar el protocolo de administración de red del dispositivo netconf en el equipo que se está sondeando. Netconf trabaja con hardware a través de una llamada a procedimiento remoto RPC y utiliza XML, en este ejemplo, para proporcionar la información que recibe.

La instalación de la versión actual de Junos PyEZ desde PyPI se realiza con el siguiente comando:

$ pip install junos-eznc

También puedes instalar desde la rama principal del proyecto en GitHub con el siguiente comando:

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

Y una opción más vía

$ pip install -r requirements.txt 

Este comando instalará bibliotecas que faltan en el sistema y que son necesarias para el funcionamiento. en mi versión requerimientos.txt Solo hay dos de ellos, las últimas versiones se indican al momento de escribir el guión:

junos-eznc
netaddr

De forma predeterminada, el script toma el nombre del usuario actual en el sistema; puede iniciar sesión con el nombre de otro usuario usando la tecla show_route.py -u getpass.getpass toma la contraseña de la entrada estándar para que no permanezca en el sistema. Para conectarse al equipo, también deberá ingresar su nombre de host o dirección IP cuando se le solicite. Se han recibido todos los datos necesarios para la autorización en el dispositivo.

Junos PyEZ admite la conexión a equipos que ejecutan Junos OS mediante la consola, telnet o netconf a través de ssh. El artículo analiza la última opción.

Para conectarse al equipo, use la clase Dispositivo del módulo jnpr.junos

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

Se realiza una solicitud para todas las rutas conocidas por el enrutador mediante una llamada a procedimiento remoto o una llamada a procedimiento remoto, lo que sea más conveniente.

data = dev.rpc.get_route_information()

Comando similar en Junos OS

user@router> show route | display xml

Al agregar rpc al final del comando, obtenemos una etiqueta de solicitud y podemos relacionarla con el nombre del método RPC, de esta manera podemos encontrar otros nombres de interés. Vale la pena señalar que la sintaxis para escribir la etiqueta de solicitud es diferente del nombre del método, es decir, los guiones deben reemplazarse con guiones bajos.

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

El resto de la parte se envolvió en un bucle while, para no repetir la solicitud al enrutador si fuera necesario verificar otra subred de las que el enrutador ya conoce. Vale la pena mencionar que el enrutador en el que estoy realizando la solicitud conoce rutas solo a través de OSPF, por lo que para un enrutador de borde es mejor cambiar un poco la solicitud para reducir el tiempo de ejecución del script.

data = dev.rpc.get_ospf_route_information()

Ahora veamos el contenido del bucle while.

Al inicio se le solicitará al usuario ingresar a una subred con una máscara y no más de tres octetos de la red de la misma subred, esto es necesario para establecer el rango de búsqueda. Realmente no me gusta esta implementación de especificar los criterios y el rango de búsqueda, pero hasta ahora no he encontrado una solución mejor. A continuación, de la lista resultante de subredes route_list, utilizando una variable que no contenga más de tres octetos, selecciono las subredes que me interesan.

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

A través de IPNetwork, el módulo netaddr, recibo subredes en forma de lista de direcciones ipv4

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

Al utilizar IPNetwork, obtengo un rango de direcciones de una red ingresada por el usuario con una máscara y genero una lista de todas las direcciones de este rango para compararlas con la lista de direcciones ocupadas.

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

Muestro la lista resultante de direcciones libres en forma de subredes.

print(netaddr.IPSet(freeip))

A continuación se muestra el script completo, probado en conmutadores utilizados 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

Fuente: habr.com

Añadir un comentario