مقال عن العمل مع Junos PyEZ - "Python microframework الذي يمكّنك من إدارة وأتمتة الأجهزة التي تعمل بنظام Junos OS" أتمتة وإدارة، كل ما نحبه. كان لكتابة البرنامج النصي الموصوف في هذه المقالة عدة أهداف - تعلم لغة Python وأتمتة المهام لجمع المعلومات أو تغيير التكوينات على الأجهزة التي تعمل بنظام Junos OS. تم اختيار هذه المجموعة المحددة من Python + Junos PyEZ بسبب انخفاض حاجز الدخول إلى لغة برمجة Python وسهولة استخدام مكتبة Junos PyEZ، والتي لا تتطلب معرفة متخصصة بنظام التشغيل Junos.
مهمة
تدقيق شبكات فرعية ipv4 المجانية التابعة للشركة. المعيار الذي يجعل الشبكة الفرعية مجانية هو عدم وجود إدخال عنها في المسارات الموجودة على المحول الذي يعمل كموجه يعمل بنظام Junos OS.
تطبيق
Python + Junos PyEZ، على الرغم من وجود إغراء للقيام بذلك من خلال paramiko وssh.exec_command،
يتم تثبيت الإصدار الحالي من 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 يأخذ getpass.getpass كلمة المرور من stdin لذلك لن تبقى كلمة المرور في النظام. للاتصال بالجهاز، ستحتاج أيضًا إلى إدخال اسم المضيف أو عنوان IP الخاص به عندما يُطلب منك ذلك. تم استلام كافة البيانات اللازمة للحصول على ترخيص على الجهاز.
يدعم Junos PyEZ الاتصال بالأجهزة التي تعمل بنظام Junos OS باستخدام وحدة التحكم أو telnet أو netconf عبر ssh. تتناول المقالة الخيار الأخير.
للاتصال بالمعدات، استخدم فئة الجهاز الخاصة بوحدة 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()")
تم لف باقي الجزء في حلقة زمنية، حتى لا يتم تكرار الطلب إلى جهاز التوجيه إذا كان من الضروري التحقق من شبكة فرعية أخرى من تلك التي يعرفها جهاز التوجيه بالفعل. تجدر الإشارة إلى أن جهاز التوجيه الذي أقوم بتقديم الطلب عليه يعرف المسارات فقط من خلال 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
المصدر: www.habr.com