Help us understand the problem. What is going on with this article?

[Ansible] Registered variable について調べてみた

More than 3 years have passed since last update.

ansibleでは、コマンド実行結果をRegistered variableに突っ込んで便利に使えます :smiley:

Registered Variablesとは?

ターゲットホストで実行したコマンドの結果を任意の変数に入れることができます。

使い方を見ていきます。ansibleのバージョンは 1.9.4 です。

サンプルとして、簡単なplaybookを作成しました。

---
- hosts: 127.0.0.1
  connection: local
  tasks:
    - name: exec whoami
      shell: whoami
      register: result
    - name: debug result var
      debug: var=result

whoamiコマンドの実行結果をregisterキーワードで設定した result 変数に受け、次のdebugタスクでハンドリングします。

変数の中身はどうなっている?

では、resultの中身はどうなっているのでしょうか? playbookの実行結果から見ていきます。

[ec2-user@ip-10-0-0-83 ~]$ ansible-playbook playbook.yml

PLAY [127.0.0.1] **************************************************************

GATHERING FACTS ***************************************************************
ok: [127.0.0.1]

TASK: [exec whoami] ***********************************************************
changed: [127.0.0.1]

TASK: [debug result var] ******************************************************
ok: [127.0.0.1] => {
    "var": {
        "result": {
            "changed": true,
            "cmd": "whoami",
            "delta": "0:00:00.002182",
            "end": "2016-01-08 04:26:38.950255",
            "invocation": {
                "module_args": "whoami",
                "module_complex_args": {},
                "module_name": "shell"
            },
            "rc": 0,
            "start": "2016-01-08 04:26:38.948073",
            "stderr": "",
            "stdout": "ec2-user",
            "stdout_lines": [
                "ec2-user"
            ],
            "warnings": []
        }
    }
}

PLAY RECAP ********************************************************************
127.0.0.1                  : ok=3    changed=1    unreachable=0    failed=0

おそらく、この中でよく使うのは、rc、 stdout、stderr、stdout_linesの4つだと思います。

stdoutが複数行の場合、\nを改行コードとしてstdoutに値がセットされます。
そして、その改行を1行づつバラしたのがstdout_linesです。
ディレクトリ一覧などを取って、ぐるぐる回す時など便利ですね。

複数回実行されるタスクの場合は?

サンプルとして、以下のようなplaybookを用意しました。
lsコマンドの結果を、statコマンドに渡しています。

---
- hosts: 127.0.0.1
  connection: local
  tasks:
    - name: ls dir
      shell: ls -U /tmp/dir
      register: file_list
    - name: stat file in dir
      shell: stat /tmp/dir/{{ item }}
      register: stat_list
      with_items: file_list.stdout_lines
    - debug: var=stat_list

結果は、こんな感じです。
変数stat_listの中に、resultsというキーで配列として実行結果がセットされています。

[ec2-user@ip-10-0-0-83 ~]$ ansible-playbook playbook.yml

PLAY [127.0.0.1] **************************************************************

GATHERING FACTS ***************************************************************
ok: [127.0.0.1]

TASK: [ls dir] ****************************************************************
changed: [127.0.0.1]

TASK: [shell stat /tmp/dir/{{ item }}] ****************************************
changed: [127.0.0.1] => (item=foo)
changed: [127.0.0.1] => (item=bar)

TASK: [debug var=stat_list] ***************************************************
ok: [127.0.0.1] => {
    "var": {
        "stat_list": {
            "changed": true,
            "msg": "All items completed",
            "results": [
                {
                    "changed": true,
                    "cmd": "stat /tmp/dir/foo",
                    "delta": "0:00:00.002497",
                    "end": "2016-01-08 05:15:36.943282",
                    "invocation": {
                        "module_args": "stat /tmp/dir/foo",
                        "module_complex_args": {},
                        "module_name": "shell"
                    },
                    "item": "foo",
                    "rc": 0,
                    "start": "2016-01-08 05:15:36.940785",
                    "stderr": "",
                    "stdout": "  File: ‘/tmp/dir/foo’\n  Size: 0         \tBlocks: 0          IO Block: 4096   regular empty file\nDevice: ca01h/51713d\tInode: 1794        Links: 1\nAccess: (0664/-rw-rw-r--)  Uid: (  500/ec2-user)   Gid: (  500/ec2-user)\nAccess: 2016-01-08 04:58:45.291452795 +0000\nModify: 2016-01-08 04:58:45.291452795 +0000\nChange: 2016-01-08 04:58:45.291452795 +0000\n Birth: -",
                    "stdout_lines": [
                        "  File: ‘/tmp/dir/foo’",
                        "  Size: 0         \tBlocks: 0          IO Block: 4096   regular empty file",
                        "Device: ca01h/51713d\tInode: 1794        Links: 1",
                        "Access: (0664/-rw-rw-r--)  Uid: (  500/ec2-user)   Gid: (  500/ec2-user)",
                        "Access: 2016-01-08 04:58:45.291452795 +0000",
                        "Modify: 2016-01-08 04:58:45.291452795 +0000",
                        "Change: 2016-01-08 04:58:45.291452795 +0000",
                        " Birth: -"
                    ],
                    "warnings": []
                },
                {
                    "changed": true,
                    "cmd": "stat /tmp/dir/bar",
                    "delta": "0:00:00.002559",
                    "end": "2016-01-08 05:15:36.999742",
                    "invocation": {
                        "module_args": "stat /tmp/dir/bar",
                        "module_complex_args": {},
                        "module_name": "shell"
                    },
                    "item": "bar",
                    "rc": 0,
                    "start": "2016-01-08 05:15:36.997183",
                    "stderr": "",
                    "stdout": "  File: ‘/tmp/dir/bar’\n  Size: 0         \tBlocks: 0          IO Block: 4096   regular empty file\nDevice: ca01h/51713d\tInode: 1795        Links: 1\nAccess: (0664/-rw-rw-r--)  Uid: (  500/ec2-user)   Gid: (  500/ec2-user)\nAccess: 2016-01-08 04:58:45.291452795 +0000\nModify: 2016-01-08 04:58:45.291452795 +0000\nChange: 2016-01-08 04:58:45.291452795 +0000\n Birth: -",
                    "stdout_lines": [
                        "  File: ‘/tmp/dir/bar’",
                        "  Size: 0         \tBlocks: 0          IO Block: 4096   regular empty file",
                        "Device: ca01h/51713d\tInode: 1795        Links: 1",
                        "Access: (0664/-rw-rw-r--)  Uid: (  500/ec2-user)   Gid: (  500/ec2-user)",
                        "Access: 2016-01-08 04:58:45.291452795 +0000",
                        "Modify: 2016-01-08 04:58:45.291452795 +0000",
                        "Change: 2016-01-08 04:58:45.291452795 +0000",
                        " Birth: -"
                    ],
                    "warnings": []
                }
            ]
        }
    }
}

