Spec-Zone.ru › Ansible 2.4

Практическое руководство по разработке модулей Ansible

В этом разделе мы пройдем процесс разработки, тестирования и отладки модуля Ansible.

Что покрывается в этом разделе:

  • Настройка среды
  • Разработка нового модуля
  • Тестирование модуля локально/непосредственно
  • Тестирование модуля с помощью плейбука
  • Отладка (локально)
  • Отладка (удаленно)
  • Единое тестирование
  • Интеграционное тестирование (скоро)
  • Связь и поддержка разработчиков
  • Благодарности

Настройка среды

  1. Клонировать репозиторий Ansible: $ git clone https://github.com/ansible/ansible.git
  2. Перейти в корневую директорию репозитория: $ cd ansible
  3. Создать виртуальную среду: $ python3 -m venv venv (или для Python 2 $ virtualenv venv. Обратите внимание, что для этого требуется установка пакета virtualenv: $ pip install virtualenv)
  4. Активировать виртуальную среду: $ . venv/bin/activate
  5. Установить требования к разработке: $ pip install -r requirements.txt
  6. Запустить скрипт настройки среды для каждого нового процесса разработки: $ . hacking/env-setup

Примечание

После первоначальной настройки выше, каждый раз, когда вы готовы начать разработку Ansible, вы должны сможете просто запустить следующее из корня репозитория Ansible: $ . venv/bin/activate && . hacking/env-setup

Разработка нового модуля

Если вы создаете новый модуль, который еще не существует, вы начнете работу с совершенно новым файлом. Вот пример:

  • Перейдите в каталог, в котором вы хотите разрабатывать новый модуль. Например: $ cd lib/ansible/modules/cloud/azure/
  • Создайте новый файл модуля: $ touch my_new_test_module.py
  • Вставьте этот пример кода в новый файл модуля: (объяснение в комментариях)
#!/usr/bin/python

ANSIBLE_METADATA = {
    'metadata_version': '1.1',
    'status': ['preview'],
    'supported_by': 'community'
}

DOCUMENTATION = '''
---
module: my_sample_module

short_description: This is my sample module

version_added: "2.4"

description:
    - "This is my longer description explaining my sample module"

options:
    name:
        description:
            - This is the message to send to the sample module
        required: true
    new:
        description:
            - Control to demo if the result of this module is changed or not
        required: false

extends_documentation_fragment:
    - azure

author:
    - Your Name (@yourhandle)
'''

EXAMPLES = '''
# Pass in a message
- name: Test with a message
  my_new_test_module:
    name: hello world

# pass in a message and have changed true
- name: Test with a message and changed output
  my_new_test_module:
    name: hello world
    new: true

# fail the module
- name: Test failure of the module
  my_new_test_module:
    name: fail me
'''

RETURN = '''
original_message:
    description: The original name param that was passed in
    type: str
message:
    description: The output message that the sample module generates
'''

from ansible.module_utils.basic import AnsibleModule

def run_module():
    # define the available arguments/parameters that a user can pass to
    # the module
    module_args = dict(
        name=dict(type='str', required=True),
        new=dict(type='bool', required=False, default=False)
    )

    # seed the result dict in the object
    # we primarily care about changed and state
    # change is if this module effectively modified the target
    # state will include any data that you want your module to pass back
    # for consumption, for example, in a subsequent task
    result = dict(
        changed=False,
        original_message='',
        message=''
    )

    # the AnsibleModule object will be our abstraction working with Ansible
    # this includes instantiation, a couple of common attr would be the
    # args/params passed to the execution, as well as if the module
    # supports check mode
    module = AnsibleModule(
        argument_spec=module_args,
        supports_check_mode=True
    )

    # if the user is working with this module in only check mode we do not
    # want to make any changes to the environment, just return the current
    # state with no modifications
    if module.check_mode:
        return result

    # manipulate or modify the state as needed (this is going to be the
    # part where your module will do what it needs to do)
    result['original_message'] = module.params['name']
    result['message'] = 'goodbye'

    # use whatever logic you need to determine whether or not this module
    # made any modifications to your target
    if module.params['new']:
        result['changed'] = True

    # during the execution of the module, if there is an exception or a
    # conditional state that effectively causes a failure, run
    # AnsibleModule.fail_json() to pass in the message and the result
    if module.params['name'] == 'fail me':
        module.fail_json(msg='You requested this to fail', **result)

    # in the event of a successful module execution, you will want to
    # simple AnsibleModule.exit_json(), passing the key/value results
    module.exit_json(**result)

def main():
    run_module()

if __name__ == '__main__':
    main()

Тестирование модуля локально/непосредственно

Вы можете протестировать модуль на локальной машине без использования удаленного хоста. Это отличный способ быстро и легко отладить локально работающий модуль.

  • Создайте файл аргументов в /tmp/args.json со следующим содержимым: (объяснение ниже)
{
    "ANSIBLE_MODULE_ARGS": {
        "name": "hello",
        "new": true
    }
}
  • Если вы используете виртуальную среду (настоятельно рекомендуется для разработки), активируйте ее: $ . venv/bin/activate
  • Настройте среду разработки: $ . hacking/env-setup
  • Запустите свой тестовый модуль локально и непосредственно: $ python ./my_new_test_module.py /tmp/args.json

