بايثون 3. أتمتة تكوين معدات الشبكة متعددة البائعين

مقدمة


يوم جيد للجميع!

أنا أعمل كمهندس شبكات لمشغل اتصالات كبير ، وتحت تحكمي هناك حديقة حيوانات كاملة لمعدات الشبكة المختلفة ، لكننا سنتحدث عن مفاتيح الوصول.

هذه المقالة ليست دليلًا للعمل ، فهي ليست الحل الوحيد ومن الواضح أنها لا تتظاهر بكونها نصًا ترشيحيًا للسنة ، لكني أريد مشاركة هذا الخلق ، وربما يكون مفيدًا لشخص ما.

ستقدم المقالة مجموعة من التعليمات البرمجية تحت المفسد ، وأدناه سيكون وصفًا مع قصاصات وتفسيرات لسبب ذلك وما هو الغرض منه.

التحدي


استخدم python3 على وجه التحديد. يجب أن يكون البرنامج النصي قادرًا على الوصول إلى المفاتيح من القائمة ، وتحديد نوع البائع ، وإعطاء الأمر المطلوب ، والتسجيل.

في الواقع كيف جئت إلى هذا


في مواجهة مشكلة صغيرة في تغيير التكوين على عدد كبير من المحولات ، سأقوم على الفور بالحجز حول نظام الإدارة المركزي لمعدات الشبكة لدينا ، كما يتوفر الكثير من التطورات من زملائي في شكل نصوص لتسهيل العمل اليدوي ، بشكل أساسي bash ، perl.

ولكن بالنسبة لي كان من المهم القيام بشيء مختلف ، لأنه لقد بدأت في تعلم python مؤخرًا وأحتاج إلى ترقية مهاراتي في البرمجة ، ويجب أن تبدو أداتي كمطرقة (سهلة الاستخدام وسهلة الصيانة). إذا كانت الفائدة لا تزال قائمة فأنا أطلب قطة.

Googling وعدم العثور على الحل المناسب (كما لو كان في المنتدى طرح هذا السؤال ، ولكن كل شيء كان خاطئًا هناك) ، قررت أن أبدأ في كتابة النص الخاص بي.

لدينا المفاتيح التالية:

  • Raisecom
  • مراجعة Qtech. 1.0
  • مراجعة Qtech. 2.0 (الفرق في بناء الجملة)
  • التكس
  • د الارتباط
  • Spawn Frankenstein التبديل مع كمامة من Qtech rev 1.0 ، والحديد من Raisecom سنطلق عليه ROS

أولاً ، استيراد المكتبات المطلوبة:

import telnetlib import time import os import sys import getpass import pexpect from telnetlib import Telnet import datetime import subprocess 

مبدئيًا ، نقوم بوصف وظيفة تعريف البائع ، لأن قررت استخدام طريقتين:

1) افترض نوع البائع (عند الدعوة لإدخال تسجيل الدخول) كما لاحظت أنه مختلف للجميع: Qtech (تسجيل الدخول :) ، Raisecom و ROS (تسجيل الدخول :) ، Eltex (اسم المستخدم :) ، D-link (اسم المستخدم)).

2) بعد تسجيل الدخول - تأكد من أن العنصر الأول قد اكتمل بدون خطأ ، ولتحديد أفضل للمفتاح الذي نعمل عليه.

