このエントリーをはてなブックマークに追加

Ansibleを支えるfact: プラットフォームの情報を取得

なんかそこはかとなくAnsibleが流行ってきているのがかなり意外な感じのr_rudiです。

さて、Chefを支えるohai。プラットフォームの情報を取得するためのライブラリに触発されて、Ansibleの機能であるfactについてご紹介したいと思います。

factって?

AnsibleにもChefと同じようにターゲットホストの情報を取得する機能があります。これを使って「Ubuntuならこれ」とか「FreeBSDならこれ」というように処理を分けたり、などができます。

具体的な使い方の例としてはこんな感じです。ここではwhenを使って、Ubuntuの場合だけ実行しています。

- name: Ubuntuの場合だけ実行する
  apt: pkg=apache2 state=present
  when: ansible_distribution == "Ubuntu"

あるいは、変数に使ったりと、いろいろなところで使えます。例えば下のtaskはawesome-i686.tar.gz を取得します。

- name: アーキテクチャを指定して取得
  get_url: url=http://example.com/awesome-{{ ansible_machine }}.tar.gz dest=/tmp/hoge.tar.gz

ちなみに、factの実行はそれなりに時間がかかるので、必要ない場合は以下のようにgather_facts: noとすると早くなります。

- hosts: localhost
  gather_facts: no

どんな情報が取れるの?

factで取得できる情報を調べるにはsetupモジュールを使います。JSON形式でずらずらと出てくることが分かります。(モジュール単体実行なのでansible-playbookではありません)

% ansible <ホストパターン> -m setup
local | success >> {
 "ansible_facts": {
     "ansible_all_ipv4_addresses": [
         "127.0.0.1"
     ],
     "ansible_all_ipv6_addresses": [],
     "ansible_architecture": "amd64",

さて、本題。

ohaiを使って情報を取得する

Ansibleのfactだけでも多くの情報が取れますが、Ohaiを使ってさらに情報を追加できます。

やり方は単にohaiを入れるだけです。ansibleは使えるのであればohaiも使って情報を追加します。

% gem install ohai

ohaiが使える状態で setup モジュールを実行すると、以下のような情報が追加されていることが分かります。ohaiで取得した情報はohai_というprefixがついています。

"ohai_hostname": "ubuntu",
"ohai_idletime": "3 days 00 hours 20 minutes 36 seconds",
"ohai_ip6address": "fe80::a00:9999:998d:395e",
"ohai_ipaddress": "127.0.0.1",
"ohai_macaddress": "08:99:99:8D:39:5E",
"ohai_os": "linux",
"ohai_os_version": "3.5.0-25-generic",

残念ながらAnsibleから利用できる情報はTop Levelの限られた情報だけです。

ohai モジュールを使うとohaiで取得した情報がすべて取れますので、registerを使ってみようとしたのですが、だめでした。(あとでコード読みます)

% ansible all -c local -m ohai

facterを使って情報を取得する

もうひとつ、Facterという同じような情報取得ライブラリがあります。ちなみにpuppetlabsが作っています。

これも同じようにsetupモジュールから使えますし、facter モジュールを別に使えます。

% gem install facter  # facterインストール
% ansible all -c local -m facter

facterで取得した情報はfacter_というprefixがついています。

自分でfactを設定する

これまでは既存のライブラリを使った情報取得でした。これらに加えてAnsibleでは自分でfactを設定できます。

ただし、1.3からですので、1.2.3ユーザーは現状ではgithubからインストールする必要があります。

自分でfactを設定するには、fact_pathにファイルを設置します。fact_pathは初期設定は/etc/ansible/facts.dとなっています。fact_pathはターゲットホストということに気をつけてください。ですから、事前にtemplateモジュールなどを使って置く必要があります。

fact_pathはsetupモジュールの引数として設定できます。先頭で実行すれば以降のtaskで使えます。

---
- hosts: local
  tasks:
  - setup: fact_path=/tmp/fact.d/
  - debug: msg={{ ansible_local.hige.number }}

静的なファイル

fact_path以下に ".fact" という拡張子がついたファイルを読み込みます。

iniファイル形式か、

% cat ./hoge.fact
[location]
city=Tokyo
phone=0399999999

JSON形式です。JSON形式では配列も使えます。

% cat ./hige.fact
{
   "name" : "Me",
   "number" : 42,
   "phones" : [ "0399999999", "0311111111" ]
}

"ansible_local.factのファイル名" 以下にこの内容が追加されます。

% %ansible all -c local -m setup
  localhost | success >> {
  (..)
      "ansible_local": {
          "hoge": {
              "location": {
                  "city": "Tokyo",
                  "phone": "0399999999"
              }
          }
      },
  (..)
  }

playbookからはこんな感じで使います。

---
- hosts: local
  tasks:
  - name: せっかくだからおれはこのfactファイルを読み込むぜ!
    debug: msg={{ ansible_local.hoge.location.city }}

動的に生成

同じ場所に実行属性があるファイルがあると実行してJSONを受け取ってくれます。

#!/bin/sh

COUNT=`who | wc -l`
cat <<EOF
{
   "ansible_facts" : {
      "users_logged_in" : $COUNT
   }
}
EOF

まとめ

Ansibleを支える技術であるfactを紹介しました。これによって、templateで埋め込んだり、場合分けを行ったりできます。また、1.3からは、自作のfactを使えるので、例えばターゲットホストの負荷状況によって動作を変える、ということも可能です。

現在ではohaiの情報全てが使えるわけではないのが悲しいですが、Pull Requestを送っているので、問題なければマージされるかと思います。

2013-10-15 追記
ついにマージされました。