ansibleで動作するモジュールを自作する方法を調べてみました。参考にしたのは、docs.ansible.com の Developing Modules です。掲載されているpythonのサンプルコードを実際に動かして、モジュールの挙動を確認してみました。実行環境は CentOS 7 + ansible 1.9.1 です。
モジュール配置先パスの設定
モジュールの配置先のパスを /etc/ansible/ansible.cfg に記述します。
"library = 配置先ディレクトリ" の行を追加します。
[記述例]
[defaults]
inventory = /etc/ansible/hosts
library = /root/ansible/modules/ # 追加
サンプルコードの作成
Developing Modules に掲載されているサンプルコード(time.py)を ansible.cfg で記載したモジュール配置先に作成します。
$ vi /root/ansible/modules/time.py
サンプルコードの内容は以下の通りです。datetimeモジュールを呼び出して、現在時刻の設定や取得を行うことができます。必要なクラスのインポート、モジュールに渡されるパラメタの解析方法、処理結果の出力方法など、基本的な手続きがコメント付きで記述されています。
#!/usr/bin/python
# import some python modules that we'll use. These are all
# available in Python's core
import datetime
import sys
import son
import os
import shlex
# read the argument string from the arguments file
args_file = sys.argv[1]
args_data = file(args_file).read()
# for this module, we're going to do key=value style arguments
# this is up to each module to decide what it wants, but all
# core modules besides 'command' and 'shell' take key=value
# so this is highly recommended
arguments = shlex.split(args_data)
for arg in arguments:
# ignore any arguments without an equals in it
if "=" in arg:
(key, value) = arg.split("=")
# if setting the time, the key 'time'
# will contain the value we want to set the time to
if key == "time":
# now we'll affect the change. Many modules
# will strive to be 'idempotent', meaning they
# will only make changes when the desired state
# expressed to the module does not match
# the current state. Look at 'service'
# or 'yum' in the main git tree for an example
# of how that might look.
rc = os.system("date -s \"%s\"" % value)
# always handle all possible errors
#
# when returning a failure, include 'failed'
# in the return data, and explain the failure
# in 'msg'. Both of these conventions are
# required however additional keys and values
# can be added.
if rc != 0:
print json.dumps({
"failed" : True,
"msg" : "failed setting the time"
})
sys.exit(1)
# when things do not fail, we do not
# have any restrictions on what kinds of
# data are returned, but it's always a
# good idea to include whether or not
# a change was made, as that will allow
# notifiers to be used in playbooks.
date = str(datetime.datetime.now())
print json.dumps({
"time" : date,
"changed" : True
})
sys.exit(0)
# if no parameters are sent, the module may or
# may not error out, this one will just
# return the time
date = str(datetime.datetime.now())
print json.dumps({
"time" : date
})
ansibleコマンドによるサンプルモジュールの実行
モジュールは処理対象のサーバに転送されてから実行され、その結果がjson形式で返されます。
・現在時刻の取得
パラメタを指定せずにモジュールを実行すると、現在時刻が json形式で出力されます。
[実行例]
$ ansible localhost -m time -k
SSH password:
localhost | success >> {
"time": "2015-05-23 21:50:50.921787"
}
・現在の設定
パラメタとして、-a オプションで時刻を指定して実行すると、モジュール内で "date -s" コマンドを実行してから、datetimeモジュールで変更後の時刻を取得し、その結果が json形式で出力されます。
[実行例]
$ ansible localhost -m time -k -a "time=21:50:50"
SSH password:
localhost | success >> {
"changed": true,
"time": "2015-05-23 21:50:50.006286"
}
この場合、実行結果に "changed": true と表示されますが、これは時刻変更が行われたことを示すためのものです。
・エラー発生時の動作
パラメタとして、-a オプションで不正な値(時刻ではない文字列)して実行すると、モジュール内での "date -s" コマンドの実行が失敗し、実行結果として以下のようなエラー情報が出力されます。
[実行例]
# ansible localhost -m time -k -a "time=hoge"
SSH password:
localhost | FAILED >> {
"failed": true,
"msg": "failed setting the time"
}
この場合、実行結果に "failed": true と表示されますが、これは処理が失敗したことを示すためのものです。また、"msg": には処理が失敗した理由を出力します。
playbook によるサンプルモジュールの実行
サンプルモジュールをplaybookから実行する場合は、playbookを以下のように記述します。
[記述例]
---
- hosts: "{{ target }}"
tasks:
- name: set time
time: time="{{ time }}"
tasks: セクションに実行するモジュール名 "time" と モジュールに渡すパラメータ "time="{{ time }}" を記述します。
playbookを実行する際には、-e オプションでモジュールを実行するノード(target)と設定する時刻(time)を指定します。
[実行例]
$ ansible-playbook time.yml -k -e "target=localhost time=23:27:00"
SSH password:
PLAY [localhost] **************************************************************
GATHERING FACTS ***************************************************************
ok: [localhost]
TASK: [set time] **************************************************************
changed: [localhost]
PLAY RECAP ********************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0
playbookの実行結果でモジュールの実行結果のサマリが出力されます。
おまけ
サンプルモジュールのテストが済んだら、NTPで時刻を正しい値に戻しておく事を強くお勧めします
$ ntpdate time.asia.apple.com