Junos PyEZ naudojant nemokamų ipv4 potinklių paieškos užduoties pavyzdį

Straipsnis apie darbą su Junos PyEZ – „Python mikrokarkasas, leidžiantis valdyti ir automatizuoti įrenginius, kuriuose veikia Junos OS“ automatizavimas ir valdymas – viskas, kas mums patinka. Rašant šiame straipsnyje aprašytą scenarijų buvo keli tikslai – išmokti Python ir automatizuoti informacijos rinkimo ar konfigūracijų keitimo užduotis įrangoje, kurioje veikia Junos OS. Šis specifinis Python + Junos PyEZ derinys buvo pasirinktas dėl mažo barjero įėjimo į Python programavimo kalbą ir Junos PyEZ bibliotekos naudojimo paprastumo, kuris nereikalauja ekspertų žinių apie Junos OS.

Užduotis

Įmonei priklausančių nemokamų ipv4 potinklių auditas. Kriterijus, kad potinklis yra nemokamas, yra tai, kad jungiklio, veikiančio kaip maršrutizatorius, kuriame veikia Junos OS, maršrutuose nėra įrašo apie jį.

Vykdymas

Python + Junos PyEZ, nors buvo pagunda tai padaryti per paramiko ir ssh.exec_command, Dėl to jums reikės sukonfigūruoti netconf įrenginio tinklo valdymo protokolą apklausoje įrangoje. Netconf dirba su aparatine įranga per nuotolinio procedūrų iškvietimą RPC ir šiame pavyzdyje naudoja XML, kad pateiktų gaunamą informaciją.

Dabartinės Junos PyEZ versijos įdiegimas iš PyPI atliekama naudojant šią komandą:

$ pip install junos-eznc

Taip pat galite įdiegti iš pagrindinės projekto šakos „GitHub“ naudodami šią komandą:

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

Ir dar vienas variantas per

$ pip install -r requirements.txt 

Ši komanda įdiegs bibliotekas, kurių trūksta sistemoje ir kurios yra būtinos darbui. Mano versijoje reikalavimai.txt Jų yra tik dvi, naujausios versijos nurodytos rašant scenarijų:

junos-eznc
netaddr

Pagal numatytuosius nustatymus scenarijus naudoja dabartinio vartotojo vardą sistemoje; galite prisijungti kito vartotojo vardu naudodami klavišą show_route.py -u getpass.getpass paima slaptažodį iš stdin, todėl slaptažodis neliks sistemoje. Norėdami prisijungti prie įrangos, taip pat turėsite įvesti jos pagrindinio kompiuterio pavadinimą arba IP adresą, kai būsite paraginti. Gauti visi įrenginio autorizacijai reikalingi duomenys.

Junos PyEZ palaiko prisijungimą prie įrangos, kurioje veikia Junos OS, naudojant konsolę, telnet arba netconf per ssh. Straipsnyje aptariamas pastarasis variantas.

Norėdami prisijungti prie įrangos, naudokite modulio jnpr.junos klasę Įrenginys

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

Prašymas pateikiamas visiems maršruto parinktuvui žinomiems maršrutams nuotoliniu būdu arba nuotoliniu būdu, atsižvelgiant į tai, kas patogiau.

data = dev.rpc.get_route_information()

Panaši komanda Junos OS

user@router> show route | display xml

Komandos gale pridėję rpc, gauname užklausos žymą ir galime ją suderinti su RPC metodo pavadinimu, tokiu būdu galime sužinoti kitus dominančius pavadinimus. Verta paminėti, kad užklausos žymos rašymo sintaksė skiriasi nuo metodo pavadinimo, būtent, brūkšnelius turėtumėte pakeisti apatiniais brūkšniais.

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

Likusi dalis buvo apvyniota trumpuoju ciklu, kad nebūtų kartojama užklausa maršrutizatoriui, jei reikia patikrinti kitą potinklį iš tų, apie kuriuos maršrutizatorius jau žino. Verta paminėti, kad maršrutizatorius, kuriame rašau užklausą, žino maršrutus tik per OSPF, todėl krašto maršrutizatoriui geriau šiek tiek pakeisti užklausą, kad sutrumpėtų scenarijaus veikimo laikas

data = dev.rpc.get_ospf_route_information()

Dabar pažiūrėkime į while ciklo turinį

Pradžioje vartotojo bus paprašyta įvesti potinklį su kauke ir ne daugiau kaip tris oktetus iš to paties potinklio tinklo, tai būtina norint nustatyti paieškos diapazoną. Man nelabai patinka toks kriterijų ir paieškos diapazono nurodymo įgyvendinimas, bet iki šiol neradau geresnio sprendimo. Tada iš gauto potinklių sąrašo maršruto_sąrašas, naudodamas kintamąjį, kuriame yra ne daugiau kaip trys oktetai, pasirenku mane dominančius potinklius

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

Per IPNetwork, netaddr modulį, gaunu potinklius ipv4 adresų sąrašo forma

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

Naudodamas IPNetwork gaunu adresų diapazoną iš vartotojo įvesto tinklo su kauke ir sugeneruoju visų šio diapazono adresų sąrašą, kad būtų galima palyginti su užimtų adresų sąrašu.

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

Pateikiu gautą nemokamų adresų sąrašą potinklių pavidalu

print(netaddr.IPSet(freeip))

Žemiau yra visas scenarijus, išbandytas su jungikliais, naudojamais kaip maršrutizatorius, modeliuose 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

Šaltinis: www.habr.com

Добавить комментарий