Builtins

本章では、Qmonus SDKがバンドル提供する組み込みオブジェクト、および組み込み関数について解説します。これらはREPL及び様々なプラグインのカスタムスクリプト空間で利用できます。

目次

Common


callout

HTTP通信を行う関数です。引数は以下の通りです。

引数 デフォルト 説明
url None 指定したURLに直接通信します。APIGWは経由しません。
endpoint APIGW 指定したエンドポイントに通信します。URLが指定されている場合は無視されます。
path None HTTPリクエストパスを指定します。URLが指定されている場合は無視されます。
method GET HTTPリクエストメソッドを指定します。デフォルトはGETです。利用できるメソッドは、POST|PUT|DELETE|GET|PATCHです。
body None HTTPリクエストボディを指定します。指定できる型は、str|list|dictです。list|dictを指定した場合はjsonシリアライズされます。
headers None HTTPリクエストヘッダを指定します。指定しない場合、Content-Typeはapplication/jsonがセットされます。
static_route None 指定した値がX-Xaas-Static-Routing拡張ヘッダにセットされます。
connect_timeout 60 HTTP接続タイムアウト(秒)です。デフォルト値は、起動パラメータcallout_connect_timeoutに従います。
request_timeout 60 HTTP要求タイムアウト(秒)です。デフォルト値は、起動パラメータcallout_request_timeoutに従います。
retry_interval 0 リトライ送信間隔(秒)です。
retry_count 0 リトライ回数です。
retry_codes [599] リトライするHTTPエラーコードリストです。
xid None トランザクションIDを指定します。
xname None トランザクション名を指定します。
delay 0 HTTP送信までの遅延時間(秒)を指定します。
authentication None 認証オプションです。
lambda_termination True lambdaサービスのCLIProxyNetconfProxyによって生成されたAPIを呼び出した際にイベントチェイン終端まで待つモードです。
validate_cert True HTTPS通信においてサーバ証明書の検証要否を指定するモードです。
ca_certs None HTTPS通信においてPEM形式のCA証明書のファイル名を指定します。
client_key None HTTPS通信においてクライアントSSL鍵のファイル名を指定します。
client_cert None HTTPS通信においてクライアントSSL証明書のファイル名を指定します。
auto_url_encode False 自動URLエンコードモードを指定します。


Warning

デフォルトでは、url及びpathについてURLエンコードされていない場合は自動的にURLエンコードが実施されることに注意してください。

起動パラメータauto_url_encodeFalseに設定した場合はこの動作は抑止されます。

ただし、callout関数に直接auto_url_encode=Trueを指定した場合は動作します。

Warning

retry_codesを指定するとリトライ動作が行われますが、このcallout処理がトランザクションスコープで行われている場合、リトライ中に他の要因でトランザクションアボートが発生してもリトライ動作が継続します。xidもしくはxnameを指定することでリトライ動作時にトランザクション状態をチェックして続行すべきでは無い場合はリトライ動作を中断し、制御を戻します。

Warning

APIGWを経由するリクエストの場合、APIGWからさらにルーティングされるリクエストについてはcallout関数におけるvalidate_certの指定は影響しません。APIGWから対向システム等にroutingするケースでvalidate_certを指定したい場合はroutingで設定する必要があります。routingでの指定がない場合、routing先へのリクエストにおけるvalidate_certのデフォルトはFalseとなることに注意してください。

以下は、url引数を指定して直接エンドポイントと通信する例です。

>>> r = await callout(url="https://www.yahoo.co.jp")↵
... print(r.code)↵
... ↵
200
↵
>>>

APIGWのルーティングが登録されている場合は、以下のようにpathを指定することで通信できます。

>>> r = await callout(path="/v2.0/tenants")
... print(r.code)↵
... ↵
200
↵
>>>

authenticationを使用したBASIC認証の例です。

response = await callout(path="/example/basicAuthentications",
                         authentication=dict(auth_mode="basic",
                                             username="admin",
                                             password="admin"))

authenticationを使用したDIGEST認証の使用例です。

response = await callout(path="/example/digestAuthentications",
                         authentication=dict(auth_mode="digest",
                                             username="admin",
                                             password="admin"))

authenticationを使用したKeystone認証の例です。

response = await callout(path="/v2.0/tenants",
                         authentication=dict(auth_mode="keystone",
                                             username="{username}",
                                             password="{password}",
                                             project_id="{project_id"}))

authenticationを使用したAWS-HMAC-V4認証の例です。

response = await callout(url="directconnect.ap-northeast-1.amazonaws.com",
                         method="POST",
                         body=dict(connectionId="xxxxx"),
                         authentication=dict(auth_mode="AWS-HMAC-V4",
                                             username="xxxxx",
                                             password="xxxxx",
                                             domain_id="ap-notrheast-1",
                                             domain_name="DirectConnect",
                                             project_id="DescribeVirtualInterfaces"))

Tip

開発者は認証オプションを使用せずに認証プロセスを記述することもできます。
認証オプションを使用すると、AXIS は認証情報をキャッシュして再利用します。
認証情報の有効期限が切れると、自動的に再キャッシュされます。


genkey

ランダムパスワード文字列を生成する関数です。

lengthは、生成する文字数を指定する引数です。デフォルトは8です。 continuityは、生成する文字列に同じ文字が連続して登場できる上限を指定する引数です。デフォルトは3です。

