(2017-01-03 : 変数の値にシークエンスやディクショナリを書けることに気付いたので修正)


Ansibleの2017年を眺めておこうを読んだけど、Ansibleのインベントリファイルは実は2.1以降YAMLで書けるという事実はきっとまだほとんど知られていないに違いない。

そりゃまあ、ドキュメントに書いてないしな。


というわけでソースがドキュメントだ。

まず、lib/ansible/inventory/dir.pyを見るとYAMLで書いたインベントリファイルの拡張子はlib/ansible/constants.pyのYAML_FILENAME_EXTENSIONSに定義されているもののうちのどれかである必要がある。
つまり、拡張子なし、yml、yaml、jsonのうちのどれかである必要がある。

lib/ansible/inventory/yaml.pyを見ると、以下のようなフォーマットで記述する必要がある。

(グループ1):
  hosts:
    (ホストa):
      (ホストaに適用する変数A): (Aの値)
      (ホストaに適用する変数B):
      - (Bの値1)
      - (Bの値2)
    (ホストb):
      (ホストbに適用する変数A): (Aの値)
      (ホストbに適用する変数B):
      - (Bの値1)
      - (Bの値2)
  vars:
    (グループ1のすべてのホストに適用する変数C): (Cの値)
    (グループ1のすべてのホストに適用する変数D):
    - (Dの値1)
    - (Dの値2)
  children:
    (子とするグループ2):
    (子とするグループ3):
(グループ2):
  hosts:
    (以下、省略)
  • ini(に似た何か)形式で書くインベントリファイルと違い、グループ名を省略してホスト名だけを書くことはできないようだ。
  • 各グループの子要素にできるのはhostsかvarsかchildrenだけ。各ホストはグループの子要素にできずhostsの子要素にする必要がある。
  • childrenに書くべきものはただのグループ名のリストであるが、シークエンスではなく値を空にしたディクショナリで記述する必要がある。
  • varsや各ホストの変数の値としてスカラーだけでなくシークエンスやディクショナリを記述できる。この点、ini(に似た何か)形式より優秀。
  • 試した限りでは、ホストに[1:9]のような繰り返しや(ホスト名):(ポート番号)のような記述も特に問題はなく想定通りに動作する。

2017-01-17追記:ini(に似た何か)形式だと暗黙的にすべてのグループがallグループのchildとなっていたが、YAML形式だとそうならない。バグだと思われるので報告した。
2017-03-29追記:本件、2.2.2で修正されたことを確認した。
https://github.com/ansible/ansible/issues/20252

2017-04-17追記:2.3.0にてallグループにホストが追加されず常に空となるバグがある。すでに修正済みなので2.3.1では直っているだろう。この修正が2.3ブランチにマージされたのは2.3.0リリースの翌日くらいだった模様。
2017-06-03追記:本件、2.3.1で修正されたことを確認した。
https://github.com/ansible/ansible/pull/23366

例として、前回の記事で使ったインベントリファイルをYAMLで書き直すと以下のようになる。

windows.hosts.yml
local_windows:
  hosts:
    local_windows:
  vars:
    ansible_host: localhost
    ansible_user: (ユーザ名)
    ansible_password: (パスワード)
    ansible_port: 5986
    ansible_connection: winrm
    ansible_winrm_server_cert_validation: ignore

また、JSONはYAMLの一種なので、JSONで書いても構わない。

windows.hosts.json
{
  "local_windows" : {
    "hosts" : {
      "local_windows" : ""
    },
    "vars" : {
      "ansible_host" : "localhost",
      "ansible_user" : "(ユーザ名)",
      "ansible_password" : "(パスワード)",
      "ansible_port" : "5986",
      "ansible_connection" : "winrm",
      "ansible_winrm_server_cert_validation" : "ignore"
    }
  }
}
TOP