"Después del juego es antes del juego"
Sepp Herberger

viernes, 7 de noviembre de 2014

Controlar nuestro SAI con nut (Parte 1)

En nuestra querida Extremadura se nos va mas de lo deseado la  corriente eléctrica (y eso que sólo consumimos el 25% de lo que generamos: en casa de herrero, cuchillo de palo) y es imprescindible un SAI para tener protegidos los servidores, el switch troncal y el router de salida a Internet. Y si el SAI lo controlamos desde uno de los servidores, mejor que mejor, pues así podremos estar avisados y llevar un registro de todo lo que pasa.
Antes de nada, hacer una distinción que no conocía y que me trajo muchos quebraderos de cabeza. Ladies and gentlemen: hay dos/tres clases de SAI.
  • Pasivo u offline: en este SAI la corriente entra de fuera y se bifurca en dos líneas paralelas, una que va a las salidas del SAI y otra que va a la batería. Cuando hay un corte de corriente la línea directa que va a la salida pierde la potencia y la batería tiene que activarse y empezar a suministrar energía. Este proceso tarda unos milisegundos llamado "tiempo de transferencia" y genera una onda cuadrada. Si el ordenador que hay conectado a la salida es demasiado sensible (por ejemplo, un servidor HP que tengo) a estas variaciones de la señal, se pondrá en modo standby e interrumpirá su funcionamiento normal. Es decir, que el SAI no servirá de nada y hasta que me di cuenta de esto estuve comiéndome el coco pensando que la fuente de alimentación del servidor era defectuosa.
  • Activo u online: en este SAI la corriente entra de fuera, pasa a la batería y luego a la salida. Es decir, la salida siempre está recibiendo energía de la batería. Si hay un corte no pasa nada: la batería sigue suministrando energía como antes sin que haya ningún tipo de distorsión. Estos SAIs son mas caros, pero no van a darnos problemas con ningún tipo de servidor.
  • Line interactive (añadido 23/11/2015): es un sistema intermedio entre los dos anteriores, basado en utilizar la batería para regular rápidamente las variaciones de tensión.
Prosigamos. Una vez montada la parte eléctrica del SAI y viendo que funciona, tenemos que enchufarlo por el cable USB  al PC que lo va a controlar. Una vez enchufado hacemos lsusb para saber como se identifica. En mi caso la salida es:
Bus 005 Device 024: ID 06da:0003 Phoenixtec Power Co., Ltd 1300VA UPS
Esto debemos anotarlo para buscar luego en Google el driver de nuestro SAI. Yo he buscado "06da:0003 nut driver" en Google, obteniendo varios enlaces con el referencias al driver nut a usar. En unos hablaban del megatec_usb y en otros del blazer_usb. Me decanté por el segundo y acerté.
Ahora procederemos a instalar los paquetes necesarios para el control: nut, nut-cgi, nut-client y nut-server. Nut es un sistema cliente-servidor, formado por un servidor (upsd-upsdrvctl) y uno o varios clientes (upsmon). Esto permite que el SAI sea monitorizado desde un ordenador al que está conectado por cable usb o serie, pero los resultados de esa monitorización estén disponibles en varios equipos (ya que normalmente un SAI suministra energía a varias máquinas). Nosotros vamos a usar un esquema simple en que solo tenemos un servidor y un cliente, alojados en el mismo PC y él se ocupa de todo.
Una vez instalados los paquetes, vamos a configurarlos. Empezamos editando /etc/nut/ups.conf:
[salicru]
driver = blazer_usb
desc = "SAI Salicru"
port = auto
vendorid = 06da
productid = 0003
bus = "005"
Comentemos:
  • [salicru]: nombre que vamos a dar al SAI para manejarlo luego.
  • desc: descripción del SAI.
  • driver: driver a usar.
  • port: puerto a usar, normalmente "auto" es suficiente. En el caso de SAIs conectados por el puerto serie podríamos tener que poner /dev/ttySX
  • vendorid, productid: los identificadores USB del SAI, mostrados con el lsusb.
  • bus: el bus USB donde va conectado el SAI, mostrado con el lsusb.
Siguiente fichero: /etc/nut/upsd.conf
ACL localhost 127.0.0.1/32
ACL local_network 172.19.231.0/24
ACL all 0.0.0.0/0

ACCEPT monitor localhost
ACCEPT local_network
REJECT all all
Aquí ponemos la red de nuestro centro (marcado en rojo). Simplemente es para decir desde que parte de la red va a permitir nut que se hagan conexiones para controlar el estado del SAI.

