quinta-feira, 7 de junho de 2012

Preservando as Permissões do Linux com Script Java Ant Build

O projeto Ant da Apache é uma biblioteca utilíssima que, lendo um pequeno script em XML, é capaz de compilar todo o código do seu projeto, empacotá-lo em arquivo JAR, WAR, EAR, ZIP ou outros formatos e ainda faz mais uma série de outras coisas divertidas, a maioria envolvendo manipulação de arquivos e diretórios.
Embora seja o compilador/empacotador padrão de quase qualquer projeto Java profissional, o Ant lida com manipulação de arquivos e execução de programas tão bem que pode facilmente ler scripts que, com certa criatividade, podem compilar e empacotar programas e C, C++, dentre outras linguagens, além de servir de empacotador para outros projetos genéricos.


  • As Permissões no Linux

(Mais informações sobre as permissões do Linux, vide aqui).
No Linux, as permissões de acesso e execução de arquivos é gravada em forma de atributos de arquivo, e estão dispersas em 3 níveis: usuário (dono do arquivo), os outros membros do grupo principal (do usuário dono do arquivo) e, finalmente, os outros usuários que sobraram. Cada um destes três níveis tem 3 atributos de permissão: leitura somente, leitura e gravação, execução. Assim, temos uma combinação de 7 possibilidades para cada nível, ficando:

0 --- sem permissão
1 --x execução
2 -w- escrita
3 -wx escrita e execução
4 r-- leitura
5 r-x leitura e execução
6 rw- leitura e escrita
7 rwx leitura, escrita e execução

Como se pode perceber, estas permissões, nesta ordem (rwx) formam uma seqüência de 3 bits, que pode então ser representada por um número octal (sim, já que 23 = 8).

0: 000
1: 001
2: 010
3: 011
4: 100
5: 101
6: 110
7: 111

Assim, se temos 3 níveis, e se cada nível pode ser representado por um número octal, então as permissões completas podem ser representadas por uma seqüência de 3 números octais. Exemplos:


rwx rwx rwx = 777
r-x r-x r-x = 555
rwx r-- r-- = 744
e assim por diante...


  • O Problema das Permissões no Linux

Muito bem, e qual o problema disso?? É bem simples, meu caro Watson...
Se a permissão de execução de um arquivo, no Linux, é tão-somente um atributo deste arquivo, como podemos preservá-lo, caso o arquivo seja compilado via Ant?? Suponhamos os seguintes cenários:

1- Que o Ant empacote um programa que tem um arquivo executável (por exemplo, script.sh) gerando um arquivo ZIP. Isso funciona?

Não funciona. O formato ZIP não retém as permissões de arquivos do Linux. Ainda que retivesse, se o programa estiver sendo empacotado numa máquina que roda outro sistema (ex: Windows), as permissões não existirão e, no momento em que o Ant ler o arquivo, elas continuarão perdidas.
Exemplo:

[Este exemplo não faz o que pretendemos]
[arquivos compilados e copiados para a pasta "build"]
<zip destfile="pacote.zip" basedir="build"/>


2- Ah, mas o Ant tem uma task tar. E se ele empacotar o programa como tar??

O formato tar suporta o que queremos, de fato, mas ainda é pouco. Exatamente porque o Java é multiplataforma, a task tar do Ant não usa o programa tar do seu Linux. Usa uma implementação totalmente feita em Java do padrão tar. Só poderia ser assim, para que a task funcionasse inclusive em máquinas que não têm o programa tar, garantindo a compatibilidade entre as diversas plataformas.
O resultado disso é que o arquivo tar é gerado perfeitamente, porém sem as permissões herdadas de cada arquivo, e sim com permissões genéricas.
Exemplo:

[Este exemplo não faz o que pretendemos]
[arquivos compilados e copiados para a pasta "build"]
<tar destfile="pacote.tar">
     <fileset dir="build" includes="**/*"/>
</tar>


  • A Solução do Problema

Finalmente, existem algumas opções que podem resolver o problema. Vamos a elas.

1- Usando o Programa tar de seu Linux

