пятница, 18 марта 2011 г.

Жабо-регэкспы

Почему-то считал, что джава умеет проводить лишь простейший поиск с помощью регэкспов, однако оказалось, что захват групп, замена - все это также возможно.
Появилась задача передать значение длины промежутка времени, выраженное в минутах, часах, днях, месяцах, годах. Что-то вроде 1d для 1 дня, 3M для 3 месяцев, 75m для 75 минут и т.д. Для разбора строки с таким значением идеально подходит регэксп с захватом групп. Числовое значение выделяем в одну группу, значение единицы времени в другую. Вот регэксп, к которому я пришел:
^([1-9][0-9]*)(y|M|d|H|m|s)$
здесь ^ - начало строки, $ - конец строки. Эти символы добавлены, чтобы исключить какие-либо еще посторонние символы. Первая группа ^([1-9][0-9]*) захватывает числовое значение. Значения вида "01" или "-2" не подходят. Вторая группа (y|M|d|H|m|s) захватывает значение единицы времени. Соответствующий джава-код для обработки значения с помощью этих групп:
            Pattern pattern = Pattern.compile(^([1-9][0-9]*)(y|M|d|H|m|s)$);
       Matcher matcher = pattern.matcher(value);
       boolean matchFound = matcher.find();

       if (matchFound) {
           String numberValue = matcher.group(1);
           String unitValue = matcher.group(2);
           int number = Integer.parseInt(numberValue);
           //do something
       }

Весьма все просто.

Задача номер два заключала в себе необходимость формата строки, задающей путь в файловой системе в зависимости от даты. Использовался синтаксис аналогичный FileNamePattern в log4j. Пример:
%d{yyyy}/%d{MM}/msg.%d{yyyy-MM-dd}.gz
Для 18 марта 2011 года из этого шаблона должно получиться 2011/03/msg.2011-03-18.gz
То есть по сути следует заменить все вхождения %d{...} соответствующими значениями переданной даты, шаблон внутри %d{...} аналогичен используемому в SimpleDateFormat. Вот код который производит необходимое форматирование:
Pattern pattern = Pattern.compile("%d\\{(.*?)\\}");
Matcher matcher = pattern.matcher(pathPattern);
String path = pathPattern;
       
while (matcher.find()) {
      SimpleDateFormat dateFormat = new SimpleDateFormat(matcher.group(1));
      path = matcher.replaceFirst(dateFormat.format(date));
      matcher.reset(path);
}

Здесь мы последовательно в цикле находим вхождение паттерна, захватываем группу, форматируем ее с помощью SimpleDateFormat и производим необходимую замену в входной строке шаблона. Выход из цикла происходит, когда в результате не найдено ни одного блока %d{...}

понедельник, 14 марта 2011 г.

Log4j эксплоит

Все мы знаем о том, как прекрасен log4j. Вставляешь выводы для разных уровней DEBUG, INFO, ERROR в коде, а потом через настройки в текстовом формате можешь контролить степень подробности описания выполнения проги. Код написанный для log4j не является бизнес логикой, он не влияет на ход выполнения проги никак, лишь описывая текущее состояние системы для последующего администрирования.
Однако log4j можно применить и непосредственно для создания функциональности.
Мне потребовалось написать программу, сохраняющую поток некоторых данных в текстовом виде, с разбиением данных на отдельные файлы в зависимости от календарного дня. Была необходима  архивация данных прошедших дней. Можно было написать все это вручную, но зачем, когда все требуемые действия умеет производить log4j.
Разбиение в зависимости от даты с последующей архивацией завершенных файлов умеет выполнять org.apache.log4j.rolling.RollingFileAppender. Это класс из дополнительного пакета log4j-extras. Так что нам понадобятся две джарки: log4j и log4j-extras. Вот пример конфигурации в log4j.xml, в которой

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">

<log4j:configuration>
  <appender name="dailyLog" class="org.apache.log4j.rolling.RollingFileAppender">
    <rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy">
      <param name="FileNamePattern" value="/tmp/my-log.%d{yyyy-MM-dd}.gz"/>
    </rollingPolicy>
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%d{HH:mm:ss,SSS} - %c{1} - %m%n"/>
    </layout>
  </appender>
  <logger name="MyBusinessData">
      <level value="info"/>
      <appender-ref ref="dailyLog"/>
  </root>
</log4j:configuration>

