Archive for the Scripts Category

Um tempo atrás escrevi um artigo sobre VPNs que abordava as vantagens e desvantagens do PPTP, e também um passo-a-passo para subir um OpenVPN autenticando com certificados e etc.

O artigo ainda está disponível na Web, e chama-se Implementando soluções de VPN. O que eu não sabia era que, embora o artigo seja meio antigo (Março de 2006) ele ainda continua funcional! Eu fui seguindo-o passo-a-passo, copiando e colando os comandos e em 15 minutos eu estava conectado à uma VPN usando roteamento com o device “tun”!

O modo de como esta VPN funciona é bem bacana, pois separa a sua rede “servidora” (ex: 192.168.0.x) da rede do cliente conectado via OpenVPN, criando uma rede como inválida qualquer como 10.8.0.x. O acesso de uma rede para a outra é feita via roteamento, descantando toda aquela nhaca de broadcast, netbios e etc.

Porém, desta vez a necessidade era diferente. Eu precisava realmente estar dentro da rede servidora, pois de dentro da rede era possível o acesso à uma outra rede, no caso uma LP com o México. A lambança era mais ou menos assim:

Rede_Mexico = 10.95.0.0/16
Rede_Servidor = 10.10.10.0/24
Rede_VPN = 10.8.0.0/24

Utilizando o device “tun” a rede VPN até chegava na rede do Servidor, porém, não chegava até a rede do México. Não duvido que seja possível de ser feito usando alguns roteamentos malucos, porém consegui resolver o problema apelando para bridges no Linux, usando o device “tap”.

O Carlos Morimoto havia postado um artigo chamado Criando bridges no OpenVPN do qual me foi muito útil, pois assim o OpenVPN conectava diretamente na rede 10.10.10.0/24 me enviando um IP que eu mesmo posso escolher via DHCP:

server-bridge 10.10.10.200 255.255.255.0 10.10.10.210 10.10.10.220

No exemplo acima, 10.10.10.200/24 será o IP do servidor, e 10.10.10.210 até 10.10.10.220 será o range oferecido aos clientes remotos que conectarem usando o OpenVPN.

Porém, para que tudo funcione a contento é necessário criar uma Bridge entre as interfaces eth0 e tap0, para que todo mundo se converse e se enxergue:

# brctl show
bridge name	bridge id		STP enabled	interfaces
br0		8000.00188be16805	no		eth0
							tap0

Neste caso, o IP não ficará nem na eth0 e nem na tap0, mas sim na br0:

# ifconfig 
br0       Link encap:Ethernet  HWaddr 00:28:0b:ef:58:75  
          inet addr:10.10.10.2  Bcast:10.10.10.255  Mask:255.255.255.0
          inet6 addr: fe80::218:8bff:fee1:6805/64 Scope:Link

Bom, chega de teoria. Os links acima possuem todo o background necessário para que você entenda a coisa passo-a-passo. Vamos logo para o que interessa: Os arquivos de configuração:

Arquivo openvpn.conf no servidor?

# /etc/openvpn/openvpn.conf
# Objetivo: Clientes remotos conectarem no mesmo range da LAN local sem roteamento
proto udp
port 1194
 
# bridge utiliza a interface "tap" em vez da "tun"
# (o tap transmite pacotes de broadcast e o tun não)
dev tap0
 
# Faixa de IPs para os clientes
server-bridge 10.10.10.200 255.255.255.0 10.10.10.210 10.10.10.220
 
# No cliente eh necessário um
# route add -net 10.95.0.0 netmask 255.255.0.0 gw 10.10.10.1 tap0
# para acessar a LP no Mexico 10.95.x.x
push "route 10.95.0.0 255.255.0.0 10.10.10.1"
 
# Compressão e persistência
comp-lzo
keepalive 10 120
ifconfig-pool-persist /etc/openvpn/ipp.txt
 
# Certificados
tls-server
ca ca.crt
cert server.crt
key server.key
dh dh1024.pem
 
# Logs e etc
status      /var/log/openvpn-status.log
log         /var/log/openvpn.log
log-append  /var/log/openvpn.log
verb 3
 
# Bridges para simular um mesmo switch entre a tap0 e a eth0
up /etc/openvpn/bridge-start
down /etc/openvpn/bridge-stop

Arquivo bridge-start:

#!/bin/bash
# /etc/openvpn/bridge-start
 
br="br0"
tap="tap0"
eth="eth0"
eth_ip="10.10.10.2"
eth_gw="10.10.10.1"
eth_netmask="255.255.255.0"
eth_broadcast="10.10.10.255"
 
for t in $tap; do
openvpn --mktun --dev $t
done
 
brctl addbr $br
brctl addif $br $eth
 
for t in $tap; do
brctl addif $br $t
done
 
for t in $tap; do
ifconfig $t 0.0.0.0 promisc up
done
 
ifconfig $eth 0.0.0.0 promisc up
ifconfig $br $eth_ip netmask $eth_netmask broadcast $eth_broadcast
#route add default gw $eth_gw dev $br
route add -net 10.95.0.0 netmask 255.255.0.0 gw 10.10.10.1 br0
 
iptables -A INPUT -i tap0 -j ACCEPT
iptables -A INPUT -i br0 -j ACCEPT
iptables -A FORWARD -i br0 -j ACCEPT

Arquivo bridge-stop:

#!/bin/bash
# /etc/openvpn/bridge-stop
 
br="br0"
tap="tap0"
ifconfig $br down
brctl delbr $br
 
for t in $tap; do
openvpn --rmtun --dev $t
done 
 
route del -net 10.95.0.0 netmask 255.255.0.0 gw 10.10.10.1 br0
ifdown eth0
ifup eth0
route add -net 10.95.0.0 netmask 255.255.0.0 gw 10.10.10.1 eth0

Arquivo no cliente:

# Cliente pode ser Linux ou Windows
remote 200.200.200.100
proto udp
port 1194
client
pull
dev tap
comp-lzo
keepalive 10 120
tls-client
ca ca.crt
cert tiagocruz.crt
key tiagocruz.key
ns-cert-type server 
verb 3

O resultado pode ser visto nos screnshoots abaixo:

openvpn

Como você deve ter percebido, apenas alguns ajustes foram necessários nos scripts que iniciam e derrubam as bridges. A parte mais chata foi automatizar a criação de rotas estáticas nos clientes, para que não fosse necessário usar o “route add” em toda a conexão. A linha do “push” resolveu este problema, inclusive apontando a rota para um host que diferente do servidor de VPN, que é o padrão.

