Artykuł o pracy z Junos PyEZ - „Mikroframework Pythona, który umożliwia zarządzanie i automatyzację urządzeń z systemem operacyjnym Junos OS” automatyzacja i zarządzanie, wszystko to, co kochamy. Pisanie skryptu opisanego w tym artykule miało kilka celów – naukę języka Python i automatyzację zadań polegających na zbieraniu informacji lub zmianie konfiguracji na sprzęcie z systemem operacyjnym Junos. Wybór tej specyficznej kombinacji Python + Junos PyEZ został podyktowany niską barierą wejścia do języka programowania Python oraz łatwością obsługi biblioteki Junos PyEZ, która nie wymaga specjalistycznej wiedzy na temat Junos OS.
Zadanie
Audyt wolnych podsieci IPv4 należących do firmy. Kryterium wolnej podsieci jest brak wpisu o niej w trasach na przełączniku pełniącym rolę routera z systemem operacyjnym Junos.
realizacja
Python + Junos PyEZ, chociaż była pokusa, żeby zrobić to poprzez paramiko i ssh.exec_command,
Instalacja aktualnej wersji Junos PyEZ z PyPI odbywa się za pomocą następującego polecenia:
$ pip install junos-eznc
Możesz także zainstalować z głównej gałęzi projektu na GitHubie za pomocą następującego polecenia:
$ pip install git+https://github.com/Juniper/py-junos-eznc.git
I jeszcze jedna opcja przez
$ pip install -r requirements.txt
Polecenie to zainstaluje biblioteki, których brakuje w systemie, a są niezbędne do działania. W mojej wersji wymagania.txt Są ich tylko dwie, najnowsze wersje są wskazane w momencie pisania scenariusza:
junos-eznc
netaddr
Domyślnie skrypt przyjmuje nazwę bieżącego użytkownika w systemie, możesz zalogować się pod nazwą innego użytkownika za pomocą klawisza show_route.py -u getpass.getpass pobiera hasło ze standardowego wejścia, więc hasło nie pozostanie w systemie. Aby połączyć się ze sprzętem, po wyświetleniu monitu będziesz musiał także wprowadzić jego nazwę hosta lub adres IP. Otrzymano wszystkie dane niezbędne do autoryzacji na urządzeniu.
Junos PyEZ obsługuje łączenie się ze sprzętem z systemem operacyjnym Junos OS za pomocą konsoli, telnetu lub netconf przez ssh. W artykule omówiono tę drugą opcję.
Aby połączyć się ze sprzętem, użyj klasy Device modułu jnpr.junos
with jnpr.junos.Device(host=router,
user=args.name,
passwd=password) as dev:
Wysyłane jest żądanie dla wszystkich tras znanych routerowi poprzez zdalne wywołanie procedury lub zdalne wywołanie procedury, w zależności od tego, co jest wygodniejsze.
data = dev.rpc.get_route_information()
Podobne polecenie w systemie operacyjnym Junos
user@router> show route | display xml
Dodając na koniec polecenia rpc, otrzymujemy znacznik żądania i możemy go dopasować do nazwy metody RPC, w ten sposób możemy poznać inne interesujące nas nazwy. Warto zauważyć, że składnia zapisu znacznika żądania różni się od nazwy metody, a mianowicie należy zastąpić łączniki znakami podkreślenia.
user@router> show route | display xml rpc
<rpc-reply >route_list = data.xpath("//rt-destination/text()")
Pozostała część została owinięta w pętlę while, aby nie powtarzać żądania do routera w przypadku konieczności sprawdzenia innej podsieci spośród tych, o których router już wie. Warto wspomnieć, że router na którym kieruję żądanie zna trasy tylko przez OSPF, więc w przypadku routera brzegowego lepiej trochę zmienić żądanie, aby skrócić czas działania skryptu
data = dev.rpc.get_ospf_route_information()
Przyjrzyjmy się teraz zawartości pętli while
Na początku użytkownik zostanie poproszony o podanie podsieci z maską i nie więcej niż trzema oktetami z sieci tej samej podsieci, jest to konieczne do ustawienia zakresu wyszukiwania. Nie bardzo podoba mi się ta implementacja określenia kryteriów i zakresu wyszukiwania, ale jak dotąd nie znalazłem lepszego rozwiązania. Następnie z powstałej listy podsieci Route_list za pomocą zmiennej zawierającej nie więcej niż trzy oktety wybieram interesujące mnie podsieci
tmp = re.search(r'^%sS*' % subnet_search, route_list[i])
Poprzez IPNetwork, moduł netaddr, otrzymuję podsieci w postaci listy adresów IPv4
range_subnet = netaddr.IPNetwork(tmp.group(0))
Korzystając z IPNetwork, pozyskuję zakres adresów z sieci wprowadzonej przez użytkownika za pomocą maski i generuję listę wszystkich adresów z tego zakresu dla porównania z listą zajętych adresów.
for i in set(net_list).difference(set(busyip)):
freeip.append(i)
Otrzymaną listę wolnych adresów wyświetlam w postaci podsieci
print(netaddr.IPSet(freeip))
Poniżej znajduje się kompletny skrypt, przetestowany na przełącznikach używanych jako router, modele 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
Źródło: www.habr.com