ansibleのログをfluentdに流す
Chef のログを Fluentd に流すという記事を読みました。Ansibleにもそのための機能があるにも関わらず、あまり情報がないのでまとめてみました。
callback plugin
Ansibleにはmoduleとは別にpluginという機構があります。例えば ` "{{lookup('file', '/etc/foo.txt') }}"` というように使うlookup pluginがあります。他にもconnectionやvarsのpluginがありますが、そのうちの一つに、callback pluginがあります。
callback pluginはその名の通り、いろいろなイベントが発生した時に自動的に呼び出されるcallbackを登録するためのpluginです。イベントの例としては、
- playbookの開始時
- taskの開始時
- task成功時
- task失敗時
- playbook終了時
などがあります。
例: fluentdへと送るplugin
moduleは各種言語で実装できるansibleなのですが、pluginは残念ながら現状pythonでしか実装できません。
ということで、実装してみた結果が以下のとおりです。callbackを登録すればいいということが分かると思います。
登録できるハンドラが多すぎてここには一部だけしか載せていません。gistにあげておきましたので、ご覧ください。関数名から雰囲気が分かると思います。
import json
import urllib
import urllib2
url = 'http://localhost:8888/ansible'
def post(category, data):
data['category'] = category
invocation = data.pop('invocation', None)
if invocation:
data['module_name'] = invocation['module_name']
data['module_args'] = invocation['module_args']
values = {'json': json.dumps(data)}
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
urllib2.urlopen(req)
class CallbackModule(object):
def on_any(self, *args, **kwargs):
pass
def runner_on_failed(self, host, res, ignore_errors=False):
res["host"] = host
post(host, 'FAILED', res)
def runner_on_ok(self, host, res):
res["host"] = host
post('OK', res)
def runner_on_error(self, host, msg):
post('ERROR', {"host": host, 'error': msg})
def runner_on_skipped(self, host, item=""):
post('SKIPPED', {"host": host, "item": item})
これをin_http経由でfluentdに流し、out_fileで書きだした結果が以下の通りです。
2014-02-16T00:18:04+09:00 ansible {"category":"Play_on_start"}
2014-02-16T00:18:05+09:00 ansible {"category":"Play_start"}
2014-02-16T00:18:10+09:00 ansible {"category":"OK","changed":true,"end":"2014-02-1515:18:10.810734","stdout":"Sat Feb 15 15:18:10 UTC 2014","cmd":["date"],"rc":0,"start":"2014-02-1515:18:10.808307","host":"docker","stderr":"","delta":"0:00:00.002427","module_name":"command","module_args":"date"}
2014-02-16T00:18:11+09:00 ansible {"verbose_always":true,"category":"OK","host":"docker","msg":"Sat Feb 15 15:18:10 UTC 2014","module_name":"debug","module_args":"msg=\"Sat Feb 15 15:18:10 UTC 2014\""}
ちょっと分かりにくいですが、3行目のtaskの結果("OK")に、start, end、そしてdeltaという実行時間が入ってるのがいいですね。もちろんstdoutという標準出力もとれています。
ちなみに実行したtaskです。
tasks:
- name: get date
command: date
register: date
- name: debug
debug: msg="{{ date.stdout }}"
導入方法
inventoryファイルと同じ階層にcallback_pluginsというディレクトリを作成し、その中にpluginファイルを置く。
デフォルトでは /usr/share/ansible/plugins 以下にある、callback_pluginに置く
ansible.cfgで指定する
callback_plugins = /usr/share/ansible_plugins/callback_plugins
という3つの方法があります。いずれも単にpythonファイルを置くだけで使えるようになります。逆に言うと、不用意に置くと勝手に実行されてしまう点には気をつけてください。
まとめ
ansibleの実行結果を得るcallback pluginを紹介し、一例としてfluentdへと送るpluginを実装しました。
fluentdに限らず、例えばfailした時にnagiosに飛ばすしたりhipchatに飛ばしたり、いろいろな役に立つと思います。