Junos PyEZ na przykładzie zadania wyszukiwania wolnych podsieci IPv4

Artykuł o pracy z Junos PyEZ - „Mikroframework Pythona, który umożliwia zarządzanie i automatyzację urządzeń z systemem operacyjnym Junos OS” automatyzacja i zarządzanie, wszystko to, co kochamy. Pisanie skryptu opisanego w tym artykule miało kilka celów – naukę języka Python i automatyzację zadań polegających na zbieraniu informacji lub zmianie konfiguracji na sprzęcie z systemem operacyjnym Junos. Wybór tej specyficznej kombinacji Python + Junos PyEZ został podyktowany niską barierą wejścia do języka programowania Python oraz łatwością obsługi biblioteki Junos PyEZ, która nie wymaga specjalistycznej wiedzy na temat Junos OS.

Zadanie

Audyt wolnych podsieci IPv4 należących do firmy. Kryterium wolnej podsieci jest brak wpisu o niej w trasach na przełączniku pełniącym rolę routera z systemem operacyjnym Junos.

realizacja

Python + Junos PyEZ, chociaż była pokusa, żeby zrobić to poprzez paramiko i ssh.exec_command, W rezultacie konieczne będzie skonfigurowanie protokołu zarządzania siecią urządzenia netconf na odpytywanym sprzęcie. Netconf współpracuje ze sprzętem poprzez zdalne wywołanie procedury RPC i, w tym przykładzie, wykorzystuje XML do dostarczania otrzymywanych informacji.

Instalacja aktualnej wersji Junos PyEZ z PyPI odbywa się za pomocą następującego polecenia:

$ pip install junos-eznc

Możesz także zainstalować z głównej gałęzi projektu na GitHubie za pomocą następującego polecenia:

$ pip install git+https://github.com/Juniper/py-junos-eznc.git

I jeszcze jedna opcja przez

$ pip install -r requirements.txt 

Polecenie to zainstaluje biblioteki, których brakuje w systemie, a są niezbędne do działania. W mojej wersji wymagania.txt Są ich tylko dwie, najnowsze wersje są wskazane w momencie pisania scenariusza:

junos-eznc
netaddr

Domyślnie skrypt przyjmuje nazwę bieżącego użytkownika w systemie, możesz zalogować się pod nazwą innego użytkownika za pomocą klawisza show_route.py -u getpass.getpass pobiera hasło ze standardowego wejścia, więc hasło nie pozostanie w systemie. Aby połączyć się ze sprzętem, po wyświetleniu monitu będziesz musiał także wprowadzić jego nazwę hosta lub adres IP. Otrzymano wszystkie dane niezbędne do autoryzacji na urządzeniu.

Junos PyEZ obsługuje łączenie się ze sprzętem z systemem operacyjnym Junos OS za pomocą konsoli, telnetu lub netconf przez ssh. W artykule omówiono tę drugą opcję.

Aby połączyć się ze sprzętem, użyj klasy Device modułu jnpr.junos

with jnpr.junos.Device(host=router,
                           user=args.name,
                           passwd=password) as dev:

Wysyłane jest żądanie dla wszystkich tras znanych routerowi poprzez zdalne wywołanie procedury lub zdalne wywołanie procedury, w zależności od tego, co jest wygodniejsze.

data = dev.rpc.get_route_information()

Podobne polecenie w systemie operacyjnym Junos

user@router> show route | display xml

Dodając na koniec polecenia rpc, otrzymujemy znacznik żądania i możemy go dopasować do nazwy metody RPC, w ten sposób możemy poznać inne interesujące nas nazwy. Warto zauważyć, że składnia zapisu znacznika żądania różni się od nazwy metody, a mianowicie należy zastąpić łączniki znakami podkreślenia.

user@router> show route | display xml rpc
<rpc-reply >route_list = data.xpath("//rt-destination/text()")

Pozostała część została owinięta w pętlę while, aby nie powtarzać żądania do routera w przypadku konieczności sprawdzenia innej podsieci spośród tych, o których router już wie. Warto wspomnieć, że router na którym kieruję żądanie zna trasy tylko przez OSPF, więc w przypadku routera brzegowego lepiej trochę zmienić żądanie, aby skrócić czas działania skryptu

data = dev.rpc.get_ospf_route_information()

Przyjrzyjmy się teraz zawartości pętli while

Na początku użytkownik zostanie poproszony o podanie podsieci z maską i nie więcej niż trzema oktetami z sieci tej samej podsieci, jest to konieczne do ustawienia zakresu wyszukiwania. Nie bardzo podoba mi się ta implementacja określenia kryteriów i zakresu wyszukiwania, ale jak dotąd nie znalazłem lepszego rozwiązania. Następnie z powstałej listy podsieci Route_list za pomocą zmiennej zawierającej nie więcej niż trzy oktety wybieram interesujące mnie podsieci

tmp = re.search(r'^%sS*' % subnet_search, route_list[i])

Poprzez IPNetwork, moduł netaddr, otrzymuję podsieci w postaci listy adresów IPv4

range_subnet = netaddr.IPNetwork(tmp.group(0))

Korzystając z IPNetwork, pozyskuję zakres adresów z sieci wprowadzonej przez użytkownika za pomocą maski i generuję listę wszystkich adresów z tego zakresu dla porównania z listą zajętych adresów.

for i in set(net_list).difference(set(busyip)):
        freeip.append(i)

Otrzymaną listę wolnych adresów wyświetlam w postaci podsieci

print(netaddr.IPSet(freeip))

Poniżej znajduje się kompletny skrypt, przetestowany na przełącznikach używanych jako router, modele 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

Źródło: www.habr.com

Dodaj komentarz