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

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