понедельник, 6 мая 2013 г.

Использование разных значений CATALINA_HOME и CATALINA_BASE в Tomcat

По умолчанию в свежеустановленном Tomcat переменные окружения CATALINA_HOME и CATALINA_BASE равны между собой - и указывают на ту директорию, где установлен tomcat (в нашем случае это директория /opt/tomcat). Во 2-й главе Tomcat: The Definitive Guide от О'Рейли описан пример использования разных значений этих переменных. При этом CATALINA_HOME указывает на местоположение неизменяемых "глобальных" директорий (bin и lib), а CATALINA_BASE - локальных (conf, logs, temp, webapps и work). В книге подробно рассматривается использование такой конфигурации для запуска нескольких экземпляров tomcat на одном сервере, но лишь вскользь упомянуто гораздо более практически полезное применение: конфигурация, позволяющая обновлять tomcat простым обновлением символической ссылки. Ниже приводится пошаговая инструкция, как это сделать. Опыты проводились на Debian sid, версии tomcat: 7.0.32  и 7.0.37, установленные простой распаковкой архивов, скачанных с http://tomcat.apache.org в директорию /opt (предполагается, что в первоначальной конфигурации /opt/tomcat является симлинком на /opt/apache-tomcat-7.0.32).

1. Создаем файл-пускач /etc/init.d/tomcat (если он еще не создан). Минимальный пример взят из 1-й главы вышеупомянутой книги:

#!/bin/sh

export CATALINA_HOME=/opt/tomcat
export CATALINA_BASE=/opt/catalina

$CATALINA_HOME/bin/catalina.sh $*


2. при остановленном томкате переносим в /opt/catalina директории с изменяемой частью сервера:

$ cd /opt/tomcat
$ mv conf logs temp webapps work ../catalina

Подразумевается, что пользователь, под которым запускается томкат, должен иметь права на чтение и запись в эти директории (для conf достаточно чтения, для webapps - если не используется autoDeploy - тоже).

3. теперь для установки новой версии томката достаточно, распаковав дистрибутив в /opt, удалить ссылку (иначе ln -sf, имеющий последним аргументом директорию - в полном соответсвии с мануалом - создаст ссылку внутри нее):

$ rm -f /opt/tomcat

и создать заново:

$ ln -s /opt/apache-tomcat-7.0.37 /opt/tomcat

и перезапустить томкат. Поддиректории в /opt/catalina будут использоваться вместо поддиректорий в /opt/tomcat с теми же именами. Для достижения большей прозрачности конфигурации можно удалить из /opt/tomcat все лишнее, но строгой необходимости в этом шаге нет. Откат на старую версию в случае проблем с новой выполняется так же легко - обратной заменой ссылки.

среда, 13 марта 2013 г.

X11 Forwarding in Solaris 11

В Solaris 11 Express из коробки X11 forwarding разрешен в /etc/sshd/sshd_config - однако не работает (о чем и сообщает при каждой попытке захода на сервер с помощью ssh -X). Для того, чтобы увидеть, в чем проблема, достаточно добавить в командную строку ssh ключ -v В составе системы просто-напросто нет программы xauth.
Поправить беду - как ни странно - можно вполне стандарным способом:
# pkg install xauth
Если после этого перезайти на серевер, сообщение об ошибке больше не выводится, но первая же X-программа, которую я попытался запустить (это была groovyConsole) умерла, сообщив об отсутствии в системе libXrender.so
Но мы уже знаем, что делать:
# pkg install libxrender
После этого groovyConsole запустилась. В процессе поиска в сети решения проблемы достаточно часто мне встречался совет, который и приведу ниже (хотя в моем случае заработало и без этого). Утверждается, что X11 forwarding работает лучше, если явно потребовать от sshd использовать IPv4. Делается это добавлением строки:
ListenAddress 0.0.0.0
в файл /etc/sshd/sshd_config. Применяемая для этой же цели в Linux инструкция:
AddressFamily inet
sshd из поставки Solaris 11 неизвестна.

