Ansible

Ansible Moduleの開発

Ansibleでは独自のモジュールを組み込み実行することができる。
pythonでプログラムが書ければ、以下のようにtaskの中で作成したモジュールを使用することができる。他にもfilterやlookup pluginsなど、module以外にも独自の拡張ができる。

- my_module:
    param_a: hello
    paramb_b: world

module作成は、公式のドキュメントやansibleのmodulesディレクトリ下のデフォルトで用意されているmoduleを見ると良いだろう。

参考

moduleの作成

まずはシンプルなmoduleを見てみる。
以下は、helloというモジュール名でechoで受け取ったメッセージを返すだけのモジュールである。

# Python2と3で同様の振る舞いをするようなおまじない
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

# https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_documenting.html#ansible-metadata-block

# Ansibleが使用するメタデータ
ANSIBLE_METADATA = {
    # moduleのバージョンではない!metadata schemaのバージョン
    'metadata_version': '1.1', 
    # 以下のステータスはAnsible Core Teamのメンバによって判断される
    'status': ['preview'],
    'supported_by': 'community'
}

# ドキュメント生成に使用される
# 以下でドキュメントを表示できる
#   $ ansible-doc -M /path/to/moduledir-t module hello
DOCUMENTATION = r'''
---
module: hello
short_description: my hello
requirements:
description:
  - echo message
options:
seealso:
author:
  - moritetu
'''

EXAMPLES = r'''
- hello:
    echo: hello world
'''

RETURN = r'''
message:
  description: echo message
  returned: always
  type: str
  sample: hello world
'''

# AnsibleModuleの読み込み
from ansible.module_utils.basic import AnsibleModule

def main():

    module = AnsibleModule(
        # moduleのパラメータ
        argument_spec=dict(
            echo=dict(type='str', required=True),
        ),
        supports_check_mode=True
    )

    if module.check_mode:
        module.exit_json(**result)

    result = dict(
        changed=False,
        message=module.params['echo'],
    )

    # moduleの出力
    module.exit_json(**result)

if __name__ == '__main__':
    main()

このmoduleは以下のような使用方法となる。

- hello:
    echo: hello world

AnsibleModule

moduleの引数

head1head2
body1body2

moduleのロード

Ansibleがデフォルトでmoduleを探索するパスに設置する、または、ansible.cfgでmoduleのパスを指定しすればよい。そうすればAnsibleがプレイブックを実行時にロードしてくれる。

ansible.cfgに指定

ansible.cfglibraryというパラメタに自作したmoduleのパスを指定する。
ディレクトリ構成は以下のとおり。

$ tree
.
├── ansible.cfg
├── mod
│   └── hello.py
└── test.yaml

1 directory, 3 files

ansible.cfg

以下では、modというディレクトリを相対パスでしている。

import json
from ansible.module_utils.basic import AnsibleModule


def main():
    module = AnsibleModule(
        argument_spec=dict(
            _path=dict(type='path', required=False),
            _raw=dict(type='raw', required=False),
            _jsonarg=dict(type='jsonarg', required=False),
            _json=dict(type='json', required=False),
            _bytes=dict(type='bytes', required=False),
            _bits=dict(type='bits', required=False),
        ),
        supports_check_mode=True
    )

    module.exit_json(
        _path=module.params['_path'],
        _raw=module.params['_raw'],
        _jsonarg=json.loads(module.params['_jsonarg']),
        _json=json.loads(module.params['_json']),
        _bytes=module.params['_bytes'],
        _bits=module.params['_bits'],
    )


if __name__ == '__main__':
    main()

以下では、ansible.cfgがあるディレクトリでplaybookを実行する。

$ ansible-playbook test.yaml -v
Using /test/ansible/module_test/ansible_cfg_module_test/ansible.cfg as config file

PLAY [localhost] **********************************************************************************

TASK [hello] **************************************************************************************
ok: [localhost] => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "message": "world"}

PLAY RECAP ****************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

サンプル fileansible_cfg_module_test.tar.gz

libraryのローカルロード

playbook及び特定のroleに対しmoduleをロードさせることができる。
playbookや特定のroleの下にlibraryフォルダを設定することで可能である。
実際に自作moduleがロードされるか確認する。

テストで使用するソースは以下のとおり。

hello.py

- hosts: localhost
  connection: local
  gather_facts: no
  tasks:
    - hello:
        _path: ${HOME}
        _raw: raw
        _jsonarg: {"hoge":[1,2,3]}
        _json: {"hoge":[1,2,3]}
        _bytes: 8Kbyte
        _bits: 16bit
      register: facts

    - debug: msg={{ facts }}

実験 プレイブックに適用する

playbookのあるパスにlibraryというディレクトリを配置する。

ディレクトリ構成は以下。

$ tree
.
├── library
│   └── hello.py
└── test.yaml

1 directory, 2 files

test.yaml

username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME']))

プレイブックを実行する。(簡単のためconnectionはlocal)

$ ls
library  test.yaml
$ ansible-playbook test.yaml -v
Using /etc/ansible/ansible.cfg as config file

PLAY [localhost] **********************************************************************************

TASK [hello] **************************************************************************************
ok: [localhost] => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "message": "world"}

PLAY RECAP ****************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

サンプルfileplaybooks_test.tar.gz

実験 特定のroleに適用する

roleの下にlibraryというディレクトリを配置する。

$ tree
.
├── db.yaml
├── roles
│   ├── db
│   │   └── tasks
│   │       └── main.yaml
│   └── web
│       ├── library
│       │   └── hello.py
│       └── tasks
│           └── main.yaml
└── web.yaml

6 directories, 5 files

web.yaml

# str
mode=dict(required=True, type='str', choices=['init', 'update'])
# list
mode=dict(required=True, type='list', choices=['init', 'update'])

roles/web/tasks/main.yaml

secret=dict(required=True, type='str', no_log=True)

db.yaml

elm=dict(required=True, type='list', elements='str')

roles/db/tasks/main.yaml

[defaults]
library = ./mod

プレイブックを実行する。

$ ansible-playbook web.yaml -v
Using /etc/ansible/ansible.cfg as config file

PLAY [localhost] **********************************************************************************

TASK [web : hello] ********************************************************************************
ok: [localhost] => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "message": "web"}

PLAY RECAP ****************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

roleがdbの場合はmoduleのロードに失敗しエラーとなる。

$ ansible-playbook db.yaml -v
Using /etc/ansible/ansible.cfg as config file
ERROR! couldn't resolve module/action 'hello'. This often indicates a misspelling, missing collection, or incorrect module path.

The error appears to be in '/test/ansible/module_test/roles_test/roles/db/tasks/main.yaml': line 1, column 3, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:


- hello: echo=db
  ^ here

サンプル fileroles_test.tar.gz

参考

参考リンク


トップ   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
目次
ダブルクリックで閉じるTOP | 閉じる
GO TO TOP