SNMP + Java-個人的な経験。 MIBファイルのパーサーの作成

SNMPは最もユーザーフレンドリーなプロトコルではありません。MIBファイルは長すぎてわかりにくいため、OIDを覚えるのは不可能です。 しかし、JavaでSNMPを使用する必要がある場合はどうでしょうか? たとえば、自動テストを記述して、SNMPサーバーAPIを確認します。



試行錯誤によって、トピックに関する情報がかなり少ない場合でも、JavaとSNMPを友達にする方法を見つけました。



この一連の記事では、プロトコルで得られた経験を共有しようとします。 このシリーズの最初の記事では、JavaでのMIBファイルのパーサーの実装について説明します。 第2部では、SNMPクライアントの作成について説明します。 3番目のパートでは、書かれたライブラリを使用した実際の例について説明します。自動テストは、SNMPを介したデバイスとの相互作用を検証します。







エントリー



それはすべて、SNMPプロトコルを使用してオーディオビデオレコーダの動作を検証する自動テストを作成するタスクから始まりました。 状況を複雑にしているのは、特にインターネットのロシア語セグメントに関しては、JavaでのSNMPとのやり取りに関する情報があまりないことです。 もちろん、C#またはPythonに目を向けることができます。 しかし、C#では、プロトコルの状況はJavaと同じくらい複雑です。 Pythonにはいくつかの優れたライブラリがありますが、JavaでのこのデバイスのREST API自動テスト用の既製のインフラストラクチャが既にありました。



他のネットワーク通信プロトコルと同様に、さまざまな種類の要求を処理するためにSNMPクライアントが必要でした。 自動テストは、スカラーおよびテーブルパラメータに対するGETおよびSET要求の成功を検証できる必要があります。 テーブルの場合、テーブル自体でこれらの操作が許可されている場合、レコードの追加と削除を検証できることも必要でした。



ただし、クライアントに加えて、ライブラリにはMIBファイルを操作するためのクラスを含める必要がありました。 このクラスは、常に変更できるものをハードコードしないように、MIBファイルを解析してデータ型、許容値の境界などを取得できる必要がありました。



Javaに適したライブラリを検索しているときに、リクエストとMIBファイルの両方で作業できる単一のライブラリが見つかりませんでした。 そのため、2つの異なるライブラリに決めました。 クライアントにとって、広く使用されているorg.snmp4j.snmp4j(https://www.snmp4j.org)の選択は非常に論理的であり、MIBファイルのパーサーにとっては、あまり知られていないnet.percederberg.mibbleライブラリ(https:// www。 mibble.org)。 snmp4jで選択が明らかだった場合は、十分に詳細な(英語ではあるが)例を含むドキュメントを入手できるミブルが選択されました。 それでは始めましょう。



MIBファイルのパーサーの作成



MIBファイルを見たことがある人なら誰でも、これが苦痛であることを知っています。 単純なパーサーを使用してこれを修正してみましょう。これにより、ファイルからの情報の検索が大幅に容易になり、特定のメソッドを呼び出すだけになります。



このようなパーサーは、MIBファイルを操作するための個別のユーティリティとして使用したり、SNMPクライアントの作成時や自動化のテスト時など、SNMPの他のプロジェクトに含めることができます。



プロジェクトの準備



組み立てを簡単にするために、Mavenを使用します。 net.percederberg.mibbleライブラリ(https://www.mibble.org)の追加に応じて、MIBファイルでの作業が容易になります。



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





中央のMavenリポジトリにないため、pom.xmlに次のコードを追加します。



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





プロジェクトがエラーなしでMavenを使用してアセンブルされた場合、すべての作業の準備ができています。 パーサークラスを作成し(MIBParserと呼びましょう)、必要なものをすべてインポートするだけです。



 import net.percederberg.mibble.*;
      
      





MIBファイルをダウンロードして検証する



クラス内には、ダウンロードしたMIBファイルを保存するためのnet.percederberg.mibble.Mibタイプのオブジェクトの1つのフィールドのみがあります。



 private Mib mib;
      
      





ファイルをアップロードするには、次のメソッドを記述します。



 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; }
      
      





クラスnet.percederberg.mibble.MIBLoaderは、ロードしようとしているファイルを検証し、他のMIBファイルからのインポートエラーを含むエラーが見つかった場合、net.percederberg.mibble.MibLoaderExceptionをスローします。同じディレクトリにないか、インポートされたMIB文字が含まれていません。



loadMibメソッドでは、すべての例外をキャッチし、それらについてログに書き込み、さらに転送します。 この段階では、作業の継続は不可能です-ファイルは無効です。



パーサーコンストラクターで記述されたメソッドを呼び出します。



 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."); }
      
      





ファイルが正常にダウンロードおよび解析された場合は、作業を続けます。



MIBファイルから情報を取得する方法



net.percederberg.mibble.Mibクラスのメソッドを使用して、getSymbol(String name)メソッドまたはgetSymbolByOid(String oid)メソッドをそれぞれ呼び出すことにより、MIBファイル内の個々の文字を名前またはOIDで検索できます。 これらのメソッドはnet.percederberg.mibble.MibSymbolオブジェクトを返します。このオブジェクトのメソッドを使用して、特定のMIBシンボルに関する必要な情報を取得します。



まず、最も簡単なメソッドから始めて、OIDでシンボルの名前を取得し、逆に名前でOIDを取得するメソッドを作成します。



 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; }
      
      





