Статия за работа с Junos PyEZ — “Python микрорамка, която ви позволява да управлявате и автоматизирате устройства, работещи с Junos OS” автоматизация и управление, всичко както го обичаме. Написването на скрипта, описан в тази статия, имаше няколко цели — изучаване на Python и автоматизиране на задачи за събиране на информация или промяна на конфигурацията на оборудване, работещо с Junos OS. Изборът на именно тази комбинация Python + Junos PyEZ беше направен поради ниския праг на достъпност на програмния език Python и простотата на използване на библиотеката Junos PyEZ, която не изисква експертни познания по Junos OS.
Задача
Аудит на свободните подсетей ipv4, принадлежащи на компанията. Критерият за това, че подсетята е свободна, е отсъствието на запис за нея в маршрутите на комутатора, изпълняващ ролята на маршрутизатор под управлението на Junos OS.
Реализация
Python + Junos PyEZ, макар да имаше изкушение да се направи чрез paramiko и ssh.exec_command, в резултат на това ще е необходимо на запитваното оборудване да се настрои протоколът за мрежово управление на устройства netconf. Netconf работи с оборудването чрез отдалечени процедури за повикване (remote procedure call RPC) и използва XML, в разглеждания пример, за предоставяне на получената информация.
Инсталирането на текущата версия на Junos PyEZ от PyPI се извършва с командата:
$ pip install junos-ezncМоже също да бъде инсталиран от основната клон на проекта в GitHub с следната команда:
$ pip install git+https://github.com/Juniper/py-junos-eznc.gitИ още една опция през
$ pip install -r requirements.txt тази команда ще инсталира липсващите в системата библиотеки, необходими за работа. В моята версия requirements.txt те са общо две, последните версии, посочени в момента на писане на скрипта:
junos-eznc
netaddrСкриптът по подразбиране взема името на текущия потребител в системата, може да се логнете с името на друг потребител, като използвате ключ show_route.py -u getpass.getpass приема парола от stdin, така че паролата няма да остане в системата. За свързване с оборудването също ще бъде необходимо да въведете при поискване неговото име на хост или IP адрес. Всички необходими данни за авторизация на устройството са получени.
Junos PyEZ поддържа свързване с оборудване, работещо с Junos OS, използвайки конзола, telnet или netconf през ssh. В статията е разгледан последният вариант.
За свързване с оборудването се използва класът Device от модула jnpr.junos
with jnpr.junos.Device(host=router,
user=args.name,
passwd=password) as dev:Изпълнява се искане за всички известни на рутера маршрути чрез отдалечено повикване на процедури или извикване на отдалечени процедури, както е удобно на всеки.
data = dev.rpc.get_route_information()Подобна команда в Junos OS
user@router> show route | display xmlДобавяйки в края на командата rpc, получаваме таг за заявка и можем да го свържем с името на метода RPC, по този начин можем да разберем и други интересни имена. Трябва да се отбележи, че синтаксисът на написването на тага за заявка се различава от името на метода, а именно трябва да заменим тиретата с долни черти.
user@router> show route | display xml rpc
route_list = data.xpath("//rt-destination/text()")Остатъчната част е обвита в цикъл while, за да не се извиква повторно заявка към рутера, ако трябва да проверим в друга подсистема от тези, които рутерът вече познава. Трябва да спомена, че рутерът, от който запитвам, познава маршрути само чрез OSPF, затова за граничния рутер е по-добре леко да променя запитването, за да съкратя времето за работа на скрипта.
data = dev.rpc.get_ospf_route_information()Сега ще се обърнем към съдържанието на цикъла while
В началото на потребителя ще бъде предложено да въведе подсистема с маска и не повече от три октета от мрежата на същата подсистема, което е необходимо за задаване на диапазона на търсене. Не съм особено доволен от такава реализация на задаването на критерия и диапазона на търсене, но засега не съм намерил по-добро решение. След това от получения списък на подсистемите route_list, използвайки променливата, съдържаща не повече от три октета, избирам интересуващи ме подсистеми.
tmp = re.search(r'^%sS*' % subnet_search, route_list[i])Чрез IPNetwork от модула netaddr, получавам подсистемите под формата на списък с ipv4 адреси.
range_subnet = netaddr.IPNetwork(tmp.group(0))Използвайки IPNetwork от въведената от потребителя мрежа с маска, получавам диапазона на адресите и формирам списък с всички адреси от този диапазон за сравнение със списъка на заетите адреси.
for i in set(net_list).difference(set(busyip)):
freeip.append(i)Полученият списък на свободните адреси извеждам в вид на подсистеми.
print(netaddr.IPSet(freeip))По-долу е представен целият скрипт, тестван на комутатори, използвани в ролята на рутер, модели 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
Източник: habr.com
