пятница, 30 марта 2012 г.

Быстрое создание образа для виртуальных машин QEMU/KVM/VirtualBox/etc

После начала изучения puppet мне частенько приходится генерировать образы для виртуальных машин, причем порой десятками. Когда-то давно, для упрощения процесса инсталяции я писал скрипт-обертку над debootstrap, который устанавливал минимальную систему, ядро и загрузчик на предварительно размеченный диск. Для этого приходилось загружать livecd, размечать там диск и после этого запускать скрипт. В принципе этого хватало, если нужно создать одну, максимум две машинки. Но если их нужно сделать десяток, то минусы этого решения вставали в полный рост.

Чтобы решить проблему более полно, я дописал недостающий функционал. Получившийся скрипт назвал bootstrapper.sh, его последнюю версию можно взять тут. Сразу после создания образа его можно использовать в KVM/Qemu.

$ sudo ./bootstrapper.sh test.raw 4G
$ kvm -m 512 -hda test.raw

Если не указать имя файла и размер, создаваемого образа, то будут выбраны дефолтные значения. Чтобы конвертировать образ в формат понятный VirtualBox, нужно выполнить его импорт:

$ VBoxManage convertfromraw test.raw test.vdi --format VDI

После этого test.vdi можно подключить в виртуальную машину VirtualBox. Скорее всего аналогично можно поступить и для VMWare, если сконвертировать в VMDK формат:

$ VBoxManage convertfromraw test.raw test.vmdk --format VMDK

вторник, 27 марта 2012 г.

MySQL: backup and partial restore

Одна из методик создания резервных копий баз данных MySQL основывается на использовании снимков LVM. Скрипт, который отвечает за создание резервной копии выглядит примерно так:

#!/bin/bash
MYSQL_VG="VolGroup00"
MYSQL_LV="mysql"
MYSQL_SRC="/mnt/mysql-root"
MYSQL_DST="root@backup.server:/backup/mysql-server"

echo "FLUSH TABLES WITH READ LOCK; \! /sbin/lvcreate -s -n ${MYSQL_LV}-backup -L 1G ${MYSQL_VG}/${MYSQL_LV}" | mysql
echo "UNLOCK TABLES" | mysql
mkdir ${MYSQL_SRC}
mount /dev/${MYSQL_VG}/${MYSQL_LV} ${MYSQL_SRC} -o ro
rsync -avzxHS --delete --numeric-ids ${MYSQL_SRC}/ ${MYSQL_DST}/
umount ${MYSQL_SRC}
rmdir ${MYSQL_SRC}
lvchange -an ${MYSQL_VG}/${MYSQL_LV}-backup
lvremove ${MYSQL_VG}/${MYSQL_LV}-backup

Примечание: примеры ориентированы на Debian Squeeze и в других дистрибутивах могут потребоваться доработки.

В самом начале буферы таблиц в MySQL базах сбрасываются на диск и вводится блокировка операций записи в таблицы. Затем создается снимок LVM тома, на котором расположены базы MySQL. После создания снимка снимается блокировка записи и MySQL продолжает работать в нормальном режиме. Расплатой за это удобство является снижение скорости дисковых операций записи в MySQL в то время, пока активен снимок LVM.

Далее снимок монтируется как обычное блочное устройство и файлы, в которых MySQL хранит базы данных, переносятся в резервную копию любым удобных способом. В примере используется rsync, что позволяет передавать по сети только измененившиеся части файлов. По окончании переноса файлов, снимок LVM размонтируется и удаляется из менеждера томов.

Таким образом делается бэкап без остановки работы сервера. Однако создание резервных копий не самоцель, их нужно также восстанавливать в случае потери данных или необходимости получить доступ к более раннему состоянию баз данных. Самый простой способ восстановить резервную копию, созданную описанных выше способом, это остановить сервер MySQL и скопировать данные обратно.

# service mysql stop
# rsync -avxzHS --delete --numeric-ids root@backup.server:/backup/mysql-server/ /var/lib/mysql/
# service mysql start