В этой конфигурации
  • осуществляется вывод логгера MyBusinessData с уровнем не ниже INFO
  • вывод осуществляется в файлы /tmp/my-log.*  - в зависимости от
    даты, так логирование, произошедшее 14 марта 2011 запишется в файл /tmp/my-log.2011.03.14; подробнее про настройку FileNamePattern здесь
  • по окончанию дня соответствующий файл архивируется gzip'ом.
  • в самом файле формат вывода определяется строчкой "%d{HH:mm:ss,SSS} - %c{1} - %m%n", где вначале идет формат времени, затем указание категории, затем само сообщение и символ новой строки. Подробнее про настройку ConversionPattern здесь

Теперь я могу записывать свои данные с помощью обычного логгера:
private Logger dataLogger = Logger.getLogger("MyBusinessData");
...
dataLogger.info(data);
и при указанной конфигурации данные будут сохраняться так как и требовалось. Однако возникает проблема которая как раз и связана со словами "при указанной конфигурации". Проблема в том, что изменив текстовый файл настройки log4j.xml (либо тупо забыв его поместить в нужное место и указать нужные значения), можно заглушить запись данных, то есть поломать программу. Гибкость настройки log4j в нашем случае оборачивается опасностью. Непорядок!
Поэтому переходим к программной настройке. Идея в том, чтобы игнорировать какие-либо настройки в текстовом файле для нашего дата-логгера, а вместо этого использовать жестко заданные в коде.
Вот те же самые настройки, произведенные программно:
dataLogger.removeAllAppenders();    //we don't want any configuration other than this
dataLogger.setAdditivity(false);    //avoid sending messages to root logger
RollingFileAppender rfa = new RollingFileAppender();
TimeBasedRollingPolicy rollingPolicy = new TimeBasedRollingPolicy();

//the smallest unit in the pattern is day, so rolling will occur at the end of each day
//.gz suffix tells log4j to compress finished day
rollingPolicy.setFileNamePattern("/tmp/my-log.%d{yyyy-MM-dd}.gz");
rollingPolicy.activateOptions();
rfa.setRollingPolicy(rollingPolicy);
PatternLayout layout = new PatternLayout();
layout.setConversionPattern("%d{HH:mm:ss,SSS} - %c{1} - %m%n");
rfa.setLayout(layout);
rfa.activateOptions();
dataLogger.addAppender(rfa);
dataLogger.setLevel(Level.INFO);

Очень важна здесь вторая строчка dataLogger.setAdditivity(false). Благодаря ей, сообщения, записываемые нашим дата-логером, не будут дублироваться на верхние уровни иерархии, в частности на рут логер. Таким образом, настроив обычное логирование даже для рута, мы не будем получать в довесок все данные логируемые нашим логером. Т.е. мы отдельно настроили дата-логер без ущерба для задачи логирования. Теперь можно удалить файл настроек log4j, либо настроить произвольным образом логирование, наша запись данных всегда будет производиться и не мешать остальному логированию. Ура!


пятница, 11 марта 2011 г.

Меняем сообщения коммитов в SVN и Trac

Случилась такая ситуация. Закомиттил я изменение и только потом вспомнил, что в сообщении коммита неплохо было бы указать, что оно относится к такому-то тикету. Вобщем, понадобилось изменить сообщение коммита.
Недолго гуглив пришел вот к такому непыльному решению:

1. Залогиниться на комп, хранящий репозиторий
2. Выполнить sudo rm -rf / Создать где-нибудь в темпе файлик с нужным сообщением для коммита:
sudo vim /tmp/new_log
3. Выполнить магическую команду:
sudo svnadmin setlog REPO_PATH -r N /tmp/new_log  --bypass-hooks
где REPO_PATH - путь к репозиторию, N - номер ревизии, чьё сообщение меняем

Теперь в репозитории красуется нужное нам название для N-й ревизии.
Однако трак не знает о нашем изменении и продолжает показывать старое сообщение. Непорядок!

4. Говорим траку перестать тупить и показать новое сообщение
sudo trac-admin TRAC_PATH resync N
где N - всё тот же номер ревизии, TRAC_PATH - путь к трак-проекту. Можно и без номера вызвать команду, тогда произойдет полная синхронизация со всеми ревизиями. Оно вам надо?
Проделать все без захода на сам сервер (без 1го пункта), удаленно нельзя, потому как 3 и 4 пункты выполняются для локальных путей. Если трак и репозиторий на отдельных компах, то надо зайти на оба. А кто сказал что будет легко?

