Предисловие
Итак, у вас есть исходный код очень нужной вам программы и некоторые количество серверов под Solaris, на которые необходимо его развернуть. Более того, для успешной компиляции нужна куча модулей Perl.
Не так давно я столкнулся с такой задачей, и, после продолжительных попыток, не могу не поделиться найденным решением.
Задача: Собрать исходный код клиента munin-node под SPARC Solaris и распространить по нескольким серверам.
Весь процесс будет описан на примере операционной системы Solaris 10 SPARC (update, мне кажется особой роли не играет, у меня был и U6, и U9) и свободного распространяего приложения munin (http://munin-monitoring.org/).
Подготовка
Для сборки пакета понадобится следующее:
- Тестовый сервер с чистой ОСью.
- Исходный код нужного приложения. У меня это будет munin-node 1.44 (на момент написания, уже была доступна версия 1.45), взятый отсюда: sourceforge.net/projects/munin/files/munin%20stable/1.4.4/munin-1.4.4.tar.gz/download
- Доступ с тестового сервера в Интернет. Либо зеркало CPAN в вашей сети. У меня был второй вариант.
- Список необходимых модулей Perl.
Вполне допускаю, что с последним пунктом могут быть проблемы. Хотя обычно разработчик явно указывает, какие модули нужны. Вся проблема в том, что разработчик вряд ли укажет о зависимостях необходимых модулей.
Сборка
Прежде всего необходимо установить модули Perl. Отчасти, именно для успешной сборки пакета, включающего в себя модули Perl, выше было указано, что необходим тестовый сервер с чистой осью. Дело в том, что все модули складируются в одном месте. Обычно это /usr/perl5/site_perl/<версия>/. Желательно, чтобы на момент установки модулей для вашей программы эта папка, как и /usr/local/perl5/<версия>/был пуст. Это облегчит процесс интеграции модулей в пакет.
Примечание: под <версия> – имеется ввиду рабочая версия Perl на сервере.
Самый простой способ – это установка с помощью CPAN.
# perl -MCPAN -e shell
cpan> install Module::Name
Нужный модуль установится, подтянув за собой все зависимости. В сети достаточно информации по CPAN, потому я опущу момент с установкой модулей. Замечу лишь, что гораздо эффективней где-нибудь у себя развернуть зеркало CPAN, чем скачивать их отдельно. Тем более, что зеркало настраивается очень быстро, и общий объем на данный момент не превышает 2гб! Ручная установка же чревата крайне долгими и неприятными поисками зависимых модулей.
Когда все модули установлены, запускаем:
# find /usr/perl5/site_perl/5.8.8/ > /tmp/perl_files
К файлу /tmp/perl_files я вернусь позже.
Теперь об исходных кодах.
Большинство сорцов позволяют при компиляции указывать путь для сборки. Иными словами, возможно указать явно, в какую директорию поместить все скомпилированные файлы.
Скомпилируем исходный код в нужную директорию (/pkg):
# make DESTDIR=/pkg # make install-common-prime DESTDIR=/pkg # make install-node DESTDIR=/pkg # make install-plugins-prime DESTDIR=/pkg
Исходный код программы munin-node скомпилирован и установлен.
Немного поясню, для чего это сделано. При обычной компиляции, без указания DESTDIR, программа установится в те директории, которые прописаны в Makefile.config. В этом случае будет тяжело собрать воедино всю информацию о том, в какие директории какие файлы были установлены.
Теперь необходимо сделать список всех файлов нашей программы:
# find /pkg -print > /tmp/files
В данном случае команда find выведет список содержимого /pkg, затем вывод команды направляется в файл /tmp/files.
После этого необходимо отредактировать файл /tmp/files, убрав из всех путей директорию /pkg.
Теперь можно установить программу, как полагается, без указания DESTDIR.
Ранее я при помощи команды find сделал файл /tmp/perl_files. Содержимое этого файла необходимо поместить в /tmp/files, причем необходимо просмотреть файл и удалить повторяющиеся строки. Строки не должны повторяться!
Можно приступать к созданию пакета. В первую очередь создаем “содержание” пакета:
# cat /tmp/files | pkgproto > /tmp/Prototype
Эта команда создаст файл /tmp/Prototype примерно подобного вида:
d none /opt 0755 root root d none /opt/munin 0755 root root d none /opt/munin/man 0755 root root d none /opt/munin/man/man3 0755 root root f none /opt/munin/man/man3/Munin::Common::TLSClient.3 0555 root root f none /opt/munin/man/man3/Munin::Common::TLS.3 0555 root root f none /opt/munin/man/man3/Munin::Common::Config.3 0555 root root f none /opt/munin/man/man3/Munin::Common::Timeout.3 0555 root root f none /opt/munin/man/man3/Munin::Common::Defaults.3 0555 root root f none /opt/munin/man/man3/Munin::Common::TLSServer.3 0555 root root f none /opt/munin/man/man3/Munin::Node::Config.3 0555 root root f none /opt/munin/man/man3/Munin::Node::Server.3 0555 root root f none /opt/munin/man/man3/Munin::Node::Service.3 0555 root root f none /opt/munin/man/man3/Munin::Node::OS.3 0555 root root f none /opt/munin/man/man3/Munin::Node::Configure::HostEnumeration.3 0555 root root f none /opt/munin/man/man3/Munin::Node::Configure::PluginList.3 0555 root root f none /opt/munin/man/man3/Munin::Node::SNMPConfig.3 0555 root root f none /opt/munin/man/man3/Munin::Node::Session.3 0555 root root f none /opt/munin/man/man3/Munin::Node::Logger.3 0555 root root f none /opt/munin/man/man3/Munin::Node::Configure::Debug.3 0555 root root f none /opt/munin/man/man3/Munin::Node::Utils.3 0555 root root f none /opt/munin/man/man3/Munin::Node::Configure::Plugin.3 0555 root root f none /opt/munin/man/man3/Munin::Node::Configure::History.3 0555 root root f none /opt/munin/man/man3/Munin::Plugin::Pgsql.3 0555 root root f none /opt/munin/man/man3/Munin::Plugin::SNMP.3 0555 root root f none /opt/munin/man/man3/Munin::Plugin.3 0555 root root d none /opt/munin/man/man1 0755 root rootf none /opt/munin/man/man1/munin-node.1 0555 root root f none /opt/munin/man/man1/munin-run.1 0555 root rootf none /opt/munin/man/man1/munindoc.1 0555 root root f none /opt/munin/man/man1/munin-node-configure.1 0555 root rootd none /opt/munin/bin 0755 root root f none /opt/munin/bin/munindoc 0555 root rootd none /opt/munin/sbin 0755 root rootf none /opt/munin/sbin/munin-run 0555 root root f none /opt/munin/sbin/munin-node-configure 0555 root rootf none /opt/munin/sbin/munin-node 0555 root root
При желании, можно отредактировать уровень доступа к каждому файлу.
Теперь в начало этого файла нужно добавить указатель на файл pkginfo, в кот��ром будет храниться информация о пакете. Также в начало можно добавить указатели на checkinstall, preinstall и postinstall, если они необходимы. Краткое описание:
- checkinstall служит для проверки перед установкой. Запускается от имени nobody. Этим скриптом можно проверить зависимости или права на директории. Если условия неудовлетворительны, скрипт закончит работу утилиты pkgadd.
- preinstall запускается от рута во время установки пакета. Этим скриптом, к примеру, можно создать пользователя для устанавливаемого пакета. Если прервать его выполнение, понадобится запустить pkgrm для удаление неудачной установки пакета.
- postinstall запускается после того, как основная часть пакета установлена. Этим скриптом, к примеру, можно создать SMF сервис, или вывести какую-либо информацию для конечного пользователя. Вариантов масса.
Все эти файлы в нашем случае должны находиться в /tmp.
Pkginfo же, в свою очередь, выглядит так:
PKG="Munin-node" NAME="Munin-node 1.44" VERSION="1.44" ARCH="sparc" CLASSES="none" CATEGORY="application" VENDOR="GNU" PSTAMP="Creator Name" EMAIL="Creator.Name@mail" BASEDIR="/"
Синтаксис для добавления pkginfo, checkinstall, preinstall и postinstall таков:
i pkginfo i checkinstall i preinstall i postinstall
Итак. Конфигурационные файлы готовы. Можно приступать к созданию пакета:
# pkgmk -o -r / -d /tmp -f Prototype
Создаем пакет, перезаписывая все предыдущие попытки (-o), используя / в качестве корневой директории (-r), собрать пакет в /tmp, используя список из файла Prototype (-f).
Теперь в /tmp можно найти каталог с собранным пакетом, пока еще не запакованный. Директория будет носить имя, указанное строке PKG в файле pkginfo. Все скрипты, если они были добавлены в Prototype, находятся в директории install. Файлы программы – в директории root. В процессе отладки установки пакета можно смело редактировать содержимое файлов. Правда при этом нужно учитывать, что контрольная сумма и размер файлов может поменяться и эти изменения необходимо отразить в файле pkgmap, в противном случае установка провалится. Приятно, что при запуске pkgadd -d установщик укажет на несоответствие размера и суммы, причем обязательно напишет правильное значение.
Осталась сущая мелочь:
# cd /tmp # tar -cf - Munin-node | gzip -9 -c > Munin-node.1.44.SPARC.pkg.tar.gz
Полученный архив можно переносить на другие серверы и запускать установку:
# gunzip -c Munin-node.1.44.SPARC.pkg.tar.gz | tar -xvf - # pkgadd -d $PWD
Основная часть закончена.
Приложение
Ниже будет приведем пример скрипта postinstall, в котором производится первоначальная настройка клиента munin-node и создается сервис (демон?) для munin-node.
#!/bin/sh # /opt/munin/sbin/munin-node-configure --shell --families=contrib,auto | sh -x svccfg -v validate /etc/opt/munin/munin-node.xml svccfg -v import /etc/opt/munin/munin-node.xml svcadm disable application/munin-node echo "Before start munin-node service DO:" echo "1. edit munin-node.conf" echo "2. configure dns client" echo "3. passwd munin user"
Файл munin-node.xml создавался отдельно.
Его содержимое:
<?xml version="1.0"?> <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> <service_bundle type="manifest" name="export"> <service name="application/munin-node" type="service" version="0"> <create_default_instance enabled="true"/> <single_instance/> <dependency name="fs" grouping="require_all" restart_on="none" type="service"> <service_fmri value="svc:/system/filesystem/local"/> </dependency> <dependency name="network" grouping="require_all" restart_on="none" type="service"> <service_fmri value="svc:/milestone/network:default"/><code> </dependency> <dependency name="name-services" grouping="require_all" restart_on="none" type="service"> <service_fmri value="svc:/milestone/name-services:default"/> </dependency> <code><exec_method name="start" type="method" exec="munin-node" timeout_seconds="60"> <method_context> <method_credential user="root" group="root"/> <method_environment> <envvar name="PATH" value="/opt/munin/sbin:/usr/bin:/bin:/opt/csw/bin"/> </method_environment> </method_context> </exec_method> <exec_method name="stop" type="method" exec=":kill" timeout_seconds="60"> <method_context/> </exec_method> </service> <code></service_bundle>
Тут стоит лишь обратить внимание на путь до исполнительного файла munin-node.
Файл preinstall: #!/bin/shgroupadd munin useradd -d /var/munin -m -s /usr/bin/bash -g munin munin cp /.profile /var/munin/ chown munin:munin /var/munin/.profile