Článek o práci s Junos PyEZ — „Python mikroframework, který umožňuje spravovat a automatizovat zařízení běžící na Junos OS“ automatizace a správa, jak to máme rádi. Cílem psaní skriptu popsaného v tomto článku bylo několik věcí — naučit se Python a automatizovat úkoly spojené se sběrem informací nebo změnou konfigurace na zařízeních pod Junos OS. Výběr této kombinace Python + Junos PyEZ byl zvolen pro nízkou překážku vstupu do programovacího jazyka Python a jednoduchost použití knihovny Junos PyEZ, která nevyžaduje odborné znalosti Junos OS.
Úkol
Audit volných podsítí ipv4 patřících společnosti. Kritériem toho, že je podsíť volná — je absence záznamu o ní v trasách na přepínači, který funguje jako směrovač pod Junos OS.
Implementace
Python + Junos PyEZ, ačkoli byla pokušení použít paramiko a ssh.exec_command, v důsledku toho bude potřeba na dotazovaném zařízení nastavit protokol správy zařízení netconf. Netconf komunikuje s hardwarem prostřednictvím vzdáleného volání procedur (remote procedure call RPC) a používá XML pro poskytování získaných informací v tomto příkladu.
Instalace aktuální verze Junos PyEZ z PyPI se provádí následujícím příkazem:
$ pip install junos-ezncTaké lze nainstalovat z hlavní větve projektu na GitHubu následujícím příkazem:
$ pip install git+https://github.com/Juniper/py-junos-eznc.gitA ještě jedna možnost přes
$ pip install -r requirements.txt tento příkaz nainstaluje chybějící knihovny potřebné pro fungování. V mé verzi requirements.txt jsou celkem dvě, verze jsou uvedeny poslední k datu psaní skriptu:
junos-eznc
netaddrSkript ve výchozím nastavení bere jméno aktuálního uživatele v systému, přihlásit se pod jménem jiného uživatele lze pomocí klíče show_route.py -u getpass.getpass bere heslo ze stdin, takže heslo nezůstane v systému. Pro připojení k zařízení bude také potřeba zadat jeho hostname nebo ip-adresu na vyžádání. Všechny potřebné údaje pro autorizaci na zařízení byly získány.
Junos PyEZ podporuje připojení k zařízením pod Junos OS pomocí konzole, telnetu nebo netconf přes ssh. V článku je podrobněji probrána poslední možnost.
Pro připojení k zařízení se používá třída Device modulu jnpr.junos
with jnpr.junos.Device(host=router,
user=args.name,
passwd=password) as dev:Provádí se dotaz na všechny známé trasy routeru přes vzdálené volání procedur nebo volání vzdálených procedur, záleží na tom, jak je to komu pohodlnější.
data = dev.rpc.get_route_information()Podobný příkaz v Junos OS
user@router> show route | display xmlPřidáním na konec příkazu rpc získáme tag dotazu a můžeme ho porovnat s názvem metody RPC, tímto způsobem lze zjistit i další zajímavé názvy. Je třeba poznamenat, že syntaxe psaní tagu dotazu se liší od názvu metody, konkrétně je třeba nahradit pomlčky podtržítky.
user@router> show route | display xml rpc
route_list = data.xpath("//rt-destination/text()")Zbytek jsem zabalil do cyklu while, abych se vyhnul opakovanému dotazu na router, pokud bude třeba ověřit v jiné podsíti, o kterých router již ví. Je třeba zmínit, že router, na kterém se dotazuji, zná trasy pouze přes OSPF, proto je lepší mírně upravit dotaz pro hraniční router, aby se zkrátil čas běhu skriptu.
data = dev.rpc.get_ospf_route_information()Nyní se podíváme na obsah cyklu while
Na začátku bude uživateli nabídnuto zadat podsíť s maskou a maximálně tři oktety z této podsítě, což je nezbytné pro stanovení rozsahu hledání. Tato implementace zadání kritéria a rozsahu hledání se mi moc nelíbí, ale zatím jsem nenašel lepší řešení. Dále z získaného seznamu podsítí route_list pomocí proměnné obsahující maximálně tři oktety vybírám ty podsítě, které mě zajímají.
tmp = re.search(r'^%sS*' % subnet_search, route_list[i])Přes IPNetwork z modulu netaddr získávám podsítě ve formě seznamu ipv4 adres.
range_subnet = netaddr.IPNetwork(tmp.group(0))Používáním IPNetwork z uživatelsky zadané sítě s maskou získávám rozsah adres a vytvářím seznam všech adres z tohoto rozsahu pro porovnání se seznamem obsazených adres.
for i in set(net_list).difference(set(busyip)):
freeip.append(i)Získaný seznam volných adres zobrazuji ve formě podsítí.
print(netaddr.IPSet(freeip))Níže je uveden celý skript, testovaný na přepínačích používaných jako routery, modely 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
Zdroj: habr.com
