てくなべ

ネットワーク、自動化などの技術的なことを書いていきます。Ansible、StackStorm等

はじめて StackStorm の Action を作ってみた

■ はじめに

2018/05/29 に開催された、Tech Night @ Shiodome # 8の中で「明日からできる、st2のActionの作り方」という発表がありました。 まだActionは作ったことがなかったのですが、これを聞いて簡単なものを作ってみようと思ってやってみました。

speakerdeck.com


■ つくるもの

何でもよかったのですが、GoogleDNS-over-HTTPSを利用して、パラメータ name で与えられた名前のAレコードをリストで返すActionを作ることにしました。


■ コードの準備

まずは、Actionの肝になるコードの準備です。 Packの作成方法がまだ理解不足だったため、default配下にしました。また、環境構築を単純化するため、 requests など別途インストールが必要なものは使わないようにしておきました。名前解決失敗時は空のリストを返すようにしました。

パス:/opt/stackstorm/packs/default/actions/dnsquery.py

from st2common.runners.base_action import Action
import json
import urllib2

class DnsQueryAction(Action):
    def run(self, name):

        url = "https://dns.google.com/resolve?name=" + name

        req = urllib2.Request(url)
        res = urllib2.urlopen(req)
        res_json  = json.loads(res.read())

        if "Answer" in res_json:
            # successed
            records = [v["data"] for v in res_json["Answer"]]
            return (True, records)
        else:
            # failed
            return (False, [])


■ metadataファイルの準備

続いて、Actionがどういうパラメータを持つかなどの情報を定義する、metadataファイルの準備です。YAML形式です。

パス:/opt/stackstorm/packs/default/actions/dnsquery.yml

---
name: "dnsquery"
runner_type: "python-script"
entry_point: "dnsquery.py"
description: "resolve dns query"
enabled: true
parameters:
    name:
        type: "string"
        description: "dns query name for type A"
        required: true


■ Actionの作成

各ファイルを作っただけでは StackStorm はまだ認識しません。st2 action create コマンドで metadata ファイルを元に Action を作成します。

[ec2-user@ip-172-31-4-147 actions]$ st2 action create /opt/stackstorm/packs/default/actions/dnsquery.yml
+-------------+----------------------------------------------------+
| Property    | Value                                              |
+-------------+----------------------------------------------------+
| id          | 5b10a7a96fb12304de15a1d2                           |
| name        | dnsquery                                           |
| pack        | default                                            |
| description | resolve dns query                                  |
| enabled     | True                                               |
| entry_point | dnsquery.py                                        |
| notify      |                                                    |
| parameters  | {                                                  |
|             |     "name": {                                      |
|             |         "required": true,                          |
|             |         "type": "string",                          |
|             |         "description": "dns query name for type A" |
|             |     }                                              |
|             | }                                                  |
| ref         | default.dnsquery                                   |
| runner_type | python-script                                      |
| tags        |                                                    |
| uid         | action:default:dnsquery                            |
+-------------+----------------------------------------------------+

作成できたようなので、 st2 action list のリストで確認します。

[ec2-user@ip-172-31-4-147 actions]$ st2 action list --pack=default
+---------------------+---------+-----------------------------------+
| ref                 | pack    | description                       |
+---------------------+---------+-----------------------------------+
| default.dnsquery    | default | resolve dns query                 |
+---------------------+---------+-----------------------------------+

認識されているようです。


■ 実行

はじめての実行(失敗・・)

それでは、st2 run による単発の実行で試してみます。

[ec2-user@ip-172-31-4-147 actions]$ st2 run default.dnsquery name=www.stackstorm.com
.
id: 5b10a8036fb12304de15a1d4
status: failed
parameters:
  name: www.stackstorm.com
