SNMP + Java - pengalaman pribadi. Menulis parser file MIB

SNMP bukan protokol yang paling mudah digunakan: file MIB terlalu panjang dan membingungkan, dan OID tidak mungkin diingat. Tetapi bagaimana jika Anda perlu bekerja dengan SNMP di Jawa? Misalnya, tulis autotest untuk memeriksa API server SNMP.

Dengan coba-coba, jika ada sedikit informasi tentang topik itu, kami masih menemukan cara untuk berteman Java dan SNMP.

Dalam seri artikel ini saya akan mencoba berbagi pengalaman yang didapat dengan protokol. Artikel pertama dalam seri ini akan dikhususkan untuk implementasi parser file MIB di Jawa. Pada bagian kedua saya akan berbicara tentang menulis klien SNMP. Pada bagian ketiga, kita akan berbicara tentang contoh nyata menggunakan perpustakaan tertulis: autotests untuk memverifikasi interaksi dengan perangkat melalui SNMP.



Entri


Semuanya dimulai dengan tugas menulis swa-uji untuk memverifikasi pengoperasian perekam audio-video melalui SNMP. Yang memperumit situasinya adalah bahwa tidak banyak informasi tentang interaksi dengan SNMP di Jawa, terutama ketika menyangkut segmen Internet berbahasa Rusia. Tentu saja, orang dapat melihat ke C # atau Python. Tetapi dalam C #, situasi protokol sekitar serumit di Jawa. Ada beberapa perpustakaan yang bagus dalam python, tetapi kami sudah memiliki infrastruktur yang siap pakai untuk autotest REST API perangkat ini di Jawa.

Seperti halnya protokol komunikasi jaringan lainnya, kami membutuhkan klien SNMP untuk bekerja dengan berbagai jenis permintaan. Autotests harus dapat memverifikasi keberhasilan GET dan SET permintaan untuk parameter skalar dan tabel. Untuk tabel, itu juga diperlukan untuk dapat memverifikasi penambahan dan penghapusan catatan, jika tabel itu sendiri memungkinkan operasi ini.

Tetapi selain klien, perpustakaan harus mengandung kelas untuk bekerja dengan file MIB. Kelas ini seharusnya bisa mem-parsing file MIB untuk mendapatkan tipe data, batasan nilai yang dapat diterima, dll., Agar tidak melakukan hardcode apa yang selalu bisa berubah.

