インフラ本部の大山裕泰です。今回は Brocade が買収したことで話題になった、イベントドリブンな Workflow エンジン StackStorm が一体どういう仕組みで動作しているか、ちょっと深堀した内容をお届けします。
StackStorm 自体については、先日行われた StackStorm 勉強会で 発表された方の資料 で詳しく解説されており、使い方についても こちら や こちら のページで詳しく解説されています。
「StackStorm を使ってみたけど、裏側で何がどうなっているかイマイチよくわからん」といったユーザ向けに、StackStorm の論理構造を解説し、StackStorm の理解の手助けが出来ればと思います。
StackStorm について
StackStorm のドキュメント を冒頭から読んでいくと、いきなり次のような図が情報します。
一見とても複雑そうです。ターゲットに紐付く依存関係を解決してコマンドを実行する “古典的なワークフローエンジン” とは違います。
初めて触るユーザや、とりあえず QuickStart だけやってみたユーザにとっては、なんでこんな複雑な機構なんだろうかと戸惑われたかもしれません。
本エントリではこうしたユーザ向けに、StackStorm の概要についての理解と、上記の内部アーキテクチャの詳細についての理解の中間的な論理構成の理解を手助けする内容を提供していきます。
StackStorm の論理構造
以下は、StackStorm がイベントを処理する仕組みについて表した図になります。
Sensor は外部で発生したイベントを監視するモノで、外部のイベントを検知した際には予め登録された Trigger にイベントの発生を通知 (以降では “Trigger を引く” と表現) します。
Trigger は Sensor から通知された外部イベントを Action が扱い易い形に正規化します。何も設定されていない状態では、Sensor が Trigger を引いても何も発生しません。Trigger が引かれた際にどういった処理 (Action/Workflow) を実行するかを規定したものが Rule になります。
Rule には二つの役割があります。一つは上述した Trigger と Action/Workflow を紐づける役割で、もう一つが Trigger パラメータと Action パラメータを変換する役割です。
StackStorm では Trigger と Action はそれぞれ独立しており、Rule によってどのような Trigger と Action を組み合わせることができます。その際、Trigger から渡されるどのパラメータを抽出し、どういったパラメータを Action に渡すかの設定を Rule に記述します。
以下の具体的なケースに置き換えて考えてみます。
ここでは Sensor, Trigger, Action にそれぞれ以下を使用し、GitHub の特定のリポジトリで Issue を作成(更新)した際に RabbitMQ にメッセージを送る仕組みになります。
尚、StackStorm では Sensor, Trigger, Action を機能毎にまとめたソフトウェアコンポーネントのことを pack と呼びます。そして、上記の github は rabbitmq のようなサードパーティの pack は (本エントリ執筆時点では) StackStorm/st2contrib リポジトリで管理する運用になっています。
Sensor ‘github.GithubRepositorySensor’ は 30 秒毎に GitHub のリポジトリの更新状況を確認し、前回の確認から更新が発生した場合には Trigger ‘github.repository_event’ を引きます。
ここでは、この Trigger が引かれた際に Action ‘rabbitmq.publish_message’ を実行する Rule ‘example.github_event_invocation’ を記述しました。この Rule の内部で Trigger パラメータ (Issue に対する操作(opened/closed)、及びタイトルと本文) を Action パラメータ (exchange, routing-key, message) を次のように変換しています。
動かしてみる
確認する GitHub のリポジトリは、GitHub pack の設定ファイル ‘/opt/stackstorm/packs/github/config.yaml’ で指定します。以下に設定ファイルの全文を示します。
---
token: "****"
repository_sensor:
event_type_whitelist:
- "IssuesEvent"
- "IssueCommentEvent"
- "ForkEvent"
- "WatchEvent"
- "ReleaseEvent"
- "PushEvent"
repositories:
- user: "userlocalhost2000"
name: "st2-test"
ここでは、この Trigger が引かれた際に Action ‘rabbitmq.publish_message’ を実行する Rule ‘example.github_event_invocation’ を記述しました。以下が設定したルールの全文になります。
---
name: 'github_event_invocation'
pack: 'example'
description: "A rule to notice updates on GitHub repositories"
enabled: true
trigger:
type: "github.repository_event"
action:
ref: "rabbitmq.publish_message"
parameters:
host: '127.0.0.1'
exchange: '{{trigger.repository}}'
routing_key: '{{trigger.payload.action}}'
message: "[{{trigger.payload.action}}] {{trigger.payload.issue.title}}\n---\n{{trigger.payload.issue.body}}"
criteria:
trigger.type:
pattern: 'IssuesEvent'
type: 'equals'
’trigger’ / ‘action’ のパラメータで、それぞれ図の Trigger / Action を指定します。’action’ の ‘parameters’ で当該アクションに渡すパラメータを指定します。ここで Trigger から渡されるパラメータと Action パラメータの変換処理を行っています。
’criteria’ パラメータは、Trigger に通知されたイベントのうち Action で処理するモノを選択する際に利用します。今回の例では Trigger はリポジトリに対する Issue の更新/コメント、Fork、Watch、Push などのイベント発生時に Sensor によって引かれますが、Issue の更新イベントだけ Action を呼ぶようにしたい場合にこのように設定します。
それでは実際に GitHub リポジトリ に Issue を作成し動作を確認します。RabbitMQ に通知された メッセージを受け取るスクリプト を実行し、リポジトリに以下のような Issue を作成します。
こうすることで Sensor が検知したイベントを Trigger に通知し、Rule に沿って RabbitMQ にメッセージが送られます。そして、先ほど実行したスクリプトで送られたメッセージを取得できることが確認できます。