Cikk a Junos PyEZ használatáról – „Python mikrokeretrendszer, amely lehetővé teszi a Junos OS-t futtató eszközök kezelését és automatizálását” automatizálás és kezelés, mindaz, amit szeretünk. A cikkben leírt szkript megírásának több célja volt – a Python tanulmányozása és az információgyűjtési vagy konfigurációs változtatási feladatok automatizálása Junos OS vezérlésű hardveren. A Python + Junos PyEZ páros választását a Python programozási nyelv alacsony belépési küszöbe és a Junos PyEZ könyvtár egyszerű használata indokolta, amely nem igényel szakértői tudást a Junos OS-ról.
Feladat
Az IPv4 szabad alhálózatok auditálása a cég tulajdonában. A szabad alhálózat kritériuma az, hogy nincs róla nyilvántartás a Junos OS-t futtató router szerepét betöltő switch útvonalán.
Megvalósítás
A Python + Junos PyEZ, noha volt kísértés a paramiko és ssh.exec_command használatára, ennek következményeként szükség lesz a lekérdezett hardveren a netconf eszközmenedzsment protokoll beállítására. A Netconf távoli eljárás meghívás (RPC) segítségével működik a hardverrel, és XML-t használ, a vizsgált példában, az nyújtott információk biztosítására.
A jelenlegi Junos PyEZ verzió telepítése a PyPI-ból a következő parancs kiadásával történik:
$ pip install junos-ezncA GitHub projekt fő ágából is telepíthető a következő parancs kiadásával:
$ pip install git+https://github.com/Juniper/py-junos-eznc.gitÉs még egy lehetőség:
$ pip install -r requirements.txt ez a parancs telepíti a hiányzó könyvtárakat, amelyek szükségesek a működéshez. Az én verziómban requirements.txt összesen kettő van, a verziók a szkript megírásának időpontjában a legutolsóak:
junos-eznc
netaddrA szkript alapértelmezetten a rendszer aktuális felhasználónevét veszi, más felhasználónévvel való bejelentkezéshez használja a show_route.py -u kulcsot, a getpass.getpass pedig az stdin-ből kéri a jelszót, így a jelszó nem marad a rendszerben. Az eszközökhöz való csatlakozáshoz emellett be kell írni a gépjármű nevét vagy IP-címét is. Minden szükséges adat az eszközre való hitelesítéshez megvan.
A Junos PyEZ támogatja a Junos OS-t futtató eszközökhöz való csatlakozást konzolon, telneten vagy ssh-n keresztüli netconf-on. A cikkben az utolsó lehetőség került bemutatásra.
Az eszközhöz való csatlakozáshoz a jnpr.junos modul Device osztályát használjuk.
with jnpr.junos.Device(host=router,
user=args.name,
passwd=password) as dev:A kérés a router által ismert összes útvonalról kerül végrehajtásra távoli eljárás meghívásán keresztül, vagy távoli eljárások hívásán, ahogy kényelmesebb a felhasználónak.
data = dev.rpc.get_route_information()Hasonló parancs a Junos OS-en
user@router> show route | display xmlHa a rpc végére adjuk a parancsot, megkapjuk a kérés címkéjét, és párosíthatjuk azt az RPC metódus nevével, ezzel a módszerrel más érdekes neveket is megtudhatunk. Érdemes megjegyezni, hogy a kérés címke írásának szintaxisa különbözik a metódus nevétől, mégpedig a kötőjelek alsó vonalakra cserélésével.
user@router> show route | display xml rpc
route_list = data.xpath("//rt-destination/text()")A maradék részt while ciklusba burkoltam, hogy ne kelljen újra végrehajtani a kérést a routeren, ha más alhálózaton kell ellenőriznünk, amelyeket a router már ismer. Érdemes megemlíteni, hogy a router, amelyen a kérést végzem, csak OSPF-en keresztül ismeri az útvonalakat, ezért a határrouter számára érdemes kissé módosítani a kérést, hogy csökkentsem a szkript futási idejét.
data = dev.rpc.get_ospf_route_information()Most térjünk rá a while ciklus tartalmára.
Kezdetben a felhasználónak javasolják, hogy adjon meg egy alhálózatot maszkkal, és legfeljebb három oktet az alhálózatból, ez szükséges a keresési tartomány meghatározásához. Nem igazán tetszik ez a megvalósítás a kritériumok és a keresési tartomány megadására, de egyelőre nem találtam jobb megoldást. A későbbiekben a route_list-ból, figyelembe véve a legfeljebb három oktetből álló változót, kiválasztom az érdekes alhálózatokat.
tmp = re.search(r'^%sS*' % subnet_search, route_list[i])Az IPNetwork modul segítségével, a netaddr-ból, listaként kapom meg az alhálózatokat ipv4 címek formájában.
range_subnet = netaddr.IPNetwork(tmp.group(0))A felhasználó által megadott hálózat IPNetwork-jével és maszkkal megkapom a címtartományt, és összeállítom az összes címet ebből a tartományból az elfoglalt címek listájával való összehasonlításhoz.
for i in set(net_list).difference(set(busyip)):
freeip.append(i)A kapott szabad címek listáját alhálózat formájában mutatom be.
print(netaddr.IPSet(freeip))Az alábbiakban a teljes szkript látható, amelyet olyan kapcsolóknál teszteltem, amelyek routerként működnek, az ex4550 és ex4600 modelleken.
#!/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
Forrás: habr.com
