После долгих поисков я пришел к выводу, что ansible (я использую последнюю стабильную на данный момент версию, v2.5.3), скорее всего, не поддерживает регистрацию переменных или уведомлений от операторов include_role и import_role.
Есть аналогичный вопрос здесь и предложение в одном из ответов: Each individual task within your include file can register variables, and you can reference those variables elsewhere.
Однако, если я последую этому предложению, мне нужно будет добавить дополнительный ненужный код во все мои включенные роли просто потому, что мне может потребоваться обходной путь на сервере специальный. Все может быстро выйти из-под контроля и стать беспорядочным, особенно в случае включения вложенных ролей (т. Е. Когда включенная роль содержит больше включенных ролей). Более того, если я использую роли из ansible-galaxy, я бы хотел придерживаться исходных версий (рассматривать роли как внешние библиотеки), а это означает, что в идеале я не хотел бы изменять код роль, поскольку это не очень интуитивно чтобы поддерживать форки всех ролей, которые нужно использовать (иначе внешние роли / библиотеки в значительной степени потеряет свое значение).
Итак, каково предлагаемое решение такой проблемы, когда кто-то хочет повторно использовать код из внешних ролей, и в зависимости от того, произошло ли какое-либо изменение вызываемой роли, что-то сделать? Я совершенно неправильно думаю о том, как я реализовал свою логику доступного playbook?
Взгляните на следующий конкретный пример того, что я пытаюсь сделать:
У меня есть разделенные задачи, которые я хочу повторно использовать в меньших ролях. В моей роли common у меня есть набор задач add-file.yml, который выглядит следующим образом (roles/common/tasks/add-file.yml):
- name: Copying file "{{ file.src }}" to "{{ file.dest }}"
copy:
src: "{{ file.src }}"
dest: "{{ file.dest }}"
owner: "{{ file.owner | default(ansible_user_id) }}"
group: "{{ file.group | default(ansible_user_id) }}"
mode: "{{ file.mode | default('preserve') }}"
when:
file.state is not defined or file.state != 'absent'
- name : Ensuring file "{{ file.dest }}" is absent
file:
path: "{{ file.dest }}"
state: "{{ file.state }}"
when:
- file.state is defined
- file.state == 'absent'
По сути, это общая настраиваемая задача для поддержки state: absent для копирования файлов до тех пор, пока не будет исправлен эта ошибка.
Затем в другой роли (назовем ее setup-XY) я делаю это в файле roles/setup-XY/tasks/main.yml:
- name: Copying X-file
import_role:
name: common
tasks_from: add-file.yml
vars:
file:
state: present
src: X-file
dest: /home/user/X-file
mode: '0640'
- name: Ensuring Yline in Z-file
lineinfile:
dest: /etc/default/Z-file
regexp: '^Yline'
line: 'Yline=123'
Затем в третьей роли (назовем ее z-script) я хочу что-то вроде этого в файле roles/z-script/tasks/main.yml:
- name: Setup-XY
include_role:
name: setup-XY
register: setupxy
- name: Run Z script if setupXY changed
shell: /bin/z-script
when: setupxy.changed
К сожалению, это не работает, поскольку строка register: setupxy регистрирует переменную setupxy, которая всегда возвращает "changed": false. Если я использую import_role вместо include_role, переменная вообще не регистрируется (остается неопределенной).
Обратите внимание, что в роли z-script я хочу запускать команду оболочки /bin/z-script всякий раз, когда обнаруживается какое-либо изменение в роли setup-XY, то есть если были изменены X-file или Z-file, и на самом деле у меня может быть гораздо больше задач в роли setup-XY.
Более того, обратите внимание, что z-script не связан с ролью setup-XY (например, z-script должен работать только на определенном сервере проблемный), поэтому код для выполнения z-script в идеале не должен поставляться вместе с ролью setup-XY (и загрязнять ее). Посмотрите на setup-XY как на внешнюю / восходящую роль в этом случае.
Извините, но ответ, который вы уже прочитали, действителен, независимо от того, насколько он вам не нравится. Также вопросы о передовой практике считаются слишком общими / требуют мнений многими пользователями SO, поэтому постарайтесь задавать четко определенные вопросы по программированию.
@techraf Я думаю, что ОП поднял веский вопрос. Кроме того, процитированному вопросу более двух лет, что само по себе дает основание искать альтернативы. Я не вижу необходимости торопиться с вашим комментарием.
@jangroth ① SO не для того, чтобы поднимать действительные баллы, а для того, чтобы задавать вопросы, как определено в Справочном центре и решено сообществом. ② На вопросы нет ограничения по времени, можно добавить ответ под 2-х лет. вопрос, если он у вас есть. ③ Я закрыл вопрос как дубликат и объяснил OP причину. Я не знаю, что в этом «резкого», почему вы почувствовали необходимость называть это так и чего вы хотели этим достичь.
@techraf Существующий вопрос, который я уже включил в свой вопрос, очень ограничен, и это не значит, что мне просто не нравится ответ; Существующий ответ просто не является решением того, что я спрашиваю и подробно описал в этом вопросе. Во всяком случае, я немного обновил вопрос и больше не прошу best practices. Теперь более конкретно. Надеюсь, вы передумаете и снова откроете этот вопрос. Спасибо.
Ответ (который хорошо написан и ни в коем случае не является «очень ограничен») для dup-target содержит простой и действительный ответ на ваш вопрос: Короткий ответ: это невозможно.. С вашими последующими правками («Не надо трогать код роли.») вам даже не нужно читать дальше.
Что касается не следует трогать код роли, ответьте мне, пожалуйста, на один вопрос. Когда вы используете роли из ansible-galaxy, вы детализируете детали, вносите ли они изменения и пытаетесь сохранить свои собственные вилки ролей, которые вы используете? Звучит не очень интуитивно. Если кому-то приходится это делать, значит, что-то идет не так, и роли теряют свое значение. Это похоже на попытку использовать библиотеку, но перед ее использованием вам предлагается изменить код библиотеки. Дело не в том, что вы не можете этого сделать, но должен быть какой-то способ достичь того, чего вы хотите, изменив свой собственный код, а не код библиотеки.
@VangelisTasoulas Это именно та проблема, с которой я столкнулся сейчас ... Есть обновления по этому поводу? По-прежнему невозможно запустить собственный обработчик при изменении задачи, произошедшей в рамках чьей-либо роли, используемой в игре?
@Drew Я уже некоторое время серьезно не работаю с ansible, и у меня до сих пор нет решения этой проблемы :(

Ты не сможешь это сделать. Вы должны понимать, что роли подобны функциям в других языках. Вы не можете полагаться на то, что происходит внутри.
Вот почему обработчики можно использовать только в текущем контексте, роли или сценарии, и вы не можете их перекрестно вызывать.
Привет, хороший вопрос. Я могу рассматривать Ansible как серию или пьесу, вызывающую роли (для меня роль - это многократно используемый и стандартный способ распространения кода Ansible). Импорт или включение ролей в другую роль - это не способ использования Ansible, IMHO. У нас есть мета для определения зависимостей ролей и сценарии для их оркестровки. По моему опыту работы с Ansible, я обнаружил, что эти роли с определенными переменными и вызовами других внешних ролей, игр, задач и т. д. Неуправляемы. Почему бы не делать из основного сценария?