Saat mencari pustaka yang sesuai untuk Java, kami tidak menemukan pustaka tunggal yang memungkinkan bekerja dengan kedua permintaan dan file MIB. Oleh karena itu, kami memilih dua perpustakaan yang berbeda. Untuk klien, pilihan dari org.snmp4j.snmp4j (https://www.snmp4j.org) yang banyak digunakan tampaknya cukup logis, dan untuk parser file MIB, pilihan dibuat untuk pustaka net.percederberg.mibble yang tidak begitu terkenal (https: // www. mibble.org). Jika dengan snmp4j pilihannya jelas, maka mibble dipilih untuk ketersediaan dokumentasi (meskipun berbahasa Inggris) yang cukup terperinci dengan contoh-contoh. Jadi mari kita mulai.

Menulis parser file MIB


Setiap orang yang pernah melihat file MIB tahu bahwa ini menyakitkan. Mari kita coba perbaiki ini dengan bantuan parser sederhana, yang akan sangat memudahkan pencarian informasi dari file, menguranginya menjadi memanggil metode tertentu.

Parser seperti itu dapat digunakan sebagai utilitas terpisah untuk bekerja dengan file MIB atau termasuk dalam proyek lain di bawah SNMP, misalnya, ketika menulis klien SNMP atau menguji otomatisasi.

Persiapan proyek


Untuk kemudahan perakitan, kami menggunakan Maven. Bergantung pada perpustakaan add net.percederberg.mibble (https://www.mibble.org), yang akan memudahkan kita untuk bekerja dengan file MIB:

<dependency> <groupId>net.percederberg.mibble</groupId> <artifactId>mibble</artifactId> <version>2.9.3</version> </dependency> 

Karena tidak terletak di repositori pusat Maven, kami menambahkan kode berikut ke pom.xml:

 <repositories> <repository> <id>opennms</id> <name>OpenNMS</name> <url>http://repo.opennms.org/maven2/</url> </repository> </repositories> 

Jika proyek dibangun menggunakan Maven tanpa kesalahan, semuanya siap untuk bekerja. Tetap hanya untuk membuat kelas parser (sebut saja MIBParser) dan mengimpor semua yang kita butuhkan, yaitu:

 import net.percederberg.mibble.*; 

Unduh dan validasikan file MIB


Di dalam kelas hanya akan ada satu bidang - objek bertipe net.percederberg.mibble.Mib untuk menyimpan file MIB yang diunduh:

 private Mib mib; 

Untuk mengunggah file, kami menulis metode ini:

 private Mib loadMib(File file) throws MibLoaderException, IOException { MibLoader loader = new MibLoader(); Mib mib; file = file.getAbsoluteFile(); try { loader.addDir(file.getParentFile()); mib = loader.load(file); } catch (MibLoaderException e) { e.getLog().printTo(System.err); throw e; } catch (IOException e) { e.printStackTrace(); throw e; } return mib; } 

Kelas net.percederberg.mibble.MIBLoader memvalidasi file yang kami coba muat dan melempar net.percederberg.mibble.MibLoaderException jika ia menemukan kesalahan di dalamnya, termasuk kesalahan impor dari file MIB lain, jika mereka jangan terletak di direktori yang sama atau tidak mengandung karakter MIB yang diimpor.

Dalam metode loadMib, kami menangkap semua pengecualian, menulis tentang mereka ke log dan meneruskan lebih jauh, karena pada tahap ini, kelanjutan pekerjaan tidak mungkin - file tidak valid.

Kami memanggil metode tertulis di konstruktor parser:

 public MIBParser(File file) throws MibLoaderException, IOException { if (!file.exists()) throw new FileNotFoundException("File not found in location: " + file.getAbsolutePath()); mib = loadMib(file.getAbsoluteFile()); if (!mib.isLoaded()) throw new MibLoaderException(file, "Not loaded."); } 

Jika file berhasil diunduh dan diuraikan, lanjutkan bekerja.

Metode untuk Mengambil Informasi dari File MIB


Dengan menggunakan metode kelas net.percederberg.mibble.Mib, Anda dapat mencari masing-masing karakter file MIB dengan nama atau OID dengan memanggil metode getSymbol (String name) atau getSymbolByOid (String oid). Metode ini mengembalikan objek net.percederberg.mibble.MibSymbol, metode yang akan kita gunakan untuk mendapatkan informasi yang diperlukan pada simbol MIB tertentu.

Mari kita mulai dengan metode yang paling sederhana dan menulis untuk mendapatkan nama simbol dengan OID-nya dan, sebaliknya, OID dengan nama:

 public String getName(String oid) { return mib.getSymbolByOid(oid).getName(); } public String getOid(String name) { String oid = null; MibSymbol s = mib.getSymbol(name); if (s instanceof MibValueSymbol) { oid = ((MibValueSymbol) s).getValue().toString(); if (((MibValueSymbol) s).isScalar()) oid = new OID(oid).append(0).toDottedString(); } return oid; } 

Mungkin ini adalah fitur dari file MIB tertentu, yang saya perlukan untuk bekerja, tetapi untuk beberapa alasan, parameter skalar mengembalikan OID tanpa nol pada akhirnya, jadi kode ditambahkan ke metode untuk mendapatkan OID, yang, jika MIB karakternya skalar, ia hanya menambahkan ".0" ke OID yang diterima menggunakan metode append (int index) dari kelas net.percederberg.mibble.OID. Jika berhasil untuk Anda tanpa kruk, selamat :)

Untuk mendapatkan sisa data pada simbol, kita menulis satu metode bantu, di mana kita mendapatkan objek net.percederberg.mibble.snmp.SnmpObjectType, yang berisi semua informasi yang diperlukan tentang simbol MIB dari mana ia diperoleh.

 private SnmpObjectType getSnmpObjectType(MibSymbol symbol) { if (symbol instanceof MibValueSymbol) { MibType type = ((MibValueSymbol) symbol).getType(); if (type instanceof SnmpObjectType) { return (SnmpObjectType) type; } } return null; } 

Sebagai contoh, kita bisa mendapatkan jenis simbol MIB:

 public String getType(String name) { MibSymbol s = mib.getSymbol(name); if (getSnmpObjectType(s).getSyntax().getReferenceSymbol() == null) return getSnmpObjectType(s).getSyntax().getName(); else return getSnmpObjectType(s).getSyntax().getReferenceSymbol().getName(); } 

Ada 2 cara untuk mendapatkan tipe, karena untuk tipe primitif, opsi pertama berfungsi:

 getSnmpObjectType(s).getSyntax().getName(); 

dan untuk yang diimpor, yang kedua:

 getSnmpObjectType(s).getSyntax().getReferenceSymbol().getName(); 

Anda bisa mendapatkan tingkat akses karakter:

 public String getAccess(String name) { MibSymbol s = mib.getSymbol(name); return getSnmpObjectType(s).getAccess().toString(); } 

Nilai valid minimum untuk parameter numerik:

 public Integer getDigitMinValue(String name) { MibSymbol s = mib.getSymbol(name); String syntax = getSnmpObjectType(s).getSyntax().toString(); if (syntax.contains("STRING")) return null; Pattern p = Pattern.compile("(-?\\d+)..(-?\\d+)"); Matcher m = p.matcher(syntax); if (m.find()) { return Integer.parseInt(m.group(1)); } return null; } 

Nilai maksimum yang diizinkan dari parameter numerik:

 public Integer getDigitMaxValue(String name) { MibSymbol s = mib.getSymbol(name); String syntax = getSnmpObjectType(s).getSyntax().toString(); if (syntax.contains("STRING")) return null; Pattern p = Pattern.compile("(-?\\d+)..(-?\\d+)"); Matcher m = p.matcher(syntax); if (m.find()) { return Integer.parseInt(m.group(2)); } return null; } 

Panjang string minimum yang diizinkan (tergantung pada jenis string):

 public Integer getStringMinLength(String name) { MibSymbol s = this.mib.getSymbol(name); String syntax = this.getSnmpObjectType(s).getSyntax().toString(); Pattern p = Pattern.compile("(-?\\d+)..(-?\\d+)"); Matcher m = p.matcher(syntax); return syntax.contains("STRING") && m.find()?Integer.valueOf(Integer.parseInt(m.group(1))):null; } 

Panjang string maksimum yang diizinkan (tergantung pada jenis string):

 public Integer getStringMaxLength(String name) { MibSymbol s = mib.getSymbol(name); String syntax = getSnmpObjectType(s).getSyntax().toString(); Pattern p = Pattern.compile("(-?\\d+)..(-?\\d+)"); Matcher m = p.matcher(syntax); if (syntax.contains("STRING") && m.find()) { return Integer.parseInt(m.group(2)); } return null; } 

Anda juga bisa mendapatkan nama semua kolom di tabel dengan namanya:

 public ArrayList<String> getTableColumnNames(String tableName) { ArrayList<String> mibSymbolNamesList = new ArrayList<>(); MibValueSymbol table = (MibValueSymbol) mib.findSymbol(tableName, true); if (table.isTable() && table.getChild(0).isTableRow()) { MibValueSymbol[] symbols = table.getChild(0).getChildren(); for (MibValueSymbol mvs : symbols) { mibSymbolNamesList.add(mvs.getName()); } } return mibSymbolNamesList; } 

Pertama, dengan cara standar, kita mendapatkan simbol MIB dengan nama:

 MibValueSymbol table = (MibValueSymbol) mib.findSymbol(tableName, true); 

Kemudian kita periksa apakah itu adalah sebuah tabel dan simbol anak MIB adalah baris dari tabel ini dan, jika kondisinya kembali benar, dalam loop kita melewati anak-anak dari baris tabel dan menambahkan nama elemen ke array yang dihasilkan:

 if (table.isTable() && table.getChild(0).isTableRow()) { MibValueSymbol[] symbols = table.getChild(0).getChildren(); for (MibValueSymbol mvs : symbols) { mibSymbolNamesList.add(mvs.getName()); } } 

Ringkasan


Metode ini cukup untuk mendapatkan informasi apa pun dari file MIB untuk setiap karakter tertentu, hanya mengetahui namanya. Misalnya, saat menulis klien SNMP, Anda dapat menyertakan pengurai di dalamnya sehingga metode klien tidak menerima OID, tetapi nama simbol MIB. Ini akan meningkatkan keandalan kode, seperti salah ketik OID mungkin tidak mengarah ke karakter yang ingin kita lihat. Dan tidak ada OID - tidak ada masalah.

Nilai tambah adalah keterbacaan kode, yang berarti pemeliharaannya. Lebih mudah untuk memahami esensi proyek jika kode beroperasi dengan nama manusia.

Aplikasi lain adalah otomatisasi uji. Dalam data uji, seseorang dapat memperoleh nilai batas parameter numerik secara dinamis dari file MIB. Jadi, jika nilai batas beberapa simbol MIB dalam versi baru dari komponen yang diuji berubah, Anda tidak perlu mengubah kode autotest.

Secara umum, menggunakan parser, bekerja dengan file MIB menjadi jauh lebih menyenangkan, dan mereka tidak lagi menyusahkan.

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


All Articles