Nota 23/11/2015: bueno, pues resulta que esta configuración está deprecated(=viejuna). Ahora la nueva sintaxis es esta descrita aquí. Basicamente con
LISTEN ip [puerto] 
indicamos a través de su IP por cual interface de red/puerto se aceptarán peticiones, en nuestro caso sería:
LISTEN 127.0.0.1
LISTEN 172.19.231.X

Siguiente fichero, /etc/nut/upsd.users:
[admin]
password = pwd_admin
allowfrom = localhost local_network
actions = SET
instcmds = ALL

[control]
password = pwd_control
allowfrom = localhost local_network
upsmon master
Son los usuarios para acceder remotamente al proceso servidor que controla el SAI desde los clientes. Lo dejamos tal cual está aquí.

Otro fichero más, /etc/nut/upsmon.conf:
MONITOR salicru@localhost 1 control pwd_control master
RUN_AS_USER nut
MINSUPPLIES 1
SHUTDOWNCMD "/root/scripts/apagar_servidores.sh"
POLLFREQ 5
POLLFREQALERT 5
HOSTSYNC 15
DEADTIME 15
POWERDOWNFLAG /etc/killpower

NOTIFYCMD "/sbin/upssched"

NOTIFYMSG ONLINE "UPS: Normal state"
NOTIFYMSG ONBATT "UPS: On battery"
NOTIFYMSG LOWBATT "UPS: Battery low"
NOTIFYMSG FSD "UPS: Starting shutdown"
NOTIFYMSG COMMOK "UPS: Communication restored"
NOTIFYMSG COMMBAD "UPS: Communication lose"
NOTIFYMSG SHUTDOWN "UPS: Shutting down"
NOTIFYMSG REPLBATT "UPS: Replace battery"

NOTIFYFLAG ONLINE SYSLOG+WALL+EXEC
NOTIFYFLAG ONBATT SYSLOG+WALL+EXEC
NOTIFYFLAG LOWBATT SYSLOG+WALL+EXEC
NOTIFYFLAG FSD SYSLOG+WALL+EXEC
NOTIFYFLAG COMMOK SYSLOG+WALL+EXEC
NOTIFYFLAG COMMBAD SYSLOG+WALL+EXEC
NOTIFYFLAG SHUTDOWN SYSLOG+WALL+EXEC
NOTIFYFLAG REPLBATT SYSLOG+WALL+EXEC

RBWARNTIME 43200
NOCOMMWARNTIME 300
FINALDELAY 0

Siguiente fichero, /etc/nut/upsset.conf:
# Network UPS Tools - upsset.conf sample file
deny from all
allow from 172.19.231.0
Aqui va el rango de direcciones de red que van a poder acceder a la página web que muestra el estado del SAI. En nuestro caso, toda nuestra red, que cada cual ponga aquí lo que estime oportuno.
Siguiente fichero, /etc/nut/hosts.conf:
# Network UPS Tools: example hosts.conf
#
# This file is used to control the CGI programs.  If you have not
# installed them, you may safely ignore or delete this file.
#
# -----------------------------------------------------------------------
#
# upsstats will use the list of MONITOR entries when displaying the
# default template (upsstats.html).  The "FOREACHUPS" directive in the
# template will use this file to find systems running upsd.
#
# upsstats and upsimage also use this file to determine if a host may be
# monitored.  This keeps evil people from using your system to annoy
# others with unintended queries.
#
# upsset presents a list of systems that may be viewed and controlled
# using this file.
#
# -----------------------------------------------------------------------
#
# Usage: list systems running upsd that you want to monitor
#
# MONITOR  ""
#
# Examples:
#
# MONITOR myups@localhost "Local UPS"
# MONITOR su2200@10.64.1.1 "Finance department"
# MONITOR matrix@shs-server.example.edu "Sierra High School data room #1"
MONITOR salicru@localhost "SAI Salicru IES Virgen de Guadalupe
Aquí va el nombre del SAI (o los SAIs) que será monitorizado y mostrado en el interfaz web de nut.

Siguiente fichero, /etc/nut/nut.conf:
# Network UPS Tools:  nut.conf
#
##############################################################################
# General section
##############################################################################
# The MODE determines which part of the NUT is to be started, and which
# configuration files must be modified.
#
# This file try to standardize the various files being found in the field, like
# /etc/default/nut on Debian based systems, /etc/sysconfig/ups on RedHat based
# systems, ... Distribution's init script should source this file to see which
# component(s) has to be started.
#
# The values of MODE can be:
# - none: NUT is not configured, or use the Integrated Power Management, or use
#   some external system to startup NUT components. So nothing is to be started.
# - standalone: This mode address a local only configuration, with 1 UPS
#   protecting the local system. This implies to start the 3 NUT layers (driver,
#   upsd and upsmon) and the matching configuration files. This mode can also
#   address UPS redundancy.
# - netserver: same as for the standalone configuration, but also need
#   some more network access controls (firewall, tcp-wrappers) and possibly a
#   specific LISTEN directive in upsd.conf.
#   Since this MODE is opened to the network, a special care should be applied
#   to security concerns.
# - netclient: this mode only requires upsmon.