Это должно быть рабочее вывод, похожее на следующее:

{"changed": true, "state": {"original_message": "hello", "new_message": "goodbye"}, "invocation": {"module_args": {"name": "hello", "new": true}}}

Файл аргументов — это просто базовый JSON-конфигурационный файл, который вы можете использовать для передачи параметров модуля для его запуска.

Тестирование модуля с помощью плейбука

Если вы хотите протестировать свой новый модуль, вы можете теперь использовать его с помощью плейбука Ansible.

  • Создайте плейбук в любом каталоге: $ touch testmod.yml
  • Добавьте следующее в новый файл плейбука:

    - name: test my new module
      connection: local
      hosts: localhost
      tasks:
      - name: run the new module
        my_new_test_module:
          name: 'hello'
          new: true
        register: testout
      - name: dump test output
        debug:
          msg: '{{ testout }}'
    
  • Запустите плейбук и проанализируйте вывод: $ ansible-playbook ./testmod.yml

Отладка (локально)

Если вы хотите выполнить отладку в модуле и пройтись по нему с отладчиком, выполняя его локально, вы можете сделать следующее:

  • Установите точку останова в модуле: import pdb; pdb.set_trace()
  • Запустите модуль на локальной машине: $ python -m pdb ./my_new_test_module.py ./args.json

Отладка (удаленно)

Если вам нужно отладить модуль, работающий на удаленном целевом узле (т.е. не на localhost), один из способов сделать это — следующий:

  • На вашей контрольной машине (на которой работает Ansible) задайте ANSIBLE_KEEP_REMOTE_FILES=1 (это сообщает Ansible сохранить модули, которые он отправляет на удаленный узел, вместо удаления их)
  • Запустите свой плейбук, нацеленный на удаленный узел, и укажите -vvvv (подробный вывод покажет вам много вещей, включая удаленное расположение, используемое Ansible для модулей)
  • Обратите внимание на удаленный путь, используемый Ansible на удаленном узле
  • Подключитесь к удаленному узлу по SSH после завершения плейбука
  • Перейдите в каталог (скорее всего, это будет ваш определенный или подразумеваемый пользователем Ansible из плейбука: ~/.ansible/tmp/ansible-tmp-...)
  • Здесь вы должны увидеть модуль, который вы выполнили со своей контрольной машины Ansible, но это сжатый файл, который Ansible отправил на удаленный узел. Вы можете запустить его, указав python my_test_module.py (не обязательно)
  • Однако для отладки нам нужно будет извлечь этот zip в исходный формат модуля: python my_test_module.py explode (Ansible распакует модуль в ./debug-dir)
  • Перейдите в ./debug-dir (обратите внимание, что извлечение привело к созданию ansible_module_my_test_module.py)
  • Измените или установите точку останова в распакованном модуле
  • Убедитесь, что распакованный модуль выполняется: $ chmod 755 ansible_module_my_test_module.py
  • Запустите распакованный модуль непосредственно, передав файл аргументов: $ ./ansible_module_my_test_module.py args (args — это файл, содержащий параметры, которые изначально передавались. Полезно для воспроизведения и отладки)

Единое тестирование

Единые тесты для модулей будут правильно расположены в ./test/units/modules. Сначала необходимо настроить среду тестирования. В этом примере мы используем Python 3.5.

  • Установите необходимые компоненты (вне вашей виртуальной среды): $ pip3 install -r ./test/runner/requirements/units.txt
  • Чтобы запустить все тесты, выполните следующие действия: $ ansible-test units --python 3.5 (вы должны запустить . hacking/env-setup перед этим)

Примечание

Ansible использует pytest для модульного тестирования.

Чтобы запустить pytest для одного тестового модуля, вы можете сделать следующее (указать путь к тестовому модулю соответствующим образом):

$ pytest -r a --cov=. --cov-report=html --fulltrace --color yes test/units/modules/.../test/my_new_test_module.py

Дальнейшие действия

Если вы начинаете новую разработку или исправляет ошибку, создайте новую ветвь:

$ git checkout -b my-new-branch.

Если вы планируете внести вклад в основной репозиторий Ansible, создайте форк репозитория Ansible в свою учетную запись GitHub и работайте с новой ветвью non-devel в вашем форке. Когда вы считаете, что у вас есть хорошее рабочее изменение кода, отправьте запрос на вытягивание в репозиторий Ansible.

Если вы хотите отправить новый модуль в основной репозиторий Ansible, сначала обязательно выполните проверки целостности. Например:

$ ansible-test sanity -v --docker --python 2.7 MODULE_NAME

Обратите внимание, что этот пример требует, чтобы docker был установлен и запущен. Если вы предпочитаете не использовать контейнер для этого, вы можете выбрать --tox вместо --docker.

Связь и поддержка разработчиков

Присоединяйтесь к каналу IRC #ansible-devel на freenode для обсуждения вопросов, связанных с разработкой Ansible.

Для вопросов и обсуждений, связанных с использованием продукта Ansible, используйте канал #ansible.

Благодарности

Благодарим Томаса Стрингера (@tstring) за предоставление исходного материала по этой теме.

© 2012–2018 Michael DeHaan
© 2018–2019 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/ansible/2.4/dev_guide/developing_modules_general.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API