Написание apply-скрипта

В парадигме, используемой фреймворком ram для написания конфигурационных юнитов действия сохранения настроек (store) и применения настроек (apply) разделены.

Смысл действия apply – примененить сохраненную конфигурацию к запущенной системе без перезагрузки. Чаще всего это означает перезапуск соответствующих сервисов.

Для удобства действия apply могут быть реализованы с помощью языка сценариев shell.

1) Перезапуск сервисов:

В качестве первоначальной реализации сервиса apply можно использовать скрипт безусловно перезапускающий нужный сервис.

Например, в системе CentOS-6 сервисы sshd и network управляются скриптами sysv с помощью утилиты service. Соответсвенно, скрипты apply для этих сервисов могут быть реализованы следующим образом:

#!/bin/sh

service sshd restart
#!/bin/sh

service network restart

В системе CentOS-7 большинство сервисов управляется с помощью systemd. Тем не менее, systemd поддерживает совместимость и предоставляет команду service.

2) Перезапуск в зависимости от состояния:

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

В зависимости от реализации sysv-скрипта для такого сервиса выполнение команды restart может привести либо к ошибке, либо к невостребованному запуску сервиса. Для исключения таких ситуаций рекомендуется использовать команду condrestart соответствующего sysv-скрипта:

#!/bin/sh

service sshd condrestart

В случае, если в sysv-скрипте нужного сервиса поддержка команды condrestart не реализована, можно воспользоваться командой status:

#!/bin/sh

if service sshd status; then
        service sshd restart
fi

В случае же, если в sysv-скрипте нужного сервиса не реализована поддержка команды condrestart и команды status – следует проанализировать реализацию сервиса, чтобы определить признаки работы сервиса. Например, в системе CentOS-6 сервис network, хоть и имеет поддержку команды status, последняя не позволяет понять был ли сервис включен или выключен. При этом реализация sysv-скрипта создает файл /var/lock/subsys/network при запуске сервиса и удаляет его при останове. Т.о. для проверки состояния сервиса network можно воспользоваться проверкой наличия этого файла:

#!/bin/sh

if [ -f /var/lock/subsys/network ]; then
        service network restart
fi

В системе CentOS-7 сервис network по прежнему реализован в качестве sysv-скрипта и этот код остается функциональным. Однако большинство демонов теперь управляются через systemd юниты. Создание файлов в /var/lock/subsys/ для таких демонов не практикуется. В качестве более переносимого механизма можно ориентироваться на pid-файлы нужных демонов. Для некоторых systemd юнитов потребуются правки для включения pid-файлов.

3) Перезапуск в зависимости от измениний:

Другим аспектом, который следует принять во внимание при написании скриптов apply – избыточность перезапуска сервисов в том случае, если конфигурация фактически не была изменена. Особенно важно учитывать этот аспект для сервисов, работа которых не должна прерываться без необходимости.

Если нужный сервис поддерживает действие reload (переконфигурация запущенного демона без перезапуска сервиса), следует воспользоваться этой функциональностью:

#!/bin/sh

if service sshd status; then
        service sshd reload
fi

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

Для примера можно рассмотреть сервис network и его конфигурационный файл – /etc/sysconfig/network. С помощью операций -ot (older than)/-nt (newer than) команды test можно сравнить даты модификации двух файлов. В случае сервиса network дата модификации конфигурационного файла сравнивается с датой модификации файла /var/lock/subsys/network, создаваемого при запуске сервиса:

#!/bin/sh

if [ -f /var/lock/subsys/network \
        -a /var/lock/subsys/network -ot /etc/sysconfig/network ]; then
        service network restart
fi

Следует принять во внимание, что если один из файлов в сравнении не существует – его время модификации принимается равным 0, если же оба файла учавствующих в сравнении не существуют – результат сравнения будет не определен (как -ot, так и -nt вернут ошибку).

Важно: проверка необходимости перезапуска сервиса на основе сравнения времени модификации конфигурационных файлов накладывает дополнительные требования к реализации скриптов store. Следует реализовывать эти скрипты таким образом, чтобы при отсутствии логических измений не происходило обновления конфигурационных файлов. Стандартные классы для работы с файлами ini и env из библиотеки ram.formats соответствуют этим требованиям.

На самом деле для конфигурации сервиса network задействовано несколько конфигурационных файлов:

/etc/sysconfig/network
/etc/sysconfig/network-scripts/ifcfg-*
/etc/sysconfig/network-scripts/route-*

Т.о. для корректной проверки необходимости перезапуска сервиса нужно проверить их все: Помимо файлов необходимо проверить также директорию /etc/sysconfig/network-scripts/, т.к. если какие-то из конфигурационных файлов были удалены – это отразится на времени изменения директории.

Следующий скрипт поочередно проверяет все указанные файлы, до тех пор пока не будет найден хотя бы один удовлетворящий условию – дата модификации конфигурационного файла больше чем дата модификации файла /var/lock/subsys/network. Если такой файл будет найден, сервис network будет перезапущен:

#!/bin/sh

if [ ! -f "/var/lock/subsys/network" ]; then
        exit 0
fi

for file in /etc/sysconfig/network \
        /etc/sysconfig/network-scripts/ \
        $(find /etc/sysconfig/network-scripts/ \
                -name 'ifcfg-*' -o -name 'route-*'); do

        if [ "/var/lock/subsys/network" -ot "${file}" ]; then
                service network restart
                break
        fi
done

4) Послесловие

В этом документе описаны методики написания скриптов apply при использовании скриптов управления сервисами на основе sysv. Тем не менее описанные методики будут актуальны и для других систем управления сервисами (upstart, systemd, monit, …).

В общем случае следует стремиться к тому, чтобы перезапуск сервисов учитывал текущее состояние сервиса и фактическое изменений конфигурационных файлов.

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