Junos PyEZ на примера на задача за търсене на свободни подсетове ipv4

Статия за работа с 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

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster