Junos の on-box Python

ネットワーク

オフラインでログに書き出すような使い方の調査を兼ねていろいろ試したメモ。

ほぼ唯一といっていい日本語文献
JunosのOn-box Pythonを使ってみる #1 Op Script #juniper – Qiita

サンプルコードなど(ただし python2.7 なので注意)
junosautomation/on-box-python/op-scripts at master · Juniper/junosautomation · GitHub
Junos バージョンごと Python3 対応は以下参照
https://www.juniper.net/documentation/jp/ja/software/junos/automation-scripting/topics/concept/junos-script-automation-python-scripts-overview.html 

スクリプトの種類について
  • op スクリプト(オペレーションスクリプト)
    • オペレーションコマンドの実行やコンフィグの変更、モニタリングなどに使用
  • commit スクリプト(commit 時に実行されるスクリプト)
    • カスタム警告の表示、カスタムログの出力、変更されたコンフィグが自社のルールに沿っているかの確認などに使用
  • event スクリプト(イベント発生時に実行されるスクリプト)
    • イベント発生時に自動でコンフィグの書き換えてパスを切り替えたりする操作に使用
    • スクリプトを定期実行したい場合もこちらの仕組みを使用
Hello World!

とりあえず Hello World を実行する。

スクリプトの実行にはコンフィグへの記載が必要

set system scripts language python3
set system scripts op file hello.py

スクリプトはそれぞれ /var/db/script 配下にフォルダがある。今回は op script を使うので /var/db/script/op/hello.py というファイルを作成。

スクリプトは shell で作成するので、start shell し、vi で以下ファイルを作成。

root@onbox-python:/var/db/scripts/op # cat hello.py 

def main():
        print ("Hello Onbox Script World!")

if __name__ == "__main__":
        main()

CLI から op hello.py を実行

root@onbox-python> op hello.py 
Hello Onbox Script World!
セッション情報の取得

SRX で session 数を見たい場合、`show security flow session summary` を使用。

root@onbox-python> show security flow session summary
Unicast-sessions: 11
Multicast-sessions: 0
Services-offload-sessions: 0
Failed-sessions: 0
Sessions-in-use: 12
  Valid sessions: 11
  Pending sessions: 0
  Invalidated sessions: 1
  Sessions in other states: 0
Maximum-sessions: 65536

コマンドと同様の情報を取得するには RPC が必要なので、`| display xml rpc` で取得。

root@onbox-python> show security flow session summary | display xml rpc 
<rpc-reply xmlns:junos="http://xml.juniper.net/junos/24.4R1.9/junos">
    <rpc>
        <get-flow-session-information>
                <summary/>
        </get-flow-session-information>
    </rpc>
    <cli>
        <banner></banner>
    </cli>
</rpc-reply>

今回の場合 `get-flow-session-information` を使いますが、PyEZ の RPC で使う際はハイフン(-)はアンダーバー(_)で置き換え。
サンプルとしてはこんな感じ。

from jnpr.junos import Device
from lxml import etree

def main():
        dev = Device()
        dev.open()

        sessions = dev.rpc.get_flow_session_information(summary=True) 
        print (etree.tostring(sessions).decode())

if __name__ == "__main__":
        main()

from jnpr.junos import Device:RPC を使用するためのデバイスへの接続処理
from lxml import etree:xml の処理のため使用
以下のようなXMLが出力される。

<security-flow-information>
<flow-session-information>
<flow-session-summary-information>
<active-unicast-sessions>
0
</active-unicast-sessions>
<active-multicast-sessions>
0
</active-multicast-sessions>
<active-services-offload-sessions>
0
</active-services-offload-sessions>
<failed-sessions>
0
</failed-sessions>
<active-drop-sessions>
0
</active-drop-sessions>
<active-sessions>
0
</active-sessions>
<active-session-valid>
0
</active-session-valid>
<active-session-pending>
0
</active-session-pending>
<active-session-invalidated>
0
</active-session-invalidated>
<active-session-other>
0
</active-session-other>
<max-sessions>
524288
</max-sessions>
</flow-session-summary-information>
</flow-session-information>
</security-flow-information>

XML をパースして <active-sessions> だけ取り出したい場合、xpass で以下のように処理が可能。

    # Retrieve flow session summary information
    sessions = dev.rpc.get_flow_session_information(summary=True)

    # Extract <active-sessions> value
    active_sessions = sessions.xpath("//active-sessions")
ファイルへの書き出し

一般的な Python でのファイル書き出しが可能。

# file open 
fo = open("/var/tmp/flow-count.log", "a+") 
fo.write(time + "\n")
fo.write(message + "\n")
fo.close()

ログの量が多い場合、ファイルサイズなども要検討。圧縮とローテーションを考慮して syslog に書き出すのもあり。