Esta sabemos que não é a melhor opção, embora funcione. Através da task exec, o Ant permite a execução de um programa externo, inclusive passando parâmetros (argumentos) para o mesmo (mais sobre esta task aqui).
O exemplo abaixo indica como chamar o programa tar de um script Ant, passando argumentos que indicam o que deve ser empacotado (diretório ".") e uma lista de arquivos a serem excluídos. O problema é que, como o programa tar normalmente só existe em ambientes Linux, para evitar erros, a task é instruída a só executar se este ambiente for detectado. Esta detecção, internamente, é feita pela propriedade de sistema "os.name".

[Este exemplo não é a melhor opção]
<exec executable="tar" output="/dev/null" os="Linux">
        <arg value="--exclude-from=arquivos_a_excluir.txt"/>
        <arg value="-cvz"/>
        <arg value="--file=${pacote.tar}"/>
        <arg value="."/>
</exec>

A fragilidade desta opção é que, dependendo de um programa externo, ela não funciona em qualquer plataforma. Se você constrói seu sistema sozinho ou se a sua equipe tem o ambiente todo padronizado, então ela pode ser usada. Caso contrário, você teria que criar tantas task exec quanto sistemas usados por sua equipe, e torcer para que, em cada sistema, todos tenham o programa tar no mesmo lugar (ou no PATH).


1- A Forma Correta

A maneira abaixo despreza chamadas para programas externas e constrói a solução ideal. Como isto é possível??
Simples, meu caro Watson: substituímos (ou incluímos) a tag (elemento) fileset pela tag tarfileset. Esta tag é específica da task tar e herda de fileset. Esta faz o mesmo que aquela, ou seja, define uma lista de arquivos para serem considerados, porém com duas propriedades (atributos) a mais, a saber:

- filemode: define as permissões de arquivo Linux que os arquivos incluídos nesta tag deverão ter após incluídos no pacote tar, independente de os arquivos originais terem ou não estas permissões.
- dirmode: faz o mesmo, porém para diretórios.

Assim, é possível se manter ou mesmo trocar as permissões de arquivos no momento de serem empacotados no pacote tar. Evidentemente, devido a esta arquitetura de trabalho, o pacote tar será formado como desejado mesmo que você esteja rodando o script Ant de ambiente Windows, que não suporta as permissões de arquivos Linux. Ou seja: funciona em qualquer plataforma, por mais louca que seja a maneira como ela armazena seus arquivos.

Veja na prática como funciona, pelo exemplo abaixo:

[Este exemplo é o recomendável]
<tar destfile="pacote.tar">
    <fileset dir="build" includes="**/*" excludes="build/script.sh"/>
    <tarfileset dir="build" includes="build/script.sh" filemode="755"/>
</tar>

 No exemplo, selecionamos os arquivo que não são executáveis dentro do elemento fileset, como é feito normalmente. Porém, excluímos o único arquivo diferente, o que queremos que seja um executável. Logo abaixo, incluímos o arquivo executável, porém agora utilizando o elemento (tag) tarfileset, que está instruído a adicioná-lo ao pacote usando as permissões 755.
Como vimos acima, as permissões são representadas por 3 algarismos octais. Os atributos filemode e dirmode de tarfileset somente recebem estes 3 algarismos numéricos. No exemplo, 755 representa: rwx  r-x  r-x, ou seja, todos podem ler e executar, mas somente o dono do arquivo pode modificá-lo.


  • Conclusões

Neste artigo apresentamos como utilizar, no escopo de um script Ant, a task tar, de modo a elegantemente preservar as permissões de arquivos Linux ao se criar um pacote. Claro, estas permissões podem inclusive serem alteradas e/ou criadas no momento do empacotamento, uma vez que esta solução é ágil e flexível. Porque a implementação do tar no Ant é feita em puro Java, a solução dispensa o uso de chamadas a programas externos, o que poderia consistir em fragilidade no script, e, o melhor de tudo, pode ser rodada a partir de qualquer sistema, mesmo aqueles para quem estas permissões não existam nativamente.
Espero ter ajudado e, claro, COMENTEM!!!

