あらゆる場所で、物理的なトラップなしで、ケーブル破壊行為に迅速に対応します

こんにちは



銅線ケーブルの損傷に迅速に対応するために、プロバイダー企業で実装されているアイデアをコミュニティと共有したいという要望があります。 ツイストペアとイーサネットについてです。 もちろん、私はエレガントなふりをしませんが、サービスは良い結果を示しました。



画像



読むのが面倒な人のために。 仕組み:半径上のセッションの落下を監視し、スイッチごとにグループ化し、回線をテストし、ヘルメット通知を行います。



企業の理由でプロジェクトコード全体を提供することはできませんが、興味のある人のためにネタバレの下にあるコードを削除します。 はい、各プロバイダーの実装は異なります。 むしろ、目標は誰かを助けるかもしれないアイデアを共有することです。



社内の機器は99%Dリンクであるため、このベンダーのSNMP MIBがリストされています。 それらのいくつかはRFCであり、他のメーカーに適しているはずです。



それがどのように出てきたかについての少しの歴史。



すべては2018年春に開始されました。テクニカルサポートグループ(TP)の負荷が増加しました。 サブスクライバーコールの処理に加えて、TPは、新しいサブスクライバーを接続するとき、および既存の顧客の復元とデバッグに向けて出発するときに、インストーラーを調整しました。 TPを少しアンロードし、インストーラーにいくつかのツールを提供する必要がありました。 サブスクライバーのログイン/契約を受け入れるメッセンジャー「ボット」を作成することが決定され、フィールドに直接インストーラーが最小限のデバッグを行うことができます。



1つのアプリケーションにすべての機能を組み込みたくありませんでした。 実際、このような機能は、コールを処理するときに同じCRMのブラウザでも役立つため、ネットワーク機器との相互作用メカニズム、課金、半径を別のサービスに入れ、APIにし、APIを介してボットとCRMの両方を接続することを決定しました何でも。



少しコードを書き、投稿の本質に移りましょう。



そして、インストーラーはフィールドで何を必要としますか:



  1. もちろんケーブルテスト
  2. ポートエラーを表示する
  3. ポートステータスを表示する
  4. ポートにMACアドレスがあるかどうかを確認します。 (突然、加入者がケーブルをWANではなくLANポートに差し込んだ)
  5. IPTVサブスクリプション
  6. 認証ログを表示する
  7. バランス状態


SNMP経由でスイッチとやり取りし、一部の場所ではtelnet経由でやり取りします。



WebフレームワークとしてBottleを使用しました。



そしてそう



必要なものをインポートします
#!/usr/bin/python # -*- coding: utf_8 -*- from bottle import route, run, template, auth_basic, request, error from lib import crm, snmp, gis, billing import time
      
      







検証のためにAPIキーとデコレータを含むシートを追加しますが、列の全員にデータを提供するわけではありません)。



コード
 apikeys = ['RANDOM_KEY1', 'RANDOM_KEY2'] api_error = '{"error":"apikey invalid"}' host_down_error = '{"error":"host down"}' def apikey_checker(fn): def wrapper(*args, **kwargs): if not check_apikey(): return api_error return fn(*args, **kwargs) return wrapper def check_apikey(): return 'apikey' in request.query and request.query['apikey'] in apikeys
      
      







実際、機器とやり取りするためのいくつかの機能があります。



コード
 @route('/port_status/<ip>/<port>') @apikey_checker def get_port_status(ip=' ', port=' '): return snmp.port_status(ip, port) @route('/cable_test/<ip>/<port>') @apikey_checker def get_cable_test(ip, port): return snmp.cable_test(ip, port)
      
      







snmpの内部には、ポート上のペアの返されたSNMPステータスの解釈を含む辞書があります。



ステータス辞書


 pair_status = { '0': 'ok', '1': 'open', '2': 'short', '3': 'open-short', '4': 'crosstalk', '5': 'unknown', '6': 'count', '7': 'no-cable', '8': 'other' }
      
      







ポート測定結果の辞書の調達。 毎回新しいものを作成しないように、コピーします。



非表示のテキスト
 pair_result = { 'pairs': { 1: { 'status': '-', 'length': '-' }, 2: { 'status': '-', 'length': '-' }, 3: { 'status': '-', 'length': '-' }, 4: { 'status': '-', 'length': '-' }, } }
      
      







機能



