Управление запланированными отчётами хостов через Cron

LinuxBeginner
Практиковаться сейчас

Введение

Надёжному планированию нужно больше подтверждений, чем успешный итог play. Вы развернёте защищённую программу отчётов для обычного пользователя, создадите стабильную именованную запись cron, увидите естественные выполнения, обновите её фазу и удалите отдельную временную запись. Итоговая проверка увидит новый запуск планировщика при сохранении постороннего существующего задания.

Разверните отчёт обычного пользователя и именованное расписание

На этом шаге вы развернёте предоставленную программу отчётов и запланируете её для пользователя automation на обоих управляемых хостах.

Cron установлен, и его демон уже работает как предварительное условие. Узлы не запускают systemd. В каждом crontab automation также есть посторонняя запись keep-existing-report; сохраните её. Модуль cron управляет стабильной именованной записью вместо замены всего crontab пользователя.

Перейдите в проект и изучите предоставленную программу управляющего узла:

cd /home/labex/project
cat files/host-report.sh

Программа добавляет временную метку UTC epoch, настоящее имя хоста и аргумент фазы в защищённый управляемый журнал. Umask 027 даёт новым файлам журнала права 0640. Оставьте программу неизменной и позвольте cron запускать её естественным образом; ручной вызов не демонстрировал бы расписание.

Определите фазу как многократно используемые входные данные:

cat > group_vars/all.yml <<'YAML'
report_phase: initial
YAML

Создайте плейбук. У задания cron есть поля минуты, часа, дня месяца, месяца и дня недели; звёздочка в каждом поле означает запуск раз в минуту. Имя создаёт маркер Ansible для последующих обновлений, а user automation выбирает crontab этого пользователя. Become позволяет управлять расписанием указанного пользователя и явным владельцем файлов; он не заставляет запланированную программу работать от root.

cat > reporting.yml <<'YAML'
- name: Manage a scheduled ordinary-user host report
  hosts: all
  gather_facts: false
  become: true
  tasks:
    - name: Prepare the ordinary user's reporting directory
      ansible.builtin.file:
        path: /home/automation/reporting
        state: directory
        owner: automation
        group: automation
        mode: "0750"

    - name: Deploy the supplied report program
      ansible.builtin.copy:
        src: /home/labex/project/files/host-report.sh
        dest: /home/automation/reporting/host-report.sh
        owner: automation
        group: automation
        mode: "0750"

    - name: Keep the named report schedule present
      ansible.builtin.cron:
        name: ansible-host-report
        user: automation
        minute: "*"
        hour: "*"
        day: "*"
        month: "*"
        weekday: "*"
        job: "/home/automation/reporting/host-report.sh {{ report_phase }}"
YAML

Проверьте и примените:

ansible-playbook reporting.yml --syntax-check
ansible-playbook reporting.yml

Изучите фактические crontab automation. Команда выполняется с become, чтобы явно указать запрашиваемую учётную запись:

ansible all -b -m ansible.builtin.command -a 'crontab -u automation -l'

Каждый должен содержать один маркер ansible-host-report и команду ежеминутного запуска плюс неизменную запись keep-existing-report. Одна строка crontab не доказывает выполнение.

Дождитесь первого естественного срабатывания планировщика. timeout ограничивает ожидание 90 секундами; цикл until в bash проверяет непустой журнал каждые две секунды. Команда только читает состояние, пока cron создаёт журнал:

ansible all -m ansible.builtin.command -a "timeout 90 bash -c 'until test -s /home/automation/reporting/host-report.log; do sleep 2; done'"
ansible all -m ansible.builtin.command -a 'cat /home/automation/reporting/host-report.log'

В каждом должна быть запись вроде time= host=web1 phase=initial с соответствующим настоящим именем хоста на web2. Временные метки различаются и должны согласовываться с естественным поминутным расписанием. Если ограниченное ожидание неуспешно, изучите расписание и работающий демон вместо самостоятельной записи успешного журнала.

Обновите одну именованную запись и увидьте новую фазу

На этом шаге вы измените входное значение задания, сохраняя его стабильный идентификатор и постороннее расписание.

Обновите сохранённое значение фазы. Задача cron сформирует новую команду, сохраняя то же имя:

cat > group_vars/all.yml <<'YAML'
report_phase: verified
YAML
ansible-playbook reporting.yml

Снова изучите оба crontab:

ansible all -b -m ansible.builtin.command -a 'crontab -u automation -l'

На каждом хосте по-прежнему должна быть ровно одна запись ansible-host-report, теперь заканчивающаяся на verified. Повторное использование имени обновляет существующую запись вместо накопления второго расписания. Keep-existing-report должен остаться неизменным.

Дождитесь нового естественного запуска с обновлённой фазой. grep -q проверяет совпадающую запись журнала без её вывода; timeout и цикл until ограничивают ожидание:

ansible all -m ansible.builtin.command -a "timeout 90 bash -c 'until grep -q phase=verified /home/automation/reporting/host-report.log; do sleep 2; done'"
ansible all -m ansible.builtin.command -a 'cat /home/automation/reporting/host-report.log'

Теперь оба должны содержать новую запись phase=verified от настоящего планировщика. Старые записи initial — полезная история, их следует сохранить. Обновление команды crontab не меняет старые строки журнала задним числом.

Удалите только именованное временное задание и сохраните стабильность отчётов

На этом шаге вы удалите временное расписание по стабильному имени и проверите, что нужный отчёт обычного пользователя продолжает выполняться.

Создайте безвредную именованную временную запись задачей cron ad hoc. Она планирует /usr/bin/true на полночь и предоставляет настоящую запись для удаления:

ansible all -b -m ansible.builtin.cron -a 'name=ansible-temporary-report user=automation minute=0 hour=0 job=/usr/bin/true'
ansible all -b -m ansible.builtin.command -a 'crontab -u automation -l'

Напишите небольшой плейбук очистки. State absent и совпадающие name/user удаляют только эту управляемую запись. Не очищайте и не заменяйте весь crontab:

cat > cleanup.yml <<'YAML'
- name: Remove only the obsolete named schedule
  hosts: all
  gather_facts: false
  become: true
  tasks:
    - name: Remove the obsolete report entry by its stable name
      ansible.builtin.cron:
        name: ansible-temporary-report
        user: automation
        state: absent
YAML
ansible-playbook cleanup.yml
ansible all -b -m ansible.builtin.command -a 'crontab -u automation -l'

Временный маркер и команда должны исчезнуть. И ansible-host-report с фазой verified, и keep-existing-report должны остаться.

Повторите оба объявления:

ansible-playbook reporting.yml
ansible-playbook cleanup.yml

Оба плейбука должны сообщать changed=0, unreachable=0 и failed=0 для обоих хостов. Cron может независимо продолжать добавлять записи журнала; эти естественные записи времени выполнения не делают декларативное развёртывание неидемпотентным.

Итоговая проверка изучает именованные задания обычного пользователя, точно развёрнутую программу и защищённые журналы, затем ожидает ещё одного естественного срабатывания планировщика на обоих хостах. Это может занять около минуты. Оставьте расписание отчёта и демон работающими, чтобы это наблюдение подтверждало продолжающееся выполнение, а не вручную подготовленный файл успеха.

Резюме

Вы управляли стабильными именованными записями cron для нужного обычного пользователя, увидели настоящее выполнение по расписанию, обновили входное значение команды без дублирования задания и удалили только временную запись. Явные права программы/журнала и сохранённые посторонние расписания оставили область действия ясной. Развёртывание повторилось без изменений, пока отчёт продолжал выполняться естественным образом.