Segue uma screnshoot mostrando o antes, o durante e o depois do super device tap :)

openvpn-rotas

Nos testes foram utilizadas as versões OpenVPN 2.1_rc7 x86_64-pc-linux-gnu no servidor rodando Ubuntu 8.04.3 LTS e o cliente OpenVPN 2.1_rc11 i486-pc-linux-gnu em um Ubuntu 9.04.

Também foi possível conectar usando a GUI do OpenVPN para Windows.

Abraços e até o próximo post! 8)

Dica rápida, sem muitas novidades. Apenas uma forma rápida de colocar um Squid 2.6.18 rodando em um Ubuntu 8.04 LTS para autenticar em um Windows 2003 Server, sem usar samba+winbind, dar join no domínio, usar ntp e etc.

A idéia é documentar uma árvore LDAP padrão do Windows, para servir como base para futuras implementações, visto que muitos admins de AD desconhecem esta informação :-)

No squid.conf, ficaria mais ou menos assim (o “\” é uma quebra de linha, porém o comando deve ficar em uma linha única):

...
acl diretoria src 10.10.10.9/32
http_access allow diretoria
 
# Autenticacao AD Windows
auth_param basic program /usr/lib/squid/ldap_auth -R -b "dc=dominio" -D "cn=tiago \
cruz,cn=users,dc=dominio" -w "senha" -f sAMAccountName=%s -h 10.10.10.10
auth_param basic children 5
auth_param basic realm Autenticacao
auth_param basic credentialsttl 5 minutes
acl ldapauth proxy_auth REQUIRED
http_access allow ldapauth
 
# White List
acl liberados dstdom_regex -i "/etc/squid/unblock.txt"
http_access allow liberados
...
# Rede Local LAN
acl rede_local src 10.10.10.0/24
http_access allow rede_local

Caso não funcione “de prima”, recomendo estes comandos para debugar o problema:

1-) Usando o LDAPSearch para ver se retorna OK:

$ ldapsearch -LLL -h 10.10.10.10 -P 3 -x -D "CN=Tiago Cruz,CN=Users,DC=Dominio" \
-W -b "DC=Dominio" "(&(&(objectClass=User)(objectCategory=Person))(sAMAccountName=tcruz))"
Enter LDAP Password: 
dn: CN=Tiago Cruz,CN=Users,DC=dominio
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: Tiago Cruz
sn: Cruz
givenName: Tiago
initials: ti
distinguishedName: CN=Tiago Cruz,CN=Users,DC=dominio
instanceType: 4
whenCreated: 20090427110042.0Z
whenChanged: 20090427190603.0Z
displayName: Tiago Cruz
uSNCreated: 555987
....

2-) Simulando o LDAP_AUTH do Squid na mão, passando na mesma linha usuário e senha desejado para ver se funciona bem:

$ /usr/lib/squid/ldap_auth -R -b "dc=dominio" -D "cn=tiago \
cruz,cn=users,dc=dominio" -w "senha" -f sAMAccountName=tcruz -h 10.10.10.10
tcruz senhacorreta
OK
tcruz senhaerrada
ERR Success

Lembrando que se você estiver usando Proxy Transparente, você deverá configurar o endereço do Proxy diretamente no navegador do usuário pois a autenticação não funcionará.

Se você não sabe se usa Proxy Transparente, seria algo mais ou menos assim:

# No squid:
http_port 3128 transparent
 
# No firewall:
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
iptables -t nat -A PREROUTING -s 10.10.10.0/255.255.255.0 -p tcp --dport 80 -j REDIRECT --to-port 3128

A idéia é pegar todo o tráfego que vem da sua rede local com destino à porta 80/tcp e encaminhar para o squid na porta 3128/tcp, de forma transparente. Funciona muito bem, mas caso você queira autenticação será necessário mexer no browser no cliente.

Para fazer uma configuração automática, sugiro a utilização de um Script de Logon mais ou menos como este arquivo “todos.bat”:

@echo off
net use f: \\server\shared
net use h: /home
regedit /s \\server\netlogon\proxy.reg

Sendo que o proxy.reg seria algo mais ou menos assim:

REGEDIT4
 
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings]
"ProxyServer"="10.10.10.1:3128"
"ProxyEnable"=dword:00000001
"EnableAutodial"=dword:00000000
"NoNetAutodial"=dword:00000000
"MigrateProxy"=dword:00000001

Mais informações:
- Configuring Squid on Linux to authenticate with Active Directory
- Configuring a Squid Server to authenticate off Active Directory
- Squid autenticado no Active Directory com Winbind
- Autenticando o SQUID no Active Directory via NTLM
- SaMBa 3.x -> Tudo o que você precisa saber (e não tinha para quem perguntar :)

Abraços e até a próxima! 8)

Teste_ESX_GFS_Ever

Já escrevemos bastante sobre Virtualização usando Xen e Cluster aqui no Blog.

Desta vez, para começar bem 2009 eu irei apenas citar alguns testes que fiz usando VMware ESX com GFS, em um Storage compartilhado, usando tecnologia Red Hat 5.2 x86_64 com um Fence_VMWare Tech Preview do RHEL 5.3 beta.

O Problema

Eu já o utilizava o GFS com Xen ou até mesmo com DRBD em Muti-Master, porém o grande problema é que não existia um fence para vmware que funcionasse a contento.

O fence_vmware, escrito em perl parou no tempo em Agosto de 2007 e fora que a VMware Perl API necessária não compila em 64 bits.

A Red Hat pretende lançar agora no RHEL 5.3 um fence_vmware re-escrito em Python, porém ele ainda não trabalha com Cluster, pois conecta-se direto na máquina física, e não no VMCenter.

A Solução

A solução é utilizar o vmware_fence_vi, também da Red Hat que está em fase de desenvolvimento atualmente, que conecta no Virtual Center e não na máquina física que pode estar morta :)

Segue o /etc/cluster/cluster.conf utilizado nos testes:

Configuração do Cluster

<cluster alias="Cluster_GFS" config_version="10" name="Cluster_GFS">
	<fence_daemon clean_start="0" post_fail_delay="0" post_join_delay="3"/>
<cman>
    <multicast addr="224.0.0.1" interface="eth1"/>
