Artigo sobre o trabalho com Junos PyEZ — “microframework Python que permite gerenciar e automatizar dispositivos que executam o Junos OS” automação e gerenciamento, tudo como gostamos. A redação do script descrito neste artigo tinha vários objetivos — estudar Python e automatizar tarefas de coleta de informações ou alteração de configuração em equipamentos sob gerenciamento do Junos OS. A escolha dessa combinação 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 conhecimentos especializados em Junos OS.
Tarefa
Auditoria de sub-redes livres ipv4 pertencentes à empresa. O critério para determinar que a sub-rede está livre é a ausência de registro dela nas rotas no switch atuando como roteador sob Junos OS.
Implementação
Python + Junos PyEZ, embora houvesse a tentação de fazer através de paramiko e ssh.exec_command, como consequência, será necessário configurar o protocolo de gerenciamento de dispositivos de rede netconf no equipamento em questão. O netconf funciona com equipamentos por meio de chamadas de procedimento remoto (remote procedure call RPC) e utiliza XML, no exemplo em consideração, para fornecer as informações obtidas.
A instalação da versão atual do Junos PyEZ do PyPI é feita com o seguinte comando:
$ pip install junos-ezncVocê também pode instalar a partir da branch principal do projeto no GitHub com o seguinte comando:
$ pip install git+https://github.com/Juniper/py-junos-eznc.gitE mais uma opção através de
$ pip install -r requirements.txt este comando instalará as bibliotecas que estão faltando no sistema e são necessárias para o funcionamento. Na minha versão, requirements.txt são apenas duas, as versões estão especificadas como as mais recentes no momento da redação do script:
junos-eznc
netaddrO script por padrão pega o nome do usuário atual no sistema, para logar-se como outro usuário, pode-se usar a chave show_route.py -u ; getpass.getpass pega a senha do stdin assim a senha não fica armazenada no sistema. Para conectar ao equipamento, também será necessário inserir, quando solicitado, seu hostname ou endereço IP. Todos os dados necessários para a autenticação no dispositivo foram obtidos.
Junos PyEZ suporta conexão com equipamentos que executam o Junos OS usando console, telnet ou netconf via ssh. Neste artigo, o último método é abordado.
Para conectar ao equipamento, utiliza-se 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 procedimentos remotos, como for mais conveniente.
data = dev.rpc.get_route_information()Comando equivalente no Junos OS
user@router> show route | display xmlAdicionando o rótulo rpc ao final do comando, teremos a tag de solicitação e podemos corresponder com o nome do método RPC, dessa forma é possível descobrir outros nomes de interesse. É importante notar que a sintaxe da tag de solicitação difere do nome do método, ou seja, devemos substituir os sinais de traço por sublinhados.
user@router> show route | display xml rpc
route_list = data.xpath("//rt-destination/text()")O restante foi encapsulado em um loop while para não executar novamente a solicitação ao roteador, caso precise verificar em outra sub-rede das quais o roteador já conhece. Vale mencionar que o roteador que estou consultando conhece as rotas apenas por OSPF, portanto, para o roteador de borda, é melhor alterar um pouco a solicitação para reduzir o tempo de execução do script.
data = dev.rpc.get_ospf_route_information()Agora vamos analisar o conteúdo do loop while
No início, o usuário será solicitado a inserir a sub-rede com a máscara e no máximo três octetos da rede dessa mesma sub-rede, isso é necessário para definir o intervalo de busca. Não gosto muito dessa implementação para definir o critério e o intervalo de busca, mas até agora não encontrei uma solução melhor. Em seguida, da lista de sub-redes route_list obtida, uso a variável contendo no máximo três octetos para selecionar as sub-redes de interesse.
tmp = re.search(r'^%sS*' % subnet_search, route_list[i])Através de IPNetwork, do módulo netaddr, obtenho sub-redes na forma de uma lista de endereços ipv4.
range_subnet = netaddr.IPNetwork(tmp.group(0))Usando IPNetwork da rede inserida pelo usuário com a máscara, obtenho o intervalo de endereços e formo 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)Exibo a lista obtida de endereços disponíveis na forma de sub-redes.
print(netaddr.IPSet(freeip))Abaixo está o script completo, testado em switches usados como roteadores, 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
