Junos PyEZ Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ Π·Π°Π΄Π°Ρ‡ΠΈ ΠΏΠΎ поиску свободных подсСтСй ipv4

Π‘Ρ‚Π°Ρ‚ΡŒΡ ΠΎ Ρ€Π°Π±ΠΎΡ‚Π΅ с Junos PyEZ β€” β€œPython microframework that enables you to 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 

эта ΠΊΠΎΠΌΠ°Π½Π΄Π° установит ΠΎΡ‚ΡΡƒΡ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ Π² систСмС Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ для Ρ€Π°Π±ΠΎΡ‚Ρ‹. Π’ ΠΌΠΎΠ΅ΠΉ вСрсии requirements.txt ΠΈΡ… всСго Π΄Π²Π΅, вСрсии ΡƒΠΊΠ°Π·Π°Π½Ρ‹ послСдниС Π½Π° ΠΌΠΎΠΌΠ΅Π½Ρ‚ написания скрипта:

junos-eznc
netaddr

Π‘ΠΊΡ€ΠΈΠΏΡ‚ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π±Π΅Ρ€Π΅Ρ‚ имя Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Π² систСмС, Π·Π°Π»ΠΎΠ³ΠΈΠ½ΠΈΡ‚ΡŒΡΡ ΠΏΠΎΠ΄ ΠΈΠΌΠ΅Π½Π΅ΠΌ Π΄Ρ€ΡƒΠ³ΠΎΠ³ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ΠΊΠ»ΡŽΡ‡ show_route.py -u <user_name> 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

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