MODE=standalone
# set upsd specific options. use "man upsd" for more info
UPSD_OPTIONS=""
# set upsmon specific options. use "man upsmon" for more info
UPSMON_OPTIONS=""
La variable MODE=standalone indica que tenemos un solo SAI y que es controlado por el PC al que está conectado localmente por el puerto USB.
Siguiente fichero, /etc/nut/upssched.conf:
# Network UPS Tools - upssched.conf

CMDSCRIPT  /root/scripts/avisoups.sh

##Hay que crear la ruta /var/run/nut/upssched/ si no existe con propietario nut:nut
#PIPEFN /var/run/nut/upssched/upssched.pipe
#LOCKFN /var/run/nut/upssched/upssched.lock
#Añadido 18/12/2015: por algún extraño motivo, la ruta 
#/var/run/nut/upssched/ es borrada periódicamente por el sistema con lo cual
#upssched deja de funcionar. La solución mas cómoda es usar /tmp/ para almacenar 
#ambos ficheros:
PIPEFN /tmp/upssched.pipe
LOCKFN /tmp/upssched.lock

# Si hay corte de corriente, se lanza un timer que esperará 300 segundos (5 minutos)
# antes de apagar
AT ONBATT * START-TIMER  ups-on-battery-shutdown  300
# Si vuelve la corriente, se cancela el timer
AT ONLINE * CANCEL-TIMER  ups-on-battery-shutdown

# Si hay corte de corriente, se lanza un timer que esperará 15 segundos
# antes de notificarlo

AT ONBATT * START-TIMER ups-on-battery 15
AT ONLINE * CANCEL-TIMER ups-on-battery

#En los siguientes eventos, llama al script de notificacion para que lo procese.
AT ONLINE * EXECUTE ups-back-on-line
AT REPLBATT * EXECUTE ups-change_battery
AT LOWBATT * EXECUTE ups-low-battery
AT COMMOK * EXECUTE ups-comunication-ok
AT COMMBAD * EXECUTE ups-comunication-bad
Nota 18/12/2015: como se puede ver en el listado anterior, he cambiado

PIPEFN /var/run/nut/upssched/upssched.pipe
LOCKFN /var/run/nut/upssched/upssched.lock

por

PIPEFN /tmp/upssched.pipe
LOCKFN /tmp/upssched.lock

ya que la ruta /var/run/nut/upssched/ es borrada periódicamente por el sistema de forma misteriosa, inhabilitando upssched. Usando tmp ya no habrá problema ya que esa ruta existe siempre y puede escribir cualquier proceso en ella.
Aquí empieza lo bueno, expliquemos:
  • CMDSCRIPT: ruta al script se ejecuta al saltar un evento del SAI, en nuestro caso /root/scripts/avisoups.sh.
  • PIPEFN, LOCKFN: rutas a ficheros creados por el servicio nut. Los quedamos tal como están, asegurándonos de que existe la carpeta /var/run/nut/upssched/ con propietario nut:nut
  • AT ONBATT * START-TIMER  ups-on-battery-shutdown  300: indicamos que cuando empiece a funcionar la batería (es decir, haya un corte de corriente) se define un temporizador de 300 segundos, al cabo del cual se dispara un evento ups-on-battery-shutdown.
  • AT ONLINE * CANCEL-TIMER  ups-on-battery-shutdown: si vuelve la corriente, se cancela el temporizador anterior.
  • AT ONBATT * START-TIMER ups-on-battery 15: ídem, pero damos un timeout de 15 segundos.
  • AT ONLINE * EXECUTE ups-back-on-line : cuando el estado del SAI cambie a online se genera un evento ups-back-online. Ídem para el resto de eventos del SAI.
Cuando sucede uno de los eventos controlados en el fichero anterior, se llama al script /root/scripts/avisoups.sh pásandole como parámetro el nombre del evento en cuestión, que recogerá en $1
Contenido de /root/scripts/avisoups.sh:
#!/bin/bash

source mail.sh

MESSAGE_MAIL=""
EVENT_TYPE=$1
APAGADO=0
FECHA=$(date)

case "$EVENT_TYPE" in
    "ups-on-battery-shutdown")
        MESSAGE_MAIL="UPS on battery: shutdown now"
        APAGADO=1
        ;;
    "ups-on-battery")
        MESSAGE_MAIL="UPS on battery: warning"
        ;;
    "ups-comunication-bad")
        MESSAGE_MAIL="Communications with UPS lost"
        ;;
    "ups-change_battery")
        MESSAGE_MAIL="UPS battery needs to be replaced"
        ;;
    "ups-back-on-line")
        MESSAGE_MAIL="UPS on line power"
        ;;
    "ups-low-battery")
        MESSAGE_MAIL="UPS battery is low"
        ;;
    "ups-comunication-ok")
        MESSAGE_MAIL="Communications with UPS established"
        ;;
