About
Games
Software
Historia
3 Agosto 2005: primera versión pública
Este documento es una pequeña receta para configurar un SAI PowerMust 600 Plus en OpenBSD empleando NUT.
En primer lugar hay que quitar de /etc/boot.conf la linea que permite ver el arranque en el puerto serie (si existe), así como la posible configuración en /etc/ttys que nos da una terminal serie, sino no podremos controlar el SAI desde ahí. Esto es habitual en servidores sin teclado ni monitor, así que cuidado.
En caso de tener alguna configuración de las descritas, reiniciamos el servidor para poder usar el interfaz por el puerto RS-232 con el protocolo smart APC (según la documentacuión), sin que interfiera la configuración anterior, y nos ponemos a mirar las opciones que tenemos en OpenBSD.
El SAI es un YUKAI PowerMust 600 Plus (600VA/360W), una opción económica y suficiente para mis necesidades. En realidad hice una mala compra, porque no comprobé compatibilidades :(. Menos mal que ha habido algo de suerte (poca).
En los ports (OpenBSD 3.6) tenemos upsd, apc-upsd y NUT. Todos productos soportan el procotolo que emplea el SAI (aparentemente), aunque solo he encontrado una página web actualizada para NUT, y además resulta que los fabricantes introducen variaciones en el protocolo... así que necesitamos un manejador específico.
Como NUT soporta mi SAI con la versión 2.0.1 y posteriores (con el driver para PowerMust 600VA Plus), pero en los ports está una versión vieja, me toca actualizar el port a mano o aplicar el parche para mi versión de NUT. He elegido esta segunda opción.
# export CVSROOT=anoncvs@anoncvs3.usa.openbsd.org:/cvs # export CVS_RSH=/usr/bin/ssh # cd /usr # mkdir -p ports/sysutils # cvs -z -q get -rOPENBSD_3_6 ports/sysutils/nut cvs server: Updating ports/sysutils/nut ... # cd ports/sysutils/nut/ # wget http://students.fct.unl.pt/~cer09566/nut/files/nut-1.4.2-powermust0.9.patch # FLAVOR=no_cgi make patch ... # cd w-nut-1.4.1-no_cgi/nut-1.4.1/ # patch -p1 < ../../nut-1.4.2-powermust0.9.patch ... # cd ../.. (editamos pkg/PLIST y añadimos bin/powermust detrás de bin/powercom) # FLAVOR=no_cgi make package ...
He resumido la salida de los distintos comandos, espero que aún así sea claro :P.
Al instalar el paquete nos indica que ha creado el usuario _nut, dónde ha dejado los ficheros de configuración (en /etc/nut/) y un ejemplo para poner el arranque en /etc/rc.local.
Ahora voy a describir los pasos habituales para configurar NUT.
Necesitamos iniciar el manejador del SAI, el demonio que obtiene la información del manejador, y un monitor que realize acciones cuando haga falta (nos quedamos sin batería).
Editamos /etc/nut/ups.conf y ponemos los datos del SAI:
[bsups]
driver=powermust
port=/dev/tty00
desc="Blackshell"
Comprobamos que el SAI se detecta correctamente:
# upsdrvctl -u _ups start Network UPS Tools - UPS driver controller 1.4.1 Network UPS Tools - Mustek PowerMust UPS driver 0.9 (1.4.1) Carlos Rodrigues (c) 2003, 2004 Serial port read timed out Serial port read ok again Mustek PowerMust UPS detected.
Echamos un vistazo /etc/nut/upsd.conf, aunque por defecto solo permite el acceso a localhost así que en un principio no hace falta tocar nada.
Añadimos un usuario a /etc/nut/upsd.users para posterior uso con upsmon:
[muser]
password=pass
allowfrom=localhost
upsmon master
Preparamos los ficheros de configuración para el usuario que correrá upsd (en el port tiene el grupo dialer), y arrancamos el demonio:
# chown root:dialer /etc/nut/upsd.conf /etc/nut/upsd.users # chmod 640 /etc/nut/upsd.conf /etc/nut/upsd.users # upsd -u _ups Network UPS Tools upsd 1.4.1 Connected to UPS [bsups]: powermust-cua00 Synchronizing...done
Ahora ya podemos empezar a hacer preguntas:
# upsc bsups@localhost battery.charge: 100.0 battery.voltage: 13.8 battery.voltage.nominal: 12.0 driver.name: powermust driver.parameter.port: /dev/cua00 driver.version: 1.4.1 driver.version.internal: 0.9 input.voltage: 230.5 input.voltage.fault: 230.0 input.voltage.maximum: 232.5 input.voltage.minimum: 223.0 output.frequency: 49.7 output.voltage: 230.5 output.voltage.target.battery: 230.0 ups.delay.shutdown: 2 ups.delay.start: 3 ups.load: 4.0 ups.mfr: Mustek ups.model: PowerMust ups.status: OL
Perfecto. Esta información es útil, pero lo que estoy buscando es que el servidor se apague cuando el SAI se quede sin baterias. Para eso necesitamos upsmon.
Su configuración está en /etc/nut/upsmon.conf y tendremos que añadir una linea para nuestro SAI:
MONITOR bsups@localhost 1 muser pass master
El resto se puede quedar por defecto, destacando SHUTDOWNCMD para indicar qué comando ejecutar para detener la máquina (sin apagarla, de eso se debe encargar el SAI, cuidado con no tener activado powerdown en nuestro /etc/rc.shutdown) .
En este punto es interesante configurar algunas notificaciones, para que se nos avise de los eventos más importantes.
Ponemos en /etc/nut/upsmon.conf la variable NOTIFYCMD a /usr/local/bin/upsnotify. Creamos un script tal que:
#!/bin/sh
# recordar hacer chmod +x
echo ${NOTIFYTYPE}: $* | mail -s "$UPSNAME NUT Notify" reidrac
Añadimos a /etc/nut/upsmon.conf las notificaciones que creamos convenientes e indicamos vía NOTIFYFLAG cómo deben informarnos:
NOTIFYMSG ONBATT "%s is on battery" NOTIFYMSG ONLINE "%s is back online" NOTIFYMSG LOWBATT "%s has a low battery!" NOTIFYMSG SHUTDOWN "System is being shutdown!" NOTIFYFLAG ONBATT SYSLOG+EXEC NOTIFYFLAG ONLINE SYSLOG NOTIFYFLAG LOWBATT SYSLOG+EXEC NOTIFYFLAG SHUTDOWN SYSLOG+EXEC
Aseguramos el fichero de configuración y arrancamos upsmon:
# chown root:dialer /etc/nut/upsmon.conf # chmod 640 /etc/nut/upsmon.conf # upsmon -u _ups Network UPS Tools upsmon 1.4.1 Using power down flag file /etc/killpower UPS: bsups@localhost (master) (power value 1)
Ahora actualizo mi /etc/rc.local como sigue:
...
# nut
if [ X"${nut_ups}" != X"NO" ]; then
echo -n " nut"
# dentro del arranque de nut
# para que funcione upssched
# y para que pueda escribir upsmon
mkdir -p /var/run/ups
chown _ups:dialer /var/run/ups
/usr/local/bin/upsdrvctl -u _ups start > /dev/null
/usr/local/sbin/upsd -i 127.0.0.1 -u _ups > /dev/null 2>&1
/usr/local/sbin/upsmon -u _ups > /dev/null 2>&1
fi
...
Y activo NUT en /etc/rc.conf.local con nut_ups="" (con "NO" lo desactivaríamos).
Desde la documentación se recomienda que añadamos al final de /etc/rc.shutdown algo como:
# OJO: POWERDOWNFLAG en upsmon.conf indica el fichero a comprobar
if [ -f /etc/killpower ]; then
echo "Killing the power, bye!"
/usr/local/bin/upsdrvctl shutdown
fi
De esta forma es nuestra máquina la que indica al SAI que debe cortar la corriente. Cuando vuelva la energía, el SAI despertará y arrancará el servidor.
Hay que tener en cuenta que nuestro SAI no espera a que acabe de cerrarse el sistema, y /etc/rc.shutdown se ejecuta con todos los discos montados normalmente y todos los procesos funcionando. Apagar así no es nada saludable.
No hay una solución fácil a este problema. Mi propuesta: sincronizamos el disco y montamos todo lo necesario en modo solo lectura.
Además hay que hacer una pequeña adaptación para que funcione el script con nuestro usuario sin privilegios, incluyendo también un hack para que el shutdown funcione. El script quedaría:
# OJO: POWERDOWNFLAG debe ser /var/run/ups/killpower
if [ -f /var/run/ups/killpower ]; then
echo "Killing the power, bye!"
# sino paramos la instancia en funcionamiento
# no podemos hacer shutdown
/usr/local/bin/upsdrvctl stop
sleep 3
# estabilizamos el disco (cuidado si hay más particiones)
/bin/sync
/sbin/umount -a
/sbin/mount -r /
/sbin/mount -r /var
/sbin/mount -r /tmp
/sbin/mount -r /usr
/usr/local/bin/upsdrvctl shutdown
fi
Con esto se minimiza el impacto del apagado ya que el disco está sincronizado y las particiones montadas en solo lectura.
Ahora solo queda probar el invento cerrando la corriente que llega al SAI (el botón de la regleta es pefecto :D), esperamos a que se descargue la batería y volvemos a dar la corriente.
Al volver a arrancar el servidor comprobaremos que se apagó normalmente (por las notificaciones, porque no aparecerá en el dmesg el peligroso mensaje: WARNING: / was not properly unmounted
, etc.).
Hasta aquí si todo marcha bien (que gracia, como si no fuera suficientemente complicado :D). Pero resulta que mi SAI no funciona como debería (tiene dos años ya) y no llega a dar avisos para nivel de batería baja (pitido cada 0.5 segundos). En lugar de eso, se apaga... así que upsmon no llega a hacer su trabajo adecuadamente.
Vamos a utilizar upssched para que gestione un temporizador durante 2 minutos y dispare el apagado una vez pasado ese tiempo. No es una solución óptima pero nos permitirá aguantar varios apagones de ese tiempo relativamente seguidos (sin tiempo para recuperar la batería).
Cambiamos ligeramente la configuración en /etc/nut/upsmon.conf:
NOTIFYCMD /usr/local/sbin/upssched NOTIFYMSG ONBATT "%s is on battery" NOTIFYMSG ONLINE "%s is back online" NOTIFYMSG LOWBATT "%s has a low battery!" NOTIFYMSG SHUTDOWN "System is being shutdown!" NOTIFYFLAG ONBATT SYSLOG+EXEC NOTIFYFLAG ONLINE SYSLOG+EXEC NOTIFYFLAG LOWBATT SYSLOG+EXEC NOTIFYFLAG SHUTDOWN SYSLOG+EXEC
Los cambios están en negrita. Ahora editamos /etc/nut/upssched.conf:
PIPEFN /var/run/ups/upssched.pipe LOCKFN /var/run/ups/upssched.lock CMDSCRIPT /usr/local/bin/upssched-cmd AT ONBATT * START-TIMER ONBATT 120 AT ONLINE * CANCEL-TIMER ONBATT AT LOWBATT * EXECUTE LOWBATT AT SHUTDOWN * EXECUTE SHUTDOWN
Creamos el /usr/local/bin/upssched-cmd con el siguiente contenido:
#!/bin/sh
# recordar chmod +x
case $1 in
ONBATT)
echo ONBATT TIMEOUT | mail -s "UPS Notify" reidrac
/usr/local/sbin/upsmon -c fsd
;;
LOWBATT)
echo LOWBATT | mail -s "UPS Notify" reidrac
;;
SHUTDOWN)
echo SHUTDOWN | mail -s "UPS Notify" reidrac
;;
*)
logger -t upssched-cmd "Unrecognized command: $1"
;;
esac
De esta forma se apagará la máquina y el SAI tras 2 minutos funcionando con la batería, cancelándose este temporizador en caso de volver la corriente en ese plazo de tiempo.
Ahora ya puedo dejar el servidor con el piloto automático e irme de vacaciones sin miedo a que un corte prolongado de electricidad fastidie alguna pieza vital del hardware de la máquina ;).
En esta receta he cubierto la configuración habitual (más algún hack), y cómo programar apagados en caso de que nuestro SAI no se comporte adecuadamente.