Ansible 自作モジュール作成 ~その3:Change要否を判定したい人生~


前回の記事1:Ansible 自作モジュール作成 ~その1:引数受け取りたい人生~
前回の記事2:Ansible 自作モジュール作成 ~その2:ただコマンドを実行したい人生~

振り返り

  • モジュールの雛形作った(その1)
  • 複数の引数受け取れた(その1)
  • 引数をコマンドと結合して実行した(その2)

参考

初期処理

おさらいもかねて。まずは雛形を作成(参考「前回の記事1」参照)。
テスト的に作成したコマンド実行部分(参考「前回の記事2」参照)は一度取り除いた。

mkfifo.py
#!/usr/bin/python
# -*- coding: utf-8 -*-

from ansible.module_utils.basic import AnsibleModule

# メイン処理
#-----------------------------------------------------------
def main():
    # AnsibleModuleクラス: moduleを作成
    module = AnsibleModule(

        # 引数受け取り
        argument_spec=dict(

            # 引数: data(str型,def:pong)
            data=dict(type='str', default='pong'),
        ),
        # 引数チェックを有効
        supports_check_mode=True
    )

    # 結果dict: resultを作成
    result = dict(
        # key: ping に引数で与えられたkey: data のvalueを格納
        ping=module.params['data'],
    )

    # resultの中身を key=value,の形で出力
    module.exit_json(**result)

if __name__ == '__main__':
    main()

これに変数の受け取り部分を実装。

mkfifo.py
: #(省略)
    # AnsibleModuleクラス: moduleを作成
    module = AnsibleModule(

        # 引数受け取り
        argument_spec=dict(

            # 引数: path(必須,str型)
            path=dict(required=True,type='str'),
            # 引数: owner(str型,デフォルト=root)
            owner=dict(type='str',default='root'),
            # 引数: group(str型,デフォルト=root)
            group=dict(type='str',default='root'),
            # 引数: mode(str型,デフォルト=0644)
            mode=dict(type='str',default='0644'),
        ),
        # 引数チェックを有効
        supports_check_mode=True
    )
: #(省略)

現時点ではOS版数やディストリビューションによる分岐は設けない。changed変数を設けるだけ…だけど、changedってどこに定義するんだ?AnsibleModuleクラスの外側で良いのかな?ちょっとお試しする。

sakrua.py
#!/usr/bin/python
# -*- coding: utf-8 -*-

from ansible.module_utils.basic import AnsibleModule

# メイン処理
#-----------------------------------------------------------
def main():
    # AnsibleModuleクラス: moduleを作成
    module = AnsibleModule(
        {}
    )

    changed = False  この値をTrueに変えたりする

    module.exit_json(changed=changed)

if __name__ == '__main__':
    main()
# changed = Trueの場合
$ ansible -i test_grp 192.168.56.104 -m sakura -M library -u root
192.168.56.104 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true
}

# changed = Falseの場合
$ ansible -i test_grp 192.168.56.104 -m sakura -M library -u root
192.168.56.104 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false
}

よしよし。AnsibleModuleクラスの外側に定義するわけだ。

Changedを判定してみる

changedTrueになる条件は以下

  1. pathで与えられた名前付きパイプが存在しない
  2. pathで与えられた名前付きパイプのower:group:modeが引数どおりではない

条件1. に関してはtest -p xxxxxReturnCodeで判断できる。
条件2. に関してはstat -c %U:%G:%aの標準出力で判断できる。

ただしstat -c %aの結果は下3桁しか出ないのでstat -c 0%aで対処する。
またstdoutは改行コードまで出力されるため比較時に\nを差し込んだ。

mkfifo.py
: #(省略)
    # 変更有無を初期化(変更なし)
    changed = False

    # testコマンドでpathに名前付きパイプが存在するか確認
    rc, stdout, stderr = module.run_command("test -p " + module.params['path'])
    # 確認結果
    if ( rc != 0 ):
        # 存在しないので変更対象
        changed = True
    else:
        # 存在する場合はowner:group:modeを取得
        rc, stdout, stderr = module.run_command("stat -c %U:%G:0%a " + module.params['path'])
        # 比較。コマンド結果は最後に改行コード \n が付くことに注意
        if ( stdout != module.params['owner'] + ':' + module.params['group'] + ':' + module.params['mode'] + '\n'):
            # owner:group:modeが異なるので変更対象
            changed = True

    # 終了
    module.exit_json(changed=changed,stdout=stdout,stderr=stderr)
: #(省略)

いったんここまでで動かしてみようかな。

$ ansible -i test_grp 192.168.56.104 -m mkfifo -M library -u root -a "path=/tmp/testfifo owner=root group=root mode=0777"
192.168.56.104 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "stderr": "",
    "stderr_lines": [],
    "stdout": "",
    "stdout_lines": []
}

試しに対象サーバ上に/tmp/testfifoを作ってみる。

# /tmp/testfifo root:root:0644 で作ってみる
$ ssh [email protected] "mkfifo /tmp/testfifo; chmod 0644 /tmp/testfifo"
$ ssh [email protected] "ls -l /tmp/testfifo"
prw-r--r--. 1 root root 0  6月  1 01:30 2020 /tmp/testfifo
$ ansible -i test_grp 192.168.56.104 -m mkfifo -M library -u root -a "path=/tmp/testfifo owner=root group=root mode=0777"
192.168.56.104 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "stderr": "",
    "stderr_lines": [],
    "stdout": "root:root:0644\n",
    "stdout_lines": [
        "root:root:0644"
    ]
}

# /tmp/testfifo root:root:0777 にしてみる
$ ssh [email protected] "chmod 0777 /tmp/testfifo"
$ ssh [email protected] "ls -l /tmp/testfifo"
prwxrwxrwx. 1 root root 0  6月  1 01:30 2020 /tmp/testfifo
$ ansible -i test_grp 192.168.56.104 -m mkfifo -M library -u root -a "path=/tmp/testfifo owner=root group=root mode=0777"
192.168.56.104 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "stderr": "",
    "stderr_lines": [],
    "stdout": "root:root:0777\n",
    "stdout_lines": [
        "root:root:0777"
    ]
}

おけ。本項はここまで。次はコマンド投入編。。は内容うすくなりそうだな。