</cman>
	<clusternodes>
		<clusternode name="cluster-01-node-01" nodeid="1" votes="1">
			<multicast addr="224.0.0.1" interface="eth1"/>
	           <fence>
        	        <method name="single">
                	        <device name="node-01"/>
	                </method>
	           </fence>
                </clusternode>
                <clusternode name="cluster-01-node-02" nodeid="2" votes="1">
			<multicast addr="224.0.0.1" interface="eth1"/>
                   <fence>
                        <method name="single">
                                <device name="node-02"/>
                        </method>
                   </fence>
                </clusternode>
                <clusternode name="cluster-01-node-03" nodeid="3" votes="1">
			<multicast addr="224.0.0.1" interface="eth1"/>
                   <fence>
                        <method name="single">
                                <device name="node-03"/>
                        </method>
                   </fence>
                </clusternode>
	</clusternodes>
	<fencedevices>
		<fencedevice agent="fence_vmware_vi" ipaddr="10.107.113.2" login="user" name="node-01" passwd="xxxxx" port="Cluster_01_Node_01"/>
		<fencedevice agent="fence_vmware_vi" ipaddr="10.107.113.2" login="user" name="node-02" passwd="xxxxx" port="Cluster_01_Node_02"/>
		<fencedevice agent="fence_vmware_vi" ipaddr="10.107.113.2" login="user" name="node-03" passwd="xxxxx" port="Cluster_01_Node_03"/>
	</fencedevices>
</cluster>

Notas:

1-) Troque parênteses por sinal de maior/ menor (maldito wordpress!) :(

2-) O IP 10.107.113.2 é o IP do Virtual Center. Ele sempre sabe onde a máquina virtual se encontra, mesmo que ela for migrada para outro host físico.