Syslog への書き出しは jcs を利用。
詳細は以下リンク。
https://www.juniper.net/documentation/us/en/software/junos/automation-scripting/topics/ref/script/junos-script-automation-function-jcs-syslog.html

import jcs
        jcs.syslog("user.info", "test from op script")

1つ目のパラメーターは facility と priority。2つ目はメッセージ。これだけで次のように出力される。

Feb 25 23:38:11  onbox-python cscript[29555]: test from op script
定期実行

定期実行はリソースの考慮なども必要。以下は SLAX script についてだが、考慮点は Python についても同様。
https://community.juniper.net/browse/blogs/blogviewer?blogkey=f9417573-338a-43f2-9b53-a67b2ed56f01 

定期実行には event-script を使用(/var/db/scripts/event に保存)。回りくどい書き方になるが、interval でイベントを生成し、そのイベントをトリガーにしてスクリプトを起動する。また、スクリプト実行用に pyscript というユーザーを作った。

set system login user pyscript class super-user authentication plain-text-password 
New password:
Retype new password:
set event-options generate-event generate-every-three-minute time-interval 180
set event-options policy get-stats-policy events generate-every-three-minute
set event-options policy get-stats-policy then event-script flow-count-logging.py
set event-options event-script file flow-count-logging.py python-script-user pyscript

実行時に syslog に以下のように出力される。チェックサムを入れていない場合 WARNING が出る。

Feb 26 01:10:27  onbox-python eventd[42146]: EVENTD_ESCRIPT_EXECUTION: Trying to execute the script 'flow-count-logging.py' from '/var/db/scripts/event/'
Feb 26 01:10:27  onbox-python cscript[50798]: CSCRIPT_SECURITY_WARNING: unsigned python script '/var/db/scripts/event/flow-count-logging.py' without checksum is executed
Source code

/var/db/scripts/event/flow-count-logging.py

from jnpr.junos import Device
from lxml import etree
import jcs
import datetime

LOG_FILE = "/var/tmp/flow-count.log"
DEBUG = False  # Set to True for debugging output

def main():
    try:
        dev = Device()
        dev.open()
    except Exception as e:
        jcs.syslog("Error: Could not open device. {e}")
        return

    # Get the current timestamp in ISO format (UTC)
    timestamp = datetime.datetime.now().isoformat()

    # Retrieve flow session summary information
    sessions = dev.rpc.get_flow_session_information(summary=True)

    if DEBUG:
        print(etree.tostring(sessions, pretty_print=True).decode())

    # Extract <active-sessions> value
    active_sessions = sessions.xpath("//active-sessions")

    if active_sessions and active_sessions[0].text:
        active_session_count = active_sessions[0].text.strip()
    else:
        active_session_count = "N/A"  # Handle missing or empty data

    message = f"Active session count: {active_session_count}"

    if DEBUG:
        print(message)

    # Append log entry to the log file
    try:
        with open(LOG_FILE, "a") as fo:
            fo.write(f"{timestamp}\n{message}\n")
    except Exception as e:
        jcs.syslog("Error: Cloud not write to log file. {e}")

if __name__ == "__main__":
    main()

実行例

# cat /var/tmp/flow-count.log 
2025-02-26T01:04:28.210709
Active session count: 0
2025-02-26T01:07:28.220234
Active session count: 0
2025-02-26T01:10:28.225049
Active session count: 0
2025-02-26T01:13:28.224987
Active session count: 0
Appendix

ソフトウェアバージョンの表示

from jnpr.junos import Device
from lxml import etree

def main():
        dev = Device()
        dev.open()
        sw_info_text = dev.rpc.get_software_information({'format':'text'})
        print(etree.tostring(sw_info_text).decode())

if __name__ == "__main__":
        main()
root@onbox-python> op test.py    
<output>
Hostname: onbox-python
Model: vSRX
Family: junos-es
Junos: 24.4R1.9
JUNOS hsm [20241219.060016_builder_junos_244_r1]
JUNOS OS Kernel 64-bit XEN [20241104.1ed86e6_builder_bsd15_244]
JUNOS modules [20241219.060016_builder_junos_244_r1]
JUNOS vsrx modules [20241219.060016_builder_junos_244_r1]
JUNOS OS libs [20241104.1ed86e6_builder_bsd15_244]
JUNOS hsm aws [20241219.060016_builder_junos_244_r1]
JUNOS OS vmguest [20241104.1ed86e6_builder_bsd15_244]
JUNOS OS libs compat32 [20241104.1ed86e6_builder_bsd15_244]
JUNOS OS runtime [20241104.1ed86e6_builder_bsd15_244]
~~~

コメント

タイトルとURLをコピーしました