Практическое руководство по разработке модулей Ansible
В этом разделе мы пройдем процесс разработки, тестирования и отладки модуля Ansible.
Что покрывается в этом разделе:
- Настройка среды
- Разработка нового модуля
- Тестирование модуля локально/непосредственно
- Тестирование модуля с помощью плейбука
- Отладка (локально)
- Отладка (удаленно)
- Единое тестирование
- Интеграционное тестирование (скоро)
- Связь и поддержка разработчиков
- Благодарности
Настройка среды
- Клонировать репозиторий Ansible:
$ git clone https://github.com/ansible/ansible.git - Перейти в корневую директорию репозитория:
$ cd ansible - Создать виртуальную среду:
$ python3 -m venv venv(или для Python 2$ virtualenv venv. Обратите внимание, что для этого требуется установка пакета virtualenv:$ pip install virtualenv) - Активировать виртуальную среду:
$ . venv/bin/activate - Установить требования к разработке:
$ pip install -r requirements.txt - Запустить скрипт настройки среды для каждого нового процесса разработки:
$ . 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