P.S.: в Solaris 10 аналогичная проблема решается установкой пакетов SUNWxwplt и SUNWxwice (также нужно убедиться, что  /usr/openwin/bin входит в PATH).

вторник, 5 февраля 2013 г.

Pseudo-targets in Groovy AntBuilder


К моему удивлению, ни в 700-страничном фолианте "Groovy in Action", ни в достаточно неплохой документации на сайте языка  не приводится пример создания с помощью AntBuilder полнофункционального проекта (т.е. не просто последовательности выполняемых задач (tasks), а совокупности взаимозависимых целей (target). Анализ имеющихся в сети исходников и сниппетов не дал ничего интереснее, чем псевдо-цели с использованием замыканий (closures). Например, такой код принимает имена задач из командной строки (почти как настоящий ant):

#!/usr/bin/env groovy
DEFAULT = 'jar'
DEST = 'target'
JAR = "$DEST/myapp.jar"
SRC = 'src'
ant = new groovy.util.AntBuilder()
ant.taskdef(name: 'groovyc', classname: 'org.codehaus.groovy.ant.Groovyc')
compile = {
    println '\ncompile:'
    ant.mkdir(dir: DEST)
    ant.groovyc(destdir: DEST, srcdir: SRC, includes: '*.groovy')
}
jar = {
    compile()
    println '\njar:'
    ant.jar(destfile: JAR, basedir: DEST, includes: '*.class')
}  
if (args) for (t in args) this[t]() else this[DEFAULT]()

Самое обидное в том, что в groovy вполне можно написать в таком стиле:

ant.target(name: 'clean') {delete(dir: DEST)}

но паче чаяния такая цель будет выполнена немедленно после объявления - а это совсем не то поведение, которое нам нужно. А из этого unresolved issue в джире кодехауза следует, что путей борьбы с данной странностью разработчики пока не придумали.

среда, 28 ноября 2012 г.

Многопользовательский VNC-сервер на RHEL5


Из коробки в RHEL5 (опыты проводились на Oracle Linux 5.8) для запуска Xvnc предназначена служба vncserver, предполагающая жескую привязку запущенных процессов к пользователям и портам (ея настройки находятся в /etc/sysconfig/vncservers). В данной статье описано более интересеное поведение: Xvnc принимает множественные соединения на одном порту и выводит окно авторизации gdm. При такой конфигурации служба vncserver должна быть остановлена. Далее: добавляем порт vnc в /etc/services:

vnc        5900/tcp

Создаем /etc/xinetd.d/vncserver:

service vnc
{
disable = no
protocol = tcp
socket_type = stream
server = /usr/bin/Xvnc
wait = no
user = nobody
server_args = -inetd –query localhost –once –geometry 1024x768 \
 –depth 16 -SecurityTypes=None
}
(строки, разделенные знаком \, на самом деле составляют одну строку)

И добаляем в /etc/gdm/custom.conf (если их там еще нет) следующие строки:

[security]
AllowRemoteRoot=true
DisallowTCP=false

[xdmcp]
Enable=true
MaxSessions=30

После перезапуска xinetd и gdm должна появиться возможность подсоединиться vnc-клиентом (например, remmina) на порт 5900.
В качестве неизбежных рюшечек избавимся от  гнома по умолчанию (ибо сервер у нас не совсем резиновый). В файл /etc/sysconfig/desktop пишем:

PREFERRED=/opt/bin/xsession.sh

Ну а сам /opt/bin/xsession.sh предоставляем фантазии читателя. Мой минималисткий вариант таков (mwm ставится из пакета openmotif):

#!/bin/sh
vncconfig -iconic &
xclock -bg black -fg green -digital -strftime '%H:%M:%S %d.%m.%y' \
 -geometry -0-0 -update 1 &
xterm -bg black -fg grey -geometry +0+0 &
exec mwm

В комментариях здесь нуждается только вторая строка - без нее не будет работать клипбоард.

вторник, 13 ноября 2012 г.

Pacemaker за 5 минут

Так уж получилось, что и старое, и новое издание Clusters from Scratch описывают слегка не ту конфигурацию, что используется на наших серверах. Поэтому пишу сам себе HOWTO. Задача: поднять двухнодовый кластер с httpd. Платформой служит Oracle Linux 6.3 из коробки.
Предварительные необходимые шаги (без детализации):
  1. отключаем selinux;
  2. разрешаем весь трафик через интерфейсы, по которым узлы будут общаться друг с другом;
  3. убеждаемся, что httpd не запускается при загрузке - и кластерный ip никем не используется;
  4. создаем одинаковый беспарольный RSA-ключ для рута на обеих узлах и взаимно авторизуем его;
  5. устанавливаем pacemaker и corosync через yum.
А теперь - за дело. /etc/corosync/corosync.conf.example содержит почти все нужное. Копируем его без суффикса example, заменяем  bindnetaddr на реальный (это адрес сети, а не хоста - он будет одинаковым на обеих узлах) и добавляем в конец секцию запуска pacemaker:
service {
        name: pacemaker
        ver: 0
}
После этого запускаем corosync:
# service corosync start
И команда
# crm status
должна показать работающий кластер из двух узлов и нуля ресурсов. Corosync будет единственным из кластерных сервисов, запускаемых при загрузке:
# chkconfig corosync on
Все остальное, что мы собираемся запускать в кластере, будет стартовать из-под него. Если первоначальные настройки должны быть сделаны симметрично на обеих узлах, то дальнейшие crm-команды выполняются только на одном из узлов.
Наша примитивная конфигурация требует слегка поменять стандартные настройки кластера. Отключаем STONITH:
# crm configure property stonith-enabled=false
И кворум (иначе в двухнодовом кластере вместе с одним из узлов умрут все сервисы):
# crm configure property no-quorum-policy=ignore
Теперь можно добавлять ресурсы. Переходящий IP-адрес:
# crm configure primitive ip0 ocf:heartbeat:IPaddr2 \
    params ip=10.1.1.251 nic=eth1 cidr_netmask=32 \
    op monitor interval=10s
И веб-сервер:
# crm configure primitive www0 lsb:/etc/init.d/httpd \
    op monitor interval=30s
т.к. наши два ресурса логически связаны (и по смыслу должны запускаться на одном и том же узле), то сгруппируем их: 
# crm configure group g0 ip0 www0
И установим порядок запуска (веб-сервер всегда после адреса):
# crm configure order ip-www inf: ip0 www0
Далее следует сводка простейших команд администрирования кластера.
Если понадобилось вывести узел из кластера (например для апргрейда):
# crm node standby
(Эта и следующая команды выполняются на том узле, которым мы манипулируем - либо третьим аргументом должно быть имя узла). Возвращение в кластер после окончания обслуживания:
# crm node online
Перемещение группы ресурсов на другой узел кластера:
# crm resource move g0
После того, как перемещение закончится, надо выполнить:
# crm resource unmove g0
иначе группа никогда не сможет вернуться на прошлый узел.
Посмотреть на работающий кластер в реальном времени можно командой
# crm_mon

Нуждающиеся в более серьезной документации, чем эта, найдут ее на ClusterLabs.

четверг, 4 октября 2012 г.

/etc как репозиторий Mercurial


Безумная идея видавшего виды админа - а почему бы не приделать к Linux хранение истории правок конфигурации? Для воплощения в жизнь используем CentOS 6.3 и Mercurial 1.4 (он показался мне капельку проще, чем Subversion - и к тому же он хранит репозиторий и рабочую копию рядом - т.е. нам не придется создавать никаких дополнительных директорий и усложнять и без того непростую иерархию). Все последующие команды выполняются от имени суперпользователя - ибо в /etc немало файлов, недоступных для чтения другим пользователям:
# cd /etc
# hg init
# hg add *
# hg commit -m 'add /etc' -u root
Теперь во-первых убеждаемся, что изуродованная таким образом система успешно перезагрузится (хотя кому может помешать директория /etc/.hg?), потом не забудем закрыть эту директорию от обычных пользователей - все-таки наш репозиторий содержит немало такого, что им знать не положено:
# chmod 700 /etc/.hg
И проверяем, как у нас все работает:
# groupadd dummies
# useradd -d /home/dummy -g dummies -p h5CVem3AekREA dummy
# hg diff
Любуемся на изменения:

diff -r 2d2839e14225 group
--- a/group Thu Oct 04 14:08:10 2012 +0400
+++ b/group Thu Oct 04 14:24:47 2012 +0400
@@ -33,3 +33,4 @@
 nfsnobody:x:65534:
 sshd:x:74:
 cgred:x:499:
+dummies:x:500:
diff -r 2d2839e14225 gshadow
--- a/gshadow Thu Oct 04 14:08:10 2012 +0400
+++ b/gshadow Thu Oct 04 14:24:47 2012 +0400
@@ -33,3 +33,4 @@
 nfsnobody:!::
 sshd:!::
 cgred:!::
+dummies:!::
diff -r 2d2839e14225 passwd
--- a/passwd Thu Oct 04 14:08:10 2012 +0400
+++ b/passwd Thu Oct 04 14:24:47 2012 +0400
@@ -18,3 +18,4 @@
 rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
 nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
+dummy:x:500:500::/home/dummy:/bin/bash
diff -r 2d2839e14225 shadow
--- a/shadow Thu Oct 04 14:08:10 2012 +0400
+++ b/shadow Thu Oct 04 14:24:47 2012 +0400
@@ -18,3 +18,4 @@
 rpcuser:!!:15617::::::
 nfsnobody:!!:15617::::::
 sshd:!!:15617::::::
+dummy:h5CVem3AekREA:15617:0:99999:7:::
Если все хорошо, записываем их:
# hg commit -m 'add dummy user' -u root
Еще для наглядности можно запустить встроенный веб-сервер:
# hg serve -d
И смотреть на репозиторий станет еще приятнее (только не забудьте сперва закрыть файрволом порт 8000 - ибо едва ли содержимое вашего /etc является зрелищем, достойным внимания всего интернета).

среда, 22 августа 2012 г.

Python MIME-библиотека и строка From в Unix-стиле



При создании тела письма с помощью питоновского класса email.message.Message (и его потомков типа email.mime.base.MIMEBase или email.mime.multipart.MIMEMultipart) первой строкой автоматически добавляется  знакомая каждому старому юниксоиду строка From без двоеточия.
Например:

$ python
>>> import  email.mime.multipart
>>> msg = email.mime.multipart.MIMEMultipart()
>>> print msg

From nobody Wed Aug 22 11:02:28 2012
Content-Type: multipart/mixed; boundary="===============1046125271=="
MIME-Version: 1.0

--===============1046125271==

--===============1046125271==--

Конечно всякий нормальный емейл-клиент реагирует на эту строку спокойно: ведь она существует в мире уже третий десяток лет, но - увы - современный мир полон ненормальными почтовыми клиентами. В одном из их - Lotus Notes 8.5.1 - наличие строки From в заголовке приводит к тому, что MIME-структура письма не отображается - и письмо выводится как простой текст.   
Как заставить Message не включать в письмо данную строку? В документации обнаружено два способа:
  1. прямой. Message имеет метод as_string(self, unix_fromline=False). Если в прошлом примере вместо print msg сделать print msg.as_string() (или - для не надеющихся на умолчательное поведение - print msg.as_string(False)), то мы получим текст сообщения без строки From.
  2. прикольный. Строку From можно заменить любой своей строкой - для этого у нашего класса есть метод set_unixfrom(self, string). Т.к. по стандарту мы можем беспрепятственно добавлять в письмо любые заголовки, начинающиеся с "X-", то сделав что-то типа: msg.set_unixfrom("X-Mailer: Python Is Not Lotu$ Note$") мы получим тело письма, которое ничем не смутит нашего капризного клиента.