среда, 9 марта 2011 г.

Установка PostgreSQL

Продолжаем обвешивать сервачок всякой всячиной.
На очереди могучий слон PostgreSQL.
За основу взята статья из убунту доков.

1. Ставим
sudo apt-get install postgresql

2. Так как это у нас отдельный сервачок постгреса, то доступ к нему будет осуществляться через юзер/пароль. Дефолтный юзер - postgres. Установим ему пароль:
sudo -u postgres psql postgres
\password postgres
#вводим пароль дважды

3. Устанавливаем возможность подключение к БД с любого адреса:
# /etc/postgresql/8.4/main/postgresql.conf
listen_addresses = '*'


4. Настраиваем аутентификацию, разрешаем пользователям с любых адресов иметь доступ ко всем базам данных и заходить под любым пользователем, при условии ввода правильного соответствующего пароля, который будет передаваться в зашифрованном md5 виде:
# добавляем строчку в /etc/postgresql/8.4/main/pg_hba.conf
host    all         all         0.0.0.0/0               md5

Дополнительно про настройки аутентификации можно почитать здесь.

5. Перезагружаем постгрес, чтобы настройки в пунктах 3 и 4 вступили в силу:
sudo /etc/init.d/postgresql-8.4 restart

Теперь к постгресу, установленном на сервачке можно подключаться с других компов-десктопов, используя годный ГУИ тул pgadmin3.
Указанная здесь конфигурация на самом деле слишком... гостеприимная, что-ли. Я сделал ее таковой лишь на время разработки, чтобы иметь возможность стучаться к БД не только с работы, но и из дома через динднс. В целом же при настройке доступа к базе следует задавать как можно более жесткие условия для прослушиваемых адресов и аутентификации.
Вот и все, спокойной ночи, девочки и мальчики, до новых встреч!

пятница, 4 марта 2011 г.

Чистим старые ядра

При очередном обновлении моей десктопной убунты, вылезла вот такая страшная ошибка:
Not enough free disk space
The upgrade needs a total of 19.9M free space on disk '/boot'. Please free at least an additional 12.2M of disk space on '/boot'. Empty your trash and remove temporary packages of former installations using 'sudo apt-get clean'.
Как же так? Забился бут?
df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda6             127G   45G   76G  37% /
none                  940M  268K  939M   1% /dev
none                  944M  372K  943M   1% /dev/shm
none                  944M  344K  943M   1% /var/run
none                  944M     0  944M   0% /var/lock
none                  944M     0  944M   0% /lib/init/rw
/dev/sdb1             459G  105G  332G  24% /var/lib/storage
/dev/sda1              92M   79M  7.4M  92% /boot


