5
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

初めてのAnsible(10章:カスタムモジュール)

Last updated at Posted at 2016-12-01

「初めてのAnsible」を読み進めながらのメモ

前掲
初めてのAnsible(1章:イントロダクション)
初めてのAnsible(2章:Playbook:始めてみよう)
初めてのAnsible(3章:インベントリ:サーバーの記述)
初めてのAnsible(4章:変数とファクト)
初めてのAnsible(7章:複雑なPlaybook)
初めてのAnsible(8章:ロール:プレイブックのスケールアップ)
初めてのAnsible(9章:Ansibleの高速化)

必要なら自分でモジュールかいてプルリクエストなげてみたらって章

カスタムモジュール

Ansibleのモジュールを記述する手段として2通りを挙げている

  • Pythonで記述する場合
  • Python以外(bashやRubyなど)で記述する場合

AnsibleがPythonでモジュールを記述するためのヘルパークラスを提供していることから、Pythonで記述することを推奨

ここでも詳細はPythonモジュールに関してのみまとめる

カスタムモジュールの置き場所

playbookが playbooks/playbook に置かれていれば
カスタムモジュールは playbooks/library/custom_module に置く

モジュール呼び出し時の挙動

Ansibleがモジュールを呼び出す際には以下のような挙動をとる

  1. (Pythonモジュールの場合} スタンドアロンのPythonスクリプトを引数付きで生成

    • ヘルパークラスのコードや引数などを埋め込み1つにまとめたPythonスクリプトを生成
  2. モジュールをホストにコピー

    • (Pythonモジュールの場合) 生成したスクリプトをコピー
    • (Pythonモジュールでない場合) playbooks/library/custom_module をコピー
  3. (Pythonモジュールでない場合) 引数ファイルをホスト上で生成

    • モジュールに渡された引数をそのまま書き込んだ引数ファイルを生成
    • カスタムモジュール内に # WANT_JSON を記述することで引数ファイルをJSONとすることも可能
  4. 引数ファイルを引数として渡しホスト上でモジュールを呼び出し

Pythonモジュール

Ansibleが提供する AnsibleModule を使うことで以下が容易になる

  • 入力のパース
  • JSONフォーマットでの出力
  • 外部プログラムの呼び出し

以下のサンプルコードを見ながらまとめる(ansiblebook/ch10/playbooks/library/can_reachより)

python: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行でエラーが起きてるよーみたいな時にわかりづらくなる
5
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?