3-) Forçamos o MultiCast pela eth1, que é uma interface dedicada para o heartbeat do Cluster. Algumas vezes o multicast tentava sair pela interface de loopback e cada máquina achava que estava sozinha no cluster :(

/etc/hosts dos servidores:

10.0.0.1 cluster-01-node-01
10.0.0.2 cluster-01-node-02
10.0.0.3 cluster-01-node-03
10.0.1.1 node-01
10.0.1.2 node-02
10.0.1.3 node-03

Script de escrita

Foi utilizado um script para escrever no storage compartilhado a cada segundo com o nome da máquina e a hora exata (minuto, segundo) da escrita.

# for i in `seq 1 1000`; do a=`echo $RANDOM | cut -c1-2`; dd if=/dev/zero of=/teste/`hostname -s`-`date +%H_%M_%S` bs=512k count=$a; sleep 1; done

Nós do Cluster

[root@cluster-01-node-02 ~]# cman_tool nodes
Node Sts Inc Joined Name
1 M 60 2009-01-06 19:46:11 cluster-01-node-01
2 M 56 2009-01-06 19:46:11 cluster-01-node-02
3 M 68 2009-01-06 19:56:35 cluster-01-node-03

Fence Device

/sbin/fence_vmware_vi - DEVEL.1229423489
 
# The Following agent has been tested on:
# VI Perl API 1.6 against:
#       VMware ESX 3.5
#       VMware ESXi 3.5 update 2
#       VMware Virtual Center 2.5
#</code>

Com a seguinte modificação na linha 13:

#sys.path.append("@FENCEAGENTSLIBDIR@")
sys.path.append("/usr/lib/fence")

Desligar máquina VIRTUAL

Teste: Desligar máquina VIRTUAL cluster-01-node-03

Resultado: GFS congelado por ~1 minuto

O que ocorreu: O fence_vmware_vi conectou no vmcenter e tirou a máquina do Cluster, liberando assim o I/O.

Desligar máquina FISICA normalmente

Teste: Desligar com reboot máquina FISICA 01 (que tinha a cluster-01-node-03)

Resultado: GFS congelado por ~2 minutos

O que ocorreu: Máquinas física iniciou o processo de reboot, a máquina virtual cluster-01-node-03 morreu e foi migrada e reiniciada em outro host físico.

PS: A máquina virtual não retornou ao seu host de origem quando a máquina física voltou

-rw-r--r-- 1 root root 44040192 Jan 6 2009 cluster-01-node-01-19_50_52
-rw-r--r-- 1 root root 15204352 Jan 6 2009 cluster-01-node-01-19_50_53
-rw-r--r-- 1 root root 10485760 Jan 6 2009 cluster-01-node-01-19_50_54
-rw-r--r-- 1 root root 41418752 Jan 6 2009 cluster-01-node-01-19_52_57
-rw-r--r-- 1 root root 17825792 Jan 6 2009 cluster-01-node-01-19_52_58
-rw-r--r-- 1 root root 23068672 Jan 6 2009 cluster-01-node-01-19_52_59
-rw-r--r-- 1 root root 6815744 Jan 6 2009 cluster-01-node-01-19_53_00
-rw-r--r-- 1 root root 49807360 Jan 6 2009 cluster-01-node-01-19_53_01
-rw-r--r-- 1 root root 10485760 Jan 6 2009 cluster-01-node-01-19_53_03

Desligar máquina FISICA brutalmente

Desligar com RESET (via RSA) máquina FISICA 02 (que tinha a cluster-01-node-03)

Resultado: GFS congelado por ~3 minutos

O que ocorreu: Máquinas física foi brutalmente desligada, a máquina virtual cluster-01-node-03 morreu e foi migrada e reiniciada em outro host físico.

O fence_vmware_vi tentou várias vezes tirar a máquina do cluster com falhas consecutivas pois a máquina não mais existia e o ESX demorou um pouco para entender o que estava acontecendo.

PS: A máquina virtual não retornou ao seu host de origem quando a máquina física voltou

-rw-r--r-- 1 root root 12058624 Jan 6 20:17 cluster-01-node-01-20_17_57
-rw-r--r-- 1 root root 11534336 Jan 6 20:17 cluster-01-node-01-20_17_58
-rw-r--r-- 1 root root 10485760 Jan 6 20:17 cluster-01-node-01-20_17_59
-rw-r--r-- 1 root root 5242880 Jan 6 20:18 cluster-01-node-01-20_18_00
-rw-r--r-- 1 root root 5767168 Jan 6 20:20 cluster-01-node-01-20_18_01
-rw-r--r-- 1 root root 6291456 Jan 6 20:21 cluster-01-node-01-20_21_00
-rw-r--r-- 1 root root 37748736 Jan 6 20:21 cluster-01-node-01-20_21_02
-rw-r--r-- 1 root root 17825792 Jan 6 20:21 cluster-01-node-01-20_21_03
-rw-r--r-- 1 root root 12582912 Jan 6 20:21 cluster-01-node-01-20_21_04
-rw-r--r-- 1 root root 34603008 Jan 6 20:21 cluster-01-node-01-20_21_05
-rw-r--r-- 1 root root 5242880 Jan 6 20:21 cluster-01-node-01-20_21_06
-rw-r--r-- 1 root root 12582912 Jan 6 20:21 cluster-01-node-01-20_21_07
-rw-r--r-- 1 root root 12582912 Jan 6 20:21 cluster-01-node-01-20_21_08

Trechos de logs

Jan  6 20:18:10 cluster-01-node-01 openais[2646]: [TOTEM] The token was lost in the OPERATIONAL state. 
Jan  6 20:18:10 cluster-01-node-01 openais[2646]: [TOTEM] Receive multicast socket recv buffer size (288000 bytes). 
Jan  6 20:18:10 cluster-01-node-01 openais[2646]: [TOTEM] Transmit multicast socket send buffer size (262142 bytes). 
Jan  6 20:18:10 cluster-01-node-01 openais[2646]: [TOTEM] entering GATHER state from 2. 
 
Jan  6 20:18:15 cluster-01-node-01 openais[2646]: [CLM  ] CLM CONFIGURATION CHANGE 
Jan  6 20:18:15 cluster-01-node-01 openais[2646]: [CLM  ] New Configuration: 
Jan  6 20:18:15 cluster-01-node-01 openais[2646]: [CLM  ] 	r(0) ip(10.0.0.1)  
Jan  6 20:18:15 cluster-01-node-01 openais[2646]: [CLM  ] 	r(0) ip(10.0.0.2)  
Jan  6 20:18:15 cluster-01-node-01 openais[2646]: [CLM  ] Members Left: 
Jan  6 20:18:15 cluster-01-node-01 fenced[2666]: cluster-01-node-03 not a cluster member after 0 sec post_fail_delay
Jan  6 20:18:15 cluster-01-node-01 openais[2646]: [CLM  ] 	r(0) ip(10.0.0.3)  
Jan  6 20:18:15 cluster-01-node-01 fenced[2666]: fencing node "cluster-01-node-03"
 
  Please use '-h' for usagcation=HASH(0x1df33bd0)ing with the remote host.eports: vmware_helper returned Cannot power off vm Cluster_01_Node_03!
Jan  6 20:18:47 cluster-01-node-01 fenced[2666]: agent "fence_vmware_vi" reports: e 
Jan  6 20:18:47 cluster-01-node-01 ccsd[2636]: Attempt to close an unopened CCS descriptor (44880). 
Jan  6 20:18:47 cluster-01-node-01 ccsd[2636]: Error while processing disconnect: Invalid request descriptor 
Jan  6 20:18:47 cluster-01-node-01 fenced[2666]: fence "cluster-01-node-03" failed
Jan  6 20:18:52 cluster-01-node-01 fenced[2666]: fencing node "cluster-01-node"
 
Jan  6 20:19:28 cluster-01-node-01 fenced[2666]: agent "fence_vmware_vi" reports: Connection timed out 
Jan  6 20:19:28 cluster-01-node-01 ccsd[2636]: Attempt to close an unopened CCS descriptor (45600). 
Jan  6 20:19:28 cluster-01-node-01 ccsd[2636]: Error while processing disconnect: Invalid request descriptor 
Jan  6 20:19:28 cluster-01-node-01 fenced[2666]: fence "cluster-01-node-03" failed
 
Jan  6 20:19:33 cluster-01-node-01 fenced[2666]: fencing node "cluster-01-node-03"
  Please use '-h' tNotConnected=HASH(0x19bb0090)mote host, since it is disconnected.ware_helper returned Cannot power on vm Cluster_01_Node_03!
Jan  6 20:19:46 cluster-01-node-01 fenced[2666]: agent "fence_vmware_vi" reports: for usage 
Jan  6 20:19:46 cluster-01-node-01 fenced[2666]: fence "cluster-01-node-03" failed
Jan  6 20:19:51 cluster-01-node-01 fenced[2666]: fencing node "cluster-01-node-03"
 
Jan  6 20:20:59 cluster-01-node-01 ccsd[2636]: Attempt to close an unopened CCS descriptor (46710). 
Jan  6 20:20:59 cluster-01-node-01 ccsd[2636]: Error while processing disconnect: Invalid request descriptor 
Jan  6 20:20:59 cluster-01-node-01 fenced[2666]: fence "cluster-01-node-03.ig.com.br" success
Jan  6 20:20:59 cluster-01-node-01 kernel: GFS: fsid=Cluster_GFS:gfs.0: jid=2: Trying to acquire journal lock...
Jan  6 20:20:59 cluster-01-node-01 kernel: GFS: fsid=Cluster_GFS:gfs.0: jid=2: Looking at journal...
Jan  6 20:20:59 cluster-01-node-01 kernel: GFS: fsid=Cluster_GFS:gfs.0: jid=2: Acquiring the transaction lock...
Jan  6 20:20:59 cluster-01-node-01 kernel: GFS: fsid=Cluster_GFS:gfs.0: jid=2: Replaying journal...
Jan  6 20:20:59 cluster-01-node-01 kernel: GFS: fsid=Cluster_GFS:gfs.0: jid=2: Replayed 79 of 93 blocks
Jan  6 20:20:59 cluster-01-node-01 kernel: GFS: fsid=Cluster_GFS:gfs.0: jid=2: replays = 79, skips = 13, sames = 1
Jan  6 20:20:59 cluster-01-node-01 kernel: GFS: fsid=Cluster_GFS:gfs.0: jid=2: Journal replayed in 1s
Jan  6 20:20:59 cluster-01-node-01 kernel: GFS: fsid=Cluster_GFS:gfs.0: jid=2: Done

Conclusão

Estes testes foram realizados buscando alternativas que reduzam o downtime dos serviços e/ou aplicações contidos em um servidor, chegando a manter sua disponibilidade próxima dos 99,999%.

Como você pôde perceber, esta estrutura permite chegarmos a este número, mas até o momento em que está sendo escrito este post, a versão usada ainda não está homologada, usando pacotes ainda em desenvolvimento (cman+fence_vmware).

Num futuro próximo, já devemos ter algum retorno das empresas desenvolvedoras, pois focam em uma fatia do merdado muito forte e competitiva ($$$).

* DRBD 8.x

DBRD é a acrônimo para o nome inglês Distributed Replicated Block Device. O DRBD consiste num módulo para o kernel de Linux que, juntamente com alguns scripts, oferece um dispositivo de bloco projetado para disponibilizar dispositivos de armazenamento distribuídos, geralmente utilizado em clusters de alta disponibilidade. Isto é feito espelhando conjuntos de blocos via rede (dedicada). O DRBD funciona, portanto, como um sistema RAID baseado em rede.

Referência: http://pt.wikipedia.org/wiki/DRBD

* GFS 1.x

O “Red Hat Global File System” é um Sistema de Arquivos para Cluster, que permite que vários nós leiam e escrevam dados simultaneamente em um dispositivo compartilhado.

O GFS suporta ACL’s e atributos extendidos, diferente se seu concorrente direto, o OCFS (Oracle Cluster File System)

Vale observar que a versão 2.0 do GFS ainda é considerado “Technology Preview” e não deve ser usado em produção.

Porém, o GFS congela todo o I/O se ele perde um nó (cliente), e fica congelado até o que o nó retorne ou que o mesmo seja “fenced”.

Referência: http://www.redhat.com/gfs/
http://en.wikipedia.org/wiki/Comparison_of_file_systems

* Fence Devices

Fence é algo difícil de traduzir para a nossa língua, assim como a palavra “proxy” O Babylon sugere “grade; muro; cercar; proteger” enquanto o Google Translator sugere “vedação”.

Enfim, é algo nesse sentido: Se um nó do cluster apresenta problemas, para evitar que esse cara escreva algo no FileSystem? e acabe por corromper o mesmo, é necessário que o mesmo seja “fenceado”, ou seja, tirado da jogada. As formas comuns se se fazer isso são:

- Desligando a alimentação de energia deles;
- Desligando a porta do switch;
- Reiniciando a máquina usando DRAC/RSA/ILO (Dell, IBM e HP respectivamente);
- Manualmente;

Utilizaremos a forma menos recomendada (manual) devido a falta de infra-estrutura para utilizarmos as demais. Um script do modificado do DRBD irá tornar o fencing_manual em um fencing automatizado :-D

Referência: http://www.everlinux.com/blog/2008/04/22/redhat-enterprise-linux-51-cluster-suite/

* LVM

Usaremos LVM para garantir flexibilidade da solução:

Criar volumes LV nas duas máquinas

# pvcreate /dev/sda9
# vgcreate vol0 /dev/sda9
# lvcreate -L 105.94G -n lvm vol0

– Configurando o DRBD

Configurar o /etc/hosts para conter todas as maquinas, principalmente o hostname no IP principal e um nome para os IPs da rede de sincronismo:

127.0.0.1 localhost.localdomain localhost
10.10.10.1 hotsite-1.com.br
10.10.10.2 hotsite-2.com.br
192.168.0.3 drbd_hotsite-1 drdb_hotsite-1.com.br
192.168.0.4 drdb_hotsite-2 drdb_hotsite-2.com.br

Configurar o /etc/drbd.conf no master e slave

# DRDB Configuration
global {
        usage-count no;
}
 
resource hotsite {
        protocol C;
 
        startup {
                wfc-timeout 0;
                degr-wfc-timeout 120;
                become-primary-on both;
        }
        disk    {
                fencing resource-and-stonith;
        }
       handlers {
                outdate-peer "/sbin/obliterate";
        }
        net     {
                cram-hmac-alg sha1;
                shared-secret "senha_secreta";
                timeout 60;
                connect-int 10;
                ping-int 10;
                max-buffers 2048;
                max-epoch-size 2048;
                allow-two-primaries;
                after-sb-0pri discard-zero-changes;
                after-sb-1pri discard-secondary;
                after-sb-2pri disconnect;
                rr-conflict violently;
        }
        syncer  {
                rate 650M;
        }
 
        on hotsite-1.com.br {
                device    /dev/drbd0;
                disk      /dev/vol0/lvm;
                address   192.168.0.3:7789;
                flexible-meta-disk internal;
        }
 
 
 
        on hotsite-2.com.br {
                device    /dev/drbd0;
                disk      /dev/vol0/lvm;
                address   192.168.0.4:7789;
                flexible-meta-disk internal;
        }
}

Inicializar as partições para o drbd no master e slave

# drbdadm create-md hotsite |
# drbdadm attach hotsite | drbdadm up hotsite
# drbdadm connect hotsite |

# drbdadm -- --overwrite-data-of-peer primary hotsite
# watch -n1 cat /proc/drbd
# drbdadm primary hotsite

Obs: Caso de erro de carga de modulo inicie o drbd com “service drbd start” mesmo acusando erro, isso fará com que carregue o modulo corretamente.

Inicializar o drbd no master e slave

# service drbd start

- Configurando o cluster para o GFS

* Crie o arquivo de configuração do cluster (/etc/cluster/cluster.conf) para o gfs, em todas as maquinas:

Vou colocar ele em um arquivo separado pois o wordpress não está(va) gostando as tags do mesmo: cluster.conf

Update:

<?xml version="1.0"?>
<cluster name="hotsite" config_version="1">
 
<cman two_node="1" expected_votes="1"/>
 
<fence_daemon post_join_delay="60">
</fence_daemon>
 
<clusternodes>
<clusternode name="drdb_hotsite-1" nodeid="1">
        <fence>
                <method name="single">
                        <device name="node1" ipaddr="192.168.0.3"/>
                </method>
        </fence>
</clusternode>
<clusternode name="drdb_hotsite-2" nodeid="2">
        <fence>
                <method name="single">
                        <device name="node2" ipaddr="192.168.0.4"/>
                </method>
        </fence>
</clusternode>
</clusternodes>
 
<fencedevices>
        <fencedevice name="manual" agent="fence_manual"/>
</fencedevices>
</cluster>

Formatar a partição DRBD com GFS

# gfs_mkfs -t hotsite:gfs-00 -p lock_dlm -j 2 /dev/drbd0

Com isto ele irá iniciar o sincronismo com slave, pode ser observado executando o comando:

# watch -n 1 cat /proc/drbd

Inicie o serviços de cluster:

# service cman start

Testando

# mount -v /dev/drbd0 /data
# for i in `seq 1 10`; do a=`echo $RANDOM`; dd if=/dev/zero of=/data/$a bs=1k count=$a; sleep 1; done
# ls -ltrk /data

Forçando um reboot:
# echo 1 > /proc/sys/kernel/sysrq
# echo b > /proc/sysrq-trigger

Para forçar o sincronismo de uma máquina
(faça somente se souber o que está fazendo)
# drbdsetup /dev/drbd0 primary -o

Ordem dos scripts:

Essa deverá ser a ordem para init level 0 e 6, pois durante o reboot/ shutdown da máquina o procedimento é o seguinte:
- Desmonta a partição
- Tira a máquina do Cluster
- Para o DRBD

[root@hotsite-2 /etc/rc0.d]# ll | egrep '(partition|drbd|cman)'
lrwxrwxrwx 1 root root 12 Jun 13 11:57 K80partition -> ../init.d/partition
lrwxrwxrwx 1 root root 14 Jun 13 11:47 K81cman -> ../init.d/cman
lrwxrwxrwx 1 root root 14 Jun 13 11:57 K82drbd -> ../init.d/drbd

Para os init level 3, 4 e 5 deverá ser:
- Coloca a máquina do Cluster
- Inicia o DRBD
- Monta a partição do drbd (pois o mesmo irá falhar durante a inicialização)

[root@hotsite-2 /etc/rc3.d]# ll | egrep '(partition|drbd|cman)'
lrwxrwxrwx 1 root root 14 Jun 13 11:55 S21cman -> ../init.d/cman
lrwxrwxrwx 1 root root 14 Jun 13 11:55 S70drbd -> ../init.d/drbd
lrwxrwxrwx 1 root root 12 Jun 13 11:55 S91partition -> ../init.d/partition

O Script obliterate

O script Obliterate foi escrito pelo Lon Hohberger e está disponível aqui.

Eu alterei as últimas linhas pois o fence_manual precisa que o comando fence_ack_manual seja executado, senão o GFS não vai liberar o I/O do cluster enquanto o outro nó não retornar com sucesso…

#
fence_node $REMOTE
fence_ack_manual -O -e -n $REMOTE
 
if [ $? -eq 0 ]; then
	# Reference:
	# http://osdir.com/ml/linux.kernel.drbd.devel/2006-11/msg00005.html
	# 7 = node got blown away.  
	exit 7
fi
 
# Fencing failed?!
exit 1

Referência: http://sources.redhat.com/cluster/wiki/DRBD_Cookbook

O script anterior foi atualizado contando com algumas melhorias sugeridas pelos seus usuários, como:

- Agora ele é escrito em Inglês, para maior portabilidade com outros usuários do xen ao redor do mundo;

- Você pode fazer backup de somente uma máquina específica, não é mais necessário esperar todo o laço terminar para ver o resultado do mesmo;

- Script parametrizado e funcões sub-divididas e

- Pequenos problemas corrigidos.

#!/bin/bash
# Backup of Xen VM's
# Tiago Cruz - tiagocruz@everlinux.com
# v 1.0	Mar/2008 - Initial version, just backup all VM's
# v 1.1 May/2008 - Now we have functions and parameters
 
export PATH=$PATH:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
BACK="_snap"
LOG=/var/log/backup.`date +%Y%m%d`
# root partition to backup ("/")
# usually the second it's swap
ROOT="1"
 
[ ! -d "/mnt/back" ] &&  mkdir -p /mnt/back
[ ! -d "/data/backup" ] &&  mkdir -p /data/backup
 
function showHelp() {
        echo " "        
        echo "Use the following parameters: "
        echo "          help   = Show this help"
        echo "          all    = Backup of all VM's"
        echo "          list   = List all VM's from this domain"
        echo "          <vm>   = Backup one specific VM"
        echo " "
	echo "ex: back_xen.sh tomcat_shop"
        echo " "
	exit 1
}
 
function listVM() {
	echo "List of VM's avaliables:"
	/usr/sbin/xm list | awk '{print $1}' | egrep -v '(Name|Domain-0)'
	echo " "
}
 
function backXen () {
	echo "Backuping machine $i..."
	echo "Please, look the progress on $LOG"
	listVM | grep $i >/dev/null
	if [ $? -ne 0 ]; then
		echo "Machine $i does not exist, aborting!"
		exit 2
	fi	
	backup
	if [ $? -eq 0 ]; then
                echo "Backup of $i completed successfully!!!"
		echo "Backup finalized on `date` with load `cat /proc/loadavg | cut -c 1-14`" >> $LOG
		echo "==============================================" >> $LOG
		echo "==============================================" >> $LOG
        fi
}
 
function backAll () {
	VMS=`xm list | awk '{print $1}' | egrep -v '(Name|Domain-0)'`
	for i in $VMS; do
		backup
	done
	echo "Backup finalized on `date` with load `cat /proc/loadavg | cut -c 1-14`" >> $LOG
	echo "==============================================" >> $LOG
	echo "==============================================" >> $LOG
}
 
function backup () {
	echo "==============================================" >> $LOG
	echo "Backup $i started on `date` with load `cat /proc/loadavg | cut -c 1-14`" >> $LOG
	DEVICE=`grep ^disk /etc/xen/$i | awk -F "Vol_LVM" '{print $2}' | cut -d / -f 2 | cut -d , -f 1`
	echo "Virtual Machine $i uses $DEVICE as storage device" >> $LOG
 
	lvcreate --snapshot -L 15G -n $i$BACK /dev/Vol_LVM/$DEVICE >> $LOG 2>&1
	[ $? -ne 0 ] && echo "Error $i: creating LVM $i$BACK" >> $LOG 
 
	kpartx -a /dev/mapper/Vol_LVM-$i$BACK >> $LOG 2>&1
	mount /dev/mapper/Vol_LVM-$i$BACK$ROOT /mnt/back/ >> $LOG 2>&1
	[ $? -ne 0 ] && echo "Error $i: mounting $i$BACK$ROOT" >> $LOG 
 
	SIZE1=`df -hP /mnt/back/ | awk '{print $3}' | grep -v Used`
	SIZE2=`df -hP /mnt/back/ | awk '{print $2}' | grep -v Size`
	echo "Backup of /dev/mapper/Vol_LVM-$i$BACK$ROOT - $SIZE1 of $SIZE2 used" >> $LOG
	tar zcf /data/backup/$i-xen.tar.gz /mnt/back >> $LOG
	[ $? -ne 0 ] && echo "Error $i: creating /LVM/backup/$i.tar.gz" >> $LOG 
 
	SIZE3=`ls -lh /LVM/backup/$i-xen.tar.gz  | awk '{print $5}'`
	echo "Created /LVM/backup/$i-xen.tar.gz with $SIZE3" >> $LOG
 
	sleep 1
	umount /mnt/back/ >> $LOG 2>&1
	[ $? -ne 0 ] && echo "Error $i: umounting $i$BACK" >> $LOG 
	kpartx -d /dev/mapper/Vol_LVM-$i$BACK >> $LOG 2>&1
	[ $? -ne 0 ] && echo "Error $i: deleting partition mappings $i$BACK" >> $LOG 
 
	echo "Removing snapshot already backuped $i$BACK" >> $LOG
	lvremove /dev/Vol_LVM/$i$BACK -f >> $LOG 2>&1
}
 
if [ "$#" -eq 0 ]; then
	showHelp
 
fi
 
case "$1" in 
	list)	listVM	;;
	all )	backAll	;;
	help)	showHelp ;;
	 *  )  	i=$1; backXen ;;
