terça-feira, 27 de fevereiro de 2018

Utilizando NUT para controle de Nobreak TS SHARA com Raspberry

Eu montei um servidor LORAWAN com um raspberry, mas ele deixava de funcionar toda semana, com o sistema de arquivo corrompido. Não encontrei problemas na memória USB por isso a causa parece ser mais por desligamento incorreto do raspberry devido falta de energia. Para isso arrumei um nobreak.

Resultado de imagem para tsshara sohos IIImagem relacionada
Nobreak TS Shara Soho II: parece a cabeça de um robo do star wars

Um nobreak protege contra falta de energia, mas precisa comunicar com o servidor, caso contrário quando a carga da bateria esgotar ele desliga o servidor incorretamente e tenho o mesmo problema. Ele também precisa ligar o servidor novamente quando a energia voltar. Estes são os nobreak gerenciaveis. Procurei o nobreak mais barato com controle por USB e encontrei o TS Shara Solo II. Encontrei os drivers na pagina do fabricante e achei que em meia hora tudo estaria funcionando...só que não!!

O programa fornecido pelo fabricante para linux é baseado no pacote NUT com drivers específicos para o TS Shara. O problema é que o drivers são compilados para plataforma x86 e não devem rodar no ARM do raspberry. De qualquer forma o software não funcionou legal no meu desktop (não investiguei porque), por isso resolvi ir direto para o NUT puro. Na página do NUT havia a informação que existia suporte para esse nobreak com o driver nutdrv_qx.

Instalei o nut:
sudo apt-get install nut-client nut-server

Fiz a configuração dele adicionando os texto abaixo em cada arquivo:

/etc/nut/nut.conf
MODE=standalone

/etc/nut/ups.conf
[tsshara]
        driver = nutdrv_qx
        desc = "tsshara"
        port = auto
        protocol = "megatec"

/etc/nut/upsd.users
[upsmon]
        password = "123456"
        upsmon master
        actions = SET
        instcmds = ALL

/etc/nut/upsmon.conf
MONITOR tsshara@localhost 1 upsmon "123456" master
NOTIFYFLAG ONBATT SYSLOG+WALL+EXEC
NOTIFYFLAG ONLINE SYSLOG+WALL+EXEC

Teste do driver. Ele deve mostrar algum erro se não funcionar.
sudo upsdrvctl start

Depois de um boot tudo estava funcionando. Para testar use:
upsc tsshara

Que deve apresentar algo assim:
Init SSL without certificate database
battery.charge: 92
battery.voltage: 12.80
battery.voltage.high: 13.00
battery.voltage.low: 10.40
battery.voltage.nominal: 12.0
device.mfr: UPS  700 VA AUT
device.model: TS Shara
device.type: ups
driver.name: nutdrv_qx
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.protocol: megatec
driver.parameter.synchronous: no
driver.version: 2.7.4
driver.version.data: Megatec 0.06
driver.version.internal: 0.28
input.current.nominal: 4.0
input.frequency: 60.0
input.frequency.nominal: 60
input.voltage: 0.0
input.voltage.fault: 0.0
input.voltage.nominal: 115
output.voltage: 111.0
ups.beeper.status: enabled
ups.delay.shutdown: 30
ups.delay.start: 180
ups.firmware: 20070731-5
ups.productid: 0035
ups.status: OB
ups.type: offline / line interactive
ups.vendorid: 0483


Mas um nobreak só resolve se ele desligar e ligar meu servidor de forma controlada. O nobreak tem suporte para desligar o servidor quando falta energia e a carga da bateria esta baixa, e religar o quando a energia voltar. Aqui que começaram os problemas. O comando para testar isso é o seguinte:

sudo upsmon -c fsd

E foi... o raspberry fez o shutdown direitinho e o nobreak desligou após 30 segundos. Após 180 segundos ele ligou novamente (mágica!!) e no meio do boot o nobreak apagou!! Após 180 segundos ele ligou novamente e apagou no meio do boot novamente. E ficou ligando e desligando até eu aceitar que alguma coisa não estava funcionando direito. O sistema de arquivo ja tinha ido pro saco e tive que restaurar a imagem para fazer o raspberry funcionar novamente.

Oque estaria causando esse apagão durante o boot?? Olhei o código fonte do NUT (que é uma das coisas mais confusas que já conheci), log do linux, recompilei o código, e sempre com o apagão no boot. Uma semana depois encontrei o problema: o nobreak sempre apagava depois de ter sido desligado por software, e 30 segundos após reconectar a porta USB. Nem importava se havia comunicação na USB, bastava por ali 5V que ele apagava depois de 30 segundos!!. Mas durante os testes quando eu utilizava o comando abaixo ele funcionava corretamente:

upscmd tsshara shutdown.return

hummm...existe alguma coisa diferente entre o upsmon  e o upscmd!A diferença que fez a diferença é que no upscmd após o comando de shutdown.return ele continua enviando comandos para ler o status do nobreak, enquanto no upsmon o shutdown.return é o último comando enviado. Alterei o driver, coloquei uma leitura de status depois no final da função de shudown e...uuhhuuu...funcionou corretamente. Isso parece ser um bug no nobreak, onde ele executa o ultimo comando enviado sempre que a USB é reconectada. O comando shutdown.return desliga o nobreak 30 segundos depois de recebido, aguarda 180 segundos e liga o sistema novamente. Sempre a USB era reconectada esse padrão acontecia. Enviar um comando diferente depois do shutdown.return parece impedir que ele fique reiniciando.

Ótimo, mas o driver não ficou legal, pois preciso recompilar o driver, dá um trabalhao, e a solução não é boa suficinete para mandar um patch no driver, pois deve ser um bug específico do TS Shara. A solução que encontrei foi alterar o script de shutdown enquanto converso com os desenvolvedores do NUT qual a melhor forma de resolver esse problema e incluir solução no pacote:

Alterei o arquivo /lib/systemd/system-shutdonw/nutshutdown:

#!/bin/sh
# comando original
#/sbin/upsmon -K >/dev/null 2>&1 && /sbin/upsdrvctl shutdown
# Comando alternativo para contornar possível bug no nobreak TS Shara
/sbin/upsmon -K >/dev/null 2>&1 && /lib/nut/nutdrv_qx -a tsshara -k; /lib/nut/nutdrv_qx -a tsshara 

O uspmon -K checa se tem a flag de shutdown ativada, se estiver chama o resto do script. O comando em seguida é para chamar a rotina de shutdown original, e o terceiro comando é para realizar a leitura de status do nobreak e evitar o bug no boot.

Esta solução não e flexível, pois amarra a configuração do nobreak com o arquivo de shutdwon. Outro problema é que diferentes plataformas utilizam o diferentes scripts de shutdown. Por exemplo esse script de shutdown não é utilizado no meu desktop ubuntu, por isso não consigo resolver esse problema no meu desktop dessa forma.

A versão utilizada do NUT é o 2.7.4. A versão no nutdrv_qx é 0.28 (versão mais antigas podem não ter suporte para o tsshara). Os pacote oficial para ubuntu é mais antigo e não funciona com esse nobreak ainda.

ps: depois de testar até o fim da carga da bateria percebi que essa configuração não funciona direito, pois o nobreak fica reiniciando mesmo quando não tem alimentação da rede. O esperado seria ele ficar desligado até a energia elétrica voltar, e somente após isso ele deveria religar.
Num próximo post vou apresentar os detalhes para resolver isso.