CLIプロキシ
CLIプロキシサービスは、ネットワーク機器やサーバに対するCLI制御をAPI化する機能を提供しています。
一つのCLIセッションで実行する一連のコマンド送受信を定義します。また送信コマンドは、Jinja2テンプレート形式で記述することができます。
コマンドテンプレートへのレンダリングパラメータは、実行時に与えることができますが、デバイスから応答された受信結果からパラメータを生成して次のコマンドテンプレートに適用することができます。
CLIプロキシの定義項目
category
: CLIプロキシのカテゴリを指定します。カテゴリは単なるラベルです。
name
: CLIプロキシの名前を指定します。ユニークである必要があります。
path
: CLIプロキシが生成するAPI待ち受けパスを指定します。ユニークである必要があります。自動生成されるAPIは全てPATCH
メソッドのみを受け付けます。
protocol
: CLIアクセスで利用するプロトコルを指定します。telnet
もしくはssh
のみ指定できます。
async
: CLIプロキシが生成するAPIの非同期モードを指定します。True
の場合、APIを要求した場合は、CLIプロキシを起動するlambdaイベントを発行してイベントIDを応答します。False
の場合、lambdaイベントの発行後、イベント収束まで待ち合わせて処理結果を応答します。
timeout
: CLIプロキシの実行によって生成されるlambdaイベントの収束タイムアウト時間を指定します。デフォルトは、300
秒です。
config
: CLIプロキシがコマンド送信する際にコンフィグモードで実行するかを指定します。Ciscoデバイスの場合は、開始時にconfig term
、終了時はend
が自動送信されます。デフォルトはFalse
です。
templates
: CLIプロキシが対象デバイスに対して送受信するコマンドや実行条件などを記述する定義ブロックです。
templates.command
: 送信するコマンドを記述します。コマンドは、Jinja2テンプレート形式で記述できます。レンダリングパラメータは、コマンド送信時点のbindings
辞書が使用されます。
templates.execution_condition
: コマンドの送信可否を判定するカスタムスクリプトを記述します。例えば、version in ["1.0", "1.1"]
と記述した場合、bindings
に存在するversion
変数が1.0もしくは1.1の場合のみコマンドが送信されます。
templates.fault_condition
: コマンドの送信時点のbindings
辞書に対してCLIプロキシの処理に失敗がないか判定するカスタムスクリプトを記述します。例えば、version not in ["1.0", "1.1"]
と記述した場合、bindings
に存在するversion
変数が1.0もしくは1.1でない場合、CLIプロキシは中断してエラーを返却します。後述するtemplates.rollback
が定義されている場合は、ロールバック動作に遷移します。
templates.prompt_terminator
: コマンド送信後に待ち受けるプロンプトを指定します。通常は自動検出されます。
templates.timeout
: コマンド送信のタイムアウトを指定します。デフォルトは、起動パラメータのssh_default_timeout
です。起動パラメータのデフォルトは60秒
です。
templates.expect_regexes
: コマンド送信後にデバイスから受信した応答メッセージに対して期待する正規表現を記述します。全ての正規表現にマッチした場合、正常と見なし、次のコマンド送信判定に遷移します。いづれかでもマッチしない場合、処理を中断してエラーを返却します。後述するtemplates.rollback
が定義されている場合は、ロールバック動作に遷移します。
templates.unexpect_regexes
: コマンド送信後にデバイスから受信した応答メッセージに対して期待しない正規表現を記述します。いづれかの正規表現にマッチした場合、異常と見なし、処理を中断してエラーを返却します。後述するtemplates.rollback
が定義されている場合は、ロールバック動作に遷移します。
templates.rollback
: CLIプロキシが何らかのエラーによって処理を中断した場合に実行されるロールバック処理を記述する定義ブロックです。
templates.rollback.command
: ロールバックで送信するコマンドを記述します。templates.command
同様にJinja2テンプレート形式で記述できます。
templates.rollback.prompt_terminator
: ロールバックコマンド送信後に待ち受けるプロンプトを指定します。通常は自動検出されます。
templates.rollback.precondition
: templates.rollback.command
の送信前に実行可否を判定するためのshowコマンドを送信したい場合に指定できる定義ブロックです。
templates.rollback.precondition.command
: 実行可否判定のために送信するコマンドを記述します。templates.command
同様にJinja2テンプレート形式で記述できます。
templates.rollback.precondition.prompt_terminator
: 実行可否判定コマンド送信後に待ち受けるプロンプトを指定します。通常は自動検出されます。
templates.rollback.precondition.expect_regexes
: 実行可否判定コマンドの応答結果に期待する正規表現を記述します。いづれかでもマッチしない場合、ロールバックは失敗とみなされエラーを返却します。
templates.rollback.precondition.unexpect_regexes
: 実行可否判定コマンドの応答結果に期待しない正規表現を記述します。いづれかでもマッチする場合、ロールバックは失敗とみなされエラーを返却します。
templates.rollback.postcondition
: templates.rollback.command
の送信後にロールバックの継続可否を判定するためのshowコマンドを送信したい場合に指定できる定義ブロックです。
templates.rollback.postcondition.command
: ロールバック継続可否判定のために送信するコマンドを記述します。templates.command
同様にJinja2テンプレート形式で記述できます。
templates.rollback.postcondition.prompt_terminator
: ロールバック継続可否判定コマンド送信後に待ち受けるプロンプトを指定します。通常は自動検出されます。
templates.rollback.postcondition.expect_regexes
: ロールバック継続可否判定コマンドの応答結果に期待する正規表現を記述します。いづれかでもマッチしない場合、ロールバックは失敗とみなされエラーを返却します。
templates.rollback.postcondition.unexpect_regexes
: ロールバック継続可否判定コマンドの応答結果に期待しない正規表現を記述します。いづれかでもマッチする場合、ロールバックは失敗とみなされエラーを返却します。
templates.parameter_bindings
: CLIプロキシの一連のコマンド処理でデバイスから受信した応答メッセージからパラメータを導出する処理を記述する定義ブロックです。
templates.parameter_bindings.name
: 導出するパラメータの変数名を指定します。
templates.parameter_bindings.regex
: 導出するパラメータに代入するための値としてデバイスの応答メッセージからテキストを抜き出す正規表現を指定します。
templates.parameter_bindings.script
: 導出するパラメータに代入するための値としてデバイスの応答メッセージからテキストを抜き出すカスタムスクリプトを記述します。カスタムスクリプトの実行空間には、デバイスの応答メッセージが代入されたoutput
変数が格納されています。output
変数を参照してカスタムスクリプトで生成した値をv
変数に代入するとtemplates.parameter_bindings.name
で指定したbindings
辞書のパラメータに値がセットされます。
aop
: CLIプロキシの実行前後に実行したい同期型のカスタムスクリプトを埋め込むことができるオプションです。
aop.pre
: CLIプロキシの実行前に実行するカスタムスクリプトを記述します。CLIプロキシの実行前にbindings
情報を加工したり、新たなbindings
パラメータを生成することができます。カスタムスクリプトの実行空間には、開始時点のbingins
パラメータがデフォルトでセットされています。
aop.post
: CLIプロキシの実行後に実行するカスタムスクリプトを記述します。CLIプロキシの実行によって確定した最終的なbindings
情報を加工したり、新たなbindings
パラメータを生成することができます。カスタムスクリプトの実行空間には、bindings
パラメータがデフォルトでセットされています。
Note
aopオプションの使い方は少し難解です。CLIプロキシ呼び出し時に全てのレンダリングパラメータを受け取る場合やCLIプロキシのコマンド送受信で生成した結果パラメータだけで事足りる場合は通常使用することはありません。呼び出し時に指定されたパラメータやCLIプロキシの処理完了時に生成されたパラメータを基に新たなパラメータを導出してコマンド送信時にレンダリングしたり、処理結果(bindings
)に追加したい場合などに使用します。
- AOP定義サンプル
以下のCLIプロキシサンプルは、grep
というパラメータを与えて実行すると事前カスタムスクリプトによってfilterCondition
というパラメータが生成されます。その後、コマンド送信が実行され、コマンドの応答からversion
パラメータが生成されます。最後に事後カスタムスクリプトによってtextVersion
というパラメータが生成されます。
- name: showVersion
path: /showVersion
protocol: ssh
templates:
- command: 'show ver {{ filterCondition }}'
parameter_bindings:
- name: version
regex: '\d{2}\.\d{2}\.\d{2}\.S'
aop:
pre: 'filterCondition = "| inc (Cisco IOS XE Software, Version)" if grep is True else ""'
post: textVersion = "v"+version
- AOP実行例
templates.command
はCLIで送信するコマンドのテンプレートです。レンダリングパラメータはCLIプロキシを呼び出す際にrequired
キーとなります。この例ではfilterCondition
が該当しますが、このパラメータは、aop.pre
によって値が生成されるため、CLIプロキシ呼び出し時は、キーのみ指定して値はNone
で構いません。
>>> r = await callout(path="/showVersion?alias=csr1000v", method=PATCH, body={"grep": True, "filterCondition": None})↵
... ↵
Connecting...
Done.
csr1000v#
show ver | inc (Cisco IOS XE Software, Version)
Cisco IOS XE Software, Version 03.15.00.S - Standard Support Release
csr1000v#
Qmonus> version = '03.15.00.S'
↵
disable
csr1000v>
Disconnecting...
Done.
>>> print(MU(json.loads(r.body)).yaml_format)↵
... ↵
↵
csr1000v:
code: 200
output:
bindings:
$alias: csr1000v
$host: 192.168.2.200
$password: qmonus
$port: '22'
$secret: qmonus
$username: qmonus
filterCondition: '| inc (Cisco IOS XE Software, Version)'
grep: true
textVersion: v03.15.00.S
version: 03.15.00.S
message: null
responses:
- |-
show ver | inc (Cisco IOS XE Software, Version)
Cisco IOS XE Software, Version 03.15.00.S - Standard Support Release
csr1000v#
status: Complete
>>>
チュートリアル
はじめてのCLIプロキシ
Cisco CSR1000vにSSH接続してバージョン情報を取得するサンプルです。
実行するコマンドは、show ver | inc (Cisco IOS XE Software, Version)
のみでバージョン情報が出力される行に絞って実行しています。
parameter_bindings
では、正規表現でバージョン番号だけを抜き出してversion
変数に代入しています。
name: showVersion
path: /showVersion
protocol: ssh
templates:
- command: 'show ver | inc (Cisco IOS XE Software, Version)'
parameter_bindings:
- name: version
regex: '\d{2}\.\d{2}\.\d{2}\.S'
CLIプロキシを実行するためには、Device
オブジェクトが必要です。Device
オブジェクトは、Qmonus SDKのインメモリストアに永続化されます。Docs » Lambda » Device
を参考にしてください。
Device
オブジェクトは以下のパラメータを定義する必要があります。
alias: csr1000v
class: simplex
device: cisco_xe
host: 192.168.2.200
port: '22'
username: qmonus
password: qmonus
secret: qmonus
parameters: {}
Warning
Device
オブジェクトには、username
、password
、secret
といったシークレット情報が含まれる為、Qmonus SDKが吐き出すプラグイン定義ファイルでは、これらのデータは暗号化される点に注意してください。
暗号化及び復号化は、Qmonus SDKの起動パラメータplugin_secret_key
が利用されます。必ず開発プロジェクト単位に払い出して設定してください。
Device
オブジェクトを作成したら、CLIプロキシを実行できます。実行する方法は、CLIProxy
組込みオブジェクトを利用する方法と生成されたAPIをリクエストする方法の2種類が提供されます。
まずは、CLIProxy
組込みオブジェクトを利用して実行してみましょう。CLIProxy
組込みオブジェクトの使用方法は、Docs » リファレンス » ビルトインオブジェクト
にも記載していますので参考にしてください。
>>> p = await CLIProxy.load("showVersion")↵
... r = await p.run("csr1000v")↵
... ↵
↵
csr1000v#
csr1000v#terminal length 0
terminal length 0
csr1000v#terminal width 511
terminal width 511
csr1000v#
csr1000v#
csr1000v#show ver | inc (Cisco IOS XE Software, Version)
show ver | inc (Cisco IOS XE Software, Version)
Cisco IOS XE Software, Version 03.15.00.S - Standard Support Release
csr1000v#
>>> print(r.bindings.version)↵
... ↵
↵
03.15.00.S
>>>
最初の実行例では、Device
オブジェクトを作成し、そのalias
を指定して実行しましたが、Device
オブジェクトを永続化したくない(インメモリストアでプラグインとしてDeviceを管理せず、リレーショナルデータベースで独自に管理したい)場合、以下のようにDevice
インスタンスを使って実行することもできます。
>>> device = Device("csr1000v", device="cisco_xe", host="192.168.2.200", username="qmonus", password="qmonus")↵
... p = await CLIProxy.load("showVersion")↵
... r = await p.run(device)↵
... ↵
↵
csr1000v#
csr1000v#terminal length 0
terminal length 0
csr1000v#terminal width 511
terminal width 511
csr1000v#
csr1000v#
csr1000v#show ver | inc (Cisco IOS XE Software, Version)
show ver | inc (Cisco IOS XE Software, Version)
Cisco IOS XE Software, Version 03.15.00.S - Standard Support Release
csr1000v#
>>> print(r.bindings.version)↵
... ↵
↵
03.15.00.S
>>>
最後に自動生成されたAPIをリクエストしてCLIプロキシを実行します。生成されるAPIの待受メソッドは、PATCH
です。リクエスト本文でコマンドテンプレートへのレンダリングパラメータを渡すこともできます。
Note
CLIプロキシを登録した際にAPI GatewayのAPIルーティングが自動追加されます。
>>> r = await callout(path="/showVersion?alias=csr1000v", method=PATCH)↵
... ↵
Connecting...
Done.
csr1000v#
show ver | inc (Cisco IOS XE Software, Version)
Cisco IOS XE Software, Version 03.15.00.S - Standard Support Release
csr1000v#
Qmonus> version = '03.15.00.S'
↵
disable
csr1000v>
Disconnecting...
Done.
>>> print(MU(json.loads(r.body)).yaml_format)↵
... ↵
↵
csr1000v:
code: 200
output:
bindings:
$alias: csr1000v
$host: 192.168.2.200
$password: qmonus
$port: '22'
$secret: qmonus
$username: qmonus
version: 03.15.00.S
message: null
responses:
- |-
show ver | inc (Cisco IOS XE Software, Version)
Cisco IOS XE Software, Version 03.15.00.S - Standard Support Release
csr1000v#
status: Complete
>>>
CLIプロキシによるコンフィグ例
interface設定のサンプルです。interface名と設定するIPアドレスとネットマスクは引数で指定できるようにします。
interfaceを活性化した後、showコマンドで状態を取得します。状態は、showコマンドの出力結果からカスタムスクリプトで送信コマンドと受信プロンプト部を除去して抽出しています。
- config: true
name: config
path: /config
protocol: ssh
templates:
- command: 'interface {{ iface }}'
- command: 'ip address {{ address }} {{ netmask }}'
- command: no shutdown
- command: 'do show ip interface brief | inc {{ iface }}'
parameter_bindings:
- name: status
script: |-
output = '\n'.join(output.split('\n')[1:-1])
v = output.split()[-1] if output.split()[1]==address else None
- REPLでの動作確認
>>> p = await CLIProxy.load("config")↵
... r = await p.run("csr1000v", params={"iface": "GigabitEthernet3", "address": "172.16.100.1", "netmask": "255.255.255.0"})↵
... ↵
↵
csr1000v#
csr1000v#terminal length 0
terminal length 0
csr1000v#terminal width 511
terminal width 511
csr1000v#
csr1000v#
csr1000v#
csr1000v#config term
config term
Enter configuration commands, one per line. End with CNTL/Z.
csr1000v(config)#
csr1000v(config)#
csr1000v(config)#
csr1000v(config)#interface GigabitEthernet3
interface GigabitEthernet3
csr1000v(config-if)#
csr1000v(config-if)#ip address 172.16.100.1 255.255.255.0
ip address 172.16.100.1 255.255.255.0
csr1000v(config-if)#
csr1000v(config-if)#no shutdown
no shutdown
csr1000v(config-if)#
csr1000v(config-if)#do show ip interface brief | inc GigabitEthernet3
do show ip interface brief | inc GigabitEthernet3
GigabitEthernet3 172.16.100.1 YES manual up up
csr1000v(config-if)#
csr1000v(config-if)#end
end
csr1000v#
csr1000v#
>>> print(r.bindings.yaml_format)↵
... ↵
↵
$alias: csr1000v
$host: 192.168.2.200
$password: s10nes
$port: '22'
$secret: s10nes
$username: hash
address: 172.16.100.1
iface: GigabitEthernet3
netmask: 255.255.255.0
status: up
>>>
- API呼び出しによる動作確認
>>> r = await callout(path="/config?alias=csr1000v", method=PATCH, body={"iface": "GigabitEthernet3", "address": "172.16.100.1", "netmask": "255.255.255.0"})↵
... ↵
Connecting...
Done.
csr1000v#
config term
Enter configuration commands, one per line. End with CNTL/Z.
csr1000v(config)#
interface GigabitEthernet3
csr1000v(config-if)#
ip address 172.16.100.1 255.255.255.0
csr1000v(config-if)#
no shutdown
csr1000v(config-if)#
do show ip interface brief | inc GigabitEthernet3
GigabitEthernet3 172.16.100.1 YES manual up up
csr1000v(config-if)#
Qmonus> status = 'up'
↵
disable
csr1000v>
Disconnecting...
Done.
>>> print(MU(json.loads(r.body)).yaml_format)↵
... ↵
↵
csr1000v:
code: 200
output:
bindings:
$alias: csr1000v
$host: 192.168.2.200
$password: s10nes
$port: '22'
$secret: s10nes
$username: hash
address: 172.16.100.1
iface: GigabitEthernet3
netmask: 255.255.255.0
status: up
message: null
responses:
- |-
interface GigabitEthernet3
csr1000v(config-if)#
- |-
ip address 172.16.100.1 255.255.255.0
csr1000v(config-if)#
- |-
no shutdown
csr1000v(config-if)#
- "do show ip interface brief | inc GigabitEthernet3\nGigabitEthernet3 172.16.100.1\
\ YES manual up up \ncsr1000v(config-if)#"
status: Complete
>>>