esac

Caso tenha problemas com o copy-past, você pode pegar o mesmo aqui: back_xen.sh.txt.

Se você usa o Xen, usa Storage Devices sob LVM, e acha importante ter um backup das mesmas, você pode utilizar/ adaptar este pequeno script que tira um snapshot e em seguida faz um “tar.gz” de todo o “/” da sua VM, e a guarda em um local para que você possa restaura-lo caso necessário. :-D

#!/bin/bash
# Backup das VM's do Xen
# Tiago Cruz - tiagocruz@everlinux.com
# Mar/2008
export PATH=$PATH:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
 
VMS=`xm list | awk '{print $1}' | egrep -v '(Name|Domain-0)'`
BACK="_snap"
LOG=/var/log/backup
# Particao root, geralmente a segunda eh swap
ROOT="1"
 
[ ! -d "/mnt/back" ] &&  mkdir -p /mnt/back
[ ! -d "/dados/backup" ] &&  mkdir -p /dados/backup
 
for i in $VMS; do
        echo "=================================================================" >> $LOG
        echo "Backup $i iniciado em `date` com load de `cat /proc/loadavg`" >> $LOG
        DEVICE=`grep disk /etc/xen/$i | awk -F "Vol_LVM" '{print $2}' | cut -d / -f 2 | cut -d , -f 1`
        echo "Maquina Virtual $i usa $DEVICE como storage device" >> $LOG
 
        lvcreate --snapshot -L 15G -n $i$BACK /dev/Vol_LVM/$DEVICE >> $LOG
        [ $? -ne 0 ] && echo "Erro $i: criando LVM $i$BACK" >> $LOG
 
        kpartx -a /dev/mapper/Vol_LVM-$i$BACK >> $LOG
        mount /dev/mapper/Vol_LVM-$i$BACK$ROOT /mnt/back/ >> $LOG
        [ $? -ne 0 ] && echo "Erro $i: montando $i$BACK$ROOT" >> $LOG
 
        SIZE1=`df -hP /mnt/back/ | awk '{print $3}' | grep -v Used`
        SIZE2=`df -hP /mnt/back/ | awk '{print $2}' | grep -v Size`
        echo "Backup de /dev/mapper/Vol_LVM-$i$BACK$ROOT - $SIZE1 de $SIZE2 usados" >> $LOG
        tar zcf /dados/backup/$i-xen.tar.gz /mnt/back >> $LOG
        [ $? -ne 0 ] && echo "Erro $i: criando /dados/backup/$i.tar.gz" >> $LOG
 
        SIZE3=`ls -lh /dados/backup/$i-xen.tar.gz  | awk '{print $5}'`
        echo "Criado /dados/backup/$i-xen.tar.gz com $SIZE3" >> $LOG
 
        umount /mnt/back/ >> $LOG
        [ $? -ne 0 ] && echo "Erro $i: desmontando $i$BACK" >> $LOG
        kpartx -d /dev/mapper/Vol_LVM-$i$BACK >> $LOG
        [ $? -ne 0 ] && echo "Erro $i: desmapeando $i$BACK" >> $LOG
 
        echo "Removendo snapshot ja backupeado $i$BACK" >> $LOG
        lvremove /dev/Vol_LVM/$i$BACK -f >> $LOG