И правда, забился... Смотрим чем же.
ls -lah /boot
total 70M
drwxr-xr-x  4 root root 3.0K 2011-02-18 15:23 .
drwxr-xr-x 22 root root 4.0K 2011-02-22 11:10 ..
-rw-r--r--  1 root root 637K 2010-09-16 21:14 abi-2.6.32-24-generic
-rw-r--r--  1 root root 637K 2010-10-17 02:46 abi-2.6.32-25-generic
-rw-r--r--  1 root root 637K 2010-11-24 15:57 abi-2.6.32-26-generic
-rw-r--r--  1 root root 637K 2010-12-02 02:48 abi-2.6.32-27-generic
-rw-r--r--  1 root root 637K 2011-01-11 03:18 abi-2.6.32-28-generic
-rw-r--r--  1 root root  512 2011-02-18 15:23 boot.0810
-rw-r--r--  1 root root  512 2011-02-18 15:23 boot.0820
-rw-r--r--  1 root root 114K 2010-09-16 21:14 config-2.6.32-24-generic
-rw-r--r--  1 root root 114K 2010-10-17 02:46 config-2.6.32-25-generic
-rw-r--r--  1 root root 114K 2010-11-24 15:57 config-2.6.32-26-generic
-rw-r--r--  1 root root 114K 2010-12-02 02:48 config-2.6.32-27-generic
-rw-r--r--  1 root root 114K 2011-01-11 03:18 config-2.6.32-28-generic
drwxr-xr-x  3 root root 6.0K 2011-02-02 11:07 grub
-rw-r--r--  1 root root 7.6M 2010-09-28 10:36 initrd.img-2.6.32-24-generic
-rw-r--r--  1 root root 7.6M 2010-11-18 10:02 initrd.img-2.6.32-25-generic
-rw-r--r--  1 root root 7.6M 2010-11-30 10:49 initrd.img-2.6.32-26-generic
-rw-r--r--  1 root root 7.6M 2011-01-21 10:42 initrd.img-2.6.32-27-generic
-rw-r--r--  1 root root 7.6M 2011-02-02 11:07 initrd.img-2.6.32-28-generic
drwx------  2 root root  12K 2010-08-27 16:56 lost+found
-rw-r--r--  1 root root 157K 2010-03-23 11:37 memtest86+.bin
-rw-r--r--  1 root root 1.7M 2010-09-16 21:14 System.map-2.6.32-24-generic
-rw-r--r--  1 root root 1.7M 2010-10-17 02:46 System.map-2.6.32-25-generic
-rw-r--r--  1 root root 1.7M 2010-11-24 15:57 System.map-2.6.32-26-generic
-rw-r--r--  1 root root 1.7M 2010-12-02 02:48 System.map-2.6.32-27-generic
-rw-r--r--  1 root root 1.7M 2011-01-11 03:18 System.map-2.6.32-28-generic
-rw-r--r--  1 root root 1.2K 2010-09-16 21:16 vmcoreinfo-2.6.32-24-generic
-rw-r--r--  1 root root 1.2K 2010-10-17 02:47 vmcoreinfo-2.6.32-25-generic
-rw-r--r--  1 root root 1.2K 2010-11-24 16:00 vmcoreinfo-2.6.32-26-generic
-rw-r--r--  1 root root 1.2K 2010-12-02 02:50 vmcoreinfo-2.6.32-27-generic
-rw-r--r--  1 root root 1.2K 2011-01-11 03:20 vmcoreinfo-2.6.32-28-generic
-rw-r--r--  1 root root 3.9M 2010-09-16 21:14 vmlinuz-2.6.32-24-generic
-rw-r--r--  1 root root 3.9M 2010-10-17 02:46 vmlinuz-2.6.32-25-generic
-rw-r--r--  1 root root 3.9M 2010-11-24 15:57 vmlinuz-2.6.32-26-generic
-rw-r--r--  1 root root 3.9M 2010-12-02 02:48 vmlinuz-2.6.32-27-generic
-rw-r--r--  1 root root 3.9M 2011-01-11 03:18 vmlinuz-2.6.32-28-generic

Гнилые старые ядра забили мой бут и не дают обновляться! Стереть их! Однако стирать нужно аккуратненько, через apt-get. Немного погуглив я нашел вот этот хороший гайд. Продублирую его здесь оставив только варианты команд для няки убунты (для второй няки генту их там и не было).

1. Узнаем, какое ядро используем сейчас:
uname -r
2.6.32-28-generic

2. Узнаем, какие ядра установлены в системе
dpkg --list 'linux-image*'
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Cfg-files/Unpacked/Failed-cfg/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                              Version                           Description
+++-=================================-=================================-==================================================================================
un  linux-image                                                   (no description available)
un  linux-image-2.6                                               (no description available)
ii  linux-image-2.6.32-24-generic     2.6.32-24.43                      Linux kernel image for version 2.6.32 on x86/x86_64
ii  linux-image-2.6.32-25-generic     2.6.32-25.45                      Linux kernel image for version 2.6.32 on x86/x86_64
ii  linux-image-2.6.32-26-generic     2.6.32-26.48                      Linux kernel image for version 2.6.32 on x86/x86_64
ii  linux-image-2.6.32-27-generic     2.6.32-27.49                      Linux kernel image for version 2.6.32 on x86/x86_64
ii  linux-image-2.6.32-28-generic     2.6.32-28.55                      Linux kernel image for version 2.6.32 on x86/x86_64
ii  linux-image-generic               2.6.32.28.32                      Generic Linux kernel image

Вот все эти позорные саботажники апгрейда! Казнить их! (кроме двух последних, действующего кернела и запасного старого).
3. Удаляем ядрышки ненужных версий (в статье, на которую я ссылаюсь, флага --purge нету, не знаю есть ли тут существенная разница, но --purge должен почистить всякие остаточные файлы)
sudo apt-get remove --purge linux-image-2.6.32-24-generic
sudo apt-get remove --purge linux-image-2.6.32-25-generic
sudo apt-get remove --purge linux-image-2.6.32-26-generic