Такой способ восстановления подходит, если нужно вернуть все базы в исходное состояние на момент создания резервной копии. Но что делать, если нужно восстановить только одну базу, одну таблицу или только несколько записей из конкретной таблицы? Что если основной сервер не допускает остановки? Конечно можно поднять отдельный MySQL сервер на другом сервере, скопировать туда бэкап и после запуска вытащить из него нужные данные посредством mysqldump. Но что делать, если другого сервера нет или версия MySQL сервера содержит патчи, которые делают резервную копию несовместимой с дистрибутивной версией? Я постараюсь дать одно из возможных решений этой проблемы.

В своем способе я также буду запускать отдельную копию MySQL сервера, но основная идея заключается в том, чтобы не копировать данные из бэкапа, а примонтировать их через сеть. Я буду использовать sshfs для этих целей. Чтобы при запуске второго сервера не изменились данные в бэкапе я применю оверлей на базе AUFS. Одна из его частей будет примонтированным бэкапом, а вторая - хранить все изменения относительно бэкапа. Таким образом я избегаю любых модификаций резервной копии.

# mkdir /mnt/mysql-{backup,datadir,tmp}
# sshfs root@backup.server:/backup/mysql-server /mnt/mysql-backup
# mount -t aufs none /mnt/mysql-datadir -o dirs=/mnt/mysql-tmp:/mnt/mysql-backup=ro
# mysqld_safe --defaults-file=/root/mysql-backup-restore.cnf

/root/mysql-backup-restore.cnf - конфигурация для второго сервера, которую я сделал на базе конфига из дистрибутива.

[mysqld]
user=root
pid-file        = /root/mysql-restore.pid
socket          = /root/mysql-restore.sock
basedir         = /usr
datadir         = /mnt/mysql-datadir
tmpdir          = /tmp
language        = /usr/share/mysql/english
skip-networking
skip-external-locking
key_buffer              = 16M
max_allowed_packet      = 16M
thread_stack            = 192K
thread_cache_size       = 8
myisam-recover         = BACKUP
query_cache_limit       = 1M
query_cache_size        = 16M
expire_logs_days        = 10
max_binlog_size         = 100M

[mysqldump]
quick
quote-names
max_allowed_packet      = 16M

[isamchk]
key_buffer              = 16M

!includedir /etc/mysql/conf.d/

После запуска вторая копия MySQL сервера доступна только через сокет /root/mysql-restore.sock, чем позволяет исключить посторонний доступ на время восстановления данных. Чтобы подключиться к запущенному серверу, нужно явно указать сокет:

# mysql -S /root/mysql-restore.sock
# mysqldump -S /root/mysql-restore.sock --add-drop-table dbname table1 table2 > dbrestore.sql

После того, как данные сняты посредством mysqldump нужно остановить вторую копию сервера. Для этого нужно выполнить:

# mysqladmin -S /root/mysql-restore.sock shutdown

Когда дополнительный сервер остановится можно отмонтировать /mnt/mysql-datadir и /mnt/mysql-backup, и удалить директории /mnt/mysql-{backup,datadir,tmp}

Несомненным преимуществом такого подхода является время, которое тратится на частичное восстановление резервной копии. Из недостатков пожалуй отсутствие sshfs и aufs во многих дистрибутивах (для centos я так и не смог найти пакета для добавления поддержки aufs). Возможно его следует заменить на любую другую реализацию union fs, но я это делать не пробовал.

вторник, 20 марта 2012 г.

New Midnight Commander releases

Today midnight commander development team announced new releases:

Debian/Ubuntu packages build process running just now and after it finished packages will be available in my repository.

About a week ago I notice that debian distribution now provide 4.8.1 release in it's archive. I hope in near future debian could include fresh versions rapidly after upstrem releases it.

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

Показ скрытых файлов в CuteFTP

Сегодня наткнулся на отсутствие скрытых файлов вроде .htaccess в листинге директорий в CuteFTP. В других ftp клиентах проблемы не было, т.к. там есть аналоги опций "Show hidden files".

Поизучав опции cuteftp сходу решение так и не нашлось. Зато пробежка в гугле дала результат:

Рецепт

Выбрать нужное соединение в "Site manager" и редактировать его свойства. На вкладке "Actions" нужно нажать кнопку "Filters...".


В открывшемся окне отметить пункт "Enable filtering", затем "Enable server-side filtering". В поле ввода вбить "-al" (без кавычек).


После этого в CuteFTP станут видны скрытые файлы.

среда, 14 марта 2012 г.

Перенос почтовых аккаунтов и форвардеров в WHM/сPanel