result:
  error: '
    The virtual environment (/opt/stackstorm/virtualenvs/default) for pack "default" does not exist. Normally this is
    created when you install a pack using "st2 pack install". If you installed your pack by some other
    means, you can create a new virtual environment using the command:
    "st2 run packs.setup_virtualenv packs=default"
    '
  traceback: "  File "/opt/stackstorm/st2/lib/python2.7/site-packages/st2actions/container/base.py", line 119, in _do_run
    (status, result, context) = runner.run(action_params)
  File "/opt/stackstorm/runners/python_runner/python_runner/python_runner.py", line 143, in run
    raise Exception(msg)
"

おっと・・・、default pack向けの virtualenv が無いためエラーになってしまいました。

エラーメッセージに親切に書かれているコマンドで virtualenv を用意します。

[ec2-user@ip-172-31-4-147 actions]$ st2 run packs.setup_virtualenv packs=default
..
id: 5b10a8cf6fb12304de15a1d7
status: succeeded
parameters:
  packs:
  - default
result:
  exit_code: 0
  result: 'Successfuly set up virtualenv for the following packs: default'
  stderr: 'st2.actions.python.SetupVirtualEnvironmentAction: DEBUG    Setting up virtualenv for pack "default" (/opt/stackstorm/packs/default)
    st2.actions.python.SetupVirtualEnvironmentAction: INFO     Virtualenv path "/opt/stackstorm/virtualenvs/default" doesn''t exist
    st2.actions.python.SetupVirtualEnvironmentAction: DEBUG    Creating virtualenv for pack "default" in "/opt/stackstorm/virtualenvs/default"
    st2.actions.python.SetupVirtualEnvironmentAction: DEBUG    Creating virtualenv in "/opt/stackstorm/virtualenvs/default" using Python binary "/opt/stackstorm/st2/bin/python"
    st2.actions.python.SetupVirtualEnvironmentAction: DEBUG    Running command "/opt/stackstorm/st2/bin/virtualenv -p /opt/stackstorm/st2/bin/python --no-download /opt/stackstorm/virtualenvs/default" to create virtualenv.
    st2.actions.python.SetupVirtualEnvironmentAction: DEBUG    Installing base requirements
    st2.actions.python.SetupVirtualEnvironmentAction: DEBUG    Installing requirement six>=1.9.0,<2.0 with command /opt/stackstorm/virtualenvs/default/bin/pip install six>=1.9.0,<2.0.
    st2.actions.python.SetupVirtualEnvironmentAction: DEBUG    No pack specific requirements found
    st2.actions.python.SetupVirtualEnvironmentAction: DEBUG    Virtualenv for pack "default" successfully created in "/opt/stackstorm/virtualenvs/default"
    '
  stdout: ''

無事に /opt/stackstorm/virtualenvs/default として virtualenvが作成されたようです。

もう一度実行(名前解決成功)

気を取り直してもう一度 Action を実行します。

[ec2-user@ip-172-31-4-147 actions]$ st2 run default.dnsquery name=www.stackstorm.com
.
id: 5b10b23e6fb12304de15a1f0
status: succeeded
parameters:
  name: www.stackstorm.com
result:
  exit_code: 0
  result:
  - 104.28.16.123
  - 104.28.17.123
  stderr: ''
  stdout: ''

無事、status: succeeded となり、2つのIPアドレスが返ってきました。

もう一度実行(名前解決失敗)

今度は、名前解決ができないパターンで試します。

[ec2-user@ip-172-31-4-147 actions]$ st2 run default.dnsquery name=hogehogehoge.stackstorm.com
.
id: 5b10b3016fb12304de15a1f3
status: failed
parameters:
  name: hogehogehoge.stackstorm.com
result:
  exit_code: 0
  result: []
  stderr: ''
  stdout: ''

無事、status: failed となり、空のリストが返ってきました。


■ まとめ

非常に簡単な例ではありますが、初めてPythonによる Action を作成して動作を確認してみました。今のところは、そこまで覚えることも多くない印象です。 基本的には既存の Action を中心に使っていきますが、それでは実現できないものについては、カスタムのActionを作って見たいと思います。

参考資料

https://docs.stackstorm.com/actions.html#writing-custom-python-actions