esac

mailSend  "$FECHA => $MESSAGE_MAIL"  "[UPS] Event $EVENT_TYPE de SAI Virgen de Guadalupe:"
echo "$FECHA => SAI: $MESSAGE_MAIL" >> /var/log/sai.log

if [ $APAGADO = "1" ]
then
    sleep 30
    /root/scripts/apagar_servidores.sh
fi
Como vemos, recoge el evento, construye un mensaje de correo y lo envia con la funcion mailSend. Adicionalmente, lo registra en /var/log/sai.log, para permitir su posterior consulta.
Destacar que si se ha disparado el evento "ups-on-battery-shutdown" es indicativo de que lleva 5 minutos cortada la corriente y para evitar males mayores ordenamos un apagado ordenado de los servidores a través del script /root/scripts/apagar_servidores.
En /root/scripts/mail.sh tenemos la función mailsend, que ya hemos usado en otras entradas del blog. Hay que configurar este comando con el usuario, contraseña y destinatario pertinentes:
function mailSend() {

    mailsend -smtp smtp.gmail.com \
        -port 587 \
        -starttls -auth \
        -user micuenta@gmail.com \
        -pass mipassword \
        -f micuenta@gmail.com \
        -t micuenta@gmail.com \
        -sub "$1" -M "$2"
}
El script de apagado de servidores, /root/scripts/apagar_servidores.sh es:
#!/bin/bash

source mail.sh

FECHA=$(date)
MESSAGE_MAIL="Apagando servidores ahora mismo desde el script /root/scripts/apagar_servidores.sh."

mailSend  "$FECHA => $MESSAGE_MAIL" "Aviso Servidor Virgen de Guadalupe"
echo "$FECHA => $MESSAGE_MAIL" >> /var/log/sai.log

ssh root@servidor "/sbin/shutdown -h +0"
sleep 1
ssh root@ldap "/sbin/shutdown -h +0"
sleep 1
/sbin/shutdown -h +0
En esta caso apagamos los servidores "servidor", "ldap" y el propio servidor donde está conectado el SAI. Hay que tener en cuenta que para poder ejecutar remotamente los comandos de apagado con ssh sin tener que introducir la contraseña debemos haber establecido una relación de confianza entre nuestros servidores.
Bueno, con todo esto ya podemos iniciar los servicios:
/etc/init.d/nut-server restart
/etc/init.d/ups-monitor restart
Y verificar que funcionan con:
upsc salicru
Cambiar "salicru" por el nombre que le hayamos puesto al SAI en /etc/nut/ups.conf. La salida será algo como:
battery.charge: 100
battery.voltage: 54.60
battery.voltage.high: 52.00
battery.voltage.low: 41.60
battery.voltage.nominal: 48.0
device.type: ups
driver.name: blazer_usb
driver.parameter.bus: 005
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.productid: 0003
driver.parameter.vendorid: 06da
driver.version: 2.6.4
driver.version.internal: 0.08
input.current.nominal: 6.0
input.frequency: 50.0
input.frequency.nominal: 50
input.voltage: 226.6
input.voltage.fault: 226.6
input.voltage.nominal: 230
output.voltage: 226.6
ups.beeper.status: enabled
ups.delay.shutdown: 30
ups.delay.start: 180
ups.load: 19
ups.productid: 0003
ups.status: OL
ups.temperature: 52.5
ups.type: offline / line interactive
ups.vendorid: 06da
Otros comandos del paquete nut que no he usado nunca, pero ahí están:
  • upscmd: permite mandar comandos al SAI, si es programable.
  • upsrw: leer/cambiar variables de un SAI programable.
  • upsd, upslog, upsdrvctl, upsmon, upssched: son comandos internos usados por los demonios, un usuario normal no suele invocarlos
Por último, podemos acceder via web al estado del SAI, con una URL como: http://servidor-nut/cgi-bin/nut/upsstats.cgi?host=salicru@localhost, cambiando host=salicru@localhost por el nombre que le hayamos puesto al SAI en /etc/nut/ups.conf, el resultado será similar a:

Bueno, con esto tendremos bajo control nuestro SAI y protegidos nuestros servidores. Además llevaremos un registro de las caídas de tensión, para poder reclamar a Iberdrola, X-DDD.
Hasta la semana que viene, sean buenos con los lusers.

No hay comentarios:

Publicar un comentario