done
 
echo "Backup finalizado em `date` com load de `cat /proc/loadavg`" >> $LOG
echo "=================================================================" >> $LOG
echo "=================================================================" >> $LOG

Trecho do log:

Backup ora_busca iniciado em Fri Mar 28 05:02:53 BRT 2008 com load de 1.31 1.33 1.21
Maquina Virtual ora_busca usa ora_busca como storage device
Logical volume “ora_busca_snap” created
Backup de /dev/mapper/Vol_LVM-ora_busca_snap1 – 16G de 95G usados
Criado /dados/backup/ora_busca-xen.tar.gz com 4.9G
Removendo snapshot ja backupeado ora_busca_snap
Logical volume “ora_busca_snap” successfully removed

1-) Estou armazenando as VMs no LVM:

# lvcreate -Ay -L 60G -n vm00 Vol_LVM
# lvcreate -Ay -L 60G -n vm01 Vol_LVM
# lvcreate -Ay -L 60G -n vm02 Vol_LVM

2-) Estou usando o “partimage-0.6.7_beta2.tar.bz2″, pois a versão stable não funciona bem em 64 bits:

3-) A primeira VM deve ser instalada/ configurada manualmente/normalmente. Depois você pode tirar uma cópia dela:

# kpartx -a /dev/mapper/Vol_LVM-vm01
# partimage -z1 save /dev/mapper/Vol_LVM-vm01p1 /LVM/vm01p1.partimg.gz