domingo, 3 de junho de 2012

Instalando um Servidor Jabber jabberd no Ubuntu ou Debian

Jabber é um serviço que implementa o protocolo XMPP (Extensible Messaging and Presence Protocol), um protocolo aberto responsável por definir padrões para a comunicação entre clientes e servidores de mensagens instantâneas. É claro que não é o único padrão neste sentido, já que temos muitos deles (como o ICQ, AIM, MSN, etc.), mas é o único realmente aberto e gratuito.
Porque o XMPP é gratuito, existem muitos servidores e clientes Jabber, que implementam este protocolo e permitem, assim, que você tenha um serviço privado de mensagens instantâneas na sua casa, sua empresa, sua lan house ou rede particular. O objetivo deste artigo é exatamente isto: ajudar-lhe a instalar e configurar seu serviço particular de mensagens instantâneas baseado em Jabber. Note que todas as ações descritas neste tutorial supõem que você tem prioridade de root.


1- De Que Programas Preciso?

Para começar, você precisa de dois tipos de programas:

  • Um servidor Jabber, que ficará em uma máquina servidora acessível via rede;
  • Um cliente Jabber, que ficará em cada máquina de usuário.

A princípio, qualquer servidor Jabber deve poder falar com qualquer cliente, sem exclusividade, já que o protocolo XMPP é aberto e único.
Consulte aqui uma lista de clientes Jabber, e consulte aqui uma lista completa de servidores Jabber.
Para efeito deste artigo, vamos utilizar o servidor jabberd, versão 14, que é um servidor leve e bastante flexível, e vamos utilizar, para testar, o cliente pidgin, que é leve e multi-plataforma.


2- Instalação dos Programas

Nas máquinas clientes (dos usuários), instale o pidgin:

apt-get install pidgin

Faça a instalação do cliente em pelo menos uma máquina, para fins de teste. Em último caso, você pode instalar o cliente e o servidor na mesma máquina, para que faça todos os testes e configurações antes da implantação na máquina servidora realmente.

Na máquina servidora, instale o jabberd:


apt-get install jabberd14

(Em algumas distribuições, há o meta-pacote "jabber", que tem o jabberd14 como dependente. Neste caso, use opcionalmente "apt-get install jabber")

Isto instala o servidor jabberd e já roda o script de inicialização, programando-o para carregar sempre durante o boot. Evidentemente, você desejará modificar as configurações do servidor, então é preciso pará-lo:

/etc/init.d/jabberd14 stop


3- Configurando o Servidor jabberd

Toda a configuração do servidor está em um único arquivo XML, que pode ser encontrado em:

/etc/jabber/jabber.xml

Já a configuração do script de inicialização, dependendo de sua distribuição, pode ser encontrada em um destes dois arquivos:

/etc/jabber/jabber.cnf (mais comum no Debian)
ou
/etc/default/jabberd14 (mais comum no Ubuntu)

O arquivo jabber.xml é vastamente documentado e já vem pronto para uso. Contudo, algumas informações você precisará alterar.


Ajustando o nome e domínio do servidor

Ache a linha:

<host><jabberd:cmdline flag="h">localhost</jabberd:cmdline></host>

E troque a referência "localhost" pelo nome de sua máquina na rede. Use aqui o que chamamos de FQDN (Full-Qualified Domain Name), ou seja, o nome da máquina com o domínio. Exemplo: se sua máquina se chama "host1" e seu domínio é "minhacasa.org", então configure esta linha assim:

<host><jabberd:cmdline flag="h">host1.minhacasa.org</jabberd:cmdline></host>

Observe que a linha acima faz menção à opção de linha de comando "-h". Esta opção é usada na inicialização do servidor pelo script e serve para indicar o nome do host que deverá ser considerado.
Portanto, uma vez alterando o nome de máquina no arquivo jabber.xml, você deve necessariamente abrir o arquivo de configuração do script e fazer a mesma alteração:

/etc/jabber/jabber.cnf (Debian):
JABBER_HOSTNAME=host1.minhacasa.org

ou

