Ansible で扱う変数

レッドハットの杉村です。Ansible のテクニカルサポートをしています。毎月1つは何か書くことを目標にしているのですが、3月があっという間に去ってしまいました。

今回はたまにお問い合わせいただく変数について紹介してみようと思います。Ansible のバージョンは Ansible Core 2.12.1 で試しています。

まずはこのような playbook を題材にしてみます。

---
- hosts: all

  tasks:
    - name: debug
      debug:
        msg: "Hello Ansible!"

実行するとこうなります。

$ ansible-playbook playbook.yml -i localhost, -e ansible_connection=local

PLAY [all] ************************************************************************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************************************************************
ok: [localhost]

TASK [debug] **********************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "Hello Ansible!"
}

PLAY RECAP ************************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

モジュールに渡す変数

この Hello Ansible! の文字列を変数にすることができます。

---
- hosts: all

  tasks:
    - name: debug
      debug:
        msg: "{{ message }}"
      vars:
        message: "Hello Ansible!"

debug モジュールについては、msg パラメータの代わりに変数を var パラメータで渡すこともできます。

---
- hosts: all

  tasks:
    - name: debug
      debug:
        var: message
        #msg: "{{ message }}"
      vars:
        message: "Hello Ansible!"

タスクに定義する形ではあまりありがたくないかもしれません。プレイに定義することが多いでしょう。

---
- hosts: all

  vars:
    message: "Hello Ansible!"

  tasks:
    - name: debug
      debug:
        var: message

ファイルに外出しすることもできます。variables.yml に書いたとします。

---
message: "Hello Ansible!"

このとき playbook.yml ではファイル名を指定します。

---
- hosts: all

  vars_files:
    - variables.yml

  tasks:
    - name: debug
      debug:
        var: message

変数の型

上の例では変数は文字列でしたが、他にもこのようなものがあります。

  • 真偽値 (true/false)
  • 文字列
  • 数値
  • ディクショナリ
  • リスト

厳密なところは YAML の文法定義などを見ていただいて、ここではざっくりと紹介します。

真偽値

true を yes と書いたり、false を no と書いたりすることもできます。わたしは true / false が好みですが、Ansible のドキュメントでは yes / no で書いてあることもよくあります。True のように大文字で始める流儀も結構目にします。

文字列

‘文字列’ や “文字列” のように書きます。”” の中で {{ }} を使って変数参照して連結するのがよくあります。

---
- hosts: all

  vars_files:
    - variables.yml

  tasks:
    - name: debug
      debug:
        msg: "Good morning! {{ message }}"

数値

file モジュールでよくひっかかるやつです。

    - name: touch
      file:
        path: /tmp/temporaryfile.tmp
        state: touch
        mode: 644

例えばこのように書いて実行しますと、このようによくわからない権限がつけられてしまいます。644 が数値として解釈されたために、8進法では 1204 となってそのように設定されます。

$ ls -l /tmp/temporaryfile.tmp 
--w----r-T. 1 sugimura sugimura 0  4月  7 14:28 /tmp/temporaryfile.tmp

正しくはこのように文字列型として指定するか、8進法の数値であることを明示するために 0 で始めます。

    - name: touch
      file:
        path: /tmp/temporaryfile.tmp
        state: touch
        mode: 0644
        # mode: "0644" ... こちらをおすすめします

ディクショナリ

key: value の組を並べたものです。

---
a_dict_variable:
  foo: true
  bar: "hello"
  baz: 123456

このような形で定義します。変数名の後に、同じレベルのインデントで key: value の形で並べていきます。

---
- hosts: all

  vars_files:
    - dict.yml

  tasks:
    - name: debug
      debug:
        var: a_dict_variable

出力してみるとこのように出てきます。{ } でくくられています。

TASK [debug] **********************************************************************************************************************************************************************
ok: [localhost] => {
    "a_dict_variable": {
        "bar": "hello",
        "baz": 123456,
        "foo": true
    }
}

中身を取り出すこともできます。

    - name: debug
      debug:
        msg: "The numeric var is {{ a_dict_variable['baz'] }}"

このように . で接続する形でも取れますが、変数名によっては取れないことがありますので注意してください。

    - name: debug
      debug:
        msg: "The numeric var is {{ a_dict_variable.baz }}"