ou
# partimage -z0 -c -d -f0 save /dev/mapper/Vol_LVM-vm01p1 /LVM/vm01p1.partimg
# kpartx -d /dev/mapper/Vol_LVM-vm01

PS: Note que se você usar compressão (-z1) a geração da imagem vai demorar mais para ser criado, porém com o tamanho bem menor (515M vs 3.7GB) . A restauração da mesma também será mais lenta.

4-) Com base na primeira VM:

# fdisk -l /dev/mapper/Vol_LVM-vm00
Disk /dev/mapper/Vol_LVM-vm00: 64.4 GB, 64424509440 bytes
255 heads, 63 sectors/track, 7832 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System
/dev/mapper/Vol_LVM-vm00p1 * 2 7395 59392305 83 Linux
/dev/mapper/Vol_LVM-vm00p2 7396 7832 3510202+ 82 Linux swap / Solaris

Você poderá preparar um arquivo, por exemplo, /tmp/parttable, com as especificações das demais partições.
1,7394,83,*
7395,,82,-

Estou usando uma partição primária para o raiz “/” (tipo 83) com ~ 60 GB e o restante para swap (tipo 82).

Você poderá usar o sfdisk e especificar os dados em: sectors, blocks, cylinders ou megabytes.

5-) Crie as partições para a segunda VM:

