Глава 8. Поиск неисправностей Ansible
Содержание
Ansible прост, но обладает изрядной мощностью. Простота Ansible означает что его действия просто понимать и следовать им. Имея возможность понимать их и следовать им критически важно при отладке неожиданного поведения. В этой главе мы изучим различные методы, которыми можно вооружаться для исследования, проникновения вовнутрь, изменения и прочей отладки операций Ansible. В данной главе мы рассмотрим такие темы:
-
Регистрация плейбуков и различные уровни её подробности
-
Самоанализ переменных
-
Отладка плейбуков
-
Консоль Ansible
-
Отладка исполнения локального кода
-
Отладка исполнения удалённого кода
Ознакомьтесь с видеоматериалами Code in Action.
Увеличение подробности вывода Ansible способно разрешать множество проблем. Начиная с неверных параметров модулей вплоть до неверных команд подключения, увеличение подробностей может оказаться критически важным в определении точного места ошибки. Регистрация плейбука и его подробность вкратце обсуждались в Главе 2, Защита ваших ключей безопасности в Ansible в отношении защиты значений секретов при исполнении плейбуков. Данный раздел более детально рассмотрит протоколирование и его степени подробности.
При исполнении плейбуков посредством ansible-playbook
получаемый вывод отображается
в стандартном выходе. При определённом по умолчанию уровне подробностей отображается очень немного информации. По
мере исполнения воспроизведения, ansible-playbook
выдать на печать некий заголовок
PLAY с самим названием этого воспроизведения. Затем для
каждой задачи выводится на печать заголовок task с названием
этой задачи. По мере того как каждый хост выполнит эту задачу, отображается название этого хоста совместно с полученным
состоянием данной задачи, которое может быть ok
, fatal
либо changed
. Никакой дополнительной информации относительно данной задачи не
отображается, например, такой что этот модуль был выполнен, все параметры предоставлены в данный модуль или значения
возвращаемых после исполнения данных. Хотя это и нормально для хорошо отлаженных плейбуков, я обычно привык желать слегка
больше информации о своих воспроизведениях. В некоторых из более ранних примеров в этой книге мы применяли более высокие
уровни детализации (verbosity) вплоть до двух (-vv
), а потому мы могли наблюдать
местоположение такой задачи и возвращаемые данные. В общей сложности имеются пять уровней детализации:
-
None: Значение уровня по умолчанию
-
Первый (-v): При котором отображаются возвращаемые данные и информация условий
-
Второй (-vv): Для получения сведений о местоположении задачи и уведомлений обработчика
-
Третий (-vvv): Предоставляет подробности о попытках подключений и информацию о вызове задачи
-
Четвёртый (-vvvv): Передаёт помимо прочего дополнительные параметры детализации во все соединения подключаемых модулей (например, передачу
-vvv
во все командыssh
{и PowerShell})
Увеличение степени детализации может помочь выявлению конкретного места в котором могли произойти ошибки, а также предоставление дополнительных внутренних сведений относительно того как Ansible выполняет свои действия.
Как мы уже упоминали в Главе 2, Защита ваших ключей безопасности в Ansible, уровень подробностей выше первого может приводить к утечке чувствительных сведений в стандартный вывод и файлы журналов, а следовательно необходимо проявлять осторожность при использовании повышения детализации в потенциально совместно применяемых средах.
В то время как значением по умолчанию в ansible-playbook
для регистрации
установлен стандартный вывод, общий объём может быть больше того буфера, который применяется в самом эмуляторе Терминала;
тем самым, может оказаться необходимым сохранять весь вывод в некий файл. Хотя различные оболочки и предоставляют некие
механизмы для перенаправления вывода, более элегантным решением является указание ansible-playbook
напрямую вести протоколирование в некий файл. Это осуществляется посредством либо задания некого
log_path
в самом файле ansible.cfg
, либо
через установку ANSIBLE_LOG_PATH
в качестве переменной окружения. Устанавливаемое
значение должно быть значением пути к некому файлу. Если этот путь не существует, Ansible попытается создать данный файл.
Если такой файл уже имеется, Ansible будет выполнять добавление в конец этого файла, что делает возможной консолидацию выполнения
множества регистрационных записей ansible-playbook
.
Само использование некого файла журнала не является взаимоисключающим в отношении регистрации в стандартном выводе. И то, и другое могут выполняться одновременно, а предоставление устанавливаемого уровня детализации имеет воздействие и на то, и на иное одновременно.
Распространённым набором проблем с котррым сталкиваются при разработке плейбуков Ansible является собственно не надлежащее применение, или неверное предположение о назначенном переменным значении. Это в особенности распространено при регистрации получаемых результатов одной задачи в некой переменной, с последующим использованием такой переменной в некой задаче или шаблоне. Если соответствующий желательный элемент получаемого результата не достигнут надлежащим образом, наш окончательный результат будет неожиданным, или возможно губительным.
Для устранения ненадлежащего применения переменной ключом является инспекция получаемого значения переменной. Самый простой способ инспекции некого значения переменной состоит в установленном модуле отладки. Такой модуль отладки позволяет отображать на экране текст в свободном виде и, как и прочие задачи, устанавливаемые для этого модуля параметры могут также пользоваться преимуществами синтаксиса шаблонов Jinja2. Давайте продемонстрируем такое применение создав некое простое воспроизведение, которое исполняет какую- то задачу, регистрирует получаемый результат и затем отображает этот результат в неком операторе отладки с применением синтаксиса Jinja2 для предоставления такой переменной:
---
- name: variable introspection demo
hosts: localhost
gather_facts: false
tasks:
- name: do a thing
uri:
url: https://derpops.bike
register: derpops
- name: show derpops
debug:
msg: "derpops value is {{ derpops }}"
Когда мы запустим это воспроизведение, мы увидим отображаемым значение для derpops
,
что отображено на следующем снимке экрана:
Модуль отладки имеет различные возможности, которые также могут оказаться полезными. Вместо вывода на печать некой
строки в произвольном виде для отладки использования шаблона, этот модуль может просто выводить на печать само значение
некой переменной. Это осуществляется использованием значения параметра var
вместо
значения параметра msg
. Давайте повторим свой пример, но в этот раз мы воспользуемся
значением параметра var
, а также мы выполним доступ только к подэлементу
server
своей переменной derpops
следующим
образом:
---
- name: variable introspection demo
hosts: localhost
gather_facts: false
tasks:
- name: do a thing
uri:
url: https://derpops.bike
register: derpops
- name: show derpops
debug:
var: derpops.server
Запуск этого видоизменённого воспроизведения отобразит лишь значение части server
нашей
переменной derpops
, что отображено на снимке экрана ниже:
В нашем примере который применял для debug
значение параметра
msg
, значение переменной необходимо предоставлять внутри фигурных скобок, в то
время как при использовании var
это не требуется. Это происходит по причине того,
что msg
ожидает некую строку, а потому Ansible приходится предоставлять эту
переменную в виде какой- то строки через свой механизм шаблона. Однако var
ожидает некой отдельной переменной без её представления.
Другой распространённой ошибкой в плейбуках является ненадлежащая ссылка на некий подэлемент какой- то составной переменной. Некая составная переменная представляет собой нечто большее чем просто какую- то строку; это или список, или хэш. Зачастую выполняется неверная ссылка на подэлемент или сам элемент будет указан ненадлежащим образом, ожидая иной тип.
Хотя со списками и достаточно просто работать, хэши предоставляют некую уникальную проблему. Хэш выступает в качестве какого- то не сортированного множества с потенциально смешанными типами, которые к тому же могут иметь включения. Некий хэш может иметь один элемент, который выступает в качестве обособленной строки, в то время как другой элемент может быть списком строк, а третий элемент может быть ещё одним хэшем с последующими элементами внутри себя. Для успеха критически важно понимать как верно получать доступ к правильному выражению.
В качестве примера давате слегка изменим своё предыдущее воспроизведение. На этот раз мы позволим Ansible собирать
факты, а затем отобразим полученное значение ansible_python
:
---
- name: variable introspection demo
hosts: localhost
tasks:
- name: show a complex hash
debug:
var: ansible_python
Получаемый вывод отображён на следующем снимке экрана:
Для изучения всех названий имеющихся подэлементов отличным вариантом будет воспользоваться
debug
для отображения всей составной переменной.
Данная переменная имеет элементы, которые являются строками, совместно с элементами, которые выступают списками строк. Давайте выполним доступ к самому последнему элементу в имеющемся перечне флагом таким образом:
---
- name: variable introspection demo
hosts: localhost
tasks:
- name: show a complex hash
debug:
var: ansible_python.version_info[-1]
Получаемый вывод отображён на снимке экрана ниже:
Поскольку флаги являются списком, мы можем воспользоваться методом
индексации списка для выбора некого определённого элемента из данного перечня. В данном случае
-1
предоставляет нам самый последний элемент из данного списка.
Сопоставление подэлементов и методов объектов Python
Менее распространённая, но сбивающая с толку засада происходит по причине причуды синтаксиса Jinja2. На составные
переменные внутри плейбуков и шаблонов Ansible можно ссылаться двумя способами. Первый стиль состоит в ссылке на самый
основной элемент по его названию, за которым следуют квадратные скобки, а сам подэлемент в кавычках внутри этих квадратных
скобок. Это собственно стандартный синтаксис вложенного сценария
(standard subscript syntax). Например, для доступа к имеющемуся подэлементу herp
в нашей переменной derp
мы применим следующее:
{{ derp['herp'] }}
Наш второй стиль является удобным методом, предоставляемым Jinja2, который состоит в использовании точки для разделения имеющихся элементов. Это имеет название нотации с точкой (dot notation) и выглядит так:
{{ derp.herp }}
Имеется едва уловимое отличие в том как работают эти стили и это обусловлено объектами и методами объектов Python.
Поскольку Jinja2 по существу является утилитой Python, переменные в Jinja2 обладают доступом к своим родным методам Python.
Некая переменная строки имеет доступ к методам строк Python, какой-то список имеет доступ к методам списка, а словарь
имеет доступ к методам словарей. Когда мы применяем свой первый стиль, Jinja2 вначале выполнит поиск соответствующего
элемента среди подэлементов по предоставленному значению имени. Если ничего не найдено, Jinja2 далее попытается выполнить
доступ некого метода Python для данного предоставленного названия. Однако, такой порядок меняется при использовании нашего
второго стиля; вначале выполняется поиск метода некого объекта Python, а если он не найден, тогда осуществляется поиск
какого- то подэлемента. Это отличие становится существенным при наличии противоречия имён между неким подэлементом и
каким- то методом. Допустим некая переменная derp
выступает какой- то составной
переменной. Эта переменная имеет некий подэлемент с названием keys
. Применение для
доступа к keys
каждого из стилей приводит в результате к различным значениям. Давайте
построим некий плейбук для демонстрации данного факта:
---
- name: sub-element access styles
hosts: localhost
gather_facts: false
vars:
- derp:
keys:
- c
- d
tasks:
- name: subscript style
debug:
var: derp['keys']
- name: dot notation style
debug:
var: derp.keys
После запуска этого воспроизведения мы ясно можем видеть отличие между своими двумя стилями. Наш первый стиль успешно
ссылается на значение подэлемента keys
, в то время как второй стиль ссылается
на метод keys
словарей Python:
В общем случае лучше избегать применение в качестве названия подэлементов тех, которые могут вступать в конфликт с методами объекта Python. Тем не менее, если это не возможно, следующим лучшим моментом будет знание об этом отличии в стилях ссылок на подэлементы и выбрать в качестве соответствующего только один.
Порой оказываются недостаточными регистрация и инспекция данных переменной для выявления некоторой проблемы. Когда это происходит, может потребоваться отладка самого плейбука или более глубокое погружение во внутренности кода Ansible. Существует два основных набора кода Ansible: тот код, который исполняется локально на самом хосте Ansible и тот код модуля, который запускается удалённо на нашем целевом хосте.
Плейбуки имеют возможность интерактивной отладки с применением стратегии исполнения, которая была введена в Ansible 2.1, а именно стратегии отладки (debug). Если некое воспроизведение применяет данную стратегию, в случае возникновения некого состояния ошибки запускается интерактивный сеанс отладки. Этот интерактивный сеанс может применяться для отображения данных переменных, отображения параметров задач, обновления параметров задач, обновления переменных, повторного исполнения задач или выхода из отладчика.
Давайте продемонстрируем это неким воспроизведением, которое имеет какую- то успешную задачу, за которой следует некая задача с ошибкой, после чего идёт окончательная успешная задача. Мы повторно воспользуемся тем плейбуком, который мы уже применяли, но слегка обновим его, как это показано в следующем коде:
---
- name: sub-element access styles
hosts: localhost
gather_facts: false
strategy: debug
vars:
- derp:
keys:
- c
- d
tasks:
- name: subscript style
debug:
var: derp['keys']
- name: failing task
debug:
msg: "this is {{ derp['missing'] }}"
- name: final task
debug:
msg: "my only friend the end"
В процессе исполнения Ansible столкнётся с некой ошибкой в нашей задаче с отказом и представит своё приглашение (отладки), как это показано на снимке экрана ниже:
Из этого приглашения мы имеем возможность отображать саму задачу и те параметры, которые применяются данной задачей
при помощи команды p
следующим образом:
Мы также имеем возможность изменять сам плейбук на лету чтобы пробовать различные значения параметров или переменных.
Давайте определим значение ошибочного ключа для своей переменной derp
и затем
попробуем выполнение вновь. Все значения переменных пребывают внутри нашего словаря верхнего уровня
vars
. Мы имеем возможность напрямую устанавливать данные переменной при помощи
синтаксиса Python и доступной команды task_vars
, а затем повторить попытку
командой r
:
Такая стратегия исполнения отладчика является удобным инструментом для быстрого взаимодействия посредством различных комбинация параметров и переменных задачи для определения верного пути продвижения. Тем не менее, по причине получаемых в результате ошибок в интерактивных консолях, данная стратегия отладчика не подходит для автоматического исполнения плейбуков, поскольку при этом отсутствует персонал за ткой консолью для манипуляций с самим отладчиком.
Совет | |
---|---|
Изменение данных внутри применяемого отладчика не приводит к сохранению этих изменений в лежащих в основе файлах. Всегда не забывайте обновлять файлы плейбука для отражения тех выявленных изменений, которые выполняются в процессе отладки. |
Локальный код Ansible представляет собой львиную долю того кода, который предоставляется Ansible. Все имеющиеся плейбуки, воспроизведения, роли и задачи разбираемого кода присутствуют локально. Весь имеющийся код, за исключением самого собираемого модуля, который передаётся на соответствующий локальный хост обитает локально.
Локальный код Ansible можно разбить на три основные раздела: опись (inventory), плейбук и исполнитель (executor). Код описи имеет дело с синтаксическим разбором данных инвентаризации из файлов хоста, динамических сценариев инвентаризации или сочетания их обоих, причём в каталогах деревьев. Код плейбука применяется для разбора самого кода YAML в объекты Python внутри Ansible. Код исполнения представляет собой API ядра и имеет дело с ветвящимися процессами, подключениями к хостам, исполняемыми модулями, обработкой результатов и многими прочими моментами. С практикой приходит понимание изучения общей области для начала отладки, но все описываемые здесь общие области выступают отправной точкой.
Поскольку Ansible написан на Python, основным инструментом для отладки исполнения локального кода является отладчик Python,
pdb
. Этот инструмент позволяет нам вставлять точки прерываний внутри имеющегося кода
Ansible и интерактивно обходить по всему исполнению кода, строка за строкой. Это чрезвычайно полезно для изучения значения
внутреннего состояния Ansible по мере выполнения локального кода. Имеется большое число книг и вебсайтов, которые описывают
использование pdb
и их можно отыскать простым веб поиском введя
Python pdb
, поэтому мы здесь не будем повторяться. Основа состоит в изменении самого
исходного файла, подлежащего отладке, вставке некой новой строки кода для создания какой- то точки прерывания и последующего
исполнения полученного кода. В том месте где была создана точка прерывания исполнение кода будет оставновлено и будет
предоставлено приглашение для изучения текущего состояния кода.
Отладка кода учёта ресурсов
Код инвентаризации имеет дело с поиском источников описи, считыванием или выполнением обнаруженных файлов, синтаксическим
разбором данных учёта в объекты инвентаризации и загрузке переменных данных для данной описи. Для отладки того как Ansible
обращается с данным учётом ресурсов, вовнутрь inventory/__init__.py
или в один из
прочих файлов внутри подкаталога inventory/
следует добавить некую точку прерывания.
Этот каталог будет расположен в той локальной файловой системе, в которой был установлен Ansible. В системе Linux он обычно
хранится в пути /usr/lib/python2.7/site-packages/ansible/inventory/
. Этот путь может
быть внутри некой виртуальной среды Python если Ansible был установлен именно таким образом. Для обнаружения того где
установлен Ansible просто наберите в своей командной строке which ansible
. Эта
команда отобразит вам где установлен исполняемый файл Ansible и может указывать некую виртуальную среду Python. Для данной
книги Ansible был установлен с применением дистрибутива Python операционной системы при исполняемых файлах Ansible
расположенных в /usr/bin/
.
Для обнаружения пути самого кода Python Ansible просто наберите
python -c "import ansible; print(ansible)"
. В моей системе это выдало
<module 'ansible' from '/usr/lib/python2.7/site-packages/ansible/__init__.pyc'>
,
из чего можно вывести, что наш каталог описи расположен в
/usr/lib/python2.7/site-packages/ansible/inventory
.
В последних выпусках Ansible этот каталог учёта ресурсов был реструктурирован и в версии 2.7 нам требуется искать
inventory/manager.py
. Здесь расположено определение некого класса для класса
Inventory
. Именно этот объект описи будет применяться при запуске плейбука и он
создаётся когда ansible-playbook
осуществляет синтаксический разбор вариантов,
предоставляемых ему в качесве источника учёта ресурсов. Вся выявление имеющейся описи выполняет метод
__init__
из класса Inventory
. Для выявления
неисправностей в этих трёх областях внутри самого метода __init__()
следует установить некую точку прерывания. Хорошим практическим приёмом будет поместить её после всех имеющихся переменных
данного класса, которые задают начальные значения и прямо перед тем как начинается обработка каких- то данных.
В версии Ansible 2.7.5.0 это будет строка 143 inventory/manager.py
, в которой
вызывается parse_sources
.
Мы можем пропустить само определение функции parse_sources
в строке
195
для вставки своей точки прерывания. Чтобы вставить точку прерывания нам вначале
требуется импортировать необходимый модуль pdb
, а затем вызвать функцию
set_trace()
следующим образом:
Для начала отладки сохраните этот исходный файл и затем исполните ansible-playbook
как обычно. По достижению установленной точки прерывания наше исполнение будет остановлено и будет отображено
приглашение на ввод pdb
:
Здесь мы можем вызывать любое число команд отладки, например такую команду
help
:
Команды where
и list
из приведённого
перечня помогут нам определить где мы находимся в своём стеке и где мы пребываем в коде:
Наша команда where
отображает нам что мы пребываем в
inventory/manager.py
, в методе parse_sources()
.
Следующий кадр вверх находится в том же самом файле, в функции __init__()
.
До этого имеется другой файл, playbook.py
, а также исполняемой функцией в этом
файле является run()
. Эта строка вызывает
ansible.inventory.InventoryManager
для создания необходимого объекта описи/
До него находится первоначальный файл, ansible-playbook
, вызывающий
cli.run()
.
Наша команда list
отображает сам исходный код вокруг нашей текущей точки
исполнения, пять строк до ней и пять строк после.
Начиная с этого места мы можем указывать pdb
выполнение строки за строкой при
помощи команды next
. И если мы выберем это, мы отследим вызов другой функции при помощи
команды step
. Также мы имеем возможность print
данных переменной для инспекции значений, что отображено на следующем снимке экрана:
Мы можем видеть, что наша переменная self._sources
имеет какое- то значение
полного пути к нашему файлу описи mastery-hosts
, который является строкой, которой
мы снабдили ansible-playbook
для описи своих данных. Мы можем продолжить
обход или выпрыгнуть прочь или просто воспользоваться командой continue
для
выполнения вплоть до следующей точки прерывания или до завершения всего кода.
Отладка кода плейбуков
Код плейбука ответственен за загрузку, синтаксический разбор и выполнение плейбуков. Основной точкой входа для
обработки плейбука является playbook/__init__.py
, внутри которой и обитает сам
класс PlayBook. Хорошим начальным местом для отладки обработчика плейбука является строка
77
:
Размещение здесь точки прерывания позволит нам отслеживать поиск самого файла плейбука и его синтаксический разбор.
В частности, выполняя пошаговый проход вызова функции self._loader.load_from_file()
,
мы будем иметь возможность следовать за действием своего синтаксического разбора.
Функция load()
нашего класса PlayBook всего лишь выполняет самый первоначальный
разбор. Для самого исполнения воспроизведений и задач применяются иные классы внутри прочих каталогов. Особый интерес
представляет каталог executor/
, который содержит файлы с классами для исполнения
плейбуков, воспроизведений и задач. Основная функция run()
, внутри самого класса
PlaybookExecutor
, определяемая внутри файла
executor/playbook_executor.py
выполняет цикл по всем имеющимся воспроизведениям в
данном плейбуке и исполняет сами воспроизведения, который, в свою очередь, выполняют имеющиеся индивидуальные задачи.
Именно эту функцию следует обходить если сталкиваетесь с некой проблемой, относящейся к разбору воспроизведения, обратных
вызовов воспроизведения или задач, тегов, выбора воспроизведений хоста, последовательных операций, исполнения обработчика
или чего- то промежуточного.
Отладка кода исполнителя
Код исполнителя в Ansible выступает кодом подключения, который связывает воедино данные учёта ресурсов, плейбуки, воспроизведения и методы подключения. В то время как каждый из этих прочих элементов кода может отлаживаться персонально, то как они взаимодействуют может изучаться внутри кода исполнителя.
Необходимые классы исполнителя определены в различных файлах внутри executor/
и самого класса PlaybookExecutor
. Этот класс обрабатывает исполнение всех
имеющихся воспроизведений и задач внутри некого определённого плейбука. Основная функция создания класса,
__init__()
, создаёт последовательности атрибутов местодержателей, а также
устанавливает некие значения по умолчанию, в то время как функция run()
является тем, где происходит всё интересное.
Отладчик часто перекидывает вас с одного файла на другой, прыгая по самой основе кода. Например, в нашей функции
__init__()
класса PlaybookExecutor
имеется код для кэширования того будет или нет исполняемый по умолчанию SSH поддерживать
ControlPersist
. ControlPersist
является
функцией SSH, которая удерживает сокеты для удалённых хостов открытыми на протяжении какого- то времени для быстрого
повторного применения. Давайте поместим здесь точку прерывания и последуем за самим кодом:
Теперь мы можем запустить свой плейбук objmethod.yml
снова чтобы получить
состояние отладки:
На потребуется шагнуть в соответствующую функцию чтобы следовать за её исполнением. Проходя пошагово данную функцию мы тем самым перейдём в друой файл:
Здесь мы имеем возможность воспользоваться list
для просмотра самого
кода в нашем новом файле:
Спустившись на несколько строк вниз мы приходим к некому блоку кода, который исполняет команду
ssh
и проверяет получаемый вывод для проверки того поддерживается ли
ControlPersist
:
Давайте спустимся ещё на пару строк и затем выведем на печать то значение, которое присвоено
err
. Это отобразит нам полученный в ssh
результат и значение всей строки, которое Ansible будет искать внутри:
Как мы можем видеть, значение искомой строки не представлено внутри значения переменной err
,
а потому значение has_cp
остаётся установленным по умолчанию
True
.
Быстрое замечание относительно ветвлений и отладки: | |
---|---|
Когда Ansible использует множество процессов для множества ветвлений, отладка становится затруднительной. Отладчик может быть прикреплён только к одному ветвлению, а не к другому, что делает очень сложным отладку данного кода. Пока вы не применяете специализированный отладчик кода множества процессов, будет лучше оставаться в одном ветвлении. {Прим. пер.: подробнее в нашем переводе Полное руководство параллельного программирования на Python Куана Нгуена.} |
Отладка удалённого кода
Удалённый код является тем кодом, который Ansible перемещает в некий удалённый хост для его последующего исполнения.
Обычно это код модуля или в определённом случае action_plugins
, другие
кусочки кодов. Применение того метода отладки, который мы обсуждали в своем предыдущем разделе для отладки исполнения модуля
отладки, не будет работать, поскольку Ansible всего лишь копирует сам код куда требуется и затем исполняет его. Нет никакого
Терминала, подключаемого к исполняемому удалённо коду, а следовательно нет никакого способа подключать его к некому приглашению
отладчика, то есть без изменения самого модуля кода.
Для отладки кода модуля нам требуется изменить сам этот код модуля чтобы вставить некую точку прерывания. Вместо
непосредственного изменения самого файла устанавливаемого модуля, создайте некую копию этого файла в каталоге
library/
относительно имеющихся плейбуков. Эта копия данного кода модуля будет применяться
вместо нашего устанавливаемого файла, что сделает более простым временное изменение модуля без разрушения прочих модулей
пользователей в вашей системе.
В отличии от прочего кода Ansible, код модуля не может напрямую отлаживаться при помощи pdb
,
так как этот код модуля собирается, а затем переправляется в некий удалённый хост. К счастью, существует некое решение в
виде слегка изменённого отладчика с названием rpdb
, Remote Python Debugger.
Это отладчик имеет возможность запуска некой службы ожидания по представленному ему порту чтобы сделать возможным
удалённое подключение к данному процессу Python. Удалённое подключение к этому процессу позволит отлаживать необходимый
код строка за строкой, в точности как мы это делали с остальным кодом Ansible.
Для демонстрации того как работает такой отладчик, вначале нам понадобится некий удалённый хост. Для данного примера
мы воспользуемся каким- то удалённым хостом с названием debug.example.com
и
установим значение IP адреса для хоста, который уже установлен и пребывает в ожидании. Затем нам требуется исполнить некий
модуль, который мы бы желали отлаживать:
---
- name: remote code debug
hosts: debug.example.com
gather_facts: false
become: true
tasks:
- name: a remote module execution
systemd:
name: nginx
state: stopped
enabled: no
Нам также потребуется некий новый файл описи для ссылки на наш новый проверочный хост - поскольку я не имею настроенным
DNS для данного хоста, я воспользуюсь специальной переменной ansible_host
в своей описи чтобы сообщить Ansible с каким именно IP адресом подключаться к
debug.example.com
:
debug.example.com ansible_host=192.168.81.154
Совет | |
---|---|
Не забывайте настраивать аутентификацию SSH между вашими двумя хостами - я применяю некий ключ SSH, поэтому мне
не требуется набирать некий пароль при каждом запуске |
Данное воспроизведение просто вызывает имеющийся модуль systemd
чтобы гарантировать
что наша служба nginx
остановлена и не будет запускаться при загрузке. Как мы
уже постулировали ранее, нам требуется сделать некую копию своего модуля службы и поместить ей в
library/
. Окончательное местоположение для копирования этого модуля службы будет
основываться на том методе, при помощи которого установлен Ansible. Обычно этот модуль будет размещаться в подкаталоге
modules/core/system/
, в котором обитает сам од Python Ansible, например, в моей системе
/usr/lib/python2.7/site-packages/ansible/modules/system/systemd.py
. Затем мы можем
изменить его поместив в него свою точку прерывания таким образом:
Мы поместим точку прерывания прямо перед моментом создания значения переменной systemctl
,
рядом со строкой 318. Вначале требуется импортировать необходимый нам модуль rpdb
(что подразумевает, что сама библиотека Python rpdb
должна иметься в этом удалённом
хосте), а затем следует создать собственно точку прерывания с помощью
set_trace()
.
Совет | |
---|---|
В CentOS 7 и прочих вариантах, как в том хосте, который применяется в нашей демонстрации,
|
В отличии от обычного отладчика, эта функция откроет некий порт и будет ожидать внешних подключений. По умолчанию
данная функция будет выполнять ожидание подключений к порту 4444
по адресу
127.0.0.1
. Однако этот адрес не выставляется в сетевой среде, поэтому в
своём примере я указываю rpdb
выполнять ожидание с адреса 0.0.0.0
,
что в действительности является всеми адресами для данного хоста. Теперь мы можем запустить этот плейбук чтобы настроить
данный сервер который будет ожидать подключения клиента:
Теперь, когдаэтот сервер запущен, мы имеем возможность подключаться к нему с другого Терминала. Подключение к этому запущенному процессу можно осуществить при помощи программы telnet:
Начиная с этого момента мы можем выполнять отладку как обычно. Всё ещё имеются все команды, которые мы применяли,
например list
для отображения где расположен текущий кадр внутри нашего
кода:
Применяя данный отладчик мы способны прогуливаться по модулю systemd
чтобы отслеживать как он определяет значение пути для последующих инструментов, отслеживать какие команды исполняются
в этом хосте, определять как вычисляется некое изменение и тому подобное. Можно обойти весь файл, включая все прочие внешние
библиотеки, используемые данным модулем, что делает также возможной отладку прочего кода вне модуля в этом удалённом
хосте.
Если данный сеанс позволяет рассматриваемому модулю чистый выход, исполнение этого плейбука будет возвращено обычным образом. Однако, если сеанс данного отладчика отключится до завершения самого модуля, наш плейбук завершится с ошибкой, что продемонстрировано на следующем снимке экрана:
По причине такой стороны воздействия будет лучше не выходить слишком рано из своего отладчика, а вместо этого вызвать
некую команду continue
когда ваша отладка завершится.
Отладка действия встраиваемого модуля
Некоторые модули на самом деле действуют как подключаемые модули. Это задачи, которые исполнят некий код локально перед
передачей кода в соответствующий удалённый хост. Никие примеры подключаемых модулей действий включают copy, fetch, script и
template. Источник для этих подключаемых модулей можно найти в plugins/action/
.
Каждый подключаемый модуль имеет свой собственный файл в этом каталоге, который можно изменить чтобы получить вставленной
точку прерывания для отладки данного кода при его исполнении, прежде чем (или вместо) отправить этот код в соответствующий
удалённый хост. Отладка этого обычно делается при помощи pdb
, так как большая часть
такого кода выполняется локально.
Ansible является частью программного обеспечения, а программное обеспечение подвержено поломкам; причём важно не то что оно ломается, а важно когда. Неверный ввод, ненадлежащие предположения и неожиданные среды, это все те моменты, которые могут повлечь к разочоровывающей ситуации когда задачи и воспроизведения не работают как ожидалось. Самостоятельный анализ и отладка являются технологиями выявления неисправностей, которые способны быстро превратить разочарование в восторг при выявлении корня зла.
В этой главе мы изучили как заставить Ansible выполнять регистрацию своих действий в некий файл, а также как изменять уровень подробностей вывода Ansible. Далее мы изучили как инспектировать переменные чтобы гарантировать что их значения в том значении что мы ожидали прежде чем переходить к подробной отладке кода Ansible. Более того, мы прошли процесс вставки точек прерывания в код ядра Ansible и выполнения сеансов как локальной, так и удалённой отладки с применением стандартных инструментов Python.
В своей следующей главе мы изучим как расширять функциональность Ansible написанием собственных модулей, подключаемых модулей и источников учёта ресурсов.