Введение
Существующие программы обслуживания требуют внимательной интеграции с декларативной автоматизацией. Вы разберётесь в различиях command, shell и script, безопасно передадите путь с пробелом, классифицируете результаты чтения и защитите настоящий результат сценария условием запуска. Конвейер и делегированные квитанции управляющего узла сделают место выполнения и распространение сбоев наблюдаемыми. Вы также вызовете настоящий сбой отсутствующего входного файла и восстановите работу.
Выполните прямую команду с безопасными аргументами
На этом шаге вы изучите управляемые входные данные через command, сохраните путь с пробелом и правильно классифицируете операцию чтения.
Предпочитайте декларативные модули, например copy и file, для управления состоянием. Command, shell и script полезны при интеграции существующего исполняемого файла или программы обслуживания. command запускает управляемый исполняемый файл без оболочки, поэтому конвейеры и перенаправления не интерпретируются. Его форма argv сохраняет каждый аргумент отдельно, включая путь с пробелами.
На каждом подготовленном целевом узле есть /home/automation/maintenance input.txt с одной строкой утверждённых данных и предварительное условие maintenance-ready. Управляющий узел предоставляет существующий сценарий внутри scripts/ для дальнейшего использования. Сохраните эти входные данные.
Перейдите в проект управляющего узла:
cd /home/labex/project
Создайте плейбук с argv. Путь с пробелом — одна запись списка YAML. register сохраняет результат исполняемого файла, включая stdout и числовой код возврата rc. Ноль обычно означает успех; ненулевой код возврата команды обычно приводит к сбою задачи.
cat > maintenance.yml <<'YAML'
- name: Inspect maintenance inputs safely
hosts: all
gather_facts: false
tasks:
- name: Read the managed input with a space-safe argument list
ansible.builtin.command:
argv:
- /usr/bin/cat
- /home/automation/maintenance input.txt
register: input_result
changed_when: false
- name: Retain the inspected input in a managed record
ansible.builtin.copy:
dest: /home/automation/command-result.txt
content: "{{ input_result.stdout }}\n"
mode: "0640"
YAML
Команда cat только читает данные, поэтому changed_when false классифицирует её результат как отсутствие изменений. Эта настройка меняет отчётность, а не фактические действия команды; её нельзя использовать для сокрытия изменений программы, меняющей состояние. Задача copy использует возвращённый stdout и записывает настоящую управляемую запись с явным завершающим переводом строки.
Проверьте и запустите плейбук:
ansible-playbook maintenance.yml --syntax-check
ansible-playbook maintenance.yml
Обе задачи чтения должны сообщить ok, а первое копирование записи изменяет каждый целевой узел. Изучите фактические записи:
ansible all -m ansible.builtin.command -a 'cat /home/automation/command-result.txt'
Каждая должна содержать Approved maintenance data. В этой версии core command может раскрывать аргументы переменных окружения через Python, хотя не вызывает оболочку. Используйте expand_argument_vars false, когда нужны буквальные аргументы с префиксом доллара; для этого фиксированного пути это не требуется.
Передайте сценарий управляющего узла и защитите его настоящий результат условием запуска
На этом шаге вы вызовете предоставленный сценарий обслуживания управляющего узла на обоих целевых узлах и избежите ненужного повторного выполнения.
Изучите предоставленную программу перед запуском:
cat scripts/host-maintenance.sh
Она проверяет входной файл maintenance-ready целевого узла до создания любого результата. Отсутствие готовности выводит ошибку и завершает работу с кодом 42. Иначе она записывает защищённый отчёт с фактическим именем целевого хоста и аргументом метки. Небольшая реализация на shell — существующие входные данные интеграции; для обычной настройки файлов используйте декларативные модули.
Модуль script передаёт источник управляющего узла на целевой узел и выполняет его там. Это отличается от command, чей исполняемый файл должен уже существовать на управляемом узле. Метка в кавычках ниже остаётся одним аргументом с пробелом. Путь creates проверяется на управляемом целевом узле: когда этот отчёт уже существует, сценарий пропускается.
Добавьте задачу script:
cat >> maintenance.yml <<'YAML'
- name: Run the supplied controller script once per target report
ansible.builtin.script:
cmd: /home/labex/project/scripts/host-maintenance.sh 'Maintenance checked'
creates: /home/automation/maintenance-run/report.txt
register: maintenance_result
failed_when: maintenance_result.rc is defined and maintenance_result.rc != 0
YAML
rc зарегистрированного результата управляет failed_when. Проверка is defined учитывает результат, не содержащий кода возврата выполнения. Не используйте ignore_errors или failed_when false, чтобы превратить настоящий сбой сценария в видимый успех.
Запустите расширенный плейбук:
ansible-playbook maintenance.yml
Оба целевых узла должны создать отчёты. Прочитайте настоящие результаты:
ansible all -m ansible.builtin.command -a 'cat /home/automation/maintenance-run/report.txt'
Каждый должен содержать собственное имя хоста и label=Maintenance checked. Повторите тот же плейбук:
ansible-playbook maintenance.yml
Сценарий должен пропускаться, поскольку его целевой отчёт существует, а оба итога — сообщать changed=0 без неуспешных/недоступных целевых узлов. Creates — условие существования, а не механизм согласования содержимого: он не исправляет повреждённый существующий отчёт и не создаёт его заново автоматически при изменении входных данных сценария.
Распространяйте сбои и делегируйте квитанции управляющему узлу
На этом шаге вы используете shell только для настоящего конвейера, сохраните отдельные квитанции управляющего узла и проверите видимый сбой сценария без подавления.
Конвейер соединяет вывод одной команды со вводом другой, поэтому ему нужна оболочка. Bash pipefail заставляет сбой команды конвейера приводить к сбою вместо того, чтобы успешная последняя команда wc скрывала его. Конвейер ниже только считает строки входных данных; changed_when false уместен, поскольку он читает без изменения состояния целевого узла. failed_when также отклоняет неожиданное число строк.
Создайте каталог квитанций управляющего узла. Каждая делегированная задача copy будет использовать исходное имя инвентаря в отдельном имени файла, не позволяя хостам перезаписывать одну общую квитанцию:
mkdir -p receipts
Добавьте задачи конвейера и квитанции. delegate_to localhost выполняет только задачу квитанции на управляющем узле; inventory_hostname по-прежнему обозначает исходный целевой узел. become false сохраняет создание файла управляющего узла под обычной учётной записью labex.
cat >> maintenance.yml <<'YAML'
- name: Count managed input lines with explicit pipeline failure propagation
ansible.builtin.shell: |
set -o pipefail
cat '/home/automation/maintenance input.txt' | wc -l
args:
executable: /bin/bash
register: line_result
changed_when: false
failed_when: line_result.rc != 0 or (line_result.stdout | trim) != '1'
- name: Store a per-target receipt on the controller
ansible.builtin.copy:
dest: "/home/labex/project/receipts/{{ inventory_hostname }}.txt"
content: |
host={{ inventory_hostname }}
input_lines={{ line_result.stdout | trim }}
mode: "0640"
delegate_to: localhost
become: false
YAML
Запустите полный процесс обслуживания:
ansible-playbook maintenance.yml
Изучите обе квитанции управляющего узла. Каждая должна обозначать собственный исходный хост и input_lines=1:
cat receipts/web1.txt receipts/web2.txt
Теперь проверьте настоящую ветвь сбоя сценария на web1. Удалите его отчёт, используемый условием запуска, и входной файл готовности модулем file; это намеренные временные изменения внутри учебного узла:
ansible web1 -m ansible.builtin.file -a 'path=/home/automation/maintenance-run/report.txt state=absent'
ansible web1 -m ansible.builtin.file -a 'path=/home/automation/maintenance-ready state=absent'
Следующий запуск должен завершить задачу сценария сбоем на web1 с rc 42 и сообщением об отсутствующем входном файле. || позволяет продолжить работу в терминале после этого ожидаемого ненулевого выхода плейбука; он не меняет классификацию сбоя Ansible:
ansible-playbook maintenance.yml || printf 'Expected missing-readiness failure\n'
Изучите путь отчёта; у web1 не должно быть вымышленного успешного отчёта после сбоя сценария:
ansible web1 -m ansible.builtin.stat -a 'path=/home/automation/maintenance-run/report.txt'
Восстановите входной файл готовности из точного источника управляющего узла и повторно запустите полный процесс:
printf 'Ready\n' > ready.txt
ansible web1 -m ansible.builtin.copy -a 'src=/home/labex/project/ready.txt dest=/home/automation/maintenance-ready mode=0644'
ansible-playbook maintenance.yml
Web1 должен успешно создать отчёт заново. Последнее повторение не должно иметь изменений, недоступных целевых узлов и сбоев:
ansible-playbook maintenance.yml
Обследования только для чтения по-прежнему выполняются, сценарий с условием запуска пропускает существующие отчёты, а каждая делегированная квитанция остаётся на управляющем узле. Это сохраняет реальные сигналы ошибок, делая успешное повторное выполнение стабильным.
Резюме
Вы использовали argv для прямого управляемого выполнения, script для передачи программы с управляющего на целевой узел и shell только для настоящего конвейера с явным распространением сбоев. Отчётность о чтении без изменений, настоящее условие creates и неподавленные коды выхода сохранили значимость результатов. Делегированные квитанции каждого хоста показали выполнение на управляющем узле, а упражнение с отсутствующим входным файлом завершилось восстановленным стабильным процессом.