docs.ansible.com

リスト

他の言語では配列と呼ぶこともあります。同じ要素を並べているものです。

変数名の後ろで - を使って並べていきます。インデントはしなくてもいいようですが、したほうが好みです。

---
list_example:
  - "item1"
  - "item2"
  - "item3"

出力してみると [ ] でくくられていることがわかります。

TASK [debug] **********************************************************************************************************************************************************************
ok: [localhost] => {
    "list_example": [
        "item1",
        "item2",
        "item3"
    ]
}

配列は [n] で参照することができます。0 始まりです。

    - name: debug
      debug:
        var: list_example[1]

[1] は2番目なので、”item2” が取れています。

TASK [debug] **********************************************************************************************************************************************************************
ok: [localhost] => {
    "list_example[1]": "item2"
}

ディクショナリとリストの組み合わせ

ディクショナリとリストを組み合わせることができます。

例えば setup モジュールではマネージドノード(管理対象)からさまざまな情報を収集して変数に格納することができますが、この変数はディクショナリとリストの組み合わせで成り立っていることがわかります。

$ ansible -m setup -i localhost, -e ansible_connection=local localhost
localhost | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.0.xxx",
            "10.88.0.1"
        ],
        "ansible_all_ipv6_addresses": [
            "2404:xxxx:xxxx:xxxx:250:56ff:xxxx:f278",
            "fe80::250:56ff:xxxx:f278",
            "fe80::54ff:d9ff:xxxx:1fe8"
        ],
        "ansible_apparmor": {
            "status": "disabled"
        },
        "ansible_architecture": "x86_64",
        "ansible_bios_date": "12/24/2020",
        "ansible_bios_vendor": "VMware, Inc.",
        "ansible_bios_version": "VMW71.00V.17369862.B64.2012240522",
        "ansible_board_asset_tag": "NA",
        "ansible_board_name": "440BX Desktop Reference Platform",
        "ansible_board_serial": "NA",
        "ansible_board_vendor": "Intel Corporation",
        "ansible_board_version": "None",
        "ansible_chassis_asset_tag": "No Asset Tag",
        "ansible_chassis_serial": "NA",
        "ansible_chassis_vendor": "No Enclosure",
        "ansible_chassis_version": "N/A",
        "ansible_cmdline": {
            "BOOT_IMAGE": "(hd0,gpt2)/vmlinuz-4.18.0-348.el8.x86_64",
            "crashkernel": "auto",
            "quiet": true,
            "rd.lvm.lv": "rhel_rhel85/swap",
            "resume": "/dev/mapper/rhel_rhel85-swap",
            "rhgb": true,
            "ro": true,
            "root": "/dev/mapper/rhel_rhel85-root"
        },
...

"ansible_facts" は {} で始まっていることから全体としてはディクショナリになっていて、その要素の "ansible_all_ipv4_addresses" では IP アドレスがリストになっていたり、"ansible_cmdline" はさらにディクショナリになっていたりということがわかります。

ansible_facts は特別な処理を行っているので、この下の要素を直接指定して値を得ることができます。

---
- hosts: all
  gather_facts: true

  tasks:
    - name: debug
      debug:
        var: ansible_architecture

リストを loop で回しつつ、その中の値をディクショナリとして参照するというのはよくある使い方です。

---
- hosts: all
  gather_facts: true

  tasks:
    - name: debug
      debug:
        msg: "{{ item.mount }} : {{ item.size_total }}"
      loop: "{{ ansible_mounts }}"

変数の加工

これまで見てきたものでほとんどの用途はカバーできますが、加工して条件判定や他のタスクに渡したくなったり、うまくループするために参照方法を工夫したいということがあります。このあたりのドキュメントをよく読んでいます。他にも役に立つものがありますので探してみてください。

docs.ansible.com

docs.ansible.com

docs.ansible.com

docs.ansible.com

終わりに

今回は Ansible で扱う変数について紹介してみました。次回はこの変数を受け渡しすることについてまとめてみようと思います。

Ansible Automation Platform の試用版はこちらをご覧ください。

www.redhat.com

Happy Automation!

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。