الوظيفة
 def who_is(): #   global ver_status global sab_versus global versus sab_versus='' ver_status='' versus='' #  a = 'Serial No.:1405' # #qtech rev1 d = 'Command: show switch' # #d-link f = 'Raisecom Operating System Software' # #raisecom h = 'QOS' # #raisecom-qtech j = 'MES1124M' # #eltex k = 'eltex' # #eltex n = 'Build245' #qtech2.0 parser=open('servers_&_log/ver.txt', 'r') #  for line in parser.readlines(): line1 = line.find(a) line4 = line.find(d) line5 = line.find(f) line6 = line.find(h) line7 = line.find(j) line8 = line.find(k) line10 = line.find(n) if line1 != -1: ver_status='qtech_rev_1.0' if line4 != -1: ver_status='d-link' if line5 != -1: ver_status='raisecom' if line6 != -1: ver_status='raisecom-qtech' sab_versus=1 if line7 !=-1: ver_status='eltex' if line8 !=-1: ver_status='eltex' if line10 != -1: ver_status = 'qtech_rev_2.0' time.sleep(0.1) parser.close() os.remove('servers_&_log/ver.txt') return ver_status,sab_versus 


الوظيفة كلها تحت المفسد. نعلن المتغيرات العالمية التي ستكون مرئية للنص برمته:

 global ver_status global sab_versus global versus 

تخزن المتغيرات a ، d ، f ، h ، j ، k ، n الكلمات الرئيسية التي سنحدد من خلالها نموذج المحول.

 a = 'Serial No.:1405' # #qtech rev1 d = 'Command: show switch' # #d-link f = 'Raisecom Operating System Software' # #raisecom h = 'QOS' # #raisecom-qtech j = 'MES1124M' # #eltex k = 'eltex' # #eltex n = 'Build245' #qtech2.0 

بعد فتح ملف ver.txt ، نقرأه سطراً بسطر ونبحث عن الإدخال بالكلمات الرئيسية ، لأنه تُرجع الدالة find () -1 إذا كانت هذه النتيجة سالبة ، وسنبني الفروع.

 parser=open('servers_&_log/ver.txt', 'r') #  for line in parser.readlines(): line1 = line.find(a) line4 = line.find(d) line5 = line.find(f) line6 = line.find(h) line7 = line.find(j) line8 = line.find(k) line10 = line.find(n) if line1 != -1: ver_status='qtech_rev_1.0' 

...

أعطي مثالا على جزء من الرمز ، والباقي تحت المفسد أعلاه.

سيتم وصف محتويات هذا الملف أدناه. بعد كل التلاعبات وتحديد البائع ، احذف ملف ver.txt.

الإعلان عن المتغيرات الرئيسية ، جسم الحلقة الرئيسية
 user='user' password='password' komm=open('servers_&_log/komm.txt') log=open('servers_&_log/log.txt','a') ######### counter_komm=0 counter_dlink=0 counter_qtech=0 counter_eltex=0 counter_raisecom=0 counter_ROS=0 counter_qtech1_0=0 counter_qtech2_0=0 ########## for host in komm.readlines(): print('connect....',host) vend = '' response = os.system('ping -c 1 ' + host) verinfo = open('servers_&_log/ver.txt', 'w') ver_status = '' sab_versus = '' if response == 0: telnet = pexpect.spawn('telnet ' + host,timeout=40) vend = telnet.expect(['login:', 'Login:', 'User Name:', 'Username']) telnet.close() tn = Telnet(host.replace('\n', ''), 23,30) try: print('Ok'+'\n') tn.read_until(b':') tn.write((user +'\n').encode('ascii')) tn.read_until(b':') tn.write((password + '\n').encode('ascii')) time.sleep(3) tn.read_until(b'#',timeout=20) except: print('connection refused' + '\n') f = open('servers_&_log/log.txt', 'a') print(host, 'connection refused', file=log) print('#' * 100, host, file=log) ###   ######################################################### if vend == 0:#    Qtech tn.write(('show ver' + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=verinfo) verinfo.close() who_is() ... 


قررت عدم الإزعاج وتعيين المتغيرات باستخدام اسم المستخدم وكلمة المرور في الجسم ، وأنا أعلم أنه ليس أمانًا ، فأنا أعمل على ذلك.

افتح ملف السجلات وقائمة المفاتيح

 komm=open('servers_&_log/komm.txt') log=open('servers_&_log/log.txt','a') 

بعد استخدام حلقة for ، اقرأ السطر بعنوان IP الخاص بالمفتاح

 for host in komm.readlines(): print('connect....',host) vend = '' 

نتحقق من توافر

 response = os.system('ping -c 1 ' + host) 

إذا كان من الممكن الوصول إليه باستخدام مكتبة pexpect ، فنحن نحاول الاتصال عبر telnet هنا في هذا التكرار ويحدث أول فحص في الدعوة ، والذي كتبت عنه في البداية.

 if response == 0: telnet = pexpect.spawn('telnet ' + host,timeout=40) vend = telnet.expect(['login:', 'Login:', 'User Name:', 'Username']) telnet.close() tn = Telnet(host.replace('\n', ''), 23,30) 

سيحصل متغير البائع على قيمة من 0 إلى 3 شاملة ، وبناءً على مطالبة تسجيل الدخول التي يراها ، سيتم تشكيل فرع آخر.

من هذا الجزء من التعليمات البرمجية ، قد يلاحظ القارئ اليقظ أنني أقوم بإجراء اتصال بالمفتاح وأغلق الاتصال على الفور ، وهذا ليس بدون سبب. حاولت استخدام مكتبة telnetlib فقط ، ولكن في الاختبار الأول ، توقف البرنامج النصي عن العمل بشكل دوري وسقط بشكل مؤقت ، وهذا العكاز يساعد كثيرًا.

بعد إغلاق الاتصال ، نقوم بإعادة الاتصال فقط باستخدام مكتبة telnetlib بالفعل.

من أجل تجنب الوقوع في الأخطاء ، قمنا بالفعل بالتحقق أعلاه من أن المفتاح يمكن الوصول إليه ، واستبعاد انقطاع البرنامج النصي أثناء التشغيل بسبب مفتاح خامل واحد ، لف كل شيء في محاولة باستثناء الكتلة.

كانت هناك حالات متكررة عندما لم يسمح أحد لنفسه بالدخول من بين 100 مفتاح.

 try: print('Ok'+'\n') tn.read_until(b':') tn.write((user +'\n').encode('ascii')) tn.read_until(b':') tn.write((password + '\n').encode('ascii')) time.sleep(3) tn.read_until(b'#',timeout=20) except: print('connection refused' + '\n') f = open('servers_&_log/log.txt', 'a') print(host, 'connection refused', file=log) print('#' * 100, host, file=log) 

...
إذا كان كل شيء على ما يرام واتصلنا ، فعلينا إدخال اسم مستخدم وكلمة مرور ،
نحن نعلم على وجه اليقين أن أي موجه للقولون يستخدم نقطتين.

لذلك نحن في انتظاره

 tn.read_until(b':') 

بعد دخولنا تسجيل الدخول

 tn.write((user +'\n').encode('ascii')) 

في انتظار القولون من كلمة المرور

 tn.read_until(b':') 

أدخل كلمة المرور

 tn.write((password + '\n').encode('ascii')) 

وننتظر 3 ثوان (فترة راحة ، وإلا قمنا بالكثير من العمل)

 time.sleep(3) 

بعد انتظار الدعوة

 tn.read_until(b'#',timeout=20) 

هنا في هذه المرحلة ، ننتقل إلى المستوى الثاني لفحص البائع.

 if vend == 0:#    Qtech tn.write(('show ver' + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=verinfo) verinfo.close() who_is() 

لأن افترضنا أننا وصلنا إلى Qtech ، وإذا قرأت بعناية ، فهناك في حديقة الحيوانات لدينا إصداران من qtech يختلفان في بناء الجملة ، ما زلنا بحاجة إلى المصالحة.

لذلك ، نعطي الأمر show ver ، ونضع جميع المخرجات في ملف ver.txt
واستدعاء الإجراء who_is () ، الذي وصفته أعلاه. فريق المعرض هو عالمي لجميع Qtech ، Raisecom ، Eltex ،

لسوء الحظ ، لا يفهم D-link ويحتاج إلى إظهار إظهار swich ، لكننا أذكياء ولم نذهب سدى بتكرار مع التعريف المفترض للبائع.

 if vend == 3:#   D-link tn.write(('show sw' + '\n').encode('ascii')) tn.write(('a' + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=verinfo) verinfo.close() who_is() 

لذا على الفور ، بعد ملاحظة صغيرة بعد الدخول إلى عرض swich ، يعرض المفتاح معلومات غير مكتملة وينتظر أن يضغط المستخدم على أي مفتاح لمزيد من الإخراج ، وبالتالي نرسل الحرف "a" لعرض المعلومات الكاملة.

 tn.write(('a' + '\n').encode('ascii')) 

لتجنب ذلك ، يمكنك إيقاف الحشو

هذا هو المكان الذي ينتهي فيه التحقق من المورد وباحتمال 99٪ يمكننا أن نفترض أننا قد حددنا بشكل صحيح نموذج التبديل ويمكننا متابعة التكوين.

لكل مفتاح ، لدينا ملف منفصل مع مجموعة من الأوامر.

كتلة التكوين
 ... elif ver_status == 'qtech_rev_1.0': tn.write(('show ver' + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=log) counter_qtech1_0+=1 komand_qtech1_0=open('servers_&_log/komand_qtech_ver1.0.txt') for kommand in komand_qtech1_0.readlines(): tn.write((kommand.replace('\n', '') + '\n').encode('ascii')) tn.write(('exit' + '\n').encode('ascii')) print(tn.read_all().decode('ascii'), file=log) print('   qtech1.0') print('Qtech rev1.0 ' + host, file=log) print('#' * 100, file=log) ################################################################################ elif ver_status == 'qtech_rev_2.0': tn.write(('show ver' + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=log) counter_qtech2_0+=1 komand_qtech2_0=open('servers_&_log/komand_qtech_ver2.0.txt') print('   qtech2.0') for kommand in komand_qtech2_0.readlines(): tn.write((kommand.replace('\n', '') + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=log) print('Qtech rev2.0 ' + host, file=log) print('#' * 100, file=log) ... 


بعد عمل الدالة وإرجاع متغير ver_status ، يمكننا مواصلة العمل مع التفرع ، لأنه نحن نعرف بالضبط أي مفتاح موجود حاليًا على الخط.
بادئ ذي بدء ، نعطي المفتاح الأمر show ver ونكتب الإخراج إلى السجل (حول d-link ، تذكر أننا نعطيه الأمر sh sw)

 tn.write(('show ver' + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=log) 

تأكد من الاحتفاظ بالعدادات لتحديد عدم المطابقة.
 counter_qtech1_0+=1 

نفتح ملف بأوامر
 komand_qtech1_0=open('servers_&_log/komand_qtech_ver1.0.txt') 

يجب أن يكون ترتيب الأوامر في الملف هو نفسه الذي سيدخله المسؤول يدويًا

مثال:

conf
vlan 2525
name SPD
int ethe 1/1
sw mode access
sw acc vl 2525
exit
exit
save
y

ثم كل شيء حسب السيناريو - نقرأ الملف حتى تنتهي الأسطر ونقوم بتنفيذها

 for kommand in komand_qtech1_0.readlines(): tn.write((kommand.replace('\n', '') + '\n').encode('ascii')) 

بعد الخروج من الحلقة ، نخبر خروج المفتاح ونقرأ جميع المخرجات إلى ملف ، وهكذا نفعل فقط مع qtech1.0 ، لأن في بعض الأحيان يتمسك البرنامج النصي تحسبًا لشيء ما وهو مع هذا التبديل ، حتى لا تثير ضجة ، بدا لي هذا الحل أكثر أناقة.

بعد تكوين المفتاح ، نقوم بزيادة العداد الإجمالي بمقدار واحد.

 counter_komm+=1 

ونبدأ من جديد ، نقرأ السطر التالي من الملف بالمفاتيح ، ونحدد النموذج ، ونقوم بالتكوين.

بعد الخروج من الدورة الرئيسية ، تحتاج إلى عمل ملخص للعمل المنجز ،
في نهاية السجل ، ندخل جميع النماذج التي قمنا بمعالجتها والتاريخ إلزامي ، حسنًا ، كيف يمكن أن يكون بدونه.

 print('\n\n\n : ', counter_komm,file=log) print('\n\nD-link:', counter_dlink,'\nQtech ver1.0:', counter_qtech1_0,'\nROS:', counter_ROS,'\nRaisecom:',counter_raisecom,'\nEltex:', counter_eltex,'\nQtech ver2.0 :', counter_qtech2_0,file=log) print('\n: ', datetime.datetime.now().isoformat(),'\n', '#'*100,'\n\n\n\n\n',file=log) verinfo.close() log.close() 

تمت معالجة هذا البرنامج النصي بشكل متكرر ولن تتوقف العملية عند هذا الحد.
شكرا لكم جميعا على اهتمامكم. النقد البناء مرحب به.

جميع التعليمات البرمجية تحت المفسد.

كود المصدر
 #!/usr/bin/python3 #22/06/2017 17:17 import telnetlib import time import os import sys import getpass import pexpect from telnetlib import Telnet import datetime import subprocess def who_is(): #     ,      . global ver_status global sab_versus global versus sab_versus='' ver_status='' versus='' a = 'Serial No.:1405' # #qtech rev1 #b = 'Serial No.:3922' # #qtech rev2 #c = 'Serial No.:5436' # #qtech rev2 #l = 'Serial No.:16101' # #qtech rev2 d = 'Command: show switch' # #d-link f = 'Raisecom Operating System Software' # #raisecom h = 'QOS' # #raisecom-qtech j = 'MES1124M' # #eltex k = 'eltex' # #eltex n = 'Build245' #qtech2.0 parser=open('servers_&_log/ver.txt', 'r') for line in parser.readlines(): line1 = line.find(a) #line2 = line.find(b) #line3 = line.find(c) line4 = line.find(d) line5 = line.find(f) line6 = line.find(h) line7 = line.find(j) line8 = line.find(k) #line9 = line.find(l) line10 = line.find(n) if line1 != -1: ver_status='qtech_rev_1.0' #if line2 != -1 or line3 != -1 or line9 !=-1: #ver_status='qtech_rev_2.0' if line4 != -1: ver_status='d-link' if line5 != -1: ver_status='raisecom' if line6 != -1: ver_status='raisecom-qtech' sab_versus=1 if line7 !=-1: ver_status='eltex' if line8 !=-1: ver_status='eltex' if line10 != -1: ver_status = 'qtech_rev_2.0' time.sleep(0.1) parser.close() os.remove('servers_&_log/ver.txt') return ver_status,sab_versus user='user' password='password' komm=open('servers_&_log/komm.txt') log=open('servers_&_log/log.txt','a') counter_komm=0 counter_dlink=0 counter_qtech=0 counter_eltex=0 counter_raisecom=0 counter_ROS=0 # counter_qtech1_0=0 counter_qtech2_0=0 for host in komm.readlines(): print('connect....',host) vend = '' #tn = Telnet(host.replace('\n', ''), 23, 20) response = os.system('ping -c 1 ' + host) verinfo = open('servers_&_log/ver.txt', 'w') ver_status = '' sab_versus = '' if response == 0: telnet = pexpect.spawn('telnet ' + host,timeout=40) vend = telnet.expect(['login:', 'Login:', 'User Name:', 'Username']) telnet.close() tn = Telnet(host.replace('\n', ''), 23,30) try: print('Ok'+'\n') tn.read_until(b':') tn.write((user +'\n').encode('ascii')) tn.read_until(b':') tn.write((password + '\n').encode('ascii')) time.sleep(3) tn.read_until(b'#',timeout=20) except: print('connection refused' + '\n') f = open('servers_&_log/log.txt', 'a') print(host, 'connection refused', file=log) print('#' * 100, host, file=log) ###   ################################################################################ if vend == 0:#    Qtech tn.write(('show ver' + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=verinfo) verinfo.close() who_is() ################################################################################ if vend == 1: #   Raisecom,Raisecom-Qtech tn.write(('show ver' + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=verinfo) verinfo.close() who_is() ################################################################################ if vend == 2:#   Eltex tn.write(('show system' + '\n').encode('ascii')) tn.write(('show ver' + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=verinfo) verinfo.close() who_is() ################################################################################ if vend == 3:#   D-link tn.write(('show sw' + '\n').encode('ascii')) tn.write(('a' + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=verinfo) verinfo.close() who_is() # ###  # ################################################################################ if ver_status == 'd-link': tn.read_until(b'#', timeout=20) tn.write(('show sw' + '\n').encode('ascii')) tn.write(('a' + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=log) print('D-link ' + host,file=log) print('#'*100,file=log) counter_dlink+=1 ################################################################################ elif ver_status == 'qtech_rev_1.0': tn.write(('show ver' + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=log) counter_qtech1_0+=1 komand_qtech1_0=open('servers_&_log/komand_qtech_ver1.0.txt') for kommand in komand_qtech1_0.readlines(): tn.write((kommand.replace('\n', '') + '\n').encode('ascii')) #print((tn.read_until(b'#').decode('ascii')), file=log) tn.write(('exit' + '\n').encode('ascii')) print(tn.read_all().decode('ascii'), file=log) print('Qtech rev1.0 ' + host, file=log) print('#' * 100, file=log) ################################################################################ elif ver_status == 'qtech_rev_2.0': tn.write(('show ver' + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=log) counter_qtech2_0+=1 komand_qtech2_0=open('servers_&_log/komand_qtech_ver2.0.txt') for kommand in komand_qtech2_0.readlines(): tn.write((kommand.replace('\n', '') + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=log) time.sleep(1) print('Qtech rev2.0 ' + host, file=log) print('#' * 100, file=log) ################################################################################ elif ver_status == 'raisecom-qtech': tn.write(('show ver' + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=log) raisecom_command = open('servers_&_log/komand_raisecom.txt') for komand in raisecom_command.readlines(): tn.write((komand.replace('\n', '') + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=log) print('ROS '+ host,file=log) print('#'*100,file=log) counter_ROS+=1 ################################################################################ elif ver_status == 'raisecom': tn.write(('show ver' + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=log) counter_raisecom+=1 raisecom_command = open('servers_&_log/komand_raisecom.txt') for komand in raisecom_command.readlines(): tn.write((komand.replace('\n', '') + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=log) print(host, ':', 'RAISECOM', file=log) print('#' * 100, host, file=log) ################################################################################ elif ver_status == 'eltex': tn.write(('show ver' + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=log) eltex_command=open('servers_&_log/komand_eltex.txt') for komand in eltex_command.readlines(): tn.write((komand.replace('\n', '') + '\n').encode('ascii')) print((tn.read_until(b'#').decode('ascii')), file=log) print('Eltex ' + host, file=log) print('#' * 100, file=log) counter_eltex+=1 else: print('no ping') counter_komm+=1 print('\n\n\n : ', counter_komm,file=log) print('\n\nD-link:', counter_dlink,'\nQtech ver1.0:', counter_qtech1_0,'\nROS:', counter_ROS,'\nRaisecom:',counter_raisecom,'\nEltex:', counter_eltex,'\nQtech ver2.0 :', counter_qtech2_0,file=log) print('\n: ', datetime.datetime.now().isoformat(),'\n', '#'*100,'\n\n\n\n\n',file=log) verinfo.close() log.close() 

Source: https://habr.com/ru/post/ar415453/


All Articles