おそらくこれらは特定のMIBファイルの機能であり、それを使用する必要がありましたが、何らかの理由で、スカラーパラメータが最後にゼロなしでOIDを返したため、OIDを取得するメソッドにコードが追加されました文字はスカラーです。net.percederberg.mibble.OIDクラスのappend(int index)メソッドを使用して、受信したOIDに「.0」を追加するだけです。 それが松葉杖なしであなたのために働くなら、おめでとう:)



シンボルの残りのデータを取得するには、1つの補助メソッドを作成します。このメソッドでは、オブジェクトnet.percederberg.mibble.snmp.SnmpObjectTypeを取得します。このメソッドには、取得元のMIBシンボルに関する必要な情報がすべて含まれています。



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





たとえば、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(); }
      
      





タイプを取得するには2つの方法があります。 プリミティブ型の場合、最初のオプションが機能します:



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





インポートされたものの場合、2番目のもの:



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





キャラクターのアクセスレベルを取得できます。



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





数値パラメーターの最小有効値:



 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; }
      
      





数値パラメーターの最大許容値:



 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; }
      
      





許可される文字列の最小長(文字列の種類によって異なります):



 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; }
      
      





最大許容文字列長(文字列のタイプに依存):



 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; }
      
      





テーブル内のすべての列の名前を名前で取得することもできます。



 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; }
      
      





まず、標準的な方法で、名前でMIBシンボルを取得します。



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





次に、それがテーブルであり、子MIBシンボルがこのテーブルの行であることを確認し、条件がtrueを返す場合、ループでテーブル行の子を調べ、結果の配列に要素名を追加します。



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





まとめ



これらのメソッドは、特定の文字ごとにMIBファイルから情報を取得するのに十分であり、その名前のみを知っています。 たとえば、SNMPクライアントを作成するときに、そのようなパーサーをクライアントに含めると、クライアントの入力メソッドはOIDではなくMIBシンボル名を受け入れることができます。 これにより、コードの信頼性が向上します。 OIDのタイプミスが、参照したい文字につながらない場合があります。 OIDはありません-問題ありません。



プラスは、コードの可読性であり、したがって、その保守性です。 コードが人間の名前で動作する場合、プロジェクトの本質を理解するのは簡単です。



別のアプリケーションはテスト自動化です。 テストデータでは、MIBファイルから動的に数値パラメーターの境界値を取得できます。 そのため、テストされたコンポーネントの新しいバージョンの一部のMIBシンボルの境界値が変更された場合、自動テストコードを変更する必要はありません。



一般に、パーサーを使用すると、MIBファイルでの作業がはるかに快適になり、そのような痛みはなくなります。



All Articles