「初めてのAnsible」を読み進めながらのメモ
前掲
初めてのAnsible(1章:イントロダクション)
初めてのAnsible(2章:Playbook:始めてみよう)
初めてのAnsible(3章:インベントリ:サーバーの記述)
初めてのAnsible(4章:変数とファクト)
初めてのAnsible(7章:複雑なPlaybook)
初めてのAnsible(8章:ロール:プレイブックのスケールアップ)
初めてのAnsible(9章:Ansibleの高速化)
必要なら自分でモジュールかいてプルリクエストなげてみたらって章
- Ansibleモジュール群のGitHub
カスタムモジュール
Ansibleのモジュールを記述する手段として2通りを挙げている
- Pythonで記述する場合
- Python以外(bashやRubyなど)で記述する場合
AnsibleがPythonでモジュールを記述するためのヘルパークラスを提供していることから、Pythonで記述することを推奨
ここでも詳細はPythonモジュールに関してのみまとめる
カスタムモジュールの置き場所
playbookが playbooks/playbook
に置かれていれば
カスタムモジュールは playbooks/library/custom_module
に置く
モジュール呼び出し時の挙動
Ansibleがモジュールを呼び出す際には以下のような挙動をとる
-
(Pythonモジュールの場合} スタンドアロンのPythonスクリプトを引数付きで生成
- ヘルパークラスのコードや引数などを埋め込み1つにまとめたPythonスクリプトを生成
-
モジュールをホストにコピー
- (Pythonモジュールの場合) 生成したスクリプトをコピー
- (Pythonモジュールでない場合)
playbooks/library/custom_module
をコピー
-
(Pythonモジュールでない場合) 引数ファイルをホスト上で生成
- モジュールに渡された引数をそのまま書き込んだ引数ファイルを生成
- カスタムモジュール内に
# WANT_JSON
を記述することで引数ファイルをJSONとすることも可能
-
引数ファイルを引数として渡しホスト上でモジュールを呼び出し
Pythonモジュール
Ansibleが提供する AnsibleModule を使うことで以下が容易になる
- 入力のパース
- JSONフォーマットでの出力
- 外部プログラムの呼び出し
以下のサンプルコードを見ながらまとめる(ansiblebook/ch10/playbooks/library/can_reachより)
#!/usr/bin/python
def can_reach(module, host, port, timeout):
nc_path = module.get_bin_path('nc', required=True)
args = [nc_path, "-z", "-w", str(timeout), host, str(port)]
(rc, stdout, stderr) = module.run_command(args)
return rc == 0
def main():
module = AnsibleModule(
argument_spec=dict(
host=dict(required=True),
port=dict(required=True, type='int'),
timeout=dict(required=False, type='int', default=3)
),
supports_check_mode=True
)
# In check mode, we take no action
# Since this module never changes system state, we just
# return changed=False
if module.check_mode:
module.exit_json(changed=False)
host = module.params['host']
port = module.params['port']
timeout = module.params['timeout']
if can_reach(module, host, port, timeout):
module.exit_json(changed=False)
else:
msg = "Could not reach %s:%s" % (host, port)
module.fail_json(msg=msg)
from ansible.module_utils.basic import *
main()
can_reach
def can_reach(module, host, port, timeout):
nc_path = module.get_bin_path('nc', required=True)
args = [nc_path, "-z", "-w", str(timeout), host, str(port)]
(rc, stdout, stderr) = module.run_command(args)
return rc == 0
get_bin_path
- 外部プログラムのパスを取得
- ここでは nc(netcat) コマンドのパスを取得
-
required=True
が指定されている場合、実行ファイルが見つからないとfail_json
メソッド(後述)をなげる
run_command
- 外部プログラムを呼び出し
- いくつかの引数をとるけどもここでは
args
についてのみまとめる- 細かいことはリンク先のコード追えばいいかな
run_command
の引数 : args
- 型 : 文字列 or リスト
- 上記の例では、引数をリストで渡している
- 実行するコマンドとそのオプション等
- 返り値は rc, stdout, stderr
AnsibleModule
module = AnsibleModule(
argument_spec=dict(
host=dict(required=True),
port=dict(required=True, type='int'),
timeout=dict(required=False, type='int', default=3)
),
supports_check_mode=True
)
argument_spec
- AnsibleModuleのとる引数のうち、唯一必須
- モジュールで使用できる引数に関する辞書
上記の例では host, port, timeout を引数としている
引数のオプション
上記の例でも引数(host, port, timeout)にオプションが指定されている
-
required
- Trueであれば引数は必須
-
type
- 引数の型を指定(デフォルトでは文字列)
- str, list, dict, bool, int, float が指定可能
-
default
- デフォルト値
-
required=False
とする場合には指定しておいた方がよい
チェックモード
- AnsibleModuleの引数の一つ
- Trueの場合にはチェックモードをサポートする
-
ansible-playbook
に -C or --check フラグを渡すことで有効化 - チェックモードでは各タスクがホストの状態を変化させるか、変化させずに成功するか、エラーを返すかといったことのみを知らせる
exit_json
/ fail_json
if module.check_mode:
module.exit_json(changed=False)
host = module.params['host']
port = module.params['port']
timeout = module.params['timeout']
if can_reach(module, host, port, timeout):
module.exit_json(changed=False)
else:
msg = "Could not reach %s:%s" % (host, port)
module.fail_json(msg=msg)
exit_json
- 成功したことを示す
- 引数 changed は必須 : ホストの状態を変化させたかどうか
- 引数 msg を利用し、メッセージを返すことも可能
fail_json
- 失敗したことを示す
- 引数 msg で失敗の理由を返すべき
モジュールの引数へのアクセス
-
argument_spec
で定義した各引数へ params によりアクセス可能
AnsibleModuleヘルパークラスのインポート
from ansible.module_utils.basic import *
- カスタムモジュールでは末尾にimport文を書いた方がよい
- 前述した通りPythonモジュールの場合、 ヘルパークラスのコードや引数などを埋め込み1つにまとめたPythonスクリプトを生成 するため、モジュール内の行番号は元のファイルと生成されたものとで異なる
- 先頭にimport文をもってきてしまうと、xx行でエラーが起きてるよーみたいな時にわかりづらくなる