4. Дополнительно погуглив, обнаружил, что после такого удаления остаются некоторые депенденси. Срубаем головы саботажникам (удаляем linux-headers для соответствующих удаленных ядер)
sudo apt-get remove --purge linux-headers-2.6.32-24-*
sudo apt-get remove --purge linux-headers-2.6.32-25-*
sudo apt-get remove --purge linux-headers-2.6.32-26-*

В результате ядра удалены, /boot освобожден. Однако в результате выполнения команд у меня появились предупреждения такого рода:
dpkg: warning: while removing linux-image-2.6.32-24-generic, directory '/lib/modules/2.6.32-24-generic' not empty so not removed
Возможно стоит вручную почистить эти каталоги, пока не стал этого делать.

пятница, 25 февраля 2011 г.

Установка Trac

Получив готовую чистую систему, я приступил к установке душки трака и няшки свн.
До этого, работая в десктоп убунте, я не слишком задавался вопросами управления пакетами, ставил все что нужно, а это нужное подтягивало дефолтные депенденси и все были счастливы.
Однако на серваке такой подход недопустим и пришлось проработать то, что я в итоге ставлю. В этом плане очень удобной оказалась программа aptitude. Пару хоткеев для нее:
  • / - поиск пакетов
  • + - установить пакет
  • - - удалить пакет
  • Enter - на пакете: описание пакета вместе с депенденси; на свернутой группе: свернуть/развернуть
  • F7 - вернуться на предыдущий экран
  • Ctrl+-> - релиз ноты выделенного пакета
  • g - применить все изменения
Этих хоткеев мне и хватило чтобы просмотреть все депенденси трака, выбрать нужные. Аптитуд очень удобно подсвечивает красным, все чего не хватает. Поэтому перед пометкой трака как устанавливаемый, я прошелся по всем красным, поотмечал предпочтительные варианты где был выбор, и уже затем отметил трак. Важно понимать, что при пометке пакета как устанавливаемый все необходимые депенденси которых не хватает (и которые заранее не были помечены в рамках текущей установки) будут автоматически помечены, но при этом приобретут статус автоматических депенденси, которые удаляются при отсутствии зависящих от них пакетов. Пакеты непосредственно выбранные пользователем самодостаточны и требует непосредственной комманды для удаления.
Таким образом одним махом я поставил apache2, trac, subversion, graphviz. В качестве базы данных я использовал sqlite3.
Настройка трака не сложна, однако наличие многочисленных и не полных гайдов сбивает.
Я взял за основу этот гайд. Приведу кратко здесь то, что использовал если вдруг вики по ссылке выпилят.

1. Создал папку для Subversion и в ней папку для проекта:
sudo mkdir /srv/svn
sudo mkdir /srv/svn/diplopod

2. Создал репозиторий в папке проекта и передал права юзеру www-data (юзер создался автоматически при установке апача):
sudo svnadmin create /srv/svn/diplopod
sudo chown -R www-data /srv/svn/diplopod

3. Создал папку для Trac и в ней папку для проекта:
sudo mkdir /srv/trac
sudo mkdir /srv/trac/diplopod

4. Создал инстанс нового трак-проекта и передал права:
sudo trac-admin /srv/trac/diplopod initenv
#здесь зададут пару вопросов, на вопрос о пути к бд ответить по умолчанию
#а путь к свн вводить полный: /srv/svn/diplopod
sudo chown -R www-data:www-data /srv/trac/diplopod
5. Для следующего шага необходимо убедиться, что установлен пакет libapache2-mod-python (да-да, это тот самый пакет. который все не рекомендуют использовать по причине скоро его депрекейшна, однако настройка трака через WSGI показалась мне непозволительным по времени досугом). После этого надо убедиться, что есть симлинк /etc/apache2/mods-enabled/python.load  на ../mods-available/python.load. В файле конфигурации апача /etc/apache2/httpd.conf добавляем:
#set up Trac handling
    SetHandler mod_python
    PythonHandler trac.web.modpython_frontend
    PythonOption TracEnvParentDir /srv/trac
    PythonOption TracUriRoot /projects
    PythonOption TracLocale "ru_RU.UTF-8"



    AuthType Basic
    AuthName "Trac"
    AuthUserFile /srv/trac/.htpasswd
    Require valid-user

