Junos PyEZ на прикладі завдання пошуку вільних підмереж ipv4

Стаття про роботу з Junos PyEZ - "Python microframework, що дає змогу manage and automate devices running 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 

ця команда встановить відсутні в системі бібліотеки, необхідні для роботи. У моїй версії вимоги.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
<rpc-reply >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

Додати коментар або відгук