# dd if=/dev/zero of=/dev/mapper/Vol_LVM-vm01 count=1 bs=512
# sfdisk -uC /dev/mapper/Vol_LVM-vm01 < /tmp/parttable

Se preferir, simplesmente faça o processo manualmente:
# fdisk /dev/mapper/Vol_LVM-vm01

6-) Crie a SWAP para o segundo device:

Será necessário usar o "kpartx" para "mapear" as partições que existem dentro do device LVM:

# kpartx -a /dev/mapper/Vol_LVM-vm01
# ll /dev/mapper/Vol_LVM-vm01*
# mkswap /dev/mapper/Vol_LVM-vm01p2

7-) Restaure a imagem da primeira VM:

- Restauração com GZIP:

# partimage restore /dev/mapper/Vol_LVM-vm02p1 /LVM/vm01p1.partimg.gz
Time elapsed: 10m:59sec
Speed: 5.16 GiB/min
Data copied: 56.64 GiB

- Restauração sem GZIP:

# partimage restore /dev/mapper/Vol_LVM-vm03p1 /LVM/vm01p1.partimg.000
Time elapsed: 1m:15sec
Speed: 2.90 GiB/min
Data copied: 3.62 GiB

8-) Monte a VM e troque endereços de IP, hostname e MAC Address:
# mount /dev/mapper/Vol_LVM-vm01p1 /mnt/xen/
# vi /mnt/xen/etc/sysconfig/network-scripts/ifcfg-eth0
# vi /mnt/xen/etc/sysconfig/network
# vi /mnt/xen/etc/hosts

PS: Use o macgen.py para alterar o MAC address:

$ cat macgen.py
#! /usr/bin/python
# macgen.py script generates a MAC address for Xen guests
#
import random
mac = [ 0x00, 0x16, 0x3e,
random.randint(0x00, 0x7f),
random.randint(0x00, 0xff),
random.randint(0x00, 0xff) ]
print ':'.join(map(lambda x: "%02x" % x, mac))

9-) Desmonte a partição, e arrume seu /etc/xen/vm02:

# umount /mnt/xen
# kpartx -d /dev/mapper/Vol_LVM-vm02

Utilize o "uuidgen" para gerar um novo UUID para sua VM.
Não esqueça de trocar também o MAC no campo "vif" e o device LVM, ex:

name = "vm02"
uuid = "82f89076-487e-4de5-ab4a-99ce07c586eb"
maxmem = 1000
memory = 800
vcpus = 1
bootloader = "/usr/bin/pygrub"
on_poweroff = "destroy"
on_reboot = "restart"
on_crash = "restart"
vfb = [ "type=vnc,vncunused=1,keymap=en-us" ]
disk = [ "phy:/dev/Vol_LVM/vm01,xvda,w" ]
vif = [ "mac=00:16:3e:5a:02:a6,bridge=xenbr0" ]

10-) Inicie a VM e corra para o abraço:

# xm create vm02 -c

Em caso de problemas, consulte este artigo: Xen: Dicas rápidas e problemas resolvidos

Caso você precise saber quanta memória seus processos do apache estão utilizando do seu SO, pode utilizar este script no crontab:

#!/bin/bash
LOG="/var/log/apache_memoria.log"
PROC=`ps -eLf | grep apache | wc -l`
rm -f /tmp/http.txt
for i in `ps -ylC httpd --sort:rss | awk '{print $8}'`; do echo $i | grep -v RSS >> /tmp/http.txt ; done
MEM=$(echo "scale=2; (`cat /tmp/http.txt | tr '\n' +`0"\)/1024 | bc)
echo "`date` -- $MEM MB utilizados pelo httpd com $PROC processos" >> $LOG

Os resultados me parecem bem interessantes... :-)

...
Tue Jan 8 12:45:01 BRST 2008 -- 765.91 MB utilizados pelo httpd
Tue Jan 8 13:00:01 BRST 2008 -- 903.92 MB utilizados pelo httpd
Tue Jan 8 13:15:01 BRST 2008 -- 689.61 MB utilizados pelo httpd
Tue Jan 8 13:30:01 BRST 2008 -- 629.17 MB utilizados pelo httpd
...

A quantidade pode variar bastante, caso seu apache seja estático ou dinâmico (com PHP por exemplo) e MPM's de prefork e worker também apresentam resultados diferentes.

Estou passando aqui somente para compartilhar um shell script para verificar o estado atual da sua controladora RAID, pois redundância é bom mas se você não trocar os discos não adianta muita coisa :-)

O script atualmente suporta:

- Controladoras da LSI Megaraid e as mais novas MegaraidSAS, usando o megarc e o MegaCli respectivamente;
- Contoladoras ServerRAID da IBM (só o modelo novo que não funciona ainda no ipssend, o “IBM ServeRAID 8k/8k-l8” e eu não entendo o motivo.);
- Controladora Mylex e RAID por Software;
- É capaz de detectar sua controladora e configurar o nrpe localmente;
- Dá permissão para o usuário do nagios usar SUID para rodar os aplicativos;

Utilize os seguintes parâmetros:
check_raid.sh detecta – Para tentar detectar sua controladora e instalar os pacotes necessários
check_raid.sh nrpe – Para configurar o daemon do nrpe para a sua controladora

check_raid.sh megaraid – Para controladoras MegaRAID (geralmente nas Dell’s Poweredge 18xx, 28xx ou mais antigas)
check_raid.sh megaraid_sas – Para controladoras MegaRAD SAS (geralmente nas Dell’s Poweredge 19xx, 29xx ou mais novas)
check_raid.sh serveraid – Para controladoras geralmente presente em máquinas IBM’s
check_raid.sh mylex – Para a controladora Mylex
check_raid.sh software – Para RAID via software

Exemplos:
check_raid.sh nrpe
check_raid.sh megaraid_sas

O script está meio bagunçado, não reconhece todas as controladoras mas é um adianto na hora de chegar centenas ou milhares de RAID’s diferentes. Caso tenha alguma contribuição, favor entrar em contato comigo (tiagocruz AT everlinux.com).

Download aqui: http://everlinux.com/raid/check_raid.sh

PS: Não enviei ao NagioExchange porque fiz a me*** de escreve-lo todo em Português do Brasil… :-(