Junos PyEZ usando o exemplo da tarefa de busca de sub-redes IPv4 gratuitas

Um artigo sobre como trabalhar com Junos PyEZ - “Microframework Python que permite gerenciar e automatizar dispositivos que executam o Junos OS” automação e gerenciamento, tudo o que amamos. Escrever o script descrito neste artigo teve vários objetivos: aprender Python e automatizar tarefas de coleta de informações ou alteração de configurações em equipamentos que executam o Junos OS. A escolha desta combinação específica de Python + Junos PyEZ foi feita devido à baixa barreira de entrada na linguagem de programação Python e à facilidade de uso da biblioteca Junos PyEZ, que não requer conhecimento especializado de Junos OS.

Tarefa

Auditoria de sub-redes ipv4 gratuitas pertencentes à empresa. O critério para que uma sub-rede seja livre é a ausência de uma entrada sobre ela nas rotas do switch que atua como um roteador executando o Junos OS.

Implementação

Python + Junos PyEZ, embora houvesse a tentação de fazer isso por meio de paramiko e ssh.exec_command, Como resultado, você precisará configurar o protocolo de gerenciamento de rede do dispositivo netconf no equipamento que está sendo pesquisado. O Netconf trabalha com hardware via RPC de chamada de procedimento remoto e utiliza XML, neste exemplo, para fornecer as informações que recebe.

A instalação da versão atual do Junos PyEZ do PyPI é feita com o seguinte comando:

$ pip install junos-eznc

Você também pode instalar a partir do branch principal do projeto no GitHub com o seguinte comando:

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

E mais uma opção via

$ pip install -r requirements.txt 

Este comando instalará bibliotecas que estão faltando no sistema e são necessárias para a operação. Na minha versão requisitos.txt Existem apenas dois deles, as versões mais recentes são indicadas no momento da escrita do script:

junos-eznc
netaddr

Por padrão, o script usa o nome do usuário atual no sistema; você pode fazer login com o nome de outro usuário usando a chave show_route.py -u getpass.getpass pega a senha do stdin para que a senha não permaneça no sistema. Para se conectar ao equipamento, você também precisará inserir o nome do host ou endereço IP quando solicitado. Todos os dados necessários para autorização no dispositivo foram recebidos.

Junos PyEZ oferece suporte à conexão com equipamentos que executam o Junos OS usando o console, telnet ou netconf via ssh. O artigo discute a última opção.

Para conectar ao equipamento, utilize a classe Device do módulo jnpr.junos

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

Uma solicitação é feita para todas as rotas conhecidas pelo roteador por meio de chamada de procedimento remoto ou chamada de procedimento remoto, o que for mais conveniente.

data = dev.rpc.get_route_information()

Comando semelhante no Junos OS

user@router> show route | display xml

Ao adicionar rpc ao final do comando, obtemos uma tag de solicitação e podemos combiná-la com o nome do método RPC, desta forma podemos descobrir outros nomes de interesse. Vale ressaltar que a sintaxe para escrever a tag request é diferente do nome do método, ou seja, deve-se substituir os hífens por sublinhados.

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

O restante da parte foi envolvido em um loop while, para não repetir a solicitação ao roteador caso fosse necessário fazer check-in em outra sub-rede daquelas que o roteador já conhece. Vale ressaltar que o roteador no qual estou fazendo a solicitação conhece rotas apenas pelo OSPF, então para um roteador de borda é melhor alterar um pouco a solicitação para diminuir o tempo de execução do script

data = dev.rpc.get_ospf_route_information()

Agora vamos dar uma olhada no conteúdo do loop while

Inicialmente, o usuário será solicitado a inserir uma sub-rede com máscara e no máximo três octetos da rede da mesma sub-rede, isso é necessário para definir o intervalo de pesquisa. Não gosto muito dessa implementação de especificação de critérios e intervalo de pesquisa, mas até agora não encontrei uma solução melhor. A seguir, da lista resultante de sub-redes route_list, usando uma variável contendo no máximo três octetos, seleciono as sub-redes que me interessam

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

Através do IPNetwork, módulo netaddr, recebo sub-redes na forma de uma lista de endereços IPv4

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

Usando IPNetwork, obtenho um intervalo de endereços de uma rede inserida pelo usuário com uma máscara e gero uma lista de todos os endereços desse intervalo para comparação com a lista de endereços ocupados.

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

Eu exibo a lista resultante de endereços gratuitos na forma de sub-redes

print(netaddr.IPSet(freeip))

Abaixo segue o script completo, testado em switches usados ​​como roteador, 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: habr.com

Adicionar um comentário