>>> print(genkey())↵
... ↵
D5AFlqE4yUoGPfUVGYuMJmm4RRli8jqk86Y3pkWfxUjYbsX3n9FyAzF8jqfHXEEJ↵
↵
>>> print(genkey(length=10, continuity=2))↵
... ↵
u66dkDHVab↵
↵`
>>>


encrypt

AES(Advanced Encryption Standard)暗号化を行う関数です。

引数 デフォルト 説明
key None 暗号鍵
origin None 暗号化するテキストデータ


decrypt

AES(Advanced Encryption Standard)複合化を行う関数です。

引数 デフォルト 説明
key None 暗号鍵
origin None 暗号データ


Tip

genkeyで暗号鍵を生成してデータを暗号化、複合化できます。

>>> data = {"name": "hoge", "description": "hogehoge"}↵
... key = genkey()↵
... v = encrypt(key, json.dumps(data))↵
... print(v)↵
... print(decrypt(key, v))↵
... ↵
↵
cPeiLVAhsWIaQY5QziCQlJdarA4GIzziIrO3Bktz2w86Km+THoLiq3pRt7rEWO/wbHI2XLfxezrl98UJz1xj5fj2tPNdiZiWEHoPHvAED4Q=
{"name":"hoge","description":"hogehoge"}
>>>


queryjoin

クエリ付きHTTPリクエストパスを簡易に作成する関数です。

>>> print(queryjoin("/hoges", status=["active", "processing"], name="test"))↵
... ↵
/hoges?status=active&status=processing&name=test↵
↵
>>>


multi

非同期呼び出しを多重実行する関数です。

await asyncio.gather(coroutines, return_exceptions=True)と同義です。

>>> responses = await multi([callout(url="http://yahoo.co.jp") for i in range(10)])↵
... print([i.code for i in responses])↵
... ↵
[200, 200, 200, 200, 200, 200, 200, 200, 200, 200]↵
↵
>>>


Awaitable

ブロッキング関数を非同期化する関数です。キーワード引数を与えることができます。

>>> print(clock.now())↵
... await Awaitable(time.sleep, 3)↵
... print(clock.now())↵
... ↵
2020-11-26 12:49:36.515718+09:00
↵
2020-11-26 12:49:39.516854+09:00
>>>


bg

バックグラウンドで非同期処理を動かす関数です。awaitでコルーチンの完了を待たずに突き放して処理させたい場合に利用します。

>>> bg(Scenario.run("sample"))↵
... ↵
↵
>>>


rendering

Templateサービスに登録されているJinja2テンプレートにレンダリングする関数です。

以下のテンプレートがTemplateサービスに登録されているものとします。

tag: config
template: |-
  hostname {{ hostName }}
  !
  enable password {{ enablepass }}
  !
  username {{ username }} password 0 {{ password }}
  no aaa new-model
  !
  int vlan 1
  ip address {{ ipAddress }} {{ subnet }}
  !
  end
expire_seconds: 10

rendering関数の使用方法は以下の通りです。

# Example of getting the result of template rendering by text
>>> r = await rendering("config", hostName="R1", enablepass="admin", username="aaa", password="bbb", ipAddress="10.10.10.101", subnet="255.255.255.0")↵
... print(r)↵
... ↵
hostname R1
!
enable password admin
!
username aaa password 0 bbb
no aaa new-model
!
int vlan 1
ip address 10.10.10.101 255.255.255.0
!
end↵
↵

尚、テンプレートはincludeを使用することもできます。

親テンプレートのサンプルです。

tag: main_template
template: |-
  name: {{ name }}
  % if age > 0:
      {% include "sub_template" %}
  % endif
expire_seconds: 3600

子テンプレートのサンプルです。

tag: sub_template
template: 'age: {{ age }}'
expire_seconds: 3600

レンダリングのサンプルです。

>>> r = await rendering("main_template", name="testUser", age=0)↵
... print(r)↵
... ↵
name: testUser↵
↵
>>> r = await rendering("main_template", name="testUser", age=10)↵
... print(r)↵
... ↵
name: testUser
    age: 10↵
↵


where_statement

SQL文におけるWHERE句を生成するユーティリティ関数です。

引数 デフォルト 説明
cls None モデルクラス
params {} パラメータ辞書
**kwargs {} キーワード引数でのパラメータ指定
>>> async with model.aiodb() as conn:↵
...     cursor = await conn.execute(model.Tenant.select().where(where_statement(model.Tenant, tenant_name=["hoge1"])))↵
...     print(cursor.rowcount)↵
... ↵
↵
1


rowtodict

データベースからフェッチした行をPythonのdictに変換する関数です。

>>> r = await SQL.run("SELECT * FROM Test;")↵
... print(r)↵
... ↵
[('VGVzdDplNDEzMzA4NDJmNzgxMWViODA2ZmFjZGU0ODAwMTEyMg==', None, None, None)]↵
>>> for i in r:↵
...     d = rowtodict(i)↵
...     print(d)↵
... ↵
{'instance': 'VGVzdDplNDEzMzA4NDJmNzgxMWViODA2ZmFjZGU0ODAwMTEyMg==', 'xid': None, 'xname': None, 'name': None}↵
>>>


and_

SQL文におけるAND条件式関数でsqlalchemy.and_へのアクセッサです。


or_

SQL文におけるOR条件式関数でsqlalchemy.or_へのアクセッサです。


not_

SQL文におけるNOT条件式関数でsqlalchemy.not_へのアクセッサです。


select

SQL文におけるSELECT式関数でsqlalchemy.sql.selectへのアクセッサです。


join

SQL文におけるJOIN式関数でsqlalchemy.sql.joinへのアクセッサです。


scp

SCP(Secure Copy Protocol)関数です。成功するとTrue、失敗するとFalseが返却されます。

引数 デフォルト 説明
host None リモートホストアドレス
port None リモートホストポート番号
username None リモートホストユーザ名
password None リモートホストパスワード
filename None リモートファイル名
text None 転送するテキスト
encoding utf-8 転送するテキストエンコーディング


sendmail

SMTP(Simple Mail Transfer Protocol)関数です。

引数 デフォルト 説明
host None メールサーバアドレス
port None メールサーバポート
sender None 送信元メールアドレス
recipients None 送信先メールアドレスリスト
username None SMTP認証ユーザ名
password None SMTP認証パスワード
subject "" メールサブジェクト
text "" メール本文
cc None Carbon Copyアドレス
bcc None Blind Carbon Copyアドレス
use_tls False TLSオプション
start_tls False 開始TLSオプション


ElementTree

XMLエレメントツリー(xml.etree.ElementTree)へのアクセッサです。


magic

dictやlistから指定したキーだけを抽出したり、抽出したキー名を変換して取り出す関数です。

>>> a = {"id": 111, "name": "hoge", "children": [{"id": 222, "name": "hogehoge1", "status": True},↵
... {"id": 333, "name": "hogehoge2", "status": False}]}↵
... b = magic(a, key_filters=["id", "children"])↵
... print(b)↵
... b = magic(a, key_filters=["id", "children"], key_converters={"id":"number"})↵
... print(b)↵
... ↵
↵
{'id': 111, 'children': [{'id': 222}, {'id': 333}]}
{'number': 111, 'children': [{'number': 222}, {'number': 333}]}
>>>


pubsub

Qmonus内部のpubsubチャネルにデータをpublishする関数です。REPLのdebugコマンドでデバッグモードにしている場合、ここでpublishされた情報がREPL上に通知されます。

引数 デフォルト 説明
event None イベント名
data None 送信データ


qprint

Qmonus内部のpubsubチャネルにテキストをpublishする関数です。REPLのdebugコマンドでデバッグモードにしている場合、ここでpublishされた情報がREPL上に通知されます。 REPL上でプラグインを動かすとプラグインで記述されているprint文はフックされてREPL上で確認できますが、REPLで動かしていない場合には確認できません。qprintはREPLで動かしていない場合でもdebugモードのREPLであれば確認できるようになります。

引数 デフォルト 説明
text None テキストメッセージ


deserialize

ATOMオブジェクトはJSONシリアライズできます。プラグイン開発者が直接ATOMオブジェクトのシリアライズ、デシリアライズを行う必要はありませんが、独自のバックアップリストア機能を作成する場合、デシリアライズには注意が必要です。シリアライズはjson.dumpsを使えますが、デシリアライズは本関数を利用する必要があります。

>>> p = atom.Port(name="lo", number=0, status=True)↵
... s = json.dumps(p)↵
... print(s)↵
... d = await deserialize(s)↵
... print(d)↵
... print(d.yaml_format)↵
... ↵
{"<AxisAtom.Port>":{"instance":"UG9ydDo1YTNhOWVjZTJmYTUxMWViYTE2YWFjZGU0ODAwMTEyMg==","changes":{},"kwargs":{"instance":"UG9ydDo1YTNhOWVjZTJmYTUxMWViYTE2YWFjZGU0ODAwMTEyMg==","xid":null,"xname":null,"name":"lo","number":0,"status":true}}}
↵
Port(instance='UG9ydDo1YTNhOWVjZTJmYTUxMWViYTE2YWFjZGU0ODAwMTEyMg==', xid=None, xname=None, name='lo', number=0, status=True)
Port:
  instance: UG9ydDo1YTNhOWVjZTJmYTUxMWViYTE2YWFjZGU0ODAwMTEyMg==
  name: lo
  number: 0
  status: true
>>>


flattening

与えられた階層辞書をjson.dumpsしてフラット化する関数です。

>>> a = {"name": "hoge", "children": {"name": "hogehoge", "description": "hogehoge"}}↵
... print(a)↵
... b = flattening(a)↵
... print(b)↵
... ↵
↵
{'name': 'hoge', 'children': {'name': 'hogehoge', 'description': 'hogehoge'}}
{'name': 'hoge', 'children': '{"name":"hogehoge","description":"hogehoge"}'}
>>>


slack

slack(https://slack.com/)にチャットメッセージを書き込む関数です。

Note

slackにメッセージを書き込むためにはAPIトークンを取得する必要があります。 https://api.slack.com/appsにアクセスしてAppを作成してください。permission scopeとしてchat:writeのロールが必要です。

Note

slackのAPIトークンは、Qmonus SDKの起動パラメータに指定することができます。 --slack_notify_token={TOKEN}

APIトークンが起動パラメータで指定されている場合、slack関数は第一引数に送信先のチャネル名(@ユーザ名も可)、第二引数にメッセージ本文を与えることでチャットが書き込まれます。

>>> await slack("test-channel", "Hello, Slack!")

APIトークンが起動パラメータに指定されていない場合は、slack関数にキーワード引数でtoken={TOKEN}として与える必要があります。


Error

例外クラスです。Qmonusプラグインで例外を送出する場合は、本クラスをスローしてください。

引数 デフォルト 説明
code 500 HTTPエラーコード
reason None HTTPエラー理由
body None HTTP本文
moreInfo None 詳細情報
raise Error(400, reason="combination error")


Cache

インメモリデーターベースへのキャッシュ操作を扱うクラスです。クラスタ環境においてもノード間でキャッシュを共有できます。

  • putメソッド

キャッシュに保存します。

引数 デフォルト 説明
key None キャッシュキー
value None キャッシュテキスト
ttl 60 生存期間(秒)


  • existsメソッド

キャッシュに指定したキーが存在するか確認します。

引数 デフォルト 説明
key None キャッシュキー


  • getメソッド

キャッシュから指定したキーの値を取得します。

引数 デフォルト 説明
key None キャッシュキー


  • deleteメソッド

キャッシュから指定したキーを削除します。

引数 デフォルト 説明
key None キャッシュキー


>>> r = await Cache.exists("sampleKey")↵
... print(r)↵
... ↵
↵
False
>>> await Cache.put("sampleKey", uuid.uuid1().hex, ttl=3600)↵
... ↵
↵
>>> r = await Cache.exists("sampleKey")↵
... print(r)↵
... ↵
↵
True
>>> v = await Cache.get("sampleKey")↵
... print(v)↵
... ↵
↵
665d67182faa11ebb24eacde48001122
>>> await Cache.delete("sampleKey")↵
... r = await Cache.exists("sampleKey")↵
... print(r)↵
... ↵
↵
False
>>>


Tip

Cacheクラスは、ScenarioやATOMなどのスクリプト空間で並列動作するサーバ間で共有可能な分散セマフォとして利用することもできます。
分散セマフォとしての利用は、以下の例のように非同期コンテキストマネージャ経由で記述します。
第一引数でロックする任意のキー名を指定します。キーワード引数ではtimeoutttlが指定できます。
timeoutのデフォルト値は、3秒です。ttlのデフォルト値は、10秒です。
ttlは、予期せぬプロセスダウンによって開放漏れが発生した場合に自動解放するまでの時間を指定します。無期限の設定は許可されません。

>>> async with Cache("test", timeout=10, ttl=20):↵
...     print("locked")↵
...     async with Cache("test", timeout=10, ttl=20):↵
...         print("locked")↵
... ↵
locked
lock timedout 'test'
>>>


clock

時刻操作クラスです。

  • clock.now() 現在時刻を取得します。起動パラメータの--timezoneに指定されたタイムゾーンが適用されます。デフォルトはAsia/Tokyoです。datetimeオブジェクトを返却します。
>>> print(clock.now())↵
... ↵
↵
2020-11-26 16:03:07.315464+09:00
>>>


  • clock.utcnow() UTC現在時刻を取得します。
>>> print(clock.utcnow())↵
... ↵
↵
2020-11-26 07:03:38.772274+00:00
>>>


  • clock.after_now() 現在時刻から指定された時刻パラメータ後のdatetimeオブジェクトを返却します。起点時刻を与えることもできます。
>>> print(clock.now())↵
... print(clock.after_now(days=1, hours=1))↵
... ↵
↵
2020-11-26 16:04:39.069598+09:00
2020-11-27 17:04:39.069649+09:00
>>> print(clock.now())↵
... base = clock.after_now(days=1)↵
... print(clock.after_now(base, hours=1))↵...起点時刻を指定したイメージ
... ↵
↵
2020-11-26 16:08:20.598098+09:00
2020-11-27 17:08:20.598142+09:00
>>>


  • clock.before_now() 現在時刻から指定された時刻パラメータ前のdatetimeオブジェクトを返却します。起点時刻を与えることもできます。
>>> print(clock.now())↵
... print(clock.before_now(minutes=30, seconds=10))↵
... ↵
↵
2020-11-26 16:05:54.312326+09:00
2020-11-26 15:35:44.312370+09:00
>>>


Geo

ジオコーディング実験中のクラスです。住所から緯度経度、緯度経度から住所を探します。

>>> l = await Geo.locate(address="高輪ゲートウェイ")↵
... print(l.yaml_format)↵
... ↵
↵
address: 高輪ゲートウェイ, 145, 第一京浜, 品川, 南青山6, 東京都, 港区, 108-0075, 日本 (Japan)
latitude: 35.6354137
longitude: 139.7406878
>>> l = await Geo.locate(latitude=l.latitude, l.longitude)↵
... print(l.yaml_format)↵
... ↵
↵
address: 高輪ゲートウェイ, 第一京浜, 品川, 南青山6, 東京都, 港区, 108-8611, 日本 (Japan)
latitude: 35.63544225
longitude: 139.7406615885073
>>>


Redis

Qmonus SDKが利用しているインメモリデータベースRedisのデータを参照するためののアクセッサクラスです。原則プラグイン開発者が利用することはありません。 infogetmgetexistskeysllenlrangelindexhkeyshexistshgethlenhvalshgetallflushallincrexpire操作だけが可能です。

>>> r = await Redis.keys("*")↵
... print(r)↵
... ↵
↵
[b'xaas.plugins.version', b'xaas.store.TRANSACTION', b'xaas.testcases', b'xaas.functions', b'xaas.testsuites', b'xaas.classes', b'xaas.fakers', b'xaas.request.queue.statistics', b'xaas.store.LAMBDA', b'xaas.illusions', b'xaas.scenarios', b'InteractiveShell', b'xaas.modelschemas', b'xaas.store.APIGW', b'xaas.store.SCENARIO', b'xaas.self.boot.uptime.127.0.0.1.9099', b'xaas.store.SCHEDULE']
>>>


SQL

SQL文を実行するクラスです。

  • SQL.run

SQL文を実行するメソッドです。

# SQLAlchemy
employees = await SQL.run(model.employee.select())

# Raw SQL statement
employees = await SQL.run("SELECT * FROM employee;")

# When using SQL function in transaction scope
async with model.aiodb() as conn:
    async with conn.begin() as tran:
        employees = await SQL.run(model.employee.select(), conn=conn)


バインドパラメータの使用例1: sqlalchemy.text

>>> from sqlalchemy import text↵
>>> await SQL.run(text('INSERT INTO Hoge(instance,name) values (:instance, :name)'), instance=uuid.uuid1().hex, name="hoge")↵
... ↵
↵
>>> select * from Hoge;↵
| instance | xid | xname | name | description |
5157c5b8498811ec8c71acde48001122 NULL NULL hoge NULL
1 rows in set
>>> await SQL.run(text('INSERT INTO Hoge(instance,name) values (:instance, :name)'), {"instance": uuid.uuid1().hex, "name": "hoge2"})↵
... ↵
↵
>>> select * from Hoge;↵
| instance | xid | xname | name | description |
5157c5b8498811ec8c71acde48001122 NULL NULL hoge NULL
97f8f4a6498811ecbfe5acde48001122 NULL NULL hoge2 NULL
2 rows in set
>>> ↵
↵
>>> await SQL.run(text('INSERT INTO Hoge(instance,name) values (:instance, :name)'), [{"instance": uuid.uuid1().hex, "name": "hoge3"}, {"instance": uuid.uuid1().hex, "name": "hoge4"}])↵
... ↵
↵
>>> select * from Hoge;↵
| instance | xid | xname | name | description |
155f2208498911ecb3c2acde48001122 NULL NULL hoge4 NULL
5157c5b8498811ec8c71acde48001122 NULL NULL hoge NULL
97f8f4a6498811ecbfe5acde48001122 NULL NULL hoge2 NULL
d76a9612498811ec98f6acde48001122 NULL NULL hoge3 NULL
4 rows in set
>>> ↵


バインドパラメータの使用例2: sqlalchemy.sql.bindparam

>>> from sqlalchemy.sql import bindparam↵
... ↵
↵
>>> await atom.Foo(name="example1", createdAt=clock.now(), status=True).save()↵
... await atom.Foo(name="example2", createdAt=clock.now(), status=True).save()↵
... await atom.Foo(name="example3", createdAt=clock.now(), status=False).save()↵
... ↵
↵
>>> select * from Foo;↵
| instance | xid | xname | name | createdAt | status |
Rm9vOmI0M2E3MzJjNTAyZDExZWQ5MTViYWNkZTQ4MDAxMTIy NULL NULL example1 2022-10-20 13:14:35 1
Rm9vOmI0M2I4MTVlNTAyZDExZWQ5MTViYWNkZTQ4MDAxMTIy NULL NULL example3 2022-10-20 13:14:35 0
Rm9vOmI0M2IxNzMyNTAyZDExZWQ5MTViYWNkZTQ4MDAxMTIy NULL NULL example2 2022-10-20 13:14:35 1
3 rows in set
>>> rows = await SQL.run(↵
...     model.Foo.select().where(model.Foo.c.createdAt<bindparam("timestamp")),↵
...     timestamp=clock.now(),↵
...     auto_compile=False↵
... )↵
... print(rows)↵
... ↵
↵
[('Rm9vOmI0M2E3MzJjNTAyZDExZWQ5MTViYWNkZTQ4MDAxMTIy', None, None, 'example1', datetime.datetime(2022, 10, 20, 13, 14, 35), True), ('Rm9vOmI0M2I4MTVlNTAyZDExZWQ5MTViYWNkZTQ4MDAxMTIy', None, None, 'example3', datetime.datetime(2022, 10, 20, 13, 14, 35), False), ('Rm9vOmI0M2IxNzMyNTAyZDExZWQ5MTViYWNkZTQ4MDAxMTIy', None, None, 'example2', datetime.datetime(2022, 10, 20, 13, 14, 35), True)]
>>> rows = await SQL.run(↵
...     model.Foo.select().where(model.Foo.c.createdAt<bindparam("timestamp")),↵
...     timestamp=clock.before_now(minutes=60),↵
...     auto_compile=False↵
... )↵
... print(rows)↵
... ↵
↵
[]
>>>
>>> rows = await SQL.run(↵
>>> model.Foo.select().where(model.Foo.c.status.in_([bindparam("status")])), auto_compile=False, status=True)↵
>>> print(rows)↵
... ↵
↵
[('Rm9vOmI0M2E3MzJjNTAyZDExZWQ5MTViYWNkZTQ4MDAxMTIy', None, None, 'example1', datetime.datetime(2022, 10, 20, 13, 14, 35), True), ('Rm9vOmI0M2IxNzMyNTAyZDExZWQ5MTViYWNkZTQ4MDAxMTIy', None, None, 'example2', datetime.datetime(2022, 10, 20, 13, 14, 35), True)]
>>> rows = await SQL.run(model.Foo.select().where(model.Foo.c.status.in_([bindparam("status")])), auto_compile=False, status=False)↵
... print(rows)↵
... ↵
↵
[('Rm9vOmI0M2I4MTVlNTAyZDExZWQ5MTViYWNkZTQ4MDAxMTIy', None, None, 'example3', datetime.datetime(2022, 10, 20, 13, 14, 35), False)]
>>>


Tip

SQL.runにステートメントをオブジェクト渡しすると自動的にコンパイルが行われます。自動コンパイルを避けるにはauto_compile=Falseを指定してください。尚、auto_compileキーワード引数はv23.1LTS以降のバージョンで使用可能となります。


  • SQL.bulkUpsert

レコードを一括挿入、もしくは更新するメソッドです。大量のテストデータなどをデータベースに一括投入する場合などで利用します。

引数 デフォルト 説明
table None ATOMクラス、modelテーブル、テーブル名のいづれかを指定します
instances [] ATOMインスタンスのリストを指定します
records [] カラム名と値の辞書オブジェクトのリストを指定します


Warning

recordsにkey/value形式でデータを渡す場合、テーブルカラムは省略できませんので必ず全てのカラムを指定してください。


>>> tenants = [atom.Tenant(tenant_id=uuid.uuid1().hex, tenant_name="tenant%d") for i in range(30000)]↵
>>> await SQL.bulkUpsert(atom.Tenant, instances=tenants)↵
... ↵
↵
>>> select count(*) from Tenant;↵
| count(*) |
30000
1 rows in set
>>>


Runtime

Runtimeクラスは、Qmonus SDKのランタイム情報にアクセスするオブジェクトです。本オブジェクトは、トラブルシューティング時にQmonusランタイムのメンテナンス全般を操作できます。詳しく知りたい方は、サポートに問い合わせしてください。
Workerサービスで無限ループで常駐するワーカー関数のbreak条件としてRuntime.running()を監視するようにしてください。

>>> print(Runtime.running())↵
... ↵
↵
True
>>>


APIGW


gRPC

gRPCクライアントを作成する関数です。使用方法はAPI GatewayのgRPCプロキシの章を参照してください。


Parse

プロトコルバッファのパーサー(google.protobuf.json_format.Parse)へのアクセッサです。JSONをプロトコルバッファオブジェクトに変換します。使用方法はAPI GatewayのgRPCプロキシの章を参照してください。


MessageToJson

プロトコルバッファのデコーダー(google.protobuf.json_format.MessageToJson)へのアクセッサです。プロトコルバッファオブジェクトをJSONに変換します。使用方法はAPI GatewayのgRPCプロキシの章を参照してください。


Transaction


transaction_active_check

トランザクションが処理中かを判定する関数です。トランザクションの状態がProcessingRecoveryProcessingCancellingSuspendingの場合はTrueを返却し、それ以外の場合はFalseが返却されます。

引数 デフォルト 説明
xid None トランザクションID
with_transaction False トランザクション情報も返却するか否かを指定できます
>>> bg(Scenario.run("sample"))↵
... await asyncio.sleep(1)↵...バックグラウンドで実行するのでトランザクション開始を待ち合わせる
... r = await get_transactions(xdomain="sample")↵
... for i in r:↵
...     isActive = await transaction_active_check(xid=i.xid, with_transaction=False)↵
...     print(isActive)↵
... ↵
↵
True
>>>


get_transactions

トランザクション情報を取得する関数です。MUオブジェクトのリストが返却されます。

引数 デフォルト 説明
xdomain None トランザクションドメイン
xtype None トランザクション種別
xid None トランザクションID
xname None トランザクション名
status None トランザクション状態


waitfor_transaction

トランザクションの状態確定を待ち合わせます。トランザクションの状態がProcessingRecoveryProcessingCancellingの場合は処理が完了するまで待ち合わせます。 それ以外の状態を検出すると状態が確定したとみなし、トランザクション情報をMU型で返却します。ポーリングタイムアウトが発生した場合は例外を発出します。

引数 デフォルト 説明
xid None トランザクションID
retry_interval 1 トランザクション状態ポーリング間隔
retry_count None トランザクション状態ポーリング最大回数


>>> await Scenario.run("sample")↵
... r = await get_transactions(xdomain="sample")↵
... for i in r:↵
...     x = await waitfor_transaction(i.xid, retry_interval=3, retry_count=60)↵
...     print(x.status)↵
... ↵
Complete↵
>>>


Counter

カウンタサービスを操作する組込みオブジェクトです。

  • Counter.allocate

Counterを払い出す関数です。

引数 デフォルト 説明
name None カウンタ名


>>> r = await Counter.allocate("orderNumber")↵
... print(r)↵
... ↵
SO00000002↵
>>>
  • Counter.release

Counterを払い戻す関数です。

引数 デフォルト 説明
name None カウンタ名
value None カウンタ値


>>> r = await Counter.allocate("vlanNumber")↵
... print(r)↵
... r = await Counter.allocate("vlanNumber")↵
... print(r)↵
... r = await Counter.allocate("vlanNumber")↵
... print(r)↵
... await Counter.release("vlanNumber", r)↵
... r = await Counter.allocate("vlanNumber")↵
... print(r)↵
... ↵
1↵
2↵
3↵
3↵
>>>


  • Counter.remains

Counterの在庫を取得する関数です。

引数 デフォルト 説明
name None カウンタ名


  • Counter.expand

inventoryタイプのCounterの最大値を拡張する関数です。

引数 デフォルト 説明
name None カウンタ名
count 0 拡張数


>>> r = await Counter.remains("vlan")↵
... print(r)↵
... ↵
↵
10
>>> for i in range(10):↵
...     r = await Counter.allocate("vlan")↵
...     print(r)↵
... ↵
10
11
12
13
14
15
16
17
18
19
>>> r = await Counter.remains("vlan")↵
... print(r)↵
... ↵
↵
0
>>> await Counter.expand("vlan", count=10)↵
... r = await Counter.remains("vlan")↵
... print(r)↵
... ↵
↵
10
>>> for i in range(10):↵
...     r = await Counter.allocate("vlan")↵
...     print(r)↵
... ↵
20
21
22
23
24
25
26
27
28
29
>>>


ipam

トランザクションサービスが提供するIPAMリソースを操作するクラスです。使用方法については、Docs » Transaction » IPアドレス管理を参照ください。


Scenario


Template

Templateをオブジェクトとして操作できるオブジェクトです。

  • Template.exists

Templateが存在しているかをチェックするクラスメソッドです。引数は、Templateのtagです。

>>> r = await Template.exists("createSubInterface")↵
... print(r)↵
... ↵
↵
True
>>>


  • Template.load

Templateオブジェクトをインスタンス化するクラスメソッドです。引数は、Templateのtagです。

>>> t = await Template.load("createSubInterface")↵
... print(t)↵
... ↵
↵
<axis.hotspot.script_runner.Template object at 0x110514d10>


  • Template.validate

Templateに設定されているschemaで指定したパラメータをバリデーションするインスタンスメソッドです。引数は、パラメータです。キーワード引数形式で指定します。
バリデーションエラーの場合は、例外を発出します。

>>> t = await Template.load("createSubInterface")↵
>>> print(t.schema)↵
... ↵
↵
{'properties': {'vlan': {'maximum': 4094, 'mininum': 1, 'type': 'integer'}}, 'required': ['vlan'], 'type': 'object'}
>>> t.validate(vlan="hoge")↵
... ↵
Invalid parameters
>>> t.validate(vlan=100)↵
... ↵
↵
>>>


  • Template.render

Templateにパラメータをレンダリングするインスタンスメソッドです。引数はパラメータです。キーワード引数形式で指定します。
Templateschemaが設定されている場合は、最初にバリデーションが実行されることに注意してください。

>>> r = await t.render(vlan=100)↵
... print(r)↵
... ↵
↵
<config>
  <cli-config-data>
    <cmd>interface gigabitEthernet 3.100</cmd>
    <cmd>encapsulation dot1Q 100</cmd>
    <cmd>ip address 172.16.100.1 255.255.255.0</cmd>
    <cmd>no shutdown</cmd>
  </cli-config-data>
</config>
>>>


get_service_config

Configプラグインを取得する関数です。

引数 デフォルト 説明
name None Config名
mu_conversion False Falseの場合はdict型で取得しますが、Trueの場合はMUにキャストされます


Tip

よくある複合的な使用例を以下に掲載します。Transacitonサーバの起動パラメータ--job_transaction_event=Trueを設定してトランザクションがAbortedに遷移したイベントを発生させ、Jobに以下のようなコードを記述してメール送信するパタンがよく使われています。

subject = "Qmonus-Notification-Transaction.Aborted"

# メール本文をtemplateレンダリングで作成
text = await rendering("mailTemplate", reason="トランザクションが中断しました")

# Configにメールサーバや送受信先の情報を設定しておき動的に取得
cfg = await get_service_config("test", mu_conversion=True)

# sendmailで送信
r = await sendmail(cfg.email.hostname, cfg.email.port, cfg.email.sender, ",".join(cfg.email.recipients), subject=subject, text=text)


task

Scenarioサーバが提供するJobプラグインはタスクイベントをコンシュームして駆動します。task関数はタスクイベントを発生させる関数です。

引数 デフォルト 説明
topic None タスクのトピック
content None タスク情報(任意のデータを持つ辞書)
expire 10 有効期限
taskid = await task("hello.job", dict(arg="hello"), expire=30)


waitfor

先述したtaskによって発行されたtaskidを指定してタスクの完了を待ち合わせる関数です。

引数 デフォルト 説明
taskid None タスクID
count 60 タスク完了ポーリング最大回数
interval 1 タスク完了ポーリング間隔
>>> taskid = await task("hello.job", dict(arg="hello"), expire=30)↵
... r = await waitfor(taskid)↵
... print(r.yaml_format)↵
... ↵
↵
completedAt: '2020-11-26T09:47:27.750420+09:00'
taskid: f43974162f8011eb806facde48001122
>>>


Scenario

シナリオをREPL上で操作するクラスです。シナリオの検索(retrieve)、ロード(load)、実行(run)ができます。

  • Scenario.retrieve

シナリオを検索するクラスメソッドです。引数でキーワードを指定した場合はシナリオ名と部分一致検索を行います。返却値は、シナリオオブジェクトのリストです。

引数 デフォルト 説明
keyword None シナリオ名部分一致検索キーワード
>>> scenarios = await Scenario.retrieve()↵
... for i in scenarios:↵
...     print(i.name)↵
... ↵
↵
example
hello
>>> scenarios = await Scenario.retrieve("ell")↵
... for i in scenarios:↵
...     print(i.name)↵
... ↵
↵
hello
>>>


  • Scenario.load

シナリオオブジェクトを取得するクラスメソッドです。引数でシナリオ名を指定する必要があります。

引数 デフォルト 説明
name None シナリオ名
>>> hello = await Scenario.load("hello")↵
... print(hello)↵
... ↵
↵
command: script
id: 298ff4c8304911eb824dacde48001122
kwargs:
  code: 'context.session.finish({"hello": True})'
>>>


  • Scenario.run

シナリオを実行するクラスメソッドです。引数でAPIリクエスト情報を指定できます。返却値は疑似HTTP応答です。

引数 デフォルト 説明
path None シナリオのHTTPリクエストパス(パス変数やクエリ指定が必要な場合は指定してください)
method GET シナリオのHTTPリクエストメソッド
headers {} シナリオのHTTPリクエストヘッダ
**kwargs {} シナリオのHTTPリクエスト本文
>>> r = await Scenario.run("hello")↵
... print(r.code)↵
... print(r.body)↵
... ↵
↵
200
b'{"hello":true}'
>>> r = await Scenario.run("example", method=POST, headers={"Content-Type": "application/json"}, name="hoge", region="jp1")↵
... print(r.code)↵
... print(r.body)↵
... ↵
↵
400
{"errorCode":400,"errorMessage":"Invalid request","moreInfo":"'hoge' does not match '^[A-Z][a-zA-Z_0-9-]+$'\n\nFailed validating 'pattern' in schema['properties']['name']:\n    {'pattern': '^[A-Z][a-zA-Z_0-9-]+$', 'type': 'string'}\n\nOn instance['name']:\n    'hoge'"}
>>> r = await Scenario.run("example", method=POST, headers={"Content-Type": "application/json"}, **{"name": "hoge", "region": "jp1"})↵
... print(r.code)↵
... print(r.body)↵
... ↵
↵
400
{"errorCode":400,"errorMessage":"Invalid request","moreInfo":"'hoge' does not match '^[A-Z][a-zA-Z_0-9-]+$'\n\nFailed validating 'pattern' in schema['properties']['name']:\n    {'pattern': '^[A-Z][a-zA-Z_0-9-]+$', 'type': 'string'}\n\nOn instance['name']:\n    'hoge'"}
>>>


Note

retrieveloadによって取得したシナリオオブジェクトは以下の操作が可能です。

  • シナリオ名を確認する
>>> hello = await Scenario.load("hello")↵
... print(hello.name)↵
... ↵
↵
hello
>>>
  • yaml定義を確認する
>>> hello = await Scenario.load("hello")↵
... print(hello)↵
... ↵
↵
command: script
id: 298ff4c8304911eb824dacde48001122
kwargs:
  code: 'context.session.finish({"hello": True})'
>>>
  • トランザクションアシストモードが有効か確認する
>>> hello = await Scenario.load("hello")↵
... print(hello.transactional)↵
... ↵
↵
False
>>> example = await Scenario.load("example")↵
... print(example.transactional)↵
... ↵
↵
True
>>>
  • 自動応答モードが有効か確認する
>>> example = await Scenario.load("example")↵
... print(example.auto_response_mode)↵
... ↵
↵
False
>>>
  • リクエスト仕様を確認する(API仕様を定義している場合のみ出力されます)
>>> example = await Scenario.load("example")↵
... print(example.requestspec)↵
... ↵
↵
body:
  properties:
    description:
      type: string
    name:
      pattern: ^[A-Z][a-zA-Z_0-9-]+$
      type: string
    region:
      enum:
      - jp1
      - jp2
      type: string
  required:
  - name
  - region
  type: object
headers:
  properties:
    Content-Type:
      default: application/json
      type: string
  required:
  - Content-Type
  type: object
params:
  properties: {}
  required: []
  type: object
resources: {}
>>>
  • リクエストヘッダ仕様を確認する(API仕様を定義している場合のみ出力されます)
>>> example = await Scenario.load("example")↵
... print(example.headersspec)↵
... ↵
↵
properties:
  Content-Type:
    default: application/json
    type: string
required:
- Content-Type
type: object
>>>
  • リクエスト本文仕様を確認する(API仕様を定義している場合のみ出力されます)
>>> example = await Scenario.load("example")↵
... print(example.bodyspec)↵
... ↵
↵
properties:
  description:
    type: string
  name:
    pattern: ^[A-Z][a-zA-Z_0-9-]+$
    type: string
  region:
    enum:
    - jp1
    - jp2
    type: string
required:
- name
- region
type: object
>>>
  • リクエストパス仕様を確認する(API仕様を定義している場合のみ出力されます)
>>> hello = await Scenario.load("hello")↵
... print(hello.resourcesspec)↵
... ↵
↵
properties:
  instanceID:
    type: string
type: object
>>>
  • リクエストクエリ仕様を確認する(API仕様を定義している場合のみ出力されます)
>>> hello = await Scenario.load("hello")↵
... print(hello.queryspec)↵
... ↵
↵
properties:
  limit:
    type: integer
  offset:
    type: integer
type: object
>>>
  • リクエストクエリパラメータを確認する(API仕様を定義している場合のみ出力されます)
>>> hello = await Scenario.load("hello")↵
... print(hello.queryparams)↵
... ↵
↵
['limit', 'offset']
>>>
  • シナリオを実行する

Scenario.runクラスメソッド同様に実行できますが、返却値は、HTTP疑似応答オブジェクトとトランザクションIDのタプルとなることに注意が必要です。トランザクションが無効なシナリオもしくはBad Requestなどの理由で開始していない場合はNoneが返却されます。

>>> hello = await Scenario.load("hello")↵
... r, _ = await hello.run()↵
... print("%d %r" % (r.code, r.body))↵
... print("xid: %r" % _)↵
... ↵
↵
200 b'{"hello":true}'
xid: None
>>>


Daemon

デーモンをREPL上で操作するクラスです。デーモンの検索(retrieve)、ロード(load)、実行(run)ができます。

  • Daemon.retrieve

デーモンを検索するクラスメソッドです。引数でキーワードを指定した場合はデーモン名と部分一致検索を行います。返却値は、デーモンオブジェクトのリストです。

引数 デフォルト 説明
keyword None デーモン名部分一致検索キーワード
>>> daemons = await Daemon.retrieve()↵
... for i in daemons:↵
...     print(i.name)↵
... ↵
↵
hellod
heatbeatd
>>> daemons = await Daemon.retrieve("ell")↵
... for i in daemons:↵
...     print(i.name)↵
... ↵
↵
hellod
>>>
  • Daemon.load

デーモンオブジェクトを取得するクラスメソッドです。引数でデーモン名を指定する必要があります。

引数 デフォルト 説明
name None デーモン名
>>> hellod = await Daemon.load("hellod")↵
... print(hellod)↵
... ↵
↵
command: script
id: 59a48e14305111eb9545acde48001122
kwargs:
  code: print("Hello, daemon!")
>>>
  • Daemon.run

デーモンを実行するクラスメソッドです。

>>> await Daemon.run("hellod")↵
... ↵
Hello, daemon!
↵
>>>


Format

フォーマットオブジェクトを操作するクラスです。フォーマット関数の実行や検索ができます。

Note

本組込みオブジェクトは、v20.12 and laterで使用できます。

  • Format.formats

登録されているフォーマットを取得するクラスメソッドです。引数にフォーマット名の部分一致検索文字列を指定して絞り込むことができます。

# 登録されている全てのフォーマット関数を取得
>>> print(Format.formats())↵
... ↵
↵
{'python': <function python_format at 0x10f7f9050>, 'cidr': <function cidr at 0x10f7f7f80>, 'datetime-local': <function datetime_local at 0x10f7f7ef0>, 'identifier': <function identifier at 0x10f7f05f0>, 'non_hyph_uuid': <function non_hyph_uuid at 0x1103c9a70>}
>>>
# 部分一致検索文字列を指定してフォーマット関数を取得
>>> print(Format.formats("uuid"))↵
... ↵
↵
{'non_hyph_uuid': <function non_hyph_uuid at 0x1103c9a70>}
>>>


  • Format.<format名>

フォーマット関数の実体を取得するクラスメソッドです。引数に値を与えることでフォーマット関数の動作確認ができます。

>>> print(Format.non_hyph_uuid(uuid.uuid1().hex))↵
... ↵
↵
True
>>> print(Format.non_hyph_uuid(uuid.uuid1().__str__()))↵
... ↵
↵
False
>>>


Model

modelschemaリソースをATOMクラスにマイグレーションするクラスです。原則プラグイン開発者が利用することはありません。古いバージョンのSDKをご利用の環境でmodelschemaからATOMへのマイグレーションを検討されている方はサポートまでご連絡ください。


Plugins

scenarioリソースやmodelschemaリソースをモダンマイグレーションするクラスです。原則プラグイン開発者が利用することはありません。古いバージョンのSDKをご利用の環境でモダンマイグレーションを検討されている方はサポートまでご連絡ください。


Faker

Fakerリソースを単体実行できるクラスです。

  • Faker.load

Fakerオブジェクトをロードしてインスタンスを取得します。ロードされたFakerには定義されているfakeメソッドが実装されているのでそのままメソッドを呼び出せます。

>>> f = await Faker.load("postHoge")↵
... for i in dir(f):↵
...     if i.startswith("_"):↵
...         continue↵
...     print(i)↵
... ↵
↵
Accepted
Conflict
InternalError
>>> r = await f.Accepted()↵
... print(r)↵
... print(r.code)↵
... print(r.body)↵
... ↵
↵
{
    "code": 200,
    "headers": {
        "Content-Type": "application/json"
    },
    "error": null,
    "body": "{\"hogeID\":\"0537784c307811ebae1cacde48001122\"}"
}
200
{"hogeID":"0537784c307811ebae1cacde48001122"}
>>>


FakeHttpResponse

FakerからHTTP疑似応答を返却する場合に利用する疑似応答クラスです。以下のように利用します。

引数 デフォルト 説明
code 200 HTTPレスポンスコード
headers {"Content-Type": "application/json"} HTTPレスポンスヘッダ
body None HTTPレスポンス本文
async def Accepted(*args, **kwargs):
    hogeID = uuid.uuid1().hex
    await Cache.put(hogeID, "Pending", 15)
    return FakeHttpResponse(body=dict(hogeID=hogeID))


Illusion

Illusionリソースがテストケースから使用されているかどうかを確認したり、使用されていないIllusionリソースを消去するクラスです。 Illusionリソースはプラグイン開発者が定義することもできますが、テストケースにFakerのfakeメソッドを直接リンクさせることで自動生成することができます。 自動生成させる場合は、気づかないうちに利用しなくなったIllusionがゴミとして残ってしまうことがあるため、本クラスでゴミを確認してクリーニングすることができます。

  • Illusion.inuse

Illusionを使用しているテストケース情報を出力します。

引数 デフォルト 説明
name None Illusion名
>>> illusions = await Illusion.inuse()↵
... print(illusions)↵
... ↵
↵
exampleDeleteFailed:
- exampleAbnormalDeleteFailed
exampleDetectedErrorHogeState:
- exampleSubnormalDryrun
exampleDryrun:
- exampleNormalDryrun
exampleGetFailed:
- exampleAbnormalGetFailed
examplePostFailed:
- examplePostFailed
exampleWaitforActiveFailed:
- exampleSubnormalWaitforActiveFailed
exampleWaitforNotFoundFailed:
- exampleAbnormalWaitforNotFoundFailed
>>>
  • Illusion.unuse

使用されていないIllusionを出力します。

>>> illusions = await Illusion.unuse()↵
... print(illusions)↵
... ↵
↵
['dummyIllusion']
>>>
  • Illusion.cleanup

使用されていないIllusionを削除します。

>>> illusions = await Illusion.unuse()↵
... print(illusions)↵
... ↵
↵
['dummyIllusion']
>>> await Illusion.cleanup()↵
... illusions = await Illusion.unuse()↵
... print(illusions)↵
... ↵
↵
[]
>>>


TDD [TODO]

REPL上でテストケースを生成するクラスです。ATOMDaemonModuleFunctionFakerのテストケース生成をサポートしています。

  • TDD.Class

ATOMのテストケース生成器を取得します。

  • TDD.Daemon

Daemonのテストケース生成器を取得します。

  • TDD.Module

Moduleのテストケース生成器を取得します。

  • TDD.Function

Functionのテストケース生成器を取得します。

  • TDD.Faker

Fakerのテストケース生成器を取得します。


Test

ユニットテストを実行するクラスです。

  • Test.run

テストケースもしくはテストスイートを単体実行します。

引数 デフォルト 説明
name None テストケースもしくはテストスイート名前
>>> await Test.run("exampleNormalDryrun")↵
... ↵
↵
[7c7d6568307511ebae1cacde48001122] Testcase.exampleNormalDryrun.preparation...[Passed]
[7c7d6568307511ebae1cacde48001122] Testcase.exampleNormalDryrun.assert_begin...[Passed]
[7c7d6568307511ebae1cacde48001122] Testcase.exampleNormalDryrun.call...[Passed]
[7c7d6568307511ebae1cacde48001122] Testcase.exampleNormalDryrun.assert_output...[Passed]
[7c7d6568307511ebae1cacde48001122] Testcase.exampleNormalDryrun.assert_progress[1]...[Passed]
[7c7d6568307511ebae1cacde48001122] Testcase.exampleNormalDryrun.assert_end...[Passed]
[7c7d6568307511ebae1cacde48001122] Testcase.exampleNormalDryrun.assert_end...[Passed]
[7c7d6568307511ebae1cacde48001122] Testcase.exampleNormalDryrun.cleanup...[Passed]
>>>


  • Test.runall

全てのテストスイートを順次実行します。テストスイートの名前のアスキーソート順に実行される点に注意してください。

>>> await Test.runall()↵
... ↵
[cb4eca38307511ebae1cacde48001122] Testsuite.exampleSuite.cleanup...[Passed]
[cb4eca38307511ebae1cacde48001122] Testsuite.exampleSuite.1/1...done
↵
>>>


  • Test.flush

テスト結果履歴を削除します。デフォルトでは、cleanupフェーズまで完了しているテスト結果履歴を削除します。cleanupフェーズまで完了していないものも強制削除したい場合はキーワード引数でforce=Trueを指定してください。

>>> await Test.flush()...cleanupフェーズまで完了しているテスト結果履歴を削除
... ↵
>>> await Test.flush(force=True)...全てのテスト結果履歴を削除
... ↵
>>>


Schedule


Booking

スケジュールサービスを利用してAPI呼び出しの予約を制御するクラスです。 API呼び出し予約はクラスメソッドで行う方法とBookingインスタンスを作成してsaveすることで行う方法の2種類が提供されています。

  • インスタンス化による予約登録
引数 デフォルト 説明
reservationDatetime None 予約実行時刻
path None HTTPリクエストパス
method GET HTTPリクエストメソッド
headers {} HTTPリクエストヘッダ
body None HTTPリクエスト本文
reservationId None 予約識別子
reservationResourceId None ターゲットリソース識別子


以下は、30分後にGET /helloを実行する予約をインスタンス化した例です。インスタンス化後にsaveメソッドを実行することでスケジュールは登録され、予約IDが払い出されます。予約IDを任意の値で指定してインスタンス化することも可能です(トランザクションサーバが提供するグローバルカウンタなどでユニークに払い出す必要があります)。 尚、予約実行時刻を指定しない場合は、saveメソッド実行時刻の3分後の時刻で予約されることに注意してください。

>>> reservation = Booking("/hello", reservationDatetime=clock.after_now(minutes=30))↵
... print(reservation)↵
... await reservation.save()↵
... print(reservation)↵
... ↵
{'path': '/hello', 'method': 'GET', 'body': None, 'reservationDatetime': datetime.datetime(2020, 11, 27, 11, 37, 28, 733670, tzinfo=<DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>), 'reservationId': None, 'reservationResourceId': None}
↵
{'path': '/hello', 'method': 'GET', 'body': None, 'reservationDatetime': datetime.datetime(2020, 11, 27, 11, 37, 28, 733670, tzinfo=<DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>), 'reservationId': '4d03278e305511eba011acde48001122', 'reservationResourceId': None}
>>> schedules↵
4d03278e305511eba011acde48001122 4d03278e305511eba011acde48001122 2020-11-27 11:37:28 Inexistent
>>>

Tip

ターゲットリソース識別子は任意の値をセットすることができますが、これは予約実行時に同一資源を同時に処理させたくない場合に排他するためのパラメータです。例えばPortオブジェクトを操作する予約が同一時刻(あるいは予約実行遅延保護時間options.execution_delay_guard_time)に競合すると予約実行が失敗するような場合、予約登録時点で排他することが可能です。同一のターゲットリソースを指定した同一時刻あるいは予約実行遅延保護時間内(デフォルトは60秒間)が競合すると409 Conflictエラーが発生します。

>>> reservation = Booking("/hello", reservationDatetime=clock.after_now(minutes=30), reservationResourceId="aaa")↵
... await reservation.save()↵
... reservation = Booking("/hello", reservationDatetime=clock.after_now(minutes=30), reservationResourceId="aaa")↵
... await reservation.save()↵
... ↵
Unable to regist booking 409
>>>


  • クラスメソッドによる予約登録

クラスメソッドによる予約登録は、必ず第一引数に予約時刻を指定します。以降のキーワード引数はインスタンス化時と同じです。返却値は予約IDとなります。

>>> reservationId = await Booking.regist(clock.after_now(minutes=30), path="/hello")↵
... print(reservationId)↵
... ↵
↵
4851a376305711eba011acde48001122
>>>


  • 予約の検索

予約を検索するクラスメソッドです。引数でキーワードを指定した場合は予約で実行するAPIのリクエストパスと部分一致検索を行います。返却値は、予約オブジェクトのリストです。

引数 デフォルト 説明
keyword None 予約リクレストパス部分一致検索キーワード
>>> reservations = await Booking.retrieve()↵
... for i in reservations:↵
...     print(i)↵
... reservations = await Booking.retrieve("Boo")↵
... for i in reservations:↵
...     print(i)↵
... ↵
{'path': '/hello', 'method': 'GET', 'body': None, 'reservationDatetime': datetime.datetime(2020, 11, 27, 12, 8, 40), 'reservationId': 'a877bf54305911eb8a59acde48001122', 'reservationResourceId': 'a877bf54305911eb8a59acde48001122'}
{'path': '/hello', 'method': 'GET', 'body': None, 'reservationDatetime': datetime.datetime(2020, 11, 27, 12, 8, 40), 'reservationId': 'a8797a4c305911eb8a59acde48001122', 'reservationResourceId': 'a8797a4c305911eb8a59acde48001122'}
{'path': '/helloBooking', 'method': 'GET', 'body': None, 'reservationDatetime': datetime.datetime(2020, 11, 27, 12, 8, 40), 'reservationId': 'a87b0ed4305911eb8a59acde48001122', 'reservationResourceId': 'a87b0ed4305911eb8a59acde48001122'}
↵
{'path': '/helloBooking', 'method': 'GET', 'body': None, 'reservationDatetime': datetime.datetime(2020, 11, 27, 12, 8, 40), 'reservationId': 'a87b0ed4305911eb8a59acde48001122', 'reservationResourceId': 'a87b0ed4305911eb8a59acde48001122'}
>>>


  • 予約の取得

予約を取得するクラスメソッドです。引数で予約IDを指定します。

引数 デフォルト 説明
reservationId None 予約ID
>>> reservation = await Booking.get("a87b0ed4305911eb8a59acde48001122")↵
... print(reservation)↵
... ↵
↵
{'path': '/helloBooking', 'method': 'GET', 'body': None, 'reservationDatetime': datetime.datetime(2020, 11, 27, 12, 8, 40), 'reservationId': 'a87b0ed4305911eb8a59acde48001122', 'reservationResourceId': 'a87b0ed4305911eb8a59acde48001122'}
>>>


  • 予約時刻の変更

予約時刻の変更は予約オブジェクトの予約時刻に変更後の時刻をセットしてsaveメソッドを実行します。

>>> reservationId = await Booking.regist(clock.after_now(minutes=30), path="/hello")↵...30分後で予約
... reservation = await Booking.get(reservationId)↵
... print(reservation.reservationDatetime)↵
... reservation.reservationDatetime = clock.after_now(minutes=5)↵...5分後に前倒し予約
... await reservation.save()↵
... reservation = await Booking.get(reservationId)↵
... print(reservation.reservationDatetime)↵
... ↵
2020-11-27 12:19:29
↵
2020-11-27 11:54:29
>>>


shiftメソッドで予約時刻を前後にシフトする変更方法もあります。

>>> reservationId = await Booking.regist(clock.after_now(minutes=30), path="/hello")↵...30分後で予約
... reservation = await Booking.get(reservationId)↵
... print(reservation.reservationDatetime)↵
... reservation.shift(minutes=5)↵...さらに5分後ろに時間シフト
... await reservation.save()↵
... reservation = await Booking.get(reservationId)↵
... print(reservation.reservationDatetime)↵
... ↵
2020-11-27 12:23:38
↵
2020-11-27 12:28:38
>>>

shiftメソッドはマイナス値を指定することで時刻の前倒しもできます。

>>> reservation = await Booking.get(reservationId)↵
... print(reservation.reservationDatetime)↵
... reservation.shift(hours=-5)↵...5時間前にシフト
... await reservation.save()↵
... reservation = await Booking.get(reservationId)↵
... print(reservation.reservationDatetime)↵
... ↵
2020-11-27 12:28:38
↵
2020-11-27 07:28:38
>>>


  • 予約の削除 予約の削除は予約オブジェクトのdestroyメソッドか予約ID指定でcancelクラスメソッドで削除する方法があります。
>>> reservationId = await Booking.regist(clock.after_now(minutes=30), path="/hello")↵
... reservation = await Booking.get(reservationId)↵
... print(reservation)↵
... await reservation.destroy()↵
... reservation = await Booking.get(reservationId)↵
... ↵
{'path': '/hello', 'method': 'GET', 'body': None, 'reservationDatetime': datetime.datetime(2020, 11, 27, 12, 29, 12), 'reservationId': '873d068e305c11eb8a59acde48001122', 'reservationResourceId': '873d068e305c11eb8a59acde48001122'}
Unable to get booking '873d068e305c11eb8a59acde48001122'
>>>
>>> reservationId = await Booking.regist(clock.after_now(minutes=30), path="/hello")↵
... reservation = await Booking.get(reservationId)↵
... print(reservation)↵
... await Booking.cancel(reservationId)↵
... reservation = await Booking.get(reservationId)↵
... ↵
{'path': '/hello', 'method': 'GET', 'body': None, 'reservationDatetime': datetime.datetime(2020, 11, 27, 12, 30, 9), 'reservationId': 'a8c602ec305c11eb8a59acde48001122', 'reservationResourceId': 'a8c602ec305c11eb8a59acde48001122'}
Unable to get booking 'a8c602ec305c11eb8a59acde48001122'
>>>


Caution

予約の変更や削除は実行保護時間に抵触しない範囲で操作可能です。


Lambda


lambda_event

Lambda Function向けのイベントを発行する関数です。イベント名とイベントハンドラに渡す任意の辞書データを引数に与えます。返り値はイベントIDです。

引数 デフォルト 説明
event None イベント名
content None イベント情報
>>> eventId = await lambda_event("hello", dict(msg="Hello, Lambda!"))↵
... print(eventId)↵
... ↵
↵
f05f4b443f6711eb850aacde48001122


lambda_convergence

Lambda Functionのイベント連鎖が収束するのを待ち合わせる関数です。イベントIDを引数に与えます。返り値はイベントツリー情報のMU型表現です。

引数 デフォルト 説明
eventId None イベントID
>>> eventId = await lambda_event("hello", dict(msg="Hello, Lambda!"))↵
... r = await lambda_convergence(eventId)↵
... print(r.yaml_format)↵
... ↵
{'msg': 'Hello, Lambda!'}
↵
chains: []
code: 200
content:
  msg: Hello, Lambda!
event: hello
expire: '2020-12-16T15:36:26.222998+09:00'
id: 52bd778e3f6811eb850aacde48001122
initiate: '2020-12-16T15:31:26.316140+09:00'
occurrence: '2020-12-16T15:31:26.222967+09:00'
output: Processed
terminate: '2020-12-16T15:31:26.318662+09:00'
>>>


LambdaBooking

スケジュールサービスを利用してLambdaイベント発行の予約を制御するクラスです。 Lambdaイベント発行予約はクラスメソッドで行う方法とLambdaBookingインスタンスを作成してsaveすることで行う方法の2種類が提供されています。
使用方法は、前述したBookingクラスと同じです。

  • インスタンス化による予約登録
引数 デフォルト 説明
reservationDatetime None 予約実行時刻
event None Lambdaイベント名
content {} Lambdaイベントハンドラに与える任意のデータ辞書


Websocket [TODO]


CLI

SSH接続してネットワーク機器にコマンド処理を行うクラスです。尚、本クラスはnetmiko(https://github.com/ktbyers/netmiko)のラッパークラスとして実装されています。 CLIセッションは、async withコンテキストマネージャを利用してオープンします。 パラメータについて詳しくはnetmikoのドキュメントを参照ください。


  • showコマンドの実行例
>>> async with CLI(host="192.168.2.200", username="qmonus", password="qmonus", device_type="cisco_xe") as conn:↵
...     out = await conn.send_command("show ver")↵
...     print(out)↵
... ↵
Cisco IOS XE Software, Version 03.15.00.S - Standard Support Release
Cisco IOS Software, CSR1000V Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 15.5(2)S, RELEASE SOFTWARE (fc3)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2015 by Cisco Systems, Inc.
Compiled Sun 22-Mar-15 01:36 by mcpre


Cisco IOS-XE software, Copyright (c) 2005-2015 by cisco Systems, Inc.
All rights reserved.  Certain components of Cisco IOS-XE software are
licensed under the GNU General Public License ("GPL") Version 2.0.  The
software code licensed under GPL Version 2.0 is free software that comes
with ABSOLUTELY NO WARRANTY.  You can redistribute and/or modify such
GPL code under the terms of GPL Version 2.0.  For more details, see the
documentation or "License Notice" file accompanying the IOS-XE software,
or the applicable URL provided on the flyer accompanying the IOS-XE
software.


ROM: IOS-XE ROMMON

csr1000v uptime is 3 minutes
Uptime for this control processor is 5 minutes
System returned to ROM by reload
System image file is "bootflash:packages.conf"
Last reload reason: <NULL>



This product contains cryptographic features and is subject to United
States and local country laws governing import, export, transfer and
use. Delivery of Cisco cryptographic products does not imply
third-party authority to import, export, distribute or use encryption.
Importers, exporters, distributors and users are responsible for
compliance with U.S. and local country laws. By using this product you
agree to comply with applicable laws and regulations. If you are unable
to comply with U.S. and local laws, return this product immediately.

A summary of U.S. laws governing Cisco cryptographic products may be found at:
http://www.cisco.com/wwl/export/crypto/tool/stqrg.html

If you require further assistance please contact us by sending email to
export@cisco.com.

License Level: ax
License Type: Default. No valid license found.
Next reload license Level: ax

cisco CSR1000V (VXE) processor (revision VXE) with 2066386K/6147K bytes of memory.
Processor board ID 9MO3W5YB3YU
3 Gigabit Ethernet interfaces
32768K bytes of non-volatile configuration memory.
3986912K bytes of physical memory.
7774207K bytes of virtual hard disk at bootflash:.

Configuration register is 0x2102
↵
>>>


  • コンフィギュレーションの例
>>> async with CLI(host="192.168.2.200", username="qmonus", password="qmonus", device_type="cisco_xe") as conn:↵
...     commands = ["line console 0", "exit"]↵
...     out = await conn.send_config_set(commands)↵
...     print(out)↵
...     out = await conn.send_command("show run")↵
...     print(out)↵
...     out = await conn.send_command("conf", pattern=r'\[terminal\]\?', strip_command=False)↵
...     out += await conn.send_command("term", strip_command=False)↵
...     out += await conn.send_command("exit", strip_command=False, strip_prompt=False)↵
...     print(out)↵
... ↵
conf t
Enter configuration commands, one per line.  End with CNTL/Z.
csr1000v(config)#line console 0
csr1000v(config-line)#exit
csr1000v(config)#end
csr1000v#
Building configuration...

Current configuration : 1263 bytes
!
! Last configuration change at 04:18:14 UTC Fri Nov 27 2020 by qmonus
!
version 15.5
service timestamps debug datetime msec
service timestamps log datetime msec
no platform punt-keepalive disable-kernel-core
platform console auto
!
hostname csr1000v
!
boot-start-marker
boot-end-marker
!
!
enable secret 5 $1$mRd1$j3Bahth4A41LK4AZkbbuL.
!
no aaa new-model
!
!
!
!
!
!
!
!
!


ip domain name ftth.ucom.ne.jp

!
!
!
!
!
!
!
!
!
!
subscriber templating
!
multilink bundle-name authenticated
!
!
!
!
!
!
!
!
!
!
!
!
!
license udi pid CSR1000V sn 9MO3W5YB3YU
license boot level ax
spanning-tree extend system-id
!
username qmonus privilege 15 secret 5 $1$WYlL$Acuu1HOExDC2nNG8LSpHT1
username ncclient privilege 15 password 0 ncclient
!
redundancy
!
!
!
!
!
!
! 
!
!
!
!
!
!
!
!
!
!
!
!
! 
! 
!
!
interface GigabitEthernet1
 ip address 192.168.2.200 255.255.255.0
 negotiation auto
!
interface GigabitEthernet2
 no ip address
 shutdown
 negotiation auto
!
interface GigabitEthernet3
 no ip address
 shutdown
 negotiation auto
!
!
virtual-service csr_mgmt
!
ip forward-protocol nd
!
no ip http server
ip http secure-server
!
!
snmp-server community public RO
!
!
control-plane
!
 !
 !
 !
 !
!
!
!
!
!
line con 0
 login local
line vty 0 4
 login local
!
netconf ssh
!
end
conf
Configuring from terminal, memory, or network [terminal]? term
Enter configuration commands, one per line.  End with CNTL/Z.exit
csr1000v#
↵
>>>
Daemon Events
Daemon Event


No Events

  Daemon Editor    daemon editor


Device

DeviceクラスはCLIProxyNetconfProxyの制御エンドポイントを表現するクラスです。Docs » Lambda » Deviceを参考にしてください。

  • Deviceをロードする
引数 デフォルト 説明
alias None Deviceの名前
>>> d = await Device.load("csr1000v")↵
... print(d)↵
... ↵
↵
<axis.hotspot.script_runner.Device object at 0x10f73eb10>
>>>


  • Deviceリストを取得する(検索キーをサポートしていないため、数が膨大な場合はloadを使用してください)
>>> devices = await Device.retrieve()↵
... print(devices)↵
... ↵
↵
[<axis.hotspot.script_runner.Device object at 0x10f73ac90>, <axis.hotspot.script_runner.Device object at 0x10f7ab990>, <axis.hotspot.script_runner.Device object at 0x10f0bdf10>]
>>>


Note

Deviceのクラスメソッドであるloadretrieveは、simplexのDeviceオブジェクトを返却します。以下のようにcomplexのaliasを指定した場合は、複合Deviceに包含されているsimplexのDeviceが全てリストで返却される点に注意してください。complexのDeviceを操作したい場合は、後述するComplexDevice組込みオブジェクトを使用してください。

>>> devices = await Device.load("csr1000v-group")↵
>>> print(devices)↵
... ↵
↵
[<axis.hotspot.script_runner.Device object at 0x10f7e40d0>, <axis.hotspot.script_runner.Device object at 0x10f7cd4d0>]
>>>


  • Deviceを作成する
>>> d1 = Device("node1", device="cisco_xe", host="192.168.2.200", username="qmonus", password="qmonus", role="test", __WORKSPACE__="axis-edge/hands-on_plugins")↵
... await d1.save()↵
... d1 = await Device.load("node1")↵
... ↵
↵
>>> print(d1)↵
... ↵
↵
<axis.hotspot.script_runner.Device object at 0x109c02fd0>
>>>


  • Deviceを削除する
>>> await d1.destroy()↵
... d1 = await Device.load("node1")↵
... ↵
Unable to load device 'node1'
>>>


  • Deviceのアクション情報を取得する
>>> print(d1.actions)↵
... ↵
↵
setInterface:
  inherit: false
  path: /config
  schema: |
    properties:
      address:
        anyOf:
        - type: boolean
        - type: 'null'
        - type: number
        - type: string
        title: address
      iface:
        anyOf:
        - type: boolean
        - type: 'null'
        - type: number
        - type: string
        title: iface
      netmask:
        anyOf:
        - type: boolean
        - type: 'null'
        - type: number
        - type: string
        title: netmask
    required:
    - iface
    - netmask
    - address
    type: object
showVersion:
  inherit: false
  path: /showVersion
  schema: |
    properties: {}
    type: object
>>>


ComplexDevice

  • ComplexDeviceをロードする
引数 デフォルト 説明
alias None ComplexDeviceの名前
>>> device = await ComplexDevice.load("nodeGroup")↵
... print(device)↵
... ↵
↵
<axis.hotspot.script_runner.ComplexDevice object at 0x11263f050>
>>>


  • ComplexDeviceリストを取得する(検索キーをサポートしていないため、数が膨大な場合はloadを使用してください)
>>> devices = await ComplexDevice.retrieve()↵
>>> print(devices)↵
... ↵
↵
[<axis.hotspot.script_runner.ComplexDevice object at 0x11250ec90>]
>>>


  • ComplexDeviceを作成する
>>> nodeGroup = ComplexDevice("nodeGroup", ["node1", "node2"], role="test")↵
... await nodeGroup.save()↵
... ↵
↵
>>> device = await ComplexDevice.load("nodeGroup")↵
... print(device)↵
... ↵
↵
<axis.hotspot.script_runner.ComplexDevice object at 0x11263f050>
>>>


  • ComplexDeviceを削除する
>>> await device.destroy()↵
... device = await ComplexDevice.load("nodeGroup")↵
... ↵
Unable to load device 'nodeGroup'
>>>


  • ComplexDeviceのアクション情報を取得する
>>> print(nodeGroup.actions)↵
... ↵
↵
setInterface:
  inherit: false
  path: /config
  schema: |
    properties:
      address:
        anyOf:
        - type: boolean
        - type: 'null'
        - type: number
        - type: string
        title: address
      iface:
        anyOf:
        - type: boolean
        - type: 'null'
        - type: number
        - type: string
        title: iface
      netmask:
        anyOf:
        - type: boolean
        - type: 'null'
        - type: number
        - type: string
        title: netmask
    required:
    - netmask
    - address
    - iface
    type: object
showVersion:
  inherit: false
  path: /showVersion
  schema: |
    properties: {}
    type: object
>>>


Note

ComplexDeviceのactionメソッドを実行すると包含している全てのDeviceに対して並列でactionが実行されます。


CLIProxy

CLIProxyクラスはlambdaサービスが提供するCLIProxyを操作するクラスです。

  • CLIProxyをロードする
引数 デフォルト 説明
name None CLIプロキシの名前
>>> p = await CLIProxy.load("CE状態確認")↵
... print(p)↵
... ↵
↵
__WORKSPACE__: sdwan
alias_only: true
async: true
category: Cisco/CE/Get_CE
config: false
name: CE状態確認
path: /v1/sdwan/cisco/ce/check
protocol: telnet
templates:
- command: show users
- command: show clock
- command: show ver | inc (uptime is|returned to ROM|System image file|Last reload)
  parameter_bindings:
  - name: show_version
    regex: '[\s\S]*'
- command: show run | include Last
  parameter_bindings:
  - name: show_run_inc_last
    regex: '[\s\S]*'
- command: show environment
- command: show ip int brief
  parameter_bindings:
  - name: show_ip_int_brief
    regex: '[\s\S]*'
- command: show int | inc (line protocol is|errors,|packets output,|packets input,)
- command: show ip access-list | sec ACL-MPLS-IN
  parameter_bindings:
  - name: show_acl_mpls
    regex: '[\s\S]*'
- command: show ip access-list | sec ACL-INET-IN
  parameter_bindings:
  - name: show_acl_inet
    regex: '[\s\S]*'
- command: |-
    {% if ce_terminal_type == "ASR1K" %}
    show ip access-list | sec ACL-GE[0-9|.]*-IN
    {% else %}
    show ip access-list | sec ACL-Vlan[0-9]*-IN
    {% endif %}
  parameter_bindings:
  - name: show_acl_vlan
    regex: '[\s\S]*'
- command: show ip bgp summary
- command: show domain {{ pfr_domain_name }} master traffic-classes | inc (BW Us|Current
    S|WAN|Dst-Site|Present State)
  parameter_bindings:
  - name: show_traffic_classes
    regex: '[\s\S]*'
- command: show ip route 0.0.0.0 0.0.0.0
- command: show dmvpn
- command: show domain {{ pfr_domain_name }} master all
- command: show domain {{ pfr_domain_name }} master peering
- command: show domain {{ pfr_domain_name }} border status
update: '2020-11-27T13:29:56.252770+09:00'
version: 1
>>>


  • CLIProxyにレンダリング可能なパラメータスキーマを確認する
>>> p = await CLIProxy.load("CE状態確認")↵
... print(p.schema)↵
... ↵
↵
properties:
  ce_terminal_type:
    anyOf:
    - type: object
    - type: array
    - type: string
    - type: number
    - type: boolean
    - type: 'null'
    title: ce_terminal_type
  pfr_domain_name:
    anyOf:
    - type: boolean
    - type: 'null'
    - type: number
    - type: string
    title: pfr_domain_name
required:
- pfr_domain_name
- ce_terminal_type
type: object
>>>


  • CLIProxyを実行する

ここで使用しているCLIProxyは別の機器向けのものを強引にCSR1000vに流しているので途中エラーが発生していますが気にしないでください。 runメソッドの引数は、lambdaサービスのDeviceリソースの名前ですので事前にデバイス情報を登録しておく必要があります。

>>> p = await CLIProxy.load("CE状態確認")↵
... r = await p.run("csr1000v")↵
... ↵
↵
>>> print(r.log)↵
... ↵
↵
csr1000v#

csr1000v#terminal length 0
terminal length 0
csr1000v#terminal width 511
terminal width 511
csr1000v#

csr1000v#

csr1000v#show users
show users
    Line       User       Host(s)              Idle       Location
*  1 vty 0     qmonus     idle                 00:00:00 192.168.2.107

  Interface    User               Mode         Idle     Peer Address

csr1000v#show clock
show clock
*04:49:35.756 UTC Fri Nov 27 2020
csr1000v#show ver | inc (uptime is|returned to ROM|System image file|Last reload)
show ver | inc (uptime is|returned to ROM|System image file|Last reload)
csr1000v uptime is 42 minutes
System returned to ROM by reload
System image file is "bootflash:packages.conf"
Last reload reason: <NULL>
csr1000v#show run | include Last
show run | include Last
! Last configuration change at 04:18:14 UTC Fri Nov 27 2020 by qmonus
csr1000v#show environment
show environment
                ^
% Invalid input detected at '^' marker.

csr1000v#show ip int brief
show ip int brief
Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       192.168.2.200   YES NVRAM  up                    up      
GigabitEthernet2       unassigned      YES NVRAM  administratively down down    
GigabitEthernet3       unassigned      YES NVRAM  administratively down down    
csr1000v#show int | inc (line protocol is|errors,|packets output,|packets input,)
show int | inc (line protocol is|errors,|packets output,|packets input,)
GigabitEthernet1 is up, line protocol is up 
     1682 packets input, 146376 bytes, 0 no buffer
     0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored
     1150 packets output, 132444 bytes, 0 underruns
     0 output errors, 0 collisions, 0 interface resets
GigabitEthernet2 is administratively down, line protocol is down 
     0 packets input, 0 bytes, 0 no buffer
     0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored
     0 packets output, 0 bytes, 0 underruns
     0 output errors, 0 collisions, 0 interface resets
GigabitEthernet3 is administratively down, line protocol is down 
     458 packets input, 52656 bytes, 0 no buffer
     0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored
     0 packets output, 0 bytes, 0 underruns
     0 output errors, 0 collisions, 0 interface resets
csr1000v#show ip access-list | sec ACL-MPLS-IN
show ip access-list | sec ACL-MPLS-IN
csr1000v#show ip access-list | sec ACL-INET-IN
show ip access-list | sec ACL-INET-IN
csr1000v#show ip access-list | sec ACL-Vlan[0-9]*-IN
show ip access-list | sec ACL-Vlan[0-9]*-IN
csr1000v#show ip bgp summary
show ip bgp summary
% BGP not active

csr1000v#show domain  master traffic-classes | inc (BW Us|Current S|WAN|Dst-Site|Present State)
show domain  master traffic-classes | inc (BW Us|Current S|WAN|Dst-Site|Present State)
                             ^
% Invalid input detected at '^' marker.

csr1000v#show ip route 0.0.0.0 0.0.0.0
show ip route 0.0.0.0 0.0.0.0
% Network not in table
csr1000v#show dmvpn
show dmvpn
Legend: Attrb --> S - Static, D - Dynamic, I - Incomplete
    N - NATed, L - Local, X - No Socket
    T1 - Route Installed, T2 - Nexthop-override
    C - CTS Capable
    # Ent --> Number of NHRP entries with same NBMA peer
    NHS Status: E --> Expecting Replies, R --> Responding, W --> Waiting
    UpDn Time --> Up or Down Time for a Tunnel
==========================================================================

csr1000v#show domain  master all
show domain  master all
                             ^
% Invalid input detected at '^' marker.

csr1000v#show domain  master peering
show domain  master peering
                             ^
% Invalid input detected at '^' marker.

csr1000v#show domain  border status
show domain  border status
                             ^
% Invalid input detected at '^' marker.

csr1000v#
>>>


  • CLIProxyをドライラン実行する

上述の例は実際のデバイスにコマンドを送信してしまいますが、送信するコマンドが正しく生成されているかだけを確認したい場合はdryrun=Trueオプションを使用してください。

>>> p = await CLIProxy.load("CE状態確認")↵
... r = await p.run("csr1000v", dryrun=True)↵
... print(r.log)↵
... ↵
↵
show users
show clock
show ver | inc (uptime is|returned to ROM|System image file|Last reload)
show run | include Last
show environment
show ip int brief
show int | inc (line protocol is|errors,|packets output,|packets input,)
show ip access-list | sec ACL-MPLS-IN
show ip access-list | sec ACL-INET-IN
show ip access-list | sec ACL-Vlan[0-9]*-IN
show ip bgp summary
show domain  master traffic-classes | inc (BW Us|Current S|WAN|Dst-Site|Present State)
show ip route 0.0.0.0 0.0.0.0
show dmvpn
show domain  master all
show domain  master peering
show domain  border status
>>>


レンダリングパラメータを渡す場合は、以下のようにparamsキーワード引数に辞書を渡してください。

>>> p = await CLIProxy.load("CE状態確認")↵
... r = await p.run("csr1000v", params={"pfr_domain_name": "test", "ce_terminal_type": "ASR1K"}, dryrun=True)↵
... print(r.log)↵
... ↵
↵
show users
show clock
show ver | inc (uptime is|returned to ROM|System image file|Last reload)
show run | include Last
show environment
show ip int brief
show int | inc (line protocol is|errors,|packets output,|packets input,)
show ip access-list | sec ACL-MPLS-IN
show ip access-list | sec ACL-INET-IN
show ip access-list | sec ACL-GE[0-9|.]*-IN
show ip bgp summary
show domain test master traffic-classes | inc (BW Us|Current S|WAN|Dst-Site|Present State)
show ip route 0.0.0.0 0.0.0.0
show dmvpn
show domain test master all
show domain test master peering
show domain test border status
>>>


NetconfProxy

NetconfProxyクラスはlambdaサービスが提供するNetconfProxyを操作するクラスです。

  • NetconfProxyをロードする
引数 デフォルト 説明
name None Netconfプロキシの名前


>>> p = await NetconfProxy.load("setVlan")↵
... print(p)↵
... ↵
↵
__FILE__: axis/handson/netconfproxy/setVlan.yml
__WORKSPACE__: axis-edge/hands-on_plugins
action:
  template: |-
    <config>
      <cli-config-data>
        <cmd>interface gigabitEthernet 3.{{ vlan }}</cmd>
        <cmd>encapsulation dot1Q {{ vlan }}</cmd>
        <cmd>ip address 172.16.{{ vlan }}.1 255.255.255.0</cmd>
        <cmd>no shutdown</cmd>
      </cli-config-data>
    </config>
name: setVlan
path: /setVlan
update: '2021-01-07T08:50:37.419463+09:00'
version: 1
>>>


  • NetconfProxyにレンダリング可能なパラメータスキーマを確認する
>>> p = await NetconfProxy.load("setVlan")↵
... print(p.schema)↵
... ↵
↵
properties:
  vlan:
    anyOf:
    - type: boolean
    - type: 'null'
    - type: number
    - type: string
    title: vlan
required:
- vlan
type: object
>>>
  • NetconfProxyを実行する

runメソッドの引数は、lambdaサービスのDeviceリソースの名前ですので事前にデバイス情報を登録しておく必要があります。

>>> p = await NetconfProxy.load("setVlan")↵
... r = await p.run("csr1000v", params={"vlan": 32})↵
... ↵
↵
>>> print(r.yaml_format)↵
... ↵
↵
bindings:
  vlan: 32
log: |-
  <config>
    <cli-config-data>
      <cmd>interface gigabitEthernet 3.32</cmd>
      <cmd>encapsulation dot1Q 32</cmd>
      <cmd>ip address 172.16.32.1 255.255.255.0</cmd>
      <cmd>no shutdown</cmd>
    </cli-config-data>
  </config>
message: null
responses:
- <?xml version="1.0" encoding="UTF-8"?><rpc-reply message-id="urn:uuid:ea9150e2-b10f-4eb4-aebe-55d17a08f0ba"
  xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><ok /></rpc-reply>
status: Complete
>>>


  • NetconfProxyをドライラン実行する

上述の例は実際のデバイスにRPCを送信してしまいますが、送信するXMLが正しく生成されているかだけを確認したい場合はdryrun=Trueオプションを使用してください。
レンダリングパラメータを渡す場合は、以下のようにparamsキーワード引数に辞書を渡してください。

>>> p = await NetconfProxy.load("setVlan")↵
... r = await p.run("csr1000v", params={"vlan": 32}, dryrun=True)↵
... ↵
↵
>>> print(r.yaml_format)↵
... ↵
↵
bindings:
  vlan: 32
log: |-
  <config>
    <cli-config-data>
      <cmd>interface gigabitEthernet 3.32</cmd>
      <cmd>encapsulation dot1Q 32</cmd>
      <cmd>ip address 172.16.32.1 255.255.255.0</cmd>
      <cmd>no shutdown</cmd>
    </cli-config-data>
  </config>
message: null
responses: []
status: Complete
>>>


Netconf

Netconfクラスは、NETCONFプロトコルのクライアントです。

Warning

本オブジェクトは、ncclient(https://github.com/ncclient/ncclient)ライブラリの非同期ラッパークラスとして実装されています。

ncclientは、Qmonus SDKの標準インストールには含まれていないため、利用する場合はプラグインのリポジトリにrequirements.txtを置いてncclientのversionを指定してご利用ください。尚、ncclient==0.6.9で動作確認されています。

NETCONFセッションは、async withコンテキストマネージャを利用してオープンします。

Netconfは、ncclient.manager.connectをノンブロッキングで実行します。引数はncclientのドキュメントを参照してください。

得られたコネクションに対してメソッドを実行する場合は全てawaitで呼び出します。利用可能なメソッドや引数は、ncclientのドキュメントを参照してください。

>>> async with Netconf(host="192.168.2.200",↵
...                    port=830,↵
...                    username="qmonus",↵
...                    password="qmonus",↵
...                    device_params=dict(name="default"),↵
...                    hostkey_verify=False) as conn:↵
...     conf = await conn.get_config(source="running")↵
...     print(conf)↵
... ↵
<?xml version="1.0" encoding="UTF-8"?><data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><cli-config-data-block>!
! Last configuration change at 03:07:59 UTC Tue Oct 27 2020
!
version 15.5
service timestamps debug datetime msec
service timestamps log datetime msec
no platform punt-keepalive disable-kernel-core
platform console auto
!
hostname csr1000v
!
boot-start-marker
boot-end-marker
!
!
no aaa new-model
!
!
interface GigabitEthernet1
 ip address 192.168.2.200 255.255.255.0
 negotiation auto
!
interface GigabitEthernet2
 no ip address
 shutdown
 negotiation auto
!
interface GigabitEthernet3
 no ip address
 shutdown
 negotiation auto
!
!
end
</cli-config-data-block></data>
↵
>>>
>>> async with Netconf(host="localhost", port=830, username="qmonus", password="qmonus",device_params=dict(name="junos"),hostkey_verify=False) as conn:↵
...     result = await conn.command("ping 161.1.150.253 count 5")↵
...     print(result)↵
...     result = await conn.load_configuration(action="set", config="set system host-name foo")↵
...     print(result)↵
... ↵
<?xml version="1.0" encoding="UTF-8"?><rpc-reply message-id="urn:uuid:8706863d-3990-446f-8d19-5422380c8536"><ping-results><target-host>
161.1.150.253
</target-host><target-ip>
161.1.150.253
</target-ip><packet-size>
56
</packet-size><probe-results-summary><probes-sent>
5
</probes-sent><responses-received>
0
</responses-received><packet-loss>
100
</packet-loss></probe-results-summary><ping-failure>
no response
</ping-failure></ping-results></rpc-reply>
↵
<?xml version="1.0" encoding="UTF-8"?><rpc-reply message-id="urn:uuid:e1d35023-eccc-4d36-a914-56957e671a13"><load-configuration-results><ok/></load-configuration-results></rpc-reply>


Collector/Reflector


SNMPv2/SNMPv3

SNMPv2クラスは、SNMPプロトコルのクライアントです。

Warning

本オブジェクトは、pysnmp(https://github.com/etingof/pysnmp)ライブラリをラップして実装されています。

>>> snmp = SNMPv2("public")↵
... r = await snmp.get("192.168.2.200", oid="1.3.6.1.2.1.1.5.0")↵
... print(MU(r).yaml_format)↵
... ↵
address: 192.168.2.200
errorIndex: null
errorIndication: null
errorStatus: null
errorVarBind: null
objectType: DisplayString
oid: 1.3.6.1.2.1.1.5.0
value: csr1000v.ftth.ucom.ne.jp
↵
>>>
>>> r = await snmp.bulk("192.168.2.200", oids=["1.3.6.1.2.1.1"])↵
... for i in r:↵
...     print(MU(i).yaml_format)↵
... ↵
address: 192.168.2.200
errorIndex: null
errorIndication: null
errorStatus: null
errorVarBind: null
oid: 1.3.6.1.2.1.1.1.0
type: DisplayString
value: "Cisco IOS Software, CSR1000V Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version\
  \ 15.5(2)S, RELEASE SOFTWARE (fc3)\r\nTechnical Support: http://www.cisco.com/techsupport\r\
  \nCopyright (c) 1986-2015 by Cisco Systems, Inc.\r\nCompiled Sun 22-Mar-15 01:36\
  \ by mcpre"
address: 192.168.2.200
errorIndex: null
errorIndication: null
errorStatus: null
errorVarBind: null
oid: 1.3.6.1.2.1.1.2.0
type: ObjectIdentity
value: SNMPv2-SMI::enterprises.9.1.1537
...
>>>
>>>
>>> r = await snmp.getInterfaces("192.168.2.200")↵
>>> for i in r:↵
...    print(i)↵
... ↵
{'index': '1', 'description': 'GigabitEthernet1'}
{'index': '2', 'description': 'GigabitEthernet2'}
{'index': '3', 'description': 'GigabitEthernet3'}
{'index': '4', 'description': 'VoIP-Null0'}
{'index': '5', 'description': 'Null0'}
↵
>>>


正常に稼動中の場合は、Trueが返却されます。OUT OF SERVICE状態もしくはGraceful Shutdown状態の場合はFalseが返却されますのでループ処理を速やかにbreakしてください。


Collection

Collectionクラスは、collectorサービスが提供するCollectionリソースを操作するクラスです。作成したCollectionの動作確認に利用できます。

  • Collection.load Collectionインスタンスをロードします。Collectionのホスト名を指定する必要があります。

  • Collection.run Collectionの収集処理を実行します。

  • Collection.getIfIndexes Collectionの収集処理実行時に自動収集されるifNameとifIndexの対応表を取得します。本メソッドはCollectorサーバでのみ実行可能です。


以下は実行例です。

>>> c = await Collection.load("csr1000v#1")↵
... r = await c.run()↵
... for i in r:↵
...     for j in i:↵
...         print(j.yaml_format)↵
... ↵
↵
address: 192.168.2.200
datetime: '2021-01-28T01:08:33+00:00'
host: csr1000v#1
oid: 1.3.6.1.2.1.1.3.0
stamp: 1611796113
type: TimeTicks
value: 9078094
address: 192.168.2.200
datetime: '2021-01-28T01:08:33+00:00'
host: csr1000v#1
oid: 1.3.6.1.2.1.6.5.0
stamp: 1611796113
type: Counter32
value: 0
address: 192.168.2.200
datetime: '2021-01-28T01:08:33+00:00'
host: csr1000v#1
oid: 1.3.6.1.2.1.6.6.0
stamp: 1611796113
type: Counter32
value: 0
address: 192.168.2.200
datetime: '2021-01-28T01:08:33+00:00'
host: csr1000v#1
oid: 1.3.6.1.2.1.31.1.1.1.6.1
stamp: 1611796113
type: Counter64
value: 1864603
address: 192.168.2.200
datetime: '2021-01-28T01:08:33+00:00'
host: csr1000v#1
oid: 1.3.6.1.2.1.31.1.1.1.6.2
stamp: 1611796113
type: Counter64
value: 1828157
address: 192.168.2.200
datetime: '2021-01-28T01:08:33+00:00'
host: csr1000v#1
oid: 1.3.6.1.2.1.31.1.1.1.6.3
stamp: 1611796113
type: Counter64
value: 1815518
address: 192.168.2.200
datetime: '2021-01-28T01:08:33+00:00'
host: csr1000v#1
oid: 1.3.6.1.2.1.31.1.1.1.10.1
stamp: 1611796113
type: Counter64
value: 142700
address: 192.168.2.200
datetime: '2021-01-28T01:08:33+00:00'
host: csr1000v#1
oid: 1.3.6.1.2.1.31.1.1.1.10.2
stamp: 1611796113
type: Counter64
value: 0
address: 192.168.2.200
datetime: '2021-01-28T01:08:33+00:00'
host: csr1000v#1
oid: 1.3.6.1.2.1.31.1.1.1.10.3
stamp: 1611796113
type: Counter64
value: 12011
>>> r = await c.getIfIndexes()↵
>>> print(r.yaml_format)↵
... ↵
↵
Gi1: '1'
Gi2: '2'
Gi3: '3'
Gi3.23: '6'
Gi3.24: '7'
Gi3.30: '8'
Gi3.31: '9'
Gi3.32: '10'
Nu0: '5'
Vo0: '4'
>>>


FIFO

FIFOクラスは、カスタムアプリケーションで利用する分散FIFOキューを提供するオブジェクトです。コンストラクタには、FIFOの名前を指定します。

>>> q = FIFO("sampleQueue")↵
... print(q)↵
... ↵
↵
<axis.hotspot.script_runner.FIFO object at 0x107a17750>
>>>


FIFOキューへのデータ挿入は、putメソッドを使用します。挿入するデータ辞書を第一引数で指定します。キューからのデータの取り出しは、コンテキストマネージャ経由でアクセスします。
尚、putするデータは、辞書型もしくはlist型のみをキューイングできます。キューが空の場合はNoneを返却します。
キューを空にする場合は、clearメソッドを使用してください。

>>> await FIFO("sampleQueue").put({"name": "hoge", "description": "hello, fifo"})↵
... async with FIFO("sampleQueue") as entry:↵
...     print(entry.yaml_format)↵
... ↵
↵
description: hello, fifo
name: hoge
>>> names = []↵
... while True:↵
...     async with FIFO("sampleQueue") as entry:↵
...         if not entry:↵
...             break↵
...         names.append(entry.name)↵
... print(names)↵
... ↵
↵
['hoge0', 'hoge1', 'hoge2', 'hoge3', 'hoge4', 'hoge5', 'hoge6', 'hoge7', 'hoge8', 'hoge9', 'hoge10', 'hoge11', 'hoge12', 'hoge13', 'hoge14', 'hoge15', 'hoge16', 'hoge17', 'hoge18', 'hoge19', 'hoge20', 'hoge21', 'hoge22', 'hoge23', 'hoge24', 'hoge25', 'hoge26', 'hoge27', 'hoge28', 'hoge29', 'hoge30', 'hoge31', 'hoge32', 'hoge33', 'hoge34', 'hoge35', 'hoge36', 'hoge37', 'hoge38', 'hoge39', 'hoge40', 'hoge41', 'hoge42', 'hoge43', 'hoge44', 'hoge45', 'hoge46', 'hoge47', 'hoge48', 'hoge49', 'hoge50', 'hoge51', 'hoge52', 'hoge53', 'hoge54', 'hoge55', 'hoge56', 'hoge57', 'hoge58', 'hoge59', 'hoge60', 'hoge61', 'hoge62', 'hoge63', 'hoge64', 'hoge65', 'hoge66', 'hoge67', 'hoge68', 'hoge69', 'hoge70', 'hoge71', 'hoge72', 'hoge73', 'hoge74', 'hoge75', 'hoge76', 'hoge77', 'hoge78', 'hoge79', 'hoge80', 'hoge81', 'hoge82', 'hoge83', 'hoge84', 'hoge85', 'hoge86', 'hoge87', 'hoge88', 'hoge89', 'hoge90', 'hoge91', 'hoge92', 'hoge93', 'hoge94', 'hoge95', 'hoge96', 'hoge97', 'hoge98', 'hoge99']
>>> await q.clear()↵
>>> ↵

Tip

FIFOは、APIGWやシナリオなどからキューイングし、Workerでそれらをコンシュームして処理するようなユースケースを想定しています。


mFIFO

mFIFOクラスは、カスタムアプリケーションで利用する分散マルチFIFOキューを提供するオブジェクトです。コンストラクタには、mFIFOの名前を指定します。

>>> q = mFIFO("sampleMultiQueue")↵
... print(q)↵
... ↵
↵
<axis.hotspot.script_runner.mFIFO object at 0x115f0be90>
>>>


mFIFOキューへのデータ挿入は、putメソッドを使用します。第一引数は、チャネル名、第二引数は、挿入するデータ辞書です。キューからのデータの取り出しは、コンテキストマネージャ経由でアクセスします。
async withブロック内では、データが取得できたチャネルを分散ロックします。また本ブロック内部で例外が発出された場合は、取り出したデータは再度同一チャネルの先頭に再挿入されます。
得られるデータオブジェクトは、queuechanneldataキーを持つMUオブジェクトです。queueには、mFIFOの名前がセットされます。channelには、データを取り出したチャネル名がセットされます。dataにはキューイングされたデータそのものがセットされます。

>>> await mFIFO("sampleMultiQueue").put("device#1", {"vlan": 3001})↵
... async with mFIFO("sampleMultiQueue") as o:↵
...     print(o.yaml_format)↵
... ↵
channel: device#1
data:
  vlan: 3001
queue: sampleMultiQueue
↵
>>>


Tip

データの挿入は、デフォルトでは最後尾に挿入されますが、キューの先頭に挿入したい場合は、topオプションをTrueに指定してください。

>>> await mFIFO("sampleMultiQueue").put("device#1", {"vlan": 3001}, top=True)↵


Tip

データ取り出し時のコンテキストマネージャを抜けるとチャネルロックが自動開放されますが、同一チャネルの読み出しに偏りが発生しないよう遅延アンロックが行われます。デフォルトでは、3秒後にチャネルロックが解放されます。遅延時間を指定する場合は以下のようにunlockDelayオプションを指定してください。

>>> await with mFIFO("sampleMultiQueue", unlockDelay=1) as o:
...     pass


deprecated


status_poll(非推奨)

将来廃止予定


allocate_counter(非推奨)

Counterを払い出す関数です。将来廃止予定のため、Counterの利用を推奨します。

引数 デフォルト 説明
name None カウンタ名


>>> r = await allocate_counter("orderNumber")↵
... print(r)↵
... ↵
SO00000001↵
>>>


futureization(非推奨)

ブロッキング関数を非同期化する関数です。キーワード引数を与えることが出来ないため、Awaitableの利用を推奨しています。

>>> print(clock.now())↵
... await futureization(time.sleep, 3)↵
... print(clock.now())↵
... ↵
2020-11-26 12:49:05.037393+09:00
↵
2020-11-26 12:49:08.038459+09:00
>>>


dict2xml(非推奨)

将来廃止予定


neo4j(非推奨)

グラフデータベースNeo4jへの接続関数です。現状の実装はブロッキングするため将来非同期化を予定しています。


nodetodict(非推奨)

グラフデータベースNeo4jから取得したデータをdictに変換する関数です。neo4jの非同期化に合わせて見直される可能性があります。

>>> with neo4j() as sess:↵
...     r = sess.run("MATCH (n)\nRETURN n")↵
...     for i in r:↵
...         print(nodetodict(i))↵
... ↵
{'name': 'top1', 'instance': 'VG9wOjhlMzg4OWM0N2I3NTExZTliMDBhMDAwYzI5ZGQ4MjUw', 'age': 10, 'status': True}↵
↵