關於使用 Junos PyEZ 的文章 - “Python 微框架使您能夠管理和自動化運行 Junos OS 的設備”自動化和管理,我們喜歡的一切。 編寫本文中描述的腳本有幾個目標 - 學習 Python 和自動化任務,以收集資訊或更改執行 Junos OS 的裝置上的配置。 選擇 Python + Junos PyEZ 的這個特定組合是因為 Python 程式語言的入門門檻較低,而 Junos PyEZ 函式庫易於使用,不需要 Junos OS 的專業知識。
任務
審計屬於公司的免費 ipv4 子網路。 子網路空閒的標準是充當執行 Junos OS 的路由器的交換器上的路由中不存在有關該子網路的條目。
履行
Python + Junos PyEZ,儘管有透過 paramiko 和 ssh.exec_command 來完成的誘惑,
使用以下命令從 PyPI 安裝目前版本的 Junos PyEZ:
$ 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 鍵以其他使用者的名稱登入getpass.getpass 從標準輸入取得密碼,因此密碼不會保留在系統中。 若要連接到設備,您還需要在出現提示時輸入其主機名稱或 IP 位址。 已收到設備授權所需的所有資料。
Junos PyEZ 支援透過 ssh 使用控制台、telnet 或 netconf 連接到執行 Junos OS 的裝置。 本文討論了後一種選擇。
若要連接到設備,請使用 jnpr.junos 模組的 Device 類
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 迴圈的內容
一開始,使用者會被要求輸入一個帶有掩碼的子網,並且來自同一子網路的網路不超過三個八位元組,這是設定搜尋範圍所必需的。 我不太喜歡這種指定條件和搜尋範圍的實現,但到目前為止我還沒有找到更好的解決方案。 接下來,從生成的子網路徑列表中,使用包含不超過三個八位元組的變量,選擇我感興趣的子網
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
來源: www.habr.com