タスクが失敗したときは?

タスクが失敗した時にRegistered variable はどうなるでしょうか?
こんな playbook を用意しました。fooというコマンドは存在しないので、エラーになります。

---
- hosts: 127.0.0.1
  connection: local
  tasks:
     - shell: /usr/bin/foo
       register: foo_result
       ignore_errors: True
     - debug: var=foo_result

実行結果です。rcに0以外が入り、stderrにエラーメッセージが入っていることが確認できます。

[ec2-user@ip-10-0-0-83 ~]$ ansible-playbook foo.yml

PLAY [127.0.0.1] **************************************************************

GATHERING FACTS ***************************************************************
ok: [127.0.0.1]

TASK: [shell /usr/bin/foo] ****************************************************
failed: [127.0.0.1] => {"changed": true, "cmd": "/usr/bin/foo", "delta": "0:00:00.001851", "end": "2016-01-08 05:42:46.712188", "rc": 127, "start": "2016-01-08 05:42:46.710337", "warnings": []}
stderr: /bin/sh: /usr/bin/foo: No such file or directory
...ignoring

TASK: [debug var=foo_result] **************************************************
ok: [127.0.0.1] => {
    "var": {
        "foo_result": {
            "changed": true,
            "cmd": "/usr/bin/foo",
            "delta": "0:00:00.001851",
            "end": "2016-01-08 05:42:46.712188",
            "invocation": {
                "module_args": "/usr/bin/foo",
                "module_complex_args": {},
                "module_name": "shell"
            },
            "rc": 127,
            "start": "2016-01-08 05:42:46.710337",
            "stderr": "/bin/sh: /usr/bin/foo: No such file or directory",
            "stdout": "",
            "stdout_lines": [],
            "warnings": []
        }
    }
}

PLAY RECAP ********************************************************************
127.0.0.1                  : ok=3    changed=1    unreachable=0    failed=0

ちなみに、公式サイトにNoteとして以下のような記述があります。

If a task fails or is skipped, the variable still is registered with a failure or skipped status, the only way to avoid registering a variable is using tags.

タスクが失敗したり、スキップしたりした場合も変数は設定されます。失敗(or スキップ)したからと言って変数が設定されないわけではないので、playbookの中で、whenキーワードで変数の宣言自体をハンドリングする(is defined)ようなtaskには注意が必要かもしれません。

まとめ

Registered variableを使うと、ターゲットホストの状態をハンドリングしながらplaybookが書けるので、とても便利です :laughing:

rcをハンドリングして細かい条件分岐をしたり、複数回実行される時のパターンのように直接with_itemsに突っ込んだり、用途はいろいろ考えられます。

実際によくやる手としては、ファイルやディレクトリをチェックしてその後の処理を分岐させたりすることなどが多いです。

そのうち、よくやるTips集などをまとめてみたいと思います。

参考

http://docs.ansible.com/ansible/playbooks_variables.html#registered-variables
http://docs.ansible.com/ansible/playbooks_conditionals.html#register-variables

szk3
My interests are AWS/GCP/VSCode/Node.js/TypeScript/golang/rust. My posts represent the views of the individual, not the official position of the organization.
lifull
日本最大級の不動産・住宅情報サイト「LIFULL HOME'S」を始め、人々の生活に寄り添う様々な情報サービス事業を展開しています。
https://lifull.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away