TechNight Shiodome #8 で発表したやつ。
明日からできる、st2のActionの作り方Wataru Manji
View Slide
自己紹介● 名前: 萬治 渉 (マンジ ワタル)● 所属:○ NTTテクノクロス株式会社 IoTイノベーション事業部○ 日本StackStormユーザ会● 仕事:○ OpenStack基盤の設計、運用、保守○ StackStorm関係色々○ その他AnsibleとかNWとか色々● 連絡先:● Twitter: @_manji0● Mail: [email protected]
みなさん、Action書いてますか???(・ω・)ノ 1. プロダクションでバリバリ書いてる2. 手習い程度に書いてる3. 公開されてるものを使ってるだけで、書いてない4. Action? ナニソレ?TodaysTarget
Action作成のノウハウはいっぱいある● Action入出力を定義する方法● ActionのPythonコードの記述方法● etc○ Workflow内で扱いやすいActionの入出力とは○ Actionの適切な粒度とは○ Actionコードの形式別の記述方法○ 開発中Actionのテスト方法○ ...おおまかな勉強順序
その中で今回話すこと● Action入出力を定義する方法○ 入力: ActionのMetadataについて○ 出力: Actionの出力形式、および構造化データの扱いについて● ActionのPythonコードの記述方法○ 基本的な形式と要素の解説● etcは話す時間が無いのでまたいつか
今回のゴール● Actionの入出力を定義する方法について理解している● Python, BashでActionコードを記述する方法を知っている= Actionの「箱」について理解しており、明日から「自分の作りたいAction」を作り始められること
※全ての前提知識について話す時間は無いピンからキリまで20分で話すのは不可能...なので、今回はAction, Workflow, Ruleなどの分類については話しません。必要に応じて以下の情報を参考にすることで、フォローできるかと思います。(どっちも作成に関わってるので、質問にも答えられます)● st2の概要&特徴○ https://speakerdeck.com/ntttechnocross/ntt-techconference-number-2-stackstorm● workflowやruleの書き方○ https://github.com/internetweek2017-st2/handson_documents
前提: チョット分かるActionの構造
チョット分かるActionの構造metadata・Actionコードの形式、path・入力の定義Actionコード・実行内容の記述・return値の定義st2・metadataに書かれた情報の管理・実行リクエストの解釈metadataで指定されたAction-Codeを指定された入力で起動実行結果をst2にreturn事前にst2へActionの情報を渡す
Actionの入出力について
それぞれ、どこで定義しているの?● 入力: metadata内○ metadata内での定義記述箇所○ 指定できるオプション● 出力: Actionコード内○ st2の出力定義○ Actionコード内での出力方法○ 構造化データの取り扱い順番に解説。
入力の定義: metadata.parameters● metadata: ActionやWorkflowの名前、コード位置や入力を定義するファイル● parametersセクションで入力を定義する○ 入力の名前○ 入力値の型○ 入力値の初期値○ 入力の必須/任意の選択○ etc...● metadataで定義していない入力は基本的に使うことができない(やり方はあるが、今回は解説しない)
metadata.parametersの記述方法(基本)# 前略parameters:hostname:type: stringrequired: truehoge:type: string...● YAMLの辞書形式で書いていく● ここでは、”hostname”と”hoge”の2つの入力を定義している● “type”の指定は必須!● “required”はオプション。trueは「起動時の入力を必須とする」という意味。required以外のオプションについては後述。
個々のparameterに指定できるオプションたち● required○ Action起動時にその入力値が指定されていない場合、エラーを出すことができる○ デフォルトはFalse● description○ その入力の役割、意味などを自由に記述することができる。あった方が親切● default○ 入力の初期値を設定できる○ requiredと組み合わせることもできるが、意味が無くなる● enum○ 入力値を選択式にする● immutable○ 入力値をユーザから入力できないようにする○ defaultとセットで使うのが基本● position○ 入力の順序を定義する
入力定義のポイント● Actionの入力はmetadataのparametersで定義する● 入力は名前付き引数として定義される● 入力値の形式や初期値などを定義できるので、「metadata内で定義している部分は」Action内でのvalidateが不要
bash(local-shell-script)でActionを作る場合Actionコード内で引数(入力)を名前で引くことができない。なので、以下のようにActionを実装する必要がある。● metadata.parametersの各要素にpositionを連続した自然数で設定する● Actionコードとなるスクリプト内で、$で参照する
出力I: st2の出力形式st2は、Actionの出力を以下のように分類している。共通 shell-script系Action Python Actionstdout result_code exit_codestderr failed result(status) succeeded赤字が実質的な差分
出力I:例(shell-script系)core.localでecho helloしてみる! failed is succeeded
出力I: 例(Python)同じようなPythonのActionを実行してみるresultの役割とは?→次項
出力II: 構造化データの取り扱い● Pythonで実装する場合○ result以下に構造化データを出力することができる○ dictをそのまま渡せばOK○ ネストしててもリストが混ざってても OK○ 型も保持される● それ以外で実装する場合○ stdoutにJSON or YAMLのStringで出力する○ 別途Jinja Filterで構造化データに変換することで、後続 Actionなどで利用可能
出力I&II: Pythonでの出力方法def run(self, **kwargs):sys.stdout.write(“ok”) ← stdoutsys.stderr.write(“error”) ← stderrreturn (True, {“fuga”: “111”, “list”: [1, 2, 3]})↑return (status, result)True → succeededFalse → failedstatus: succeededexit_code: 0result:fuga: “111”list:- 1- 2- 3stdout: “ok”stderr: “error”
出力定義のポイント● 基本的にテキストで出力する● PythonでActionを作ることで、resultという表現力の高い出力形式を使える○ hash, listを用いた構造化データの記述が可能○ 出力値の型の保持が可能
PythonでのActionコード記述方法
Pythonでの書き方from st2common.runners.base_action import Actionclass TestAction(Action):def run(self, arg1, arg2, **kwargs):# なんらかの処理return (True, result)
Pythonでの書き方from st2common.runners.base_action import Actionclass TestAction(Action):def run(self, arg1, arg2, **kwargs):# なんらかの処理return (True, result)特別な理由が無い限り、とりあえず書く
Pythonでの書き方from st2common.runners.base_action import Actionclass TestAction(Action):def run(self, arg1, arg2, **kwargs):# なんらかの処理return (True, result)名前は自由だが、Action名と対応が取れるのが望ましい
Pythonでの書き方from st2common.runners.base_action import Actionclass TestAction(Action):def run(self, arg1, arg2, **kwargs):# なんらかの処理return (True, result)st2は自動的にrunメソッドを実行するので、必須。(同クラス内に、runから呼ばれるメソッドを独自に書いても OK)
Pythonでの書き方from st2common.runners.base_action import Actionclass TestAction(Action):def run(self, arg1, arg2, **kwargs):# なんらかの処理return (True, result)引数(入力)はmetadata.parametersで設定したものが名前付きで渡されるので、列挙してもいいし dictで拾ってもよい
Pythonでの書き方from st2common.runners.base_action import Actionclass TestAction(Action):def run(self, arg1, arg2, **kwargs):# なんらかの処理return (True, result)● 何もreturnしない場合○ status = succeededになる○ resultは空になる(None)● Trueだけ返した場合: 同上● タプルを返した場合○ 1つ目のBoolがActionの実行成否になる○ 2つ目のデータがそのまま resultに入る
応用: exit_codeを定義するfrom st2common.runners.base_action import Actionclass TestAction(Action):def run(self, arg1, arg2, **kwargs):# なんらかの処理if hoge is None:sys.stderr.write(‘hoge err’)exit(2)exit(exit_code)で定義することが可能status: failed---exit_code: 2result: Nonestdout: “”stderr: “hoge err”exit_code != 0の場合、Actionは失敗する
returnとexitの使い分け● 正常系、準正常系を通ったときにはreturnで返すべき○ returnでないと、構造化データを返せない○ statusは可変だが、exit_codeは0に固定される● exitを使うのは特殊ケースのみにすべき○ stdout, stderr, exit_codeしか返せない = テキストと数値だけしか返せない→ Actionを異常終了させるときに使うと綺麗だと思う (stderr + errno)
まとめ
やったね!Actionが書けるよ!● metadata内のparametersを設定できるようになったので、○ 入力を定義することができるようになった!○ 簡単な入力規則を定義することができるようになった!● Python形式のAction出力の定義方法と全体の書き方が分かったので、○ ナニカを実行するActionを書けるようになった!○ 構造化データを含む自由度の高いActionを作れるようになった!
明日からActionを作り始める、その前に公式ドキュメントの以下の節は読んでおこう!● https://docs.stackstorm.com/actions.html#action-metadata● https://docs.stackstorm.com/actions.html#writing-custom-python-actions概要は説明したので、理解も補足もスムーズにいくはず!