/etc/default/jabberd14 (Ubuntu):
HOSTNAME=host1.minhacasa.org

 Ainda falta um passo: neste arquivo de configuração do script acima, há referência ao diretório de spool. Este diretório é onde o jabberd armazena todos os dados dos usuários criados (que são arquivos XML contendo as informações de usuário, como login e senha, e o ícone do mesmo). Para cada opção de host o jabberd necessita de um sub-diretório dentro do spool de mesmo nome do host.
Assim, se seu diretório de spool é /var/spool/jabberd/, então você deve criar o diretório:

mkdir /var/spool/jabberd/host1.minhacasa.org

 Verifique com que usuário o seu jabberd roda. Em geral, ele roda com usuário e grupo chamado "jabberd". Assim, atribua este diretório a estes usuário e grupo:

chown jabberd /var/spool/jabberd/host1.minhacasa.org
chgrp jabberd /var/spool/jabberd/host1.minhacasa.org


Ajustando a porta

Se você chegou até aqui, seu servidor jabberd já está pronto para rodar perfeitamente. Contudo, ele vai rodar nas portas padrões do Jabber, a porta 5222 (para acesso sem encriptação) e 5223 (para acesso com encriptação). É fortemente recomendável, especialmente se seu servidor estará aberto para acesso externo via internet, que você troque a porta.
Para tanto, localize no arquivo jabber.xml mencionado acima as linhas:

<ip port="5222"/> (usada para acesso sem SSL)
<tls port='5223'/> (usada para acesso com SSL)

Troque os valores 5222 e 5223 para valores que você desejar. É imprescindível, entretanto, que você verifique o firewall de sua máquina onde está instalado o jabberd para se certificar de que as portas escolhidas estão abertas para acesso conforme você deseja. De outro modo, o servidor ficará inacessível.


Cadastramento de usuários

O jabberd vem, por padrão, disponível para aceitar que qualquer novo usuário se cadastre (registre) no sistema. Caso esta não seja a opção de seu desejo, então visite, no arquivo jabber.xml mencionado acima, as tags <register> e escolha a opção que mais lhe convenha.
Para eliminar totalmente a opção de registro automático pelo usuário, elimine deste arquivo todas as tags <register>.
Caso você queira ter total controle sobre os usuários e deseja registrá-los através de um serviço web ou criando-os a mão mesmo, você deverá saber a sintaxe do arquivo XML de usuário para escrevê-lo, ou confiar em um script que faça isto. Se é este seu desejo, veja bons scripts administrativos do Jabber aqui e aqui.
Lembre-se de que, para o Jabber, o nome do usuário sempre tem a fórmula:

nomeusuario@host.dominio
Arquivo: "/var/spool/jabberd/host.dominio/nomeusuario.xml"

Muitos clientes só conseguirão cadastrar ou localizar usuários usando esta forma acima.
Também é importante lembrar-se de que, se você fará o cadastramento de usuários manualmente ou através de outro sistema, os arquivos XML de cada usuário deverão ser atribuídos aos usuário e grupo do jabberd, conforme fizemos com o diretório de spool acima.


4- Reiniciando o Servidor

Após concluídas todas estas modificações, o servidor precisa ser reiniciado. Para tanto, rode os comandos:

/etc/init.d/jabberd14 stop (caso ainda não o tenha feito)
/etc/init.d/jabberd14 start

Para verificar se o servidor rodou usando o nome de host adequado, consulte o comando executado pelo script:

ps ax | grep jabberd

Deve surgir algo como:

2764 pts/1    S      0:00 /usr/sbin/jabberd --background -h host1.minhacasa.org -s /var/spool/jabberd

onde:

--background: informa que o serviço deve rodar como deamon, ou seja, em segundo plano.
-h: informa o nome do host (e, conseqüentemente, a pasta a ser lida dentro do spool);
-s: indica o local onde está o spool.


5- Conclusões

Bom, ao final deste tutorial, você deverá estar com um servidor Jabber rodando perfeitamente. Deve também ser capaz de criar usuários e configurar facilmente um cliente, como o Pidgin. Espero ter ajudado e conto com suas impressões nos comentários!!