てくなべ (tekunabe)

ansible / network automation / 学習メモ

Ansible でインベントリファイルを用意せずに対象ホストを指定する方法

-i にカンマ区切りで直接ホストを指定できる

通常、 ansible-playbook コマンドや ansible コマンドのオプション -i オプションでは、イベントリファイル名を指定することが多いと思います。 この -i オプションですが、インベントリファイルを用意することなく、対象ホストをカンマ区切りで直接指定することもできます。


例えば、rt01sw01 を対象とする場合は、以下のように指定します。

ansible-playbook -i rt01,sw01 playbook.yml


対象が1ホストだけの場合は、末尾のカンマを残したかたちにします。

ansible-playbook -i rt01, playbook.yml


なお、末尾のカンマがないと、インベントリファイル名が指定されたとみなされます。

ansible-playbook -i rt01 playbook.yml

(この場合 rt01 というインベントリファイルを探しいく)

インベントリファイルを用意するほどでもないときは、この方法を利用してみてはいかがでしょうか。


参考

コマンドオプションヘルプ (or comma separated host list と記載あり)

[vagrant@centos7 ~]$ ansible-playbook
Usage: ansible-playbook [options] playbook.yml [playbook2 ...]

Runs Ansible playbooks, executing the defined tasks on the targeted hosts.

(略)
  -i INVENTORY, --inventory=INVENTORY, --inventory-file=INVENTORY
                        specify inventory host path or comma separated host
                        list. --inventory-file is deprecated