Сегодня очередной раз переносил почтовые аккаунты с одного сервера на другой (оба под управлением WHM/cPanel). Потому сделаю себе пометку, чтобы не забыть в будущем как это делается.

Аккаунты и пароли переносятся на новый сервер простым копированием пользовательских ~/etc и ~/mail. Я это делаю через FTP. Чтобы перенести почтовые форвардеры, нужно копировать содержимое /etc/valiases. Обычно там больше, чем реально нужно, поэтому можно ограничиться нужными доменами.

Привязку unix юзера к домену в cPanel можно глянуть в /etc/domainusers.

пятница, 9 марта 2012 г.

Добавляем поддержку новой платы в Arduino IDE

В процессе переделки своего гигрометра с Arduino на самодельную плату пришлось задуматься о поддержке последней в Arduino IDE. Первый вариант "градусника" был собран на базе Freeduino 2009, который есть аналог Arduino Duemilanove, поэтому проблем не было. После перехода на собственную плату на базе Atmega8a пришлось отказаться от загрузчика и заливать прошивку через программатор. В качестве программатора у меня используется USBAsp v2.0, который был куплен на ebay.


С заливкой простеньких программок вида "помигать светодиодом" проблем не возникло. А вот собрать arduino-проект и залить его оказалось сложнее. Чтобы не писать длинные Makefile'ы я просто решил добавить поддержку своей новой платы в IDE. В этом нет ничего сложного, но есть пара подводных камней, на которые я наткнулся в процессе.

Типичная рекомендация из гугла - добавить описание своей платы и программатора в файлы boards.txt и programmers.txt, поставляемые с Arduino IDE. Мне не понравился такой подход, т.к. при апгрейде IDE мои изменения будут утеряны и придется снова все повторить.

Дальнейшее гугление привело меня на форум, где описывали похожий случай. Оказывается IDE позволяет определить пользовательский конфиг в папке со скетчами. В моем случае это ~/development/arduino, значит конфиги будут лежать в ~/development/arduino/hardware/own/boards.txt и ~/development/arduino/hardware/own/programmers.txt соответственно.

После добавления описаний получилось:
$ cat ~/development/arduino/hardware/own/boards.txt
own.name=Generic ATmega8 board
own.upload.using=usbasp
own.upload.maximum_size=8192

own.build.mcu=atmega8
own.build.f_cpu=16000000L
own.build.core=arduino

Фьюзы были прошиты заранее, когда игрался с простыми примерами. В моем случае lfuse=0xff hfuse=0xd9

$ cat ~/development/arduino/hardware/own/programmers.txt
usbasp.name=USBAsp
usbasp.communication=usb
usbasp.protocol=usbasp

Теперь в IDE появился мой программатор и плата. Запускаю компиляцию и... облом не может инклудить файл WProgram.h. Далее нагуглилось, что WProgram.h - файл принадлежащий платформе "arduino". Это та самая опция own.build.core=arduino, которую я просто скопировал из примера, но не задумывался о ее назначении.

Чтобы не плодить копии сделал символическую ссылку на директорию, поставляемую с arduino ide.
$ mkdir ~/development/arduino/hardware/own/cores
$ ln -s /usr/share/arduino/hardware/arduino/cores/arduino ~/development/arduino/hardware/own/cores/arduino

После этого заработала компиляция и скетч загрузился на плату.

вторник, 6 марта 2012 г.

Домашний гигрометр на atmega8

Для измерений влажности в домашних условиях я приобрел на ebay датчик DHT22. Этот датчик позволяет с достаточной точностью измерять относительную влажность и температуру. Вот выдержка из его datasheet:

Measuring range: humidity 0-100% RH; temperature -40~125‌°C
Accuracy: humidity ±2%RH (Max ±5%RH); temperature ±0.2°C


Этого более чем достаточно для домашних измерений. Первый вариант я собрал на базе arduino - фотографию можно найти в этом посте. Позже появилось желание собрать это устройство на печатной плате и выбросить все лишние компоненты.

В качестве базового контроллера был взят atmega8a. Схему перенес с arduino на плату для быстрого прототипирования.


Код проекта компилируется на ~5kB, при этом свободными остается примерно 3kB для расширения функционала. В будущем планирую задействовать в проекте USART для расширения функционала в будущем.