ケーブルテスト
 def cable_test(ip, port): if not check_ip(ip): #        IP return {'error': "IP %s invalid" % (ip)} host_status = check_host(ip) #       if host_status['status'] == 'down': return {'error': u" "} result = copy.deepcopy(pair_result) #   ,   UP, ..     #     . if port_status(ip, port)['status'] == 'down': try: mib = '.1.3.6.1.4.1.171.12.58.1.1.1.12.%s' % str( port) #      #         snmp_int_set(ip, mib, 1) time.sleep(1) #    result['pairs'][1]['status'] = pair_status[ snmp_get(ip, '.1.3.6.1.4.1.171.12.58.1.1.1.4.%s' % str(port))] result['pairs'][2]['status'] = pair_status[ snmp_get(ip, '.1.3.6.1.4.1.171.12.58.1.1.1.5.%s' % str(port))] result['pairs'][3]['status'] = pair_status[ snmp_get(ip, '.1.3.6.1.4.1.171.12.58.1.1.1.6.%s' % str(port))] result['pairs'][4]['status'] = pair_status[ snmp_get(ip, '.1.3.6.1.4.1.171.12.58.1.1.1.7.%s' % str(port))] result['pairs'][1]['length'] = snmp_get( ip, '.1.3.6.1.4.1.171.12.58.1.1.1.8.%s' % str(port)) result['pairs'][2]['length'] = snmp_get( ip, '.1.3.6.1.4.1.171.12.58.1.1.1.9.%s' % str(port)) result['pairs'][3]['length'] = snmp_get( ip, '.1.3.6.1.4.1.171.12.58.1.1.1.10.%s' % str(port)) result['pairs'][4]['length'] = snmp_get( ip, '.1.3.6.1.4.1.171.12.58.1.1.1.11.%s' % str(port)) return result except Exception as e: print(e) return {'error': u'    '} else: return {'error': u'    .   Link UP.'}
      
      







関数が戻ります



結果
 { "pairs": { "1": { "status": "other", "length": "0" }, "2": { "status": "open", "length": "4" }, "3": { "status": "open", "length": "4" }, "4": { "status": "other", "length": "0" } } }
      
      







後で、スクリプト専用の別の同様の関数を追加しました。1つではなく、入力としてポートのリストを受け入れ、テストする前にポートのステータスをチェックしません。これは、リンクの大幅なドロップでは必要ありません。



それがボットのように見え始めたものです



画像



さて、ポストの本質について。



サーバーのデバッグ実装の前に、post habr.com/post/188730で説明されているものと同様のテクノロジーが使用されていました 。 SNMPラダーが有効になっているポートでループします。 「飛行機」が港に落ちたとき、これに関するメッセージが監視に落ちました。



まず、スクリプトをねじ込んで、追跡されたリンクが落ちたときに、デバッグサーバーがスイッチに移動し、ポートが実際に横たわっているかどうかを確認し、点滅していないことを確認し、そのペアが開いているか短絡しているかを確認してから、オペレーターにメッセージを送信しました。



ただし、このような物理的なトラップが発生したのはスイッチの約10%のみであり、これはわずかでした。



後にモニターの半径が思いつきました。 また、これにより、監視範囲の割合を最大100%まで増やすことができました。 そして、ここではすべてがプロバイダーインフラストラクチャとはすでに異なっています。



特定のスイッチから落ちたクライアントセッションの数を定期的に確認します。 次の形式のcircuit_idを使用すると、これを簡単に実行できます。



D4:CA:6D:0A:66:C9 :: 192.168.20.86 :: 20



ここには、サブスクライバのMAC、IPスイッチ、サブスクライバのポート番号があります。 つまり デバッグに必要なものすべて。

完了したセッションをIPスイッチごとにグループ化します。このようなセッションがいくつかある場合(トリガーは1分あたり2セッションに設定されています)、スクリプトはデバッグサーバーに接続し、ドロップされたセッションのポートをテストします。 ポートがまだ存在し、ケーブルペアが開いているか短絡しており、少なくとも2つのポートの長さが同じ(+-2メートル)で、スイッチの目でケーブルカットが正確に見える場合、状況を疑い、オペレーターにメッセージを送信します。



もちろん、家のライトが点滅するとき、または加入者がケーブルを同時にオフにし、長さが同じであることが偶然一致する場合、誤検出がありますが、これは彼らが言うように、やり過ぎが良い場合です。 さらに、長さ(短い長さにのみ対応)、同時ドロップ数などに制限を加えることができます。



これが不審なイベントの実際のレポートです。



画像



そして、そのようなメッセージを処理した結果



画像



スクリプトが同様のメッセージを送信し、数秒後にスイッチがオフラインになった場合がありました。 光学系が損傷している場合、ソフトウェアの速度がそうでなければ、家の典型的な停電と間違えられていたでしょう。



別の時、管理会社は警告なしに屋根の修理を開始し、機関銃を持ったVOKhRが彼らに飛んで行き、錠前屋に突然のストレスがかかった。



そのため、スクリプトは良好な結果を示し始め、4か月以上の作業で、VOKhR、警察、およびプロバイダーの従業員自身が10件以上の破壊行為を成功裏に完了しました。 したがって、私はそのような監視の概念を共有することにしました。



現在、スクリプトは、物理的な「トラップ」やSNMPトラップなしで約15,000台のスイッチを監視しています。



新年の皆さんに幸運を!



All Articles