РАШИД АЧИЛОВ, поклонник FreeBSD с 14-летним опытом использования ее в совмещенных с Windows сетях и сторонник Open Source. Администратор сетей и средств защиты крупной торговой сети
Один UPS на двоих
FreeBSD в домене Windows
Ситуация, когда к одному UPS подключено несколько серверов, – не исключение, а скорее правило. Как вовремя отключить сервер, если программа для работы с данным UPS существует только для Windows?
И вольт 220 – и то пополам...
На сегодняшний день существует широкий диапазон устройств, способных обеспечивать резервное питание серверов в той мере, в которой это необходимо. Далеко не ко всем устройствам (а точнее говоря только к UPS производства APC [1]) существуют клиенты под FreeBSD, позволяющие принимать по сети сообщения от сетевых UPS и соответственно обрабатывать их. Как поступить в том случае, если имеется только клиент под Windows, а необходимо запрограммировать реакцию на сообщение UPS о том, что необходимо прервать работу в связи с пропаданием питания?
Моделировать ситуацию будем в следующих условиях – имеется UPS Powerware 9120 [2], к которому подключены компьютер под управлением Windows и компьютер под управлением FreeBSD. Управление UPS осуществляется через поставляемый вместе с UPS кабель RS-232 с компьютера с ОС Windows, на котором установлено программное обеспечение LanSafe. LanSafe можно бесплатно скачать непосредственно с сайта производителя [2]. Требуется – при долговременном пропадании питания вместе с корректным завершением работы сервера под управлением ОС Windows корректно завершать работу сервера под управлением FreeBSD.
Задача эта на самом деле решается достаточно просто в том случае, когда программное обеспечение для управления UPS имеет возможность по наступлению некоторого события выполнять определенную внешнюю команду. Уже упомянутый выше LanSafe имеет возможность на каждое событие (а их достаточно много) настроить три вида реакции – оповещение по почте, оповещение широковещательным сообщением и выполнение внешней команды, причем все виды реакции можно настраивать независимо друг от друга.
Таким образом, обработка события Power failure (пропадание напряжения питания), которое возникает в том случае, если исчезает напряжение питания, будет происходить согласно следующей схеме (см. рис. 1).
Рисунок 1. Последовательность обработки события UPS для двух серверов
Для реализации данной схемы нам понадобится, кроме самого LanSafe:
- Для Windows – программа удаленного выполнения команд по протоколу SSH plink.exe и программа генерации ключей SSH (входят в состав бесплатного SSH-клиента PuTTY, скачать можно с [3]).
- Для FreeBSD – программа выполнения команды от имени другого пользователя sudo (ports/security/sudo) и SSH-сервер для приема и обработки команды. Можно использовать стандартный OpenSSH, но я предпочитаю сервер от SSH Communication Inc. (ports/security/ssh2-nox11).
Итак, в общем случае задача может быть сформулирована так: «Как из одной программы запустить другую на удаленном сервере». Сформулировав же задачу в общем виде, переходим к частностям.
Частности
Подробности реализации мы начнем рассматривать с последнего звена цепочки – с сервера FreeBSD. Чтобы отправить на него команду, необходимо, чтобы кто-то эту команду принял. Этот «кто-то» будет у нас псевдопользователем (то есть пользователем, не имеющим пароля, но имеющим допустимый шелл) upsadmin.
Создаем учетную запись пользователя:
# pw useradd upsadmin -d /usr/home/upsadmin -m -s /bin/sh -c "UPS administrator" -h -
В случае успешного завершения команда pw не выводит ничего. Переключаемся на учетную запись этого пользователя (то, что все это выполняется от пользователя root, я думаю, упоминать излишне) и настраиваем SSH для использования беспарольной авторизации по публичному ключу:
# su -l upsadmin
# ssh-keygen2 -t dsa
Generating 2048-bit dsa key pair
3 o.oOo..oOo.o
Key generated.
2048-bit dsa, upsadmin@citycat.shelton.net, Wed Oct 28 2009
00:37:39 +0600
Passphrase :
Again :
Key is stored with NULL passphrase.
(You can ignore the following warning if you are generating hostkeys.)
This is not recommended. Don't do this unless you know what you're doing.
If file system protections fail (someone can access the keyfile),
or if the super-user is malicious, your key can be used without
the deciphering effort.
Private key saved to /usr/home/upsadmin/.ssh2/id_dsa_2048_a
Public key saved to /usr/home/upsadmin/.ssh2/id_dsa_2048_a.pub |
Предупреждение о возможном нарушении политики безопасности, при которой каждый личный ключ из пары ключей должен быть защищен паролем (а иначе злоумышленник, получивший доступ к нему, сможет им воспользоваться), игнорируем – мы не будем пользоваться собственными ключами пользователя upsadmin.
Переходим в каталог .ssh2 (он будет создан автоматически) и создаем два пустых файла – identification и authorization.
В файл identification прописываем строку:
IdKey id_dsa_2048_a
Файл authorization пока не трогаем, он нам понадобится потом.
Далее наделяем пользователя upsadmin правами на выключение и перезагрузку компьютера. Устанавливаем пакет sudo, если он не установлен, и прописываем в файле /usr/local/etc/sudoers (он будет автоматически создан и заполнен примерами) следующие строки:
# Cmnd alias specification
Cmnd_Alias SHUTDOWN = /sbin/shutdown
Cmnd_Alias HALT = /sbin/halt
Cmnd_Alias REBOOT = /sbin/reboot
Cmnd_Alias IPFW = /sbin/ipfw
# UPS remote command executor
upsadmin ALL=(root) NOPASSWD: SHUTDOWN, NOPASSWD: HALT, NOPASSWD: REBOOT, NOPASSWD: IPFW
Последняя команда (IPFW) нам понадобится только для тестирования, после того как все будет отлажено, ее можно и нужно убрать. Что мы описали данными строками? Мы описали, что при выполнении через sudo команд shutdown, halt, reboot и ipfw пользователь upsadmin по уровню привилегий равен администратору (root) и при выполнении этих команд ему нет необходимости вводить свой пароль.
Проверяем.
# su -l upsadmin
$ sudo ipfw sh
ipfw: DEPRECATED: 'sh' matched 'show' as a sub-string
… (вывод удален)
65000 0 0 allow ip from any to any
65535 457 45540 deny ip from any to any |
Отлично. Теперь создадим предыдущий элемент схемы – скрипт, который будет выдавать команду выключения питания. Выполняться этот скрипт будет от пользователя upsadmin. Для того чтобы не указывать расположение скрипта, просто создадим в домашнем каталоге пользователя upsadmin каталог bin.
Почему именно bin? Мы указали /bin/sh в качестве стартового шелла. При запуске /bin/sh автоматически выполняется его стартовый скрипт – файл .profile в домашнем каталоге пользователя (подробнее – man sh). Файл .profile, как правило, содержит следующую строку:
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/
sbin:/usr/local/bin:/usr/X11R6/bin:$HOME/bin; export PATH
Эта строка определяет, где /bin/sh будет искать программу в том случае, если она запускается без указания пути. Проверьте, что PATH содержит $HOME/bin. Разумеется, можно создать каталог с другим именем и указать его имя в PATH или вообще не создавать ничего и каждый раз указывать полный путь.
Сам скрипт – это всего лишь две строчки:
#!/bin/sh
logger -i -p local6.info -t lansafe Shutdown started
sudo shutdown -p now
Первая строка добавлена исключительно для удобства – при выполнении скрипта всякий раз в файл, определяемый /etc/syslog.conf как local6, будут записываться сообщения о причине выключения. Предварительно необходимо определить в /etc/syslog.conf facility local6, например, следующим образом:
local6.* /var/log/powerdown
При этом все сообщения с facility local6 будут направляться в файл /var/log/powerdown. Строго говоря, пример не совсем корректный, так как в этот файл могут быть направлены сообщения от любой программы, присвоившей своим сообщениям facility local6. Для большей корректности следовало бы написать так:
!lansafe
local6.* /var/log/powerdown
Ну вот, теперь достаточно запустить скрипт powerdown (так называется файл скрипта) – питание будет выключено. Переходим еще левее по схеме – к скрипту, выполняемому на Windows. Вот здесь нам и понадобится заполнить файл authorization в каталоге .ssh2. Прописываем в него такую строчку:
Key winbox.pub
Прописывается сюда имя файла публичного ключа, по которому будет выполняться авторизация. Файл этот, разумеется, сначала должен быть создан. Причем именно на том компьютере, с которого будет запускаться команда, в нашем случае на том, к которому подключен UPS. Вот для этого нам и понадобится программа puttygen.exe, которая в PuTTY играет роль, аналогичную команде ssh2-keygen, Запускаем и создаем личный и общий ключи (см. рис. 2).
Рисунок 2. Создание пары ключей с помощью программы puttygen.exe
Сохраняем файлы winbox.ppk (приватный ключ) и winbox.pub (публичный ключ). Пароль на приватный ключ не устанавливаем. Мы используем авторизацию по публичному ключу только для того, чтобы избежать задания паролей в открытом тексте. Какой же нам смысл задавать пароль на ключ, который все равно потребуется указывать в открытом виде?
Файл winbox.pub распространяем свободно – в частности, его нужно поместить в подкаталог .ssh2 домашнего каталога пользователя upsadmin на сервере FreeBSD. Файл же winbox.ppk оберегайте насколько возможно – именно он является аналогом пароля. Хищение приватного ключа, не защищенного паролем, автоматически означает, что любой сможет выдать себя за лицо, которое этим ключом авторизуется. Разумеется, это недостаток данного способа, но... за удобство надо чем-то платить?
После этого мы можем, запуская программу plink.exe, выполнять команды на сервере FreeBSD от имени того пользователя, которое указываем, в нашем случае upsadmin (см. рис. 3):
echo "Testing connection on UNIX server..."
plink.exe -ssh -P 22 -2 -i winbox.ppk upsadmin@192.168.1.1 ls -la
Подробно все ключи к команде plink описаны в документации на PuTTY – файле putty.chm.
Рисунок 3. Выполнение команды из среды Windows на удаленном сервере
Создаем для файлов отдельный каталог, например c:upsmgmt, и переносим в него все файлы, что нам понадобятся: приватный ключ winbox.ppk, программу plink.exe. Сюда же можно положить и публичный ключ winbox.pub.
И наконец, пишем собственно сам скрипт:
с:
cd upsmgmt
plink.exe -ssh -P 22 -2 -i winbox.ppk upsadmin@192.168.1.1 "powerdown"
Относительно этого скрипта следует сделать несколько замечаний.
- Во-первых, когда мы запускаем скрипт вручную, он запускается в том каталоге, в котором мы в данный момент находимся. Когда же скрипт будет запущен программой LanSafe, то он запустится в том каталоге, который Windows полагает «по умолчанию». Скорее всего, это не будет интересующий нас каталог, потому перед запуском команды необходимо явно указать переход в нужный нам каталог (в примере c: emp2).
- Во-вторых, powerdown – не стандартная команда FreeBSD, а имя скрипта, который мы создали на предыдущих шагах. Этот скрипт лежит в %HOME%/bin, потому путь к нему можно не указывать.
Что ж, осталось последнее. Сохраняем скрипт в файл, например testlink.bat, и помещаем его в тот каталог, в который делаем переход (в примере c:upsmgmt).
Запускаем программу LanSafe, выбираем пункт Configuration -> Event Notification и в настройках для события Power failure задаем выполнение команды c:upsmgmt estlink.bat с задержкой в 5 секунд (такая короткая задержка только для тестирования, в реальной жизни, конечно же, задержка должна быть больше) (см. рис. 4).
Рисунок 4. Настройка LanSafe на выполнение команды при пропадании питания
Все. Цепочка замкнулась. При возникновении события Power failure после заданной задержки будет запущен скрипт testlink.bat, который запустит plink.exe, который запустит powerdown на удаленном сервере, который в свою очередь запустит команду «shutdown -p now».
К особенностям поведения здесь можно отнести одну вещь – при первом запуске скрипта непосредственно самим LanSafe plink.exe выдает запрос на кэширование ключа узла (точно так же, как он это делает всегда при первом подключении). Все бы ничего, но только нужно учитывать тот факт, что запрос этот выдается исключительно на консоль сервера Windows.
Если настраивать LanSafe, находясь в терминальной сессии, запроса мы не увидим до тех пор, пока не перехватим консоль с помощью программ NetOp или Radmin, поэтому перед тем как начинать эксплуатацию системы, необходимо провести тестовый запуск, для чего в настройках LanSafe есть кнопка Test, позволяющая вручную имитировать наступление тестируемого события.
Существуют ли альтернативы описанному способу? Да, компания Eaton выпускает LanSafe не только для операционных систем Windows, но и для Linux тоже [4], в списке поддерживаемых дистрибутивов – Red Hat версии 3 (ESи AS), версии 4 и 5 (ES, AS и Desktop), Fedora Core версии 5-8 и SuSE версии 8-10 (в том числе и Enterprise Linux Server). Вполне возможно попробовать его запустить, установив модуль совместимости с Linux-программами (ports/emulators/lunux-base-f7 или ports/emulators/linux-base-f8). При этом прием оповещения от контроллера UPS настраивается стандартным способом.
***
Описанный здесь способ – это всего лишь еще одна «малая механизация», набор несложных инструментов, который один раз настраиваешь на совершение определенных действий – и про них можно навсегда забыть, скрипты будут выполняться, серверы выключаться в нужное время... И дом, который построил Джек, не рухнет, по крайней мере, из-за неверного выключения питания.
- Сайт American Power Conversion, производителя UPS APC – http://www.apcc.com.
- Сайт Eaton, производителя UPS Powerware – http://powerquality.eaton.com/Russia/?cx=67.
- Сайт программы PuTTY – http://www.putty.org.
- Ссылка для загрузки LanSafe версии 6 – http://powerquality.eaton.com/Support/Software-Drivers/Downloads/lansafe6.asp.