segunda-feira, 9 de janeiro de 2012

Backup no escuro com o udev e o systemd

CENÁRIO

Máquina rodando uma instalação mínima do Fedora 16 em modo texto. Típico caso de um servidor quieto lá no seu canto rodando Samba. Como é uma rede Windows, onde a única máquina Linux é esse Fedora, o meu HD externo está formatado em NTFS para facilitar a troca de arquivos com os demais PCs.

OBJETIVO

Fazer com que, ao plugar um HD externo -- e sem intervenção do usuário --, seja feito backup de uma pasta com o rsync e que toque um bipe para avisar quando terminou.

PACOTES NECESSÁRIOS

# yum -y install beep rsync ntfs-3g

PASSOS

Plugue o seu HD externo na máquina com o Fedora. Agora você precisará de um monitor nela, ou então acesso por SSH.

Identifique o dispositivo do HD externo rodando o blkid:

# blkid
...
/dev/sdc1: LABEL="BKP" UUID="XXXXXXXXXXXXXXXX" TYPE="ntfs"

Adicione uma regra para o udev, criando um aquivo na pasta /etc/udev/rules.d/ (por exemplo: 99-externo.rules)

ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_LABEL}=="BKP", ENV{ID_FS_TYPE}=="ntfs", ENV{UDISKS_IGNORE}="1", TAG+="systemd", ENV{SYSTEMD_WANTS}+="backup.service"

Eu usei uma regra que filtra pelo rótulo do volume e pelo tipo de sistema de arquivo. Você pode usar o UUID se quiser (ENV{ID_FS_UUID}), ou qualquer outra característica que o udev lhe fornecer:

# udevadm info --query=env --name=/dev/sdc1

O udev monitora a pasta e aplica as regras na hora. Não é necessário reiniciar. A regra diz para o systemd rodar o serviço backup.service, que criaremos a seguir, assim que o dispositivo for conectado.

O gerenciador de pacotes da distribuição coloca os serviços em /usr/lib/systemd/system/. Essa pasta não deve ser editada manualmente. O campo do administrador é a pasta /etc/systemd/system/. No caso do systemd se deparar com arquivos unit com mesmo nome nas duas pastas, o da pasta /etc tem prioridade.

/etc/systemd/system/backup.service

[Unit]
Description=Faz backup para HD externo
ConditionPathExists=/mnt/backup

[Service]
Type=oneshot
ExecStartPre=/usr/bin/mount -v -o context="system_u:object_r:public_content_rw_t:s0",x-gvfs-hide LABEL=BKP /mnt/backup
ExecStart=/usr/bin/rsync -avhW --update --delete /srv/pub /mnt/backup
ExecStartPost=/usr/bin/umount -v /mnt/backup ; /usr/bin/beep -l 600 ; /usr/bin/sleep 0.2 ; /usr/bin/beep -l 600

Crie a pasta /mnt/backup, que servirá de ponto de montagem, e rode systemctl daemon-reload para o systemd atualizar a lista de arquivos unit.

A lógica de operação é a seguinte. Quando o udev detectar que o HD externo foi plugado e que o rótulo e o tipo de sistema de arquivos batem, ele avisa o systemd para rodar o serviço backup.service. O serviço é do tipo "oneshot" para os comandos postos em ExecStartPre, ExecStart e ExecStartPost serem executados serialmente. O primeiro monta a partição usando o rótulo, o segundo roda o rsync e o último desmonta a partição e toca um bipe para avisar que o HD externo pode ser removido.

Adapte o comando rsync à vontade. Se precisar executar mais comandos, serviços "oneshot" podem ter a opção ExecStart declarada mais de uma vez (são executadas na ordem que forem encontradas no arquivo). Ou, se realmente precisar de shell script, pode criar um (/usr/local/libexec é um bom lugar) e especificá-lo em ExecStart.

Por padrão o systemd direciona STDOUT para o syslog, assim todas as mensagens dos programas executados vão para /var/log/messages (ou para o Journal). Por esse motivo, rsync, mount e umount estão com a opção -v (verbose), para ter um histórico do que foi feito em cada backup no log do sistema.

O Fedora não carrega mais o módulo pcspkr por padrão. Descomente a linha alias platform:pcspkr pcspkr no arquivo /etc/modprobe.d/beep.conf para ter o falante de volta. Se você tiver caixinhas de som, pode instalar o ALSA e usar o aplay se quiser.

Documentação do systemd: http://0pointer.de/blog/projects/systemd-docs.html

[Atualização - 24/11/2012] Não estava mais funcionando no Fedora 18 por causa do SELinux. Desde o F16 a política foi apertada e o rsync começou a ser bloqueado. Para resolver, adicionado ao comando do mount:

-o context="system_u:object_r:public_content_rw_t:s0"

assim o kernel falsifica um label "public_content_rw_t" mesmo em sistemas de arquivos que não suportam atributos estendidos (ou mesmo em sistemas nativos que os suportam).

Depois, é necessário habilitar os dois booleanos a seguir:

# setsebool -P rsync_client 1
# setsebool -P rsync_anon_write 1

Fiz mais algumas pequenas mudanças, como ConditionPathExists no arquivo .service, mount/umount com -v, ACTION=="add" e ENV{SYSTEMD_WANTS}+ na regra do udev.

MIÚDOS

- Não funcionará com o Gnome (ou outro DE) rodando, pois o udisks/gvfs montará automaticamente o dispositivo. [Atualização - 30/01/2015] ENV{UDISKS_IGNORE}="1" e x-gvfs-hide devem evitar isso.
- Serve também para pendrive ou qualquer outro dispositivo USB Mass Storage, além de eSATA.

Nenhum comentário:

Postar um comentário