StackStormで機能を拡張するには、主にpackを作ることになります。
ここでは、StackStormの公式リポジトリにある st2sdk
を使って、pack開発と簡単なテストを行います。
最初にまとめ
st2sdkでできること
- packの最低限の作成を簡単に行うことができます。
- StackStormに登録するpackとして、必要最低限のテストを回すことができます。
st2sdkでできないこと
- packの機能テストはできません(あくまでpackを作り、python的に問題ないことを確認し、そしてStackStormで問題なく読み込めることが確認できるだけ)。従って、そもそも作成しているpackが要件を満たしているかを確認することができません。
st2sdkのメリット
いちいちStackStorm自体の環境を作る必要がありません(とはいえMongoDBとRabbitMQは必要ですが)。
環境をガッツリ作らずに、packの開発を進めることができるのは便利です。
今回はさらに簡単に環境を用意できる、Dockerfile一式を用意しています。
st2sdkのデメリット
基本的に使う分にはデメリットはないと思います。
特にscaffold(初期pack作成)は頻繁に使うのではないでしょうか。
ただ、デメリットはないといえばないのですが、そもそも使うほどまであるのだろうか?というコマンドは存在します…。
st2sdkを利用する
以下に、簡単にst2sdk
を利用するための環境一式をDockerで用意しました。
この後は、上記を使って実際に動かしてみます。
ここからは、公式のst2sdkのREADMEにあるコマンドを1つずつ確認してみます。
初期pack作成
$ st2sdk bootstrap <作成したいpackファイルのパス>
多分最もよく使うコマンドで、これから開発対象となるpack一式を作成してくれます。
$ st2sdk bootstrap packs/pack_test
以下のような構成のものが簡単に作成されます。
packs/pack_test
├── README.md
├── actions
├── config.yaml
├── pack.yaml
└── sensors
yamlのフォーマットチェック(バリデーション)
$ st2-check-validate-yaml-file <yamlファイルのパス>
yamlファイルが、正しくyaml形式であるかをチェックします。
$ st2-check-validate-yaml-file packs/pack_test/pack.yaml
Validating YAML syntax for file packs/pack_test/pack.yaml...
$ echo $?
0
行っていることはものすごく単純で、単にPythonのpyyamlを使って、ファイルをyaml形式として読み込めるかどうかを見ているだけです。
注意しなければならないのが、yaml形式であるかどうかを見ているだけなので、このyamlがStackStorm的にどうなのかというチェックは一切行っていません。
jsonのフォーマットチェック(バリデーション)
$ st2-check-validate-json-file <jsonファイルのパス>
jsonファイルが、正しくjson形式であるかをチェックします。
$ echo '{ "hoge": "fuga" }' > packs/pack_test/test.json
$ st2-check-validate-json-file packs/pack_test/test.json
Validating JSON syntax for file packs/pack_test/test.json...
$ echo $?
0
こちらもyamlと同じく、単純にjson形式であるかどうかだけを見ています。
packメタデータ存在チェック
$ st2-check-validate-pack-metadata-exists <packのパス>
packにメタデータとなるpack.yaml
が存在するかどうかをチェックします。
通常、packは直下にpack.yaml
が存在しなければなりません。また、そのファイルにはそのpackの概要が記述されることになります。
$ st2-check-validate-pack-metadata-exists packs/pack_test
$ echo $?
0
ただこのコマンドは、本当にpack.yaml
が存在するかどうかだけしか見ません。pack.yaml
にStackStormとして必要な記述がなされていなかったとしても何も起こらないどころか、yamlとして正常でなかったとしてもコマンドは通ります。
このコマンド、意味があるのだろうか…。
packの登録チェック
$ st2-check-register-pack-resources <packのパス>
実際にStackStormに登録できるかどうかを見ます。内容に不備があるとエラーになります。このコマンドのために、実際にStackStormが動作する環境を用意する必要はありません。代わりに、以下が必要です。
- StackStorm用のRabbitMQ(初期状態でOK)
- StackStorm用のMongoDB(初期状態でOK)
- このコマンドで利用する
st2.tests.conf
ファイルで、上記リソースにアクセスするための設定が書かれていること-
/usr/bin
や/usr/local/bin
配下に上記confファイルがあるようです。(confなのに)
-
- 公式st2リポジトリがcloneされており、
ST2_REPO_PATH
環境変数がそこを向いていること
これらの設定は、今回用意したDocker環境では全て設定済みですので、興味があればDockerfileをご覧ください。
このコマンドは、初回実行時にst2リポジトリのrequirements.txt
を読んで、必要なモジュールをインストールするため、初回実行時は時間がかかります。
$ git clone https://github.com/StackStorm/st2contrib.git
Cloning into 'st2contrib'...
remote: Counting objects: 21369, done.
remote: Compressing objects: 100% (269/269), done.
remote: Total 21369 (delta 157), reused 0 (delta 0), pack-reused 21096
Receiving objects: 100% (21369/21369), 6.39 MiB | 658.00 KiB/s, done.
Resolving deltas: 100% (13351/13351), done.
Checking connectivity... done.
$ cd st2contrib/
$ st2-check-register-pack-resources packs/csv
Registering content from pack csv
2016-10-09 17:09:04,853 INFO [-] Connecting to database "st2" @ "mongo:27017" as user "None".
2016-10-09 17:09:04,972 INFO [-] =========================================================
2016-10-09 17:09:04,972 INFO [-] ############## Registering triggers #####################
2016-10-09 17:09:04,973 INFO [-] =========================================================
2016-10-09 17:09:04,980 INFO [-] Registered 0 triggers.
2016-10-09 17:09:04,980 INFO [-] =========================================================
2016-10-09 17:09:04,980 INFO [-] ############## Registering sensors ######################
2016-10-09 17:09:04,980 INFO [-] =========================================================
2016-10-09 17:09:04,980 INFO [-] Registered 0 sensors.
2016-10-09 17:09:04,981 INFO [-] =========================================================
2016-10-09 17:09:04,981 INFO [-] ############## Registering actions ######################
2016-10-09 17:09:04,981 INFO [-] =========================================================
2016-10-09 17:09:05,219 INFO [-] Registered 2 actions.
2016-10-09 17:09:05,219 INFO [-] =========================================================
2016-10-09 17:09:05,219 INFO [-] ############## Registering rules ########################
2016-10-09 17:09:05,219 INFO [-] =========================================================
2016-10-09 17:09:05,230 INFO [-] Registered 0 rules.
2016-10-09 17:09:05,230 INFO [-] =========================================================
2016-10-09 17:09:05,230 INFO [-] ############## Registering aliases ######################
2016-10-09 17:09:05,230 INFO [-] =========================================================
2016-10-09 17:09:05,230 INFO [-] Registered 0 aliases.
2016-10-09 17:09:05,230 INFO [-] =========================================================
2016-10-09 17:09:05,231 INFO [-] ############## Registering policy types #################
2016-10-09 17:09:05,231 INFO [-] =========================================================
2016-10-09 17:09:05,252 INFO [-] Registered 3 policy types.
2016-10-09 17:09:05,253 INFO [-] =========================================================
2016-10-09 17:09:05,253 INFO [-] ############## Registering policies #####################
2016-10-09 17:09:05,254 INFO [-] =========================================================
2016-10-09 17:09:05,254 INFO [-] Registered 0 policies.
2016-10-09 17:09:05,254 INFO [-] =========================================================
2016-10-09 17:09:05,254 INFO [-] ############## Registering configs ######################
2016-10-09 17:09:05,254 INFO [-] =========================================================
2016-10-09 17:09:05,255 INFO [-] Registered 0 configs.
注意
st2sdk bootstrap
で作成した直後のpackをテストするとエラーになる
タイトルの通りなのですが、下記の通り、 st2sdk bootstrap
コマンドで作成したpackを、何の変更もせずにテストにかけると、途中でエラーになります。
st2-check-register-pack-resources packs/pack_test
Registering content from pack pack_test
2016-10-09 16:30:04,399 INFO [-] Connecting to database "st2" @ "mongo:27017" as user "None".
2016-10-09 16:30:08,357 INFO [-] =========================================================
2016-10-09 16:30:08,358 INFO [-] ############## Registering triggers #####################
2016-10-09 16:30:08,358 INFO [-] =========================================================
2016-10-09 16:30:08,377 ERROR [-] Failed to register pack "pack_test"
Traceback (most recent call last):
File "/tmp/st2/st2common/st2common/bootstrap/base.py", line 117, in register_pack
pack_db, _ = self._register_pack(pack_name=pack_name, pack_dir=pack_dir)
File "/tmp/st2/st2common/st2common/bootstrap/base.py", line 132, in _register_pack
pack_db = self._register_pack_db(pack_name=pack_name, pack_dir=pack_dir)
File "/tmp/st2/st2common/st2common/bootstrap/base.py", line 164, in _register_pack_db
pack_db = Pack.add_or_update(pack_db)
File "/tmp/st2/st2common/st2common/persistence/base.py", line 163, in add_or_update
model_object = cls._get_impl().add_or_update(model_object)
File "/tmp/st2/st2common/st2common/models/db/__init__.py", line 252, in add_or_update
instance.save()
File "/usr/local/lib/python2.7/site-packages/mongoengine/document.py", line 304, in save
self.validate(clean=clean)
File "/usr/local/lib/python2.7/site-packages/mongoengine/base/document.py", line 413, in validate
raise ValidationError(message, errors=errors)
ValidationError: ValidationError (PackDB:None) (Field is required: ['description'])
2016-10-09 16:30:08,378 INFO [-] Registered 0 triggers.
2016-10-09 16:30:08,379 INFO [-] =========================================================
2016-10-09 16:30:08,379 INFO [-] ############## Registering sensors ######################
2016-10-09 16:30:08,379 INFO [-] =========================================================
2016-10-09 16:30:08,385 INFO [-] Registered 0 sensors.
2016-10-09 16:30:08,385 INFO [-] =========================================================
2016-10-09 16:30:08,385 INFO [-] ############## Registering actions ######################
2016-10-09 16:30:08,386 INFO [-] =========================================================
2016-10-09 16:30:08,550 INFO [-] Registered 0 actions.
2016-10-09 16:30:08,551 INFO [-] =========================================================
2016-10-09 16:30:08,551 INFO [-] ############## Registering rules ########################
2016-10-09 16:30:08,551 INFO [-] =========================================================
2016-10-09 16:30:08,639 INFO [-] Registered 0 rules.
2016-10-09 16:30:08,639 INFO [-] =========================================================
2016-10-09 16:30:08,639 INFO [-] ############## Registering aliases ######################
2016-10-09 16:30:08,639 INFO [-] =========================================================
2016-10-09 16:30:08,641 INFO [-] Registered 0 aliases.
2016-10-09 16:30:08,641 INFO [-] =========================================================
2016-10-09 16:30:08,641 INFO [-] ############## Registering policy types #################
2016-10-09 16:30:08,641 INFO [-] =========================================================
2016-10-09 16:30:08,714 INFO [-] Registered 3 policy types.
2016-10-09 16:30:08,715 INFO [-] =========================================================
2016-10-09 16:30:08,715 INFO [-] ############## Registering policies #####################
2016-10-09 16:30:08,715 INFO [-] =========================================================
2016-10-09 16:30:08,722 INFO [-] Registered 0 policies.
2016-10-09 16:30:08,722 INFO [-] =========================================================
2016-10-09 16:30:08,722 INFO [-] ############## Registering configs ######################
2016-10-09 16:30:08,723 INFO [-] =========================================================
2016-10-09 16:30:08,725 INFO [-] Registered 0 configs.
$ echo $?
0 # 戻り値0...?
読んで字のごとしなのですが、description
が空になっているため、エラーになります。
---
name: packs/pack_test
description: # ここが空欄になっているからエラー
version: 0.1
author: John Doe
email: john.doe@example.com
じゃあそれst2-check-validate-yaml-file
コマンド側でバリデーションしてくれればいいんじゃないの?と思わなくもないです。
あと最大の問題は、これが戻り値0(つまり正常終了扱い)であることです。
必ず、コマンド実行時にカレントディレクトリ配下にpacks/<パック名>
という構成で実行しなければならない
例えば、テストしたい対象のpackが/root/st2contrib/packs/csv
というパスに存在するものだった場合、必ず /root/st2contrib/
に移動してからコマンドを実行する必要があります。つまり、カレントディレクトリの直下にpacks
というディレクトリが存在する位置にいなければなりません。
つまり、以下のようになります。
$ cd /root/st2contrib
$ st2-check-register-pack-resources packs/csv
カレントディレクトリがこれ以外だと(actionを書いている場合)必ず失敗します。
$ cd /tmp
$ st2-check-register-pack-resources /root/st2contrib/packs/csv
Registering content from pack csv
2016-10-09 17:30:03,078 INFO [-] Connecting to database "st2" @ "mongo:27017" as user "None".
2016-10-09 17:30:03,169 INFO [-] =========================================================
2016-10-09 17:30:03,169 INFO [-] ############## Registering triggers #####################
2016-10-09 17:30:03,169 INFO [-] =========================================================
2016-10-09 17:30:03,176 INFO [-] Registered 0 triggers.
2016-10-09 17:30:03,176 INFO [-] =========================================================
2016-10-09 17:30:03,176 INFO [-] ############## Registering sensors ######################
2016-10-09 17:30:03,176 INFO [-] =========================================================
2016-10-09 17:30:03,177 INFO [-] Registered 0 sensors.
2016-10-09 17:30:03,177 INFO [-] =========================================================
2016-10-09 17:30:03,177 INFO [-] ############## Registering actions ######################
2016-10-09 17:30:03,177 INFO [-] =========================================================
2016-10-09 17:30:03,389 WARNING [-] Failed to register actions: Content pack "csv" is not found or doesn't contain actions directory. Searched in: packs/
Traceback (most recent call last):
File "/tmp/st2/st2common/bin/st2-register-content", line 22, in <module>
sys.exit(content_loader.main(sys.argv[1:]))
File "/tmp/st2/st2common/st2common/content/bootstrap.py", line 354, in main
register_content()
File "/tmp/st2/st2common/st2common/content/bootstrap.py", line 313, in register_content
register_actions()
File "/tmp/st2/st2common/st2common/content/bootstrap.py", line 195, in register_actions
raise e
st2common.exceptions.apivalidation.ValueValidationException: Content pack "csv" is not found or doesn't contain actions directory. Searched in: packs/
Registering resources for pack csv failed
$ echo $?
1 # 戻り値も1...
どうやら、action登録時に、actionはカレントディレクトリ直下のpacks
を見に行っているためのようです。これは、st2.tests.conf
に以下の記載があるためです。
[content]
system_packs_base_path =
packs_base_paths = packs/ # この記述のせい
もちろんこれを変更すれば動きます。
pythonファイルのlint(静的解析)
$ st2-check-pylint-pack <packのパス>
pylintをかけて、コードの静的解析を行います。
ただこれを動かすためには、以下の条件があります。
- virtualenv環境であること、しかも環境名が
virtualenv
であること - lintの設定ファイルは
./lint-configs/python/.pylintrc
に格納されていること
前者は、ここにソースがあるのですが、がっつり以下のように書かれているため、環境名がvirtualenv
に縛られます。
if [[ ${PYTHON_BINARY} != *"virtualenv/bin/python" ]]; then
echo "Script must run under a virtual environment which is created in the Make target"
exit 2
fi
後者もソースの記述によるもので、st2contribはその構成ではあるのですが、なんでそこに固定するのか…。
if [ ${ACTION_PYTHON_FILES_COUNT} -gt 0 ]; then
find ${PACK_PATH}/actions -name "*.py" -print0 | xargs -0 ${PYTHON_BINARY} -m pylint -E --rcfile=./lint-configs/python/.pylintrc && echo "--> No pylint issues found in actions." || exit $?
fi
これらは、今回作ったDockerfileでも対応していません。一応、st2contribに対して動かすには以下のようにすれば動きます。
$ virtualenv virtualenv
New python executable in /root/virtualenv/bin/python2
Also creating executable in /root/virtualenv/bin/python
Installing setuptools, pip, wheel...done.
$ source virtualenv/bin/activate
(virtualenv) $ cd st2contrib/
(virtualenv) $ st2-check-pylint-pack packs/csv
Running pylint on pack: csv
--> No pylint issues found in actions.
テストのカバレッジ計測
$ st2-check-print-pack-tests-coverage <packのパス>
作成したpack中のactionに対応するテストが存在するか、カバレッジを計測します。
$ st2-check-print-pack-tests-coverage st2contrib/packs/csv
====== st2contrib/packs/csv ======
Python Actions missing tests:
format.py (st2contrib/packs/csv/tests/test_action_format.py not found)
Python Tests with no actions:
Python Test Coverage:
Actions: 1/2
ただこれは、test_action_<action名>.py
というファイルが存在するかどうかしか見ていません。
中のテストがなんであっても、最悪空ファイルであったとしても、カバレッジとしてカウントされてしまいます。
命名規則自体はこちらに従っているものではあるので正しいのですが、とはいえカバレッジってそういうものなの…?という気がしてなりません。
最後に所感など
とにかく提供されるコマンドが、内部にパスを埋め込みまくりで、開発だからといって自由なパスにpackを置いてしまうと基本的に動きません。これが、st2sdk
のREADME.md
にも書かれていないせいで、謎のエラーで止まることが何度も何度も何度も…。本当に辛かった…。
コマンドを提供してくれること自体はありがたいのですが、これ使うの?使えるの?といういまいち重要度が謎なものもいっぱいあり、scaffold以外は「とりあえず」的な位置付けであることは否めません。
CIにこれらのコマンドをとりあえず突っ込んでおくくらいがいいのかもしれません。