6. Замечаем добавление локали ru_RU.UTF-8 в первом блоке. Я добавил ее, чтобы даты отображались в траке в привычном для нас формате (по-умолчанию там MM/DD/YY что как бы совсем не удобно). На данный момент это единственный способ изменить формат даты - через локаль. Для функционирования локали нужно проверить наличие пакета locales, установить если отсутствует. Далее добавляем ру-локаль:
sudo locale-gen ru_RU.UTF-8
sudo dpkg-reconfigure locales

7. Далее генерим файл с паролями для трак-логина:
sudo htpasswd -c .htpasswd admin
Здесь флаг "-c" устанавливается только при создании первого юзера. В дальнейшем вызывать эту же команду но без этого флага.

8. Добавляем права админу трака:
sudo trac-admin /srv/trac/diplopod permission add admin TRAC_ADMIN
9. Для возможности влиять на тикеты через свн коммиты добавляем в /srv/trac/diplopod/conf/trac.ini :
[components]
tracopt.ticket.commit_updater.* = enabled

...смотрим сюда. Зачеркнутое верно лишь для версии трака 0.12.
Теперь когда коммит включает какое-либо изменение для тикета #123 мы в сообщении коммита пишем "Refs #123 - такие то изменения" и в тикете будет добавлена ссылка на этот коммит. Если же коммит фиксает тикет и мы хотим сразу тикет закрыть, то в сообщении коммита пишем "Fixes #123 - такие-то изменения".

10. Остается добавить поддержку свн репозитория через проткоол http. Для этого в файле /etc/apache2/mods-available/dav_svn.conf добавляем:

     DAV svn
     SVNParentPath /srv/svn
     SVNListParentPath On
     AuthType Basic
     AuthName "Subversion Repository"
     AuthUserFile /etc/subversion/passwd
    
        Require valid-user
    


Здесь используется файл с паролями /etc/subversion/passwd. Он генерится следующим образом:
sudo htpasswd -c /etc/subversion/passwd svn_user
Отличие от шага 7 в том, что здесь мы создаем юзера для Subversion, а там создавали для трака. Как и там флаг "-c" здесь только для первого юзера.

11. Перезагружаемся
sudo /etc/init.d/apache2 restart

Ну и кажется всё. После этого все должно заработать.
Графвиз-плагин включается через ГУИ админки, пока не пробовал его.











четверг, 24 февраля 2011 г.

Подготовка дисков и разделов

Итак после первого впечатления от знакомства с сервачком приступил к установке системы.
Предустановлена была няшная кубунта, и, в последний раз вглянув на красивые сглаженные окошки со всплывающими свистелками и перделками, я ребутнулся чтобы остаться в суровом консольном мире навсегда.
Как уже было сказано, fake-RAID от интела оказался сплошным разочарованием, так что я просто его отключил, перевев контроллер дисков в режим Advanced Host Controller Interface (AHCI). Отличается от стандартного IDE режима наличием дополнительных фич, таких как hot swap дисков и Native Command Queuing (NCQ). Последнее теоретически должно придать перфомансу дискам. Более подробно про IDE vs AHCI здеся.
В итоге я получил 4 отдельных диска на этапе установки.
Для установки использовал лайв сиди Ubuntu 10.04 server edition. К слову, 10.04 это Long Term Support (LTS) релиз, который для серверного варианта поддерживается 5 лет. Юху!
Установка в целом прошла гладко, если не считать крайней конфузный интерфейс для настройки софтового RAID с помощью mdraid, предлагаемого по-умолчанию визардом. Очень неудобно и результаты тех или иных действий порой совершенно нелогичны. Это привело к тому что я отбросил первоначальную идею навернуть поверх всего этого бутерброда еще и Logical Volume Manager (LVM). На фриноде порекомендовали LVM как средство постоянного аптайма сервака при отсутствии каких-либо заметных ухудшений производительности. Ну да хрен с ним, еще будет возможность переставить.
Лучшее, как говорится. враг хорошего и после мучительных стенаний относительно разбиения/собирания дисков в рейды я пришел к следующей суровейшей системе, которая конечно же будет работать хуже самой простой.

