Junos PyEZ ved hjælp af opgaven med at finde ledige ipv4-subnetter

Artikel om arbejde med Junos PyEZ – “Python-mikroframework, der gør det muligt at administrere og automatisere enheder, der kører Junos OS” automation og styring, alt hvad vi elsker. Målet med at skrive det script, der er beskrevet i denne artikel, var at opnå flere mål – at lære Python og at automatisere opgaver omkring indsamling af information eller ændring af konfigurationer på udstyr, der kører Junos OS. Valget af denne kombination Python + Junos PyEZ blev gjort på grund af den lave indgangsbarriere til programmeringssproget Python og biblioteket Junos PyEZs enkelhed, som ikke kræver ekspertviden om Junos OS.

Regler for godkendelse af merge-requests

Revision af tilgængelige ipv4-undernetværk i virksomheden. Kriteriet for, at et undernet er ledigt, er fraværet af en post om det i ruterne på switchen, der fungerer som router under Junos OS.

Implementering

Python + Junos PyEZ, selvom der var en fristelse til at gøre det via paramiko og ssh.exec_command, som følge heraf skal der konfigureres netconf-protokollen på det undersøgte udstyr. Netconf arbejder med udstyr via remote procedure call (RPC) og bruger XML til at levere de modtagne oplysninger i det betragtede eksempel.

Installationen af den aktuelle version af Junos PyEZ fra PyPI udføres med følgende kommando:

$ pip install junos-eznc

Man kan også installere fra hovedgrenen af projektet på GitHub med følgende kommando:

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

Og endnu en mulighed gennem

$ pip install -r requirements.txt 

denne kommando vil installere de biblioteker, der mangler i systemet og som er nødvendige for at fungere. I min version requirements.txt er der kun to, versionerne er angivet som de nyeste på tidspunktet for skrivningen af scriptet:

junos-eznc
netaddr

Scriptet tager som standard navnet på den aktuelle bruger i systemet, man kan logge ind med navnet på en anden bruger ved at bruge nøglen show_route.py -u getpass.getpass accepterer password fra stdin, så passwordet forbliver ikke i systemet. For at oprette forbindelse til udstyret skal man også indtaste dets hostname eller ip-adresse efter anmodning. Alle nødvendige oplysninger til autentifikation på enheden er blevet indhentet.

Junos PyEZ understøtter oprettelse af forbindelse til udstyr, der kører Junos OS ved hjælp af konsol, telnet eller netconf gennem ssh. Artiklen omhandler den sidste mulighed.

For at oprette forbindelse til udstyret bruges Device-klassen fra jnpr.junos-modulet

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

Anmodningen om alle kendte ruter til routeren udføres via fjernprocedureopkald eller procedureopkald, alt efter hvad der er nemmest for en.

data = dev.rpc.get_route_information()

En tilsvarende kommando på Junos OS

user@router> show route | display xml

Ved at tilføje rpc i slutningen af kommandoen, får vi forespørgsels-tagget og kan matche det med navnet på RPC-metoden, på denne måde kan vi finde andre interessante navne. Det er værd at bemærke, at syntaksen for at skrive forespørgselstagget adskiller sig fra navnet på metoden, idet bindestreger skal erstattes med understregninger.

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

Resten blev indkapslet i en while-løkke, så vi ikke behøver at forespørge routeren igen, hvis vi skal tjekke i et andet subnet, som routeren allerede kender. Det skal nævnes, at routeren, jeg forespørger på, kun kender ruter via OSPF, så for grænserouteren er det bedre at ændre forespørgslen lidt for at reducere scriptets køretid.

data = dev.rpc.get_ospf_route_information()

Lad os nu se nærmere på indholdet af while-løkken.

I starten vil brugeren blive bedt om at indtaste et subnet med maske og ikke mere end tre oktetter fra netværket i det samme subnet; dette er nødvendigt for at bestemme søgeområdet. Jeg er ikke meget tilfreds med den måde at angive kriterier og søgeområde på, men indtil videre har jeg ikke fundet nogen bedre løsning. Herefter vælger jeg de interessante subnets fra den modtagne liste over subnets route_list ved hjælp af en variabel, der indeholder ikke mere end tre oktetter.

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

Gennem IPNetwork fra netaddr-modulet får jeg subnets i form af en liste over ipv4 adresser.

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

Ved at bruge IPNetwork fra det subnet, som brugeren har indtastet med maske, får jeg rækkevidden af adresser og danner en liste over alle adresser inden for denne rækkevidde for at sammenligne med listen over optagne adresser.

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

Den opnåede liste over ledige adresser viser jeg som subnets.

print(netaddr.IPSet(freeip))

Nedenfor er skriptet fuldt ud, testet på switchene, der anvendes som routere, modellerne 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

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster