Python3. Otomatisasi konfigurasi peralatan jaringan multi-vendor

Kata Pengantar


Hari baik untuk semua!

Saya bekerja sebagai insinyur jaringan untuk operator telekomunikasi besar, dan di bawah kendali saya ada banyak kebun binatang dari berbagai peralatan jaringan, tetapi kita akan berbicara tentang sakelar akses.

Artikel ini bukan panduan untuk bertindak, ini bukan satu-satunya solusi dan jelas tidak berpura-pura menjadi skrip nominasi tahun ini, tapi saya ingin membagikan kreasi ini, dan mungkin itu akan bermanfaat bagi seseorang.

Artikel ini akan memberikan blok kode di bawah spoiler, dan di bawahnya akan ada deskripsi dengan kliping dan penjelasan mengapa begitu dan untuk apa.

Tantangan


Gunakan python3 secara khusus. Script harus bisa masuk ke switch dari daftar, menentukan jenis vendor, memberikan perintah yang diperlukan, log.

Sebenarnya bagaimana saya sampai pada ini


Dihadapkan dengan masalah kecil mengubah konfigurasi pada sejumlah besar switch, saya akan segera melakukan reservasi tentang sistem administrasi terpusat untuk peralatan jaringan yang kami miliki, banyak perkembangan rekan-rekan saya dalam bentuk skrip untuk memfasilitasi pekerjaan manual juga tersedia, terutama bash, perl.

Tetapi bagi saya itu penting untuk melakukan sesuatu yang berbeda, karena Saya mulai belajar python baru-baru ini dan saya perlu meningkatkan keterampilan saya dalam pemrograman, dan alat saya akan terlihat seperti palu (mudah digunakan, dan mudah dirawat). Jika minat masih ada maka saya minta kucing.

Googling dan tidak menemukan solusi yang tepat (seolah-olah di forum pertanyaan ini dimunculkan, tetapi semuanya salah di sana), saya memutuskan untuk mulai menulis skrip saya sendiri.

Kami memiliki sakelar berikut:

  • Raisecom
  • Qtech rev. 1.0
  • Qtech rev. 2.0 (perbedaan dalam sintaks)
  • Eltex
  • D-link
  • Spawn Frankenstein beralih dengan moncong dari Qtech rev 1.0, dan besi dari Raisecom kita akan menyebutnya ROS

Pertama, impor perpustakaan yang diperlukan:

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

Awalnya, kami menjelaskan fungsi definisi vendor, karena memutuskan untuk menggunakan dua metode:

1) Anggap vendor seperti apa (atas undangan untuk memasukkan login) seperti yang saya perhatikan berbeda untuk semua orang: Qtech (login :), Raisecom dan ROS (Login :), Eltex (Nama Pengguna :), D-link (Nama Pengguna)).

2) setelah masuk - pastikan bahwa item pertama selesai tanpa kesalahan, dan untuk identifikasi yang lebih baik dari switch mana kita berada.

Fungsi
 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 


Seluruh fungsi berada di bawah spoiler. Kami mendeklarasikan variabel global yang akan terlihat oleh seluruh skrip:

 global ver_status global sab_versus global versus 

variabel a, d, f, h, j, k, n menyimpan kata kunci yang dengannya kita selanjutnya akan menentukan model switch.

 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 

Setelah membuka file ver.txt, kami membacanya baris demi baris dan memeriksa entri dengan kata kunci, karena fungsi find () mengembalikan -1 jika hasil ini negatif, dan kami akan membangun cabang.

 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' 

...

Saya memberikan contoh bagian dari kode, sisanya di bawah spoiler di atas.

Isi file ini akan dijelaskan di bawah ini. Setelah semua manipulasi dan mendefinisikan vendor, hapus file ver.txt.

Deklarasi variabel utama, badan loop utama
 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() ... 


Saya memutuskan untuk tidak repot dan mengatur variabel dengan login dan kata sandi di dalam tubuh, saya tahu itu bukan keamanan, saya sedang mengusahakannya.

Buka file untuk log dan daftar sakelar

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

Setelah kita menggunakan for loop, bacalah baris dengan alamat ip switch

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

Kami memeriksa ketersediaannya

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

Jika dapat diakses menggunakan pexpect library, kami berusaha untuk terhubung melalui telnet di sini pada iterasi ini dan cek pertama pada undangan terjadi, yang saya tulis di awal.

 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) 

Variabel vend akan mendapatkan nilai dari 0 hingga 3 inklusif, dan tergantung pada prompt login yang dilihatnya, cabang selanjutnya akan dibentuk.

Dari kode ini, pembaca yang memperhatikan dapat melihat bahwa saya membuat koneksi ke sakelar dan segera menutup koneksi, dan ini tidak biasa. Saya mencoba menggunakan hanya perpustakaan telnetlib, tetapi pada tes pertama, skrip secara berkala macet dan jatuh karena batas waktu, dan kruk ini sangat membantu.

Setelah menutup koneksi, kami melakukan koneksi ulang hanya menggunakan telnetlib library.

Untuk menghindari kesalahan, kami telah memeriksa di atas bahwa sakelar dapat diakses, dan mengecualikan gangguan skrip selama operasi karena satu sakelar idle, bungkus semuanya dalam percobaan kecuali blok.

Ada kasus berulang ketika dari 100 switch satu tidak membiarkan dirinya masuk.

 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) 

...
Jika semuanya baik-baik saja dan kita terhubung, maka kita perlu memasukkan nama pengguna dan kata sandi,
kami tahu pasti bahwa setiap tanda titik dua menggunakan titik dua.

Jadi kami menunggunya

 tn.read_until(b':') 

Setelah kita masuk login

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

Menunggu titik dua dari kata sandi

 tn.read_until(b':') 

Masukkan kata sandi

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

Dan kita menunggu 3 detik (jeda, kalau tidak kita telah melakukan begitu banyak pekerjaan)

 time.sleep(3) 

Setelah menunggu undangan

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

Di sini, pada tahap ini, kita beralih ke tingkat kedua untuk memeriksa vendor.

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

Karena kami berasumsi bahwa kami sampai di Qtech, dan jika Anda membaca dengan seksama, maka di kebun binatang kami ada dua versi qtech yang berbeda dalam sintaksisnya, kami masih perlu berdamai.

Oleh karena itu, kami memberikan perintah show ver, taruh semua output di file ver.txt
dan panggil prosedur who_is (), yang saya jelaskan di atas. Tim acara ver bersifat universal untuk semua Qtech, Raisecom, Eltex,

Sayangnya, D-link tidak mengerti dan dia perlu mengatakan show swich, tapi kami pintar dan tidak sia-sia memperkenalkan iterasi dengan definisi yang seharusnya dari vendor.

 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() 

Jadi segera, sebuah komentar kecil setelah memasuki show swich, switch menampilkan informasi yang tidak lengkap dan menunggu pengguna untuk menekan tombol apa saja untuk output lebih lanjut, dan oleh karena itu kami kemudian mengirim karakter "a" untuk menampilkan informasi lengkap.

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

Untuk menghindari ini, Anda dapat mematikan clipadding

Di sinilah verifikasi vendor berakhir dan dengan probabilitas 99% kami dapat mengasumsikan bahwa kami telah mengidentifikasi model switch dengan benar dan kami dapat melanjutkan dengan konfigurasi.

Untuk setiap sakelar, kami memiliki file terpisah dengan sekumpulan perintah.

Blok konfigurasi
 ... 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) ... 


Setelah fungsi berhasil dan mengembalikan variabel ver_status, kita dapat melanjutkan bekerja dengan percabangan, karena kami tahu persis saklar mana yang saat ini ada di telepon.
Pertama-tama, kita berikan perintah switch show ver dan tulis outputnya ke log (tentang d-link, ingat kita berikan itu perintah sh sw)

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

Pastikan untuk menyimpan penghitung untuk mengidentifikasi ketidaksesuaian.
 counter_qtech1_0+=1 

Kami membuka file dengan perintah
 komand_qtech1_0=open('servers_&_log/komand_qtech_ver1.0.txt') 

Urutan perintah dalam file harus sama dengan yang dimasukkan oleh administrator secara manual

Contoh:

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

Kemudian semuanya sesuai dengan skenario - kita membaca file sampai garis berakhir dan kita jalankan

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

Setelah keluar dari loop, kami memberi tahu switch untuk keluar dan membaca semua output ke file, dan kami hanya melakukannya dengan qtech1.0, karena kadang-kadang skrip bertahan untuk mengantisipasi sesuatu dan dengan saklar ini, agar tidak membuat keributan, solusi ini bagi saya tampak lebih elegan.

Setelah sakelar dikonfigurasi, kami menambah penghitung total dengan satu.

 counter_komm+=1 

Dan kita mulai dari awal, baca baris berikutnya dari file dengan sakelar, tentukan modelnya, dan buat konfigurasi.

Setelah keluar dari siklus utama, Anda perlu membuat ringkasan dari pekerjaan yang dilakukan,
di akhir log, kami memasukkan semua model yang kami proses dan tanggal wajib, yah, bagaimana bisa tanpa itu.

 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() 

Script ini telah berulang kali diproses dan prosesnya tidak akan berhenti di situ.
Terima kasih atas perhatiannya. Kritik konstruktif dipersilahkan.

Semua kode di bawah spoiler.

Kode sumber
 #!/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/id415453/


All Articles