Первые 4 ГБ Дисков 1 и 2 в RAID0 - R0
Следующие 90 ГБ Дисков 1 и 2 в RAID1  - R1.1
Оставшиеся 900 ГБ Дисков 1 и 2 в RAID1 -  R1.2
Диски 3 и 4 полностью в RAID1 - R1.3
Рейды R1.2 и R1.3 в RAID0  - R10

На выходе получаем R0 - 8 ГБ, R1.1 - 90 ГБ, R10 - 1.9 ТБ
На R0 организовываю swap
R1.1 разбиваю на два партишна: 30 ГБ ext3 под / , 60 ГБ ext3 под /srv
На R10 ставлю xfs, замаунченый на /var

Вот такой вот винегрет, хз что из этого выйдет, будем тестировать.
К слову, создать файловую систему на R1.1  на этапе установки я смог лишь одну, ту которая под рут. Попытка создать вторую на 60 ГБ под /srv приводила лишь к страшному красному окну с надписью "Failed!". Пришлось ручками уже на рабочей системе допиливать. Использовал при этом устройства /dev/md* которые были созданы mdraid-ом.
# /dev/md3 это мой R1.1, на котором разделы для / и /srv
sudo fdisk /dev/md3

Command (m for help):  n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4):  2
...
# далее дефолтные значения начала и конца, чтобы заполнить все оставшееся место
Command (m for help): p
    Device Boot      Start         End      Blocks   Id  System
/dev/md3p1   *           1        3648    29295616   83  Linux
/dev/md3p2            3648       11671    64450667+  83  Linux
Command (m for help): w
После того как раздел был создан и изменения записаны осталось только создать файловую систему и замаунтить ее.
# без -j создалась бы ext2, а так будет ext3
sudo mke2fs -j /dev/md3p2

#смотрим в /etc/fstab  и срем кирпичом от UUID
cat /etc/fstab
#              
proc            /proc           proc    nodev,noexec,nosuid 0       0

# / was on /dev/md3p1 during installation
UUID=e6f5000d-5501-48b2-81bf-8389e6757b5c /               ext3    errors=remount-ro 0       1
...
Небольшое отступление. Почему вместо привычных /dev/sda1 в /etc/fstab мы иногда видим такие вот страшные UUID. Смысл здесь в том, что /dev/sdXX - привязка к слоту материнки. Если у вас скажем два диска в слотах 1 и 2,  и вы скажем приобрели новый диск и вам вдруг позарез нужно вставить этот новый диск между двумя старыми, то старые разместите в слотах 1 и 3, а новый в 2. В итоге получим несоответствие в системе, которая ожидает один из старых дисков в слоте 2, а получает там новый диск. Примдется бутаться как-нить по особому и править fstab. При использовании же UUID ничего править не придется, все заработает сразу, так как UUID раздела не зависит от того, где стоит диск. Как видно, ситуация в крайней степени сферическая, но чтобы построить новое, сохранить лучшее я решил таки замапить и свой раздел через UUID:
# узнаем UUID раздельчика
sudo dumpe2fs /dev/md3p2 | grep -i uuid
Filesystem UUID:          36fbe572-4678-47be-a477-4d28d4a6ae07

sudo vim /etc/fstab
# и добавляем строчки
# /srv was on /dev/md3p2
UUID=36fbe572-4678-47be-a477-4d28d4a6ae07 /srv            ext3    defaults        0       2

Здесь defaults - маунт флаги (точнее их отсутствие), 0 - не производить никаких бекап манипуляций с разделом, 2 - проверка ошибок файловой системы осуществлять позже чем у рута. Сохраняем.
Так как система теперь использует UUID вместо устройства, следует самим помнить что скрывается под тем или иным UUID в fstab, для этого я и добавил коммент по аналогии с теми, которая умненькая убунточка сама сгенерила. Однако это всего лишь для удобства. Если же устройство забылось то всегда можно узнать его по данному UUID:
ls -l /dev/disk/by-uuid/36fbe572-4678-47be-a477-4d28d4a6ae07
lrwxrwxrwx 1 root root 11 2011-02-24 11:06 /dev/disk/by-uuid/36fbe572-4678-47be-a477-4d28d4a6ae07 -> ../../md3p2
После прописанного маунта остается либо ребутнуться либо вручную замаунтить наш раздел:
sudo mount /dev/md3p2 /srv
После этого диски были готовы к работе. Ура!