[https://docs.ansible.com/ansible/2.9/plugins/inventory/host_list.html:title]

docker run で Ansible の Playbook を実行する

ansible のリポジトリに ansible-runner なるものを見つけました。

github.com

デモ用に docker で ansible を動かす例が載っていました。

docker run -it --rm -e RUNNER_PLAYBOOK=test.yml ansible/ansible-runner:latest

手元に ansible がない環境で docker run 経由で ansible を動かす、という方法は面白いなと思ったので試すことにしました。

f:id:akira6592:20180607161707g:plain

実行される Playbook は、

ansible-runner/test.yml at master · ansible/ansible-runner · GitHub

のようです。

- hosts: all
  tasks:
    - debug: msg="Test!"

Vagrant で手軽に VM ごと StackStorm の環境を準備する

■ はじめに

StackStorm の環境を準備するには、インストールスクリプトを実行する方法や Ansible の Playbook を実行する方法などがありますが、先日の公式ブログでは vagrantVMごと StackStorm の環境を準備する方法が紹介されていました。

stackstorm.com

公式ドキュメントの「Vagrant & Virtual Appliance」にも、記載されていましたので、これらの情報をもとに試しに、環境を準備して、ごく簡単な動作確認をします。

環境:

※ Ansible で StackStorm にインストールする場合はこちら http://tekunabe.hatenablog.jp/entry/2018/03/12


■ StackStorm 入りのVMの準備と起動

以下の2行だけです。

vagrant init stackstorm/st2
vagrant up

vagrant init stackstorm/st2 で最低限の Vagrantfile が生成され、その情報をもとに vagrant upVMを起動するという流れです。

akirapc:st2 akira$ vagrant init stackstorm/st2
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.
akirapc:st2 akira$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'stackstorm/st2' could not be found. Attempting to find and install...
    default: Box Provider: virtualbox
    default: Box Version: >= 0
==> default: Loading metadata for box 'stackstorm/st2'
    default: URL: https://vagrantcloud.com/stackstorm/st2
==> default: Adding box 'stackstorm/st2' (v2.7.2-20180523) for provider: virtualbox
    default: Downloading: https://vagrantcloud.com/stackstorm/boxes/st2/versions/2.7.2-20180523/providers/virtualbox.box
==> default: Successfully added box 'stackstorm/st2' (v2.7.2-20180523) for 'virtualbox'!
==> default: Importing base box 'stackstorm/st2'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'stackstorm/st2' is up to date...
==> default: Setting the name of the VM: stackstorm
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
    default: Adapter 2: hostonly
==> default: Forwarding ports...
    default: 443 (guest) => 9000 (host) (adapter 1)
    default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default:
    default: Vagrant insecure key detected. Vagrant will automatically replace
    default: this with a newly generated keypair for better security.
    default:
    default: Inserting generated public key within guest...
    default: Removing insecure key from the guest if it's present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
[default] GuestAdditions 5.2.12 running --- OK.
==> default: Checking for guest additions in VM...
==> default: Setting hostname...
==> default: Configuring and enabling network interfaces...
==> default: Mounting shared folders...
    default: /vagrant => /Users/akira/Documents/git/python_test/vagrant/st2
==> default: Running provisioner: st2-version (shell)...
    default: Running: inline script
    default: st2 2.7.2, on Python 2.7

==> default: Machine 'default' has a post `vagrant up` message. This is a message
==> default: from the creator of the Vagrantfile, and not from Vagrant itself:
==> default:
==> default:   ███████╗████████╗██████╗      ██████╗ ██╗  ██╗
==> default:   ██╔════╝╚══██╔══╝╚════██╗    ██╔═══██╗██║ ██╔╝
==> default:   ███████╗   ██║    █████╔╝    ██║   ██║█████╔╝
==> default:   ╚════██║   ██║   ██╔═══╝     ██║   ██║██╔═██╗
==> default:   ███████║   ██║   ███████╗    ╚██████╔╝██║  ██╗
==> default:   ╚══════╝   ╚═╝   ╚══════╝     ╚═════╝ ╚═╝  ╚═╝
==> default:
==> default:   To access the Web UI, head to:
==> default:     https://10.10.10.10/
==> default:     Username: st2admin
==> default:     Password: Ch@ngeMe
==> default:
==> default:   Thanks for trying StackStorm!


CLIの確認

SSHログイン

そのまま vagrant ssh コマンドでログインできます。

akirapc:st2 akira$ vagrant ssh
Welcome to StackStorm v2.7.2 (Ubuntu 16.04 LTS GNU/Linux x86_64)

 * Documentation: https://docs.stackstorm.com/
 * Community: https://stackstorm.com/community-signup
 * Forum: https://forum.stackstorm.com/
 * Enterprise: https://stackstorm.com/#product

Last login: Wed Jun  6 11:59:12 2018 from 10.0.2.2
vagrant@stackstorm:~$ hostname
stackstorm
vagrant@stackstorm:~$ uname -a
Linux stackstorm 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
vagrant@stackstorm:~$

ログインできました。Ubutuを利用しているようです。

なお、VirtualBoxVM として SSH へポートフォワーディングは 2222/TCP に設定されますので、ssh コマンドやターミナルソフトでログインする場合は、 2222/TCP を指定します。 ユーザー名、パスワードともに vagrant です。秘密鍵を利用する場合は .vagrant/machines/default/virtualbox/private_key を指定します。

akirapc:st2 akira$ ssh vagrant@localhost -p 2222
vagrant@localhost's password:
Welcome to StackStorm v2.7.2 (Ubuntu 16.04 LTS GNU/Linux x86_64)

 * Documentation: https://docs.stackstorm.com/
 * Community: https://stackstorm.com/community-signup
 * Forum: https://forum.stackstorm.com/
 * Enterprise: https://stackstorm.com/#product

vagrant@stackstorm:~$ hostname
stackstorm

StackStorm ログイン(認証)

StackStormの各種操作には、StackStormへのログインが必要です。ここでは環境変数トークンを仕込む方法でログインと同等の状態にします。 ユーザーは st2admin、パスワードは Ch@ngeMe です。

vagrant@stackstorm:~$ export ST2_AUTH_TOKEN=`st2 auth -t -p Ch@ngeMe st2admin`

st2 run 動作確認

簡単な動作確認として st2 run コマンドで date コマンドを実行します。

vagrant@stackstorm:~$ st2 run core.local -- date -R
.
id: 5b17d02802ebd505e4388361
status: succeeded
parameters:
  cmd: date -R
result:
  failed: false
  return_code: 0
  stderr: ''
  stdout: Wed, 06 Jun 2018 12:14:33 +0000
  succeeded: true

正常に実行できました。


GUI(Web)の確認

ログイン

今度は、Web画面の確認をします。 VMの設定で、9000/TCP から 443/TCP へのポートフォワーディングが設定されていますので、ホストOSのブラウザから https://localhost:9000 にアクセスします。 CLI と居と同じく、ユーザーは st2admin、パスワードは Ch@ngeMe です。 f:id:akira6592:20180606212440p:plain

ログ確認

ログイン後トップ画面の左の方で、先程CLIから実行した st2 run core.local -- date -R のログが確認できます。 f:id:akira6592:20180606212652p:plain


■ ログイン情報まとめ

初期のログイン情報は以下のとおりです。

ログイン方法 ポート番号 ユーザー名 パスワード 備考
SSH 2222 vagrant vagrant 秘密鍵 .vagrant/machines/default/virtualbox/private_key
Web 9000 st2admin Ch@ngeMe https://localhost:9000
st2 login - st2admin Ch@ngeMe


■ まとめ

VagrantVirtualBox で艱難に OSごと StackStorm の環境を準備できることが確認できました。 特に OS/ディストリビューションにこだわりがなく、とにかく手軽にローカルに StackStorm の独立した環境を準備するには、この Vagnrant の方法が良いのではないかと思います。

日本のネットワーク機器ベンダーの Ansible 対応状況(Alaxala・APRESIA・古河電工)

■ はじめに

Ansible は Cisco、Juniper、ARISTAなどのネットワーク機器にも対応しています。 公式ドキュメント上のネットワークモジュールの一覧ページを確認すると分かりますが、日本のネットワーク機器に対応するモジュールは標準モジュールにはありません。 ただ、今年に入って日本のネットワーク機器ベンダーが Ansible に対応する動きが見られます。

この記事では、Alaxalaと、APRESIAの対応状況について調べた範囲でご紹介します。(いずれも本記事執筆時点)


■ Alaxala はサードパーティモジュールを提供済み

Alaxala は、対応モジュールを提供済みです。

Ansibleを活用したITインフラの運用自動化ソリューションを強化:アラクサラネットワークス株式会社

会員専用サイトから無償でダウンロード可能で、日本語マニュアルも用意されています。

提供モジュールは以下。

  • ax_command
  • ax_config
  • ax_facts

パッと見、オプション含めて既存の標準モジュールに合わせた仕様で作られているようでした。

また、Interop Tokto 2018 で、デモの展示があるそうです。

OSSである運用自動化ツールAnsibleを活用したプロビジョニングのデモを行います。

Interop Tokyo 2018:出展のご案内:アラクサラネットワークス株式会社

Interopレポート (2019/02/06 追記) tekunabe.hatenablog.jp


■ APRESIA は "将来実装予定" → 提供開始

2018年5月23日:APRESIA Systemsが次世代モバイル向けにネットワーク装置を発表|ニュースリリース|APRESIA | APRESIA Systems株式会社

上記 Apresia22000シリーズのニュースリリースに、将来実装予定と注釈がついていますが

– 収集した情報を更に詳細に分析するためのツールやOSS、AI、機械学習との連携を容易にするTelemetryやansibleなどの標準技術やAPIの実装

とありました。

詳細は不明ですが、こちらもサードパーティモジュールとして提供されるのかもしれません。

[2022/10/21 追記] 提供されたことがアナウンスされました。

古河電工 は JANOG43 のブースで展示 (2019/02/06 追記)

2019年1月に開催された、JANOG43 Meeting in Yamanasi のブースで、Ansible モジュールを使ったデモをされていました。

デモの内容は、Zabbixで機器の障害を検出したら予備機(マネジメントIPだけ設定済み)にコンフィグを投入して、切り替えるといったものでした。

モジュールの提供方法については検討中とのことでした。


■ まとめ

他にもあるかもしれませんが、 日本のネットワーク機器ベンダーの Ansible 対応状況についてまとめました。 もしかしたら今後も対応するベンダーが現れるかもしれませんので、引き続きにしていこうと思います。

Ansible の loop は flatten されない(with_items ではなく with_list と同じ)

■ はじめに

Ansible 2.5 で with_* の代わりに利用できる loop キーワードが利用できるようになりました。

今まで with_items と同じと思い込んでいたのですが、そうではなく with_list と同じ、ということに気がついたのでまとめます。 違いは、一段階flatten(ネストを平らにして展開)されるか、されないかです。

キーワード  flatten
with_items 一段階 flatten される
with_listloop flatten されない

■ 検証

違いを確認するために、簡単な Playbook で検証します。

Playbook

- hosts: localhost
  gather_facts: no
  connection: local

  vars:
    testitems:
      - [1, 2]
      - 3

  tasks:
    - name: with_items
      debug:
        msg: "{{ item }}"
      with_items: "{{ testitems }}"

    - name: with_list
      debug:
        msg: "{{ item }}"
      with_list: "{{ testitems }}"

    - name: normal loop
      debug:
        msg: "{{ item }}"
      loop: "{{ testitems }}"

実行結果

akira:~/environment $ ansible-playbook -i inventory looptest.yml 

PLAY [localhost] ***********************************************

TASK [with_items] **********************************************
ok: [localhost] => (item=None) => {
    "msg": 1
}
ok: [localhost] => (item=None) => {
    "msg": 2
}
ok: [localhost] => (item=None) => {
    "msg": 3
}

TASK [with_list] ***********************************************
ok: [localhost] => (item=None) => {
    "msg": [
        1, 
        2
    ]
}
ok: [localhost] => (item=None) => {
    "msg": 3
}

TASK [normal loop] *********************************************
ok: [localhost] => (item=None) => {
    "msg": [
        1, 
        2
    ]
}
ok: [localhost] => (item=None) => {
    "msg": 3
}

PLAY RECAP *****************************************************
localhost       : ok=3    changed=0    unreachable=0    failed=0   

このように、 [[1, 2], 3] というネストされたリストが、

  • with_items は flatten されて、 123 という3回のループ
  • with_listloop は flatten されず、 [1, 2]3 という2回のループ

になったことが確認できました。

with_items を loop で置き換えるなら、| flatten(levels=1) する

loop でも flatten フィルターを通すと flatten されて、 with_items と同じ動作になります。

    - name: loop with flatten
      debug:
        msg: "{{ item }}"
      loop: "{{ testitems | flatten(levels=1) }}"
akira:~/environment $ ansible-playbook -i inventory looptest.yml 

PLAY [localhost] ***********************************************

TASK [loop with flatten] ***************************************
ok: [localhost] => (item=None) => {
    "msg": 1
}
ok: [localhost] => (item=None) => {
    "msg": 2
}
ok: [localhost] => (item=None) => {
    "msg": 3
}

PLAY RECAP ************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0   


■ まとめ

  • 通常の loop は、with_list と同じく、 flatten されない

  • フィルター| flatten(levels=1)| を通すと、with_items と同じく一段階 flatten される

ということが分かりました。これから Playbook のサンプルは with_* ではなく、 loop が増えてくるのではないかと思います。

参考

Ansible 2.5 へのポーティングガイドで with_x から loop への以降方法が記載されています。 https://docs.ansible.com/ansible/latest/porting_guides/porting_guide_2.5.html#migrating-from-with-x-to-loop

StackStorm で Slack 投稿時に特定のアクションをするルールを作ってみた

■ はじめに

以前のエントリで、 StackStorm の Slack Pack の Action を利用して、Slack への投稿を試しました。

tekunabe.hatenablog.jp

今回は、Action ではなく、Trigger や Sensor を使って Slack 上のイベントを拾って何かする、という機能を試してみます。


■ ためすこと

Slack の投稿を検出して、以下のようにテキストファイルに出力する、という簡単な処理をためすことにします。

名前: 投稿内容
名前: 投稿内容
名前: 投稿内容
名前: 投稿内容


■ 準備

トークンの取得

連携のためには Slack のトークンが必要です。 Slack Pack の GitHub リポジトリの README に説明があります。 今回は、とにかく簡単に試したかったため、「For testing purposes..」の下りで説明されている方法でトークンを取得しました。

Slack Pack の設定

先程取得したトークンを、st2 pack config slack コマンドで設定します。

今回は以下の値にして、他はデフォルトのままにしました。

設定項目 備考
post_message_action.username akira6592 任意の名前
post_message_action.webhook_url (着信WebフックのURL)
sensor.token (先程控えたトークン)
admin.organization admin 任意の名前

途中、以下のように聞かれますのでエンターを押します。

Do you want to preview the config in an editor before saving? [y]:

設定内容がテキストとしてエディタで開かれるので、確認後エディタを終了します。

最後に

Do you want me to save it? [y]: 

と聞かれるのでエンターを押します。


■ Slack Trigger の仕様調査

後で必要になる情報を調べておきます。

Slack Pack に含まれる Trigger を調べます。

[ec2-user@ip-172-31-4-147 ~]$ st2 trigger list -p slack
+---------------+-------+------------------------------------------------------+
| ref           | pack  | description                                          |
+---------------+-------+------------------------------------------------------+
| slack.message | slack | Trigger which indicates a new message has been       |
|               |       | posted to a channel                                  |
+---------------+-------+------------------------------------------------------+

slack.message という Trigger があり、新着メッセージを拾えるようです。

次に、この Trigger の詳細を調べます。

[ec2-user@ip-172-31-4-147 ~]$ st2 trigger get slack.message
+-------------------+--------------------------------------------------------------+
| Property          | Value                                                        |
+-------------------+--------------------------------------------------------------+
| id                | 5b0b5b426fb12304dc0e014f                                     |
| ref               | slack.message                                                |
| pack              | slack                                                        |
| name              | message                                                      |
| description       | Trigger which indicates a new message has been posted to a   |
|                   | channel                                                      |
| parameters_schema |                                                              |
| payload_schema    | {                                                            |
|                   |     "type": "object",                                        |
|                   |     "properties": {                                          |
|                   |         "text": {                                            |
|                   |             "type": "string"                                 |
|                   |         },                                                   |
|                   |         "timestamp_raw": {                                   |
|                   |             "type": "string"                                 |
|                   |         },                                                   |
|                   |         "user": {                                            |
|                   |             "type": "object"                                 |
|                   |         },                                                   |
|                   |         "channel": {                                         |
|                   |             "type": "object"                                 |
|                   |         },                                                   |
|                   |         "timestamp": {                                       |
|                   |             "type": "integer"                                |
|                   |         }                                                    |
|                   |     }                                                        |
|                   | }                                                            |
| tags              |                                                              |
| uid               | trigger_type:slack:message                                   |
+-------------------+--------------------------------------------------------------+

例えば、投稿内容そのものは text で取得できそうです。

Slack Pack の GitHub リポジトリの README の slack.message trigger に、ペイロードのサンプルが載っていました。

(引用)

{
    "user": {
        "first_name": "Tomaz",
        "last_name": "Muraus",
        "is_owner": false,
        "name": "kami",
        "real_name": "Tomaz Muraus",
        "is_admin": false,
        "id": "U0CCCCC"
    },
    "channel": {
        "topic": "",
        "id": "C0CCCCCC",
        "name": "test"
    },
    "timestamp": 1419164091,
    "timestamp_raw": "1419164091.00005",
    "text": "This is a test message."
}

例えば、投稿者の名前は user.name で取得できそうです。


■ ルールの作成

何が起きたときに何をする、というルールを作成します。

ルールの書き方は、公式ドキュメントの Quick Start の Define a Ruleを参考にしました。後でわかりましたが、ここでの ~/slack.log/home/stanley/slack.log になります。

r_slack.yml

---
name: "r_slack"
pack: "test"
description: "test rule for slack"
enabled: true

trigger:
  type: "slack.message"
  parameters: {}
action:
  ref: "core.local"
  parameters:
    cmd: "echo \"{{trigger.user.name}}: {{trigger.text}}\" >>  ; sync"

続いて、ルールを登録します。

[ec2-user@ip-172-31-4-147 ~]$ st2 rule create r_slack.yml 
+-------------+--------------------------------------------------------------+
| Property    | Value                                                        |
+-------------+--------------------------------------------------------------+
| id          | 5b128cfd6fb12304f47d825c                                     |
| name        | r_slack                                                      |
| pack        | test                                                         |
| description | test rule for slack                                          |
| action      | {                                                            |
|             |     "ref": "core.local",                                     |
|             |     "parameters": {                                          |
|             |         "cmd": "echo "{{trigger.user.name}}:                 |
|             | {{trigger.text}}" >> ~/slack.log ; sync"                     |
|             |     }                                                        |
|             | }                                                            |
| criteria    |                                                              |
| enabled     | True                                                         |
| ref         | test.r_slack                                                 |
| tags        |                                                              |
| trigger     | {                                                            |
|             |     "type": "slack.message",                                 |
|             |     "ref": "slack.message",                                  |
|             |     "parameters": {}                                         |
|             | }                                                            |
| type        | {                                                            |
|             |     "ref": "standard",                                       |
|             |     "parameters": {}                                         |
|             | }                                                            |
| uid         | rule:test:r_slack                                            |
+-------------+--------------------------------------------------------------+

念の為、ルールのリストを確認します。

[ec2-user@ip-172-31-4-147 ~]$ st2 rule list -p test
+--------------+------+---------------------+---------+
| ref          | pack | description         | enabled |
+--------------+------+---------------------+---------+
| test.r_slack | test | test rule for slack | True    |
+--------------+------+---------------------+---------+

無事に登録されたようです。


■ おためし

それではいよいよ試してみます。

Slack の general チャンネルに Hello, Slack! と投稿すると、/home/stanley/slack.log

yokochi: Hello, Slack!

と書き込まれました。

デモ動画 f:id:akira6592:20180603133910g:plain

試した限り、今回利用したトークンでは、いずれかのユーザーが general に投稿したイベントを取得することができるようです。他のチャンネルではイベントを取得することができませんでした。


■ まとめ

簡単な例ですが、Slack Pack の Trigger を利用して、Slack に投稿があったら何かする、というルールの動作の確認ができました。 chatops Pack でも色々できそうなので調べてみたいと思います。

はじめて 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