Статия за работа с 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, така паролата не остава в системата. За свързване с оборудването също ще е необходимо при запитване да се въведе неговото hostname или 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
