Artikel om arbete med Junos PyEZ â "Python-mikrahĂ€ftet som möjliggör att hantera och automatisera enheter som kör Junos OS" automatisering och hantering, precis som vi Ă€lskar. Syftet med att skriva skriptet som beskrivs i denna artikel var att studera Python och automatisera uppgifter för att samla in information eller Ă€ndra konfigurationer pĂ„ utrustning som kör Junos OS. Valet av denna kombination Python + Junos PyEZ gjordes pĂ„ grund av den lĂ„ga tröskeln för att komma in i programmeringssprĂ„ket Python och enkelheten i att anvĂ€nda biblioteken Junos PyEZ, som inte krĂ€ver expertkunskaper i Junos OS.
Uppgift
Revision av lediga IPv4-subnÀt som tillhör företaget. Kriteriet för att ett subnÀt ska vara ledigt Àr att det inte finns nÄgon post om det i routingen pÄ switchen som fungerar som router som kör Junos OS.
Implementering
Python + Junos PyEZ, Àven om det fanns en frestelse att göra det via paramiko och ssh.exec_command, sÄ kommer det dÀrför att krÀvas att den utrustning som frÄgas har nÀtverksstyrprotokollet netconf konfigurerat. Netconf fungerar med utrustning genom att anvÀnda fjÀrranropningsprocedurer (remote procedure call, RPC) och anvÀnder XML i det hÀr exemplet för att tillhandahÄlla den mottagna informationen.
Installation av den nuvarande versionen av Junos PyEZ frÄn PyPI görs med följande kommando:
$ pip install junos-ezncDet kan ocksÄ installeras frÄn huvudgrenen av projektet pÄ GitHub med följande kommando:
$ pip install git+https://github.com/Juniper/py-junos-eznc.gitOch ytterligare ett alternativ genom
$ pip install -r requirements.txt detta kommando installerar de bibliotek som saknas i systemet som Àr nödvÀndiga för att fungera. I min version requirements.txt Àr det totalt tvÄ, versionerna anges sist pÄ skrivandet av skriptet:
junos-eznc
netaddrSkriptet tar som standard det aktuella anvÀndarnamnet i systemet, för att logga in som en annan anvÀndare kan du anvÀnda nyckeln show_route.py -u getpass.getpass tar emot lösenordet frÄn stdin sÄ att lösenordet inte stannar kvar i systemet. För att ansluta till utrustningen kommer det ocksÄ att behöva ange dess hostname eller IP-adress pÄ begÀran. All information som behövs för autentisering pÄ enheten har erhÄllits.
Junos PyEZ stöder anslutning till utrustning som kör Junos OS via konsol, telnet eller netconf via ssh. I artikeln diskuteras det senaste alternativet.
För att ansluta till utrustningen anvÀnds klassen Device i modulen jnpr.junos
med jnpr.junos.Device(host=router,
user=args.name,
passwd=password) som dev:Ett anrop görs för att hÀmta alla kÀnda rutter till routern via en RPC eller ett avlÀgset funktionsanrop, vad som helst som passar bÀst.
data = dev.rpc.get_route_information()Motsvarande kommando i Junos OS
user@router> show route | display xmlGenom att lÀgga till rpc i slutet av kommandot fÄr vi taggen för begÀran och kan matcha den med namnet pÄ RPC-metoden, pÄ detta sÀtt kan vi Àven fÄ andra intressanta namn. Det bör noteras att syntaxen för att skriva begÀrstagen skiljer sig frÄn metodens namn, nÀmligen att vi ska byta ut bindestrecken mot understreck.
user@router> show route | display xml rpc
route_list = data.xpath("//rt-destination/text()")Resten av koden har jag lagt i en while-loop för att inte behöva göra en ny begÀran till routern, om jag behöver kontrollera en annan subnet som routern redan kÀnner till. Det Àr vÀrt att nÀmna att routern jag frÄgar kÀnner endast till rutter via OSPF, dÀrför Àr det bÀttre att Àndra begÀran nÄgot för att minska scriptets körningstid.
data = dev.rpc.get_ospf_route_information()Nu ska vi titta pÄ innehÄllet i while-loopen
I början kommer anvÀndaren att uppmanas att ange en subnet med mask och högst tre oktetter frÄn det nÀtverket, vilket Àr nödvÀndigt för att ange sökomrÄdet. Jag gillar inte riktigt denna implementering av kriteriet och sökomrÄdet, men jag har Ànnu inte hittat en bÀttre lösning. Sedan frÄn den erhÄllna listan av subnet routes_list vÀljer jag de intressanta subnÀt med hjÀlp av en variabel som innehÄller högst tre oktetter.
tmp = re.search(r'^%sS*' % subnet_search, route_list[i])Via IPNetwork, modulen netaddr, fÄr jag subnÀt i form av en lista med ipv4-adresser.
range_subnet = netaddr.IPNetwork(tmp.group(0))Genom att anvÀnda IPNetwork frÄn det nÀtverk som anvÀndaren angav med mask fÄr jag en adressintervall och formar en lista med alla adresser inom det intervallet för att jÀmföra med listan med upptagna adresser.
for i in set(net_list).difference(set(busyip)):
freeip.append(i)Den erhÄllna listan med lediga adresser skriver jag ut i form av subnÀt.
print(netaddr.IPSet(freeip))Nedan finns hela skriptet, testat pÄ switchar som anvÀnds som routrar, modeller 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
KĂ€lla: habr.com
