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

jueves, 9 de mayo de 2019

Configuración de pórtatiles TechComputer TC11

Nos han llegado unos portátiles TechComputer TC11, unos clónicos que internamente se identifican (usando dmidecode podemos verlo) como P325J. Traen una imagen de Xubuntu 18 para miniportátiles casi totalmente configurada. Anotaré en esta entrada las modificaciones que vaya haciendo.

Lo primero es definir en /etc/escuela2.0 las variables que identifican al nuevo modelo de equipo, de cara a aplicar reglas puppet:
# cat /etc/escuela2.0
SISTEMA=ubuntu1804
USO=portatiles
HARDWARE=TC11
USUARIO=alumno

Para los portátiles tengo un módulo puppet "xubuntu18_portatil_ajustes", en la cual hay un case por $hardware:

...
case $hardware {
    "TC11": {
       file {"/etc/X11/xorg.conf.d":
            owner => root , group => root , mode => 644 , 
            ensure => directory,
       }

       file {"/etc/X11/xorg.conf.d/10-xorg-tc11.conf":
            owner => root , group => root , mode => 644 , 
            source => "puppet:///modules/xubuntu18_portatil_ajustes/10-xorg-tc11.conf",
       }
       #Cambia resolucion del grub para que en consola aparezca bien el contenido.
       file { "/etc/default/grub":
            source => "puppet:///modules/xubuntu18_portatil_ajustes/grub.default.TC11",
            owner => root , group => root , mode => 644 , 
       }
       exec { "update-grub2":
            subscribe => File ["/etc/default/grub"],
            refreshonly => true
       }
       #Certificado ldap
       file { "/etc/ldap/ssl/ldap-server-pubkey.pem":
            owner => root , group => root , mode => 644 , 
            source => "puppet:///modules/xubuntu18_portatil_ajustes/ldap-server-pubkey.pem",
       }
    }
...

Lo que hacemos es:
  1. Añadir un /etc/X11/xorg.conf.d/10-xorg-tc11.conf con una configuración personalizada de Xorg. Por defecto estos portátiles vienen con una resolución altísima que deja la letra muy pequeña. El fichero 10-xorg-tc11.conf para una resolución de 1360x768 (se pueden probar otras resoluciones posibles usando el comando xrandr en un terminal) sería:
    Section "Device"
            ### Available Driver options are:-
            ### Values: <i>: integer, <f>: float, <bool>: "True"/"False",
            ### <string>: "String", <freq>: "<f> Hz/kHz/MHz",
            ### <percent>: "<f>%"
            ### [arg]: arg optional
            #Option "ColorKey" "integer"
            #Option "DRI" "string"
            #Option "CacheLines" "integer"
            #Option "DDC" "boolean"
            #Option "Dac6Bit" "boolean"
            #Option "XvMCSurfaces" "integer"
            #Option "Accel" "boolean"
            #Option "Present" "boolean"
            #Option "AccelMethod" "string"
            #Option "TearFree" "boolean"
            #Option "ReprobeOutputs" "boolean"
            #Option "VideoKey" "integer"
            #Option "XvPreferOverlay" "boolean"
            #Option "Backlight" "string"
            #Option "CustomEDID" "string"
            #Option "FallbackDebug" "boolean"
            #Option "DebugFlushBatches" "boolean"
            #Option "DebugFlushCaches" "boolean"
            #Option "DebugWait" "boolean"
            #Option "HWRotation" "boolean"
            #Option "VSync" "boolean"
            #Option "PageFlip" "boolean"
            #Option "SwapbuffersWait" "boolean"
            #Option "TripleBuffer" "boolean"
            #Option "Tiling" "boolean"
            #Option "LinearFramebuffer" "boolean"
            #Option "RelaxedFencing" "boolean"
            #Option "XvMC" "boolean"
            #Option "Throttle" "boolean"
            #Option "HotPlug" "boolean"
            #Option "Virtualheads" "integer"
            #Option "ZaphodHeads" "string"
            #Option "ZaphodHeads" "LVDS1,VGA1"
            #Option "ZaphodHeads" "0,2:HDMI1,DP2"
            #Option "Position" "0 0"
            #Option "Position" "1024 0"
            #Option "RightOf" "Laptop FoodBar Internal Display"
            #Option "monitor-LVDS" "Laptop FooBar Internal Display"
            #Option "monitor-VGA" "Some Random CRT"
            Identifier  "Card0"
            Driver      "intel"
            BusID       "PCI:0:2:0"
    EndSection
    
    Section "Screen"
        Identifier "Screen0"
        Device     "Card0"
        Monitor    "Monitor0"
        SubSection             "Display"
                Depth               24
                Modes              "1360x768" #Choose the resolution
        EndSubSection
    EndSection
    

  2. De igual manera, el grub aparece con una letra minúscula, para solucionar esto debemos meter un nuevo fichero /etc/default/grub y regenerarlo:
    # If you change this file, run 'update-grub' afterwards to update
    # /boot/grub/grub.cfg.
    # For full documentation of the options in this file, see:
    #   info -f grub -n 'Simple configuration'
    
    GRUB_DEFAULT=0
    GRUB_HIDDEN_TIMEOUT=0
    GRUB_HIDDEN_TIMEOUT_QUIET=true
    GRUB_TIMEOUT=10
    GRUB_TIMEOUT_STYLE=menu
    GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
    GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
    GRUB_CMDLINE_LINUX="ipv6.disable=1"
    
    # Uncomment to enable BadRAM filtering, modify to suit your needs
    # This works with Linux (no patch required) and with any kernel that obtains
    # the memory map information from GRUB (GNU Mach, kernel of FreeBSD ...)
    #GRUB_BADRAM="0x01234567,0xfefefefe,0x89abcdef,0xefefefef"
    
    # Uncomment to disable graphical terminal (grub-pc only)
    #GRUB_TERMINAL=console
    
    # The resolution used on graphical terminal
    # note that you can use only modes which your graphic card supports via VBE
    # you can see them in real GRUB with the command `vbeinfo'
    GRUB_GFXMODE=800x600
    
    # Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux
    #GRUB_DISABLE_LINUX_UUID=true
    
    # Uncomment to disable generation of recovery mode menu entries
    #GRUB_DISABLE_RECOVERY="true"
    
    # Uncomment to get a beep at grub start
    #GRUB_INIT_TUNE="480 440 1"
    GRUB_DISABLE_OS_PROBER=true
    

  3. Los portátiles no traen /etc/ldap/ssl/ldap-server-pubkey.pem, por lo que si usamos Secure LDAP la autenticación nos fallará. Metemos la clave (cogida de otra máquina que si la traiga) por si nos hace falta.
Seguiremos añadiendo cosas en este mismo post según vayan apareciendo problemas a resolver.

Addenda 17/mayo/2019:
  • Algunos portátiles una vez arrancados no cogen red y dan continuos errores en consola de RTC. Eso se debe a que tienen mal la fecha y debemos pulsar ESC o Supr en el inicio para entrar en la BIOS y meter la fecha correcta manualmente.
  • En algún portátil nos ha sucedido que en el arranque no carga el grub, sino que se muestra:
    Que es una shell de EFI. Eso sucede porque en la BIOS no está configurado bien el orden de arranque de dispositivos, el cual debe ser:

Addenda 20/mayo/2019:
Cuando vamos a consola con CTRL-ALT-F1 todo se ve con letra minúscula, tal como se veía el GRUB inicialmente. La modificación hecha antes para arreglarlo en el GRUB no funciona una vez se ha cargado el sistema.

La solución es hacer un script que cargue un font que sea mas visible. El script se llamará /usr/bin/local/fontset:
#!/bin/sh
setfont /usr/share/consolefonts/Uni3-TerminusBold32x16.psf.gz
Después hacemos ejecutable dicho script y lo invocamos en el inicio de sesión de root, añadiendo al final de /root/.profile:
test "$TERM" == "linux" && /usr/local/bin/fontset
Otra solución que he probado es quedar /etc/default/console-setup así:
# CONFIGURATION FILE FOR SETUPCON
# Consult the console-setup(5) manual page.
ACTIVE_CONSOLES="/dev/tty[1-6]"
CHARMAP="UTF-8"
CODESET="Lat15"
FONTFACE="Terminus"
FONTSIZE="16x32"
VIDEOMODE=
FONT="Lat15-Terminus32x16.psf.gz"
Y ejecutar después:
# cp /usr/share/consolefonts/Lat15-Terminus32x16.psf.gz /etc/console-setup/
# update-initramfs -u
# reboot
Esto hace que el cambio de tamaño de font sea ya desde la petición de login...pero en la consola 2 y sucesivas (CTRL-ALT-F2, F3,..). En la primera consola (CTRL-ALT-F1) no comprendo por qué motivo no se cambia.

Si en lugar de estas 3 últimas líneas hacemos "setupcon" se consigue un resultado similar, pero en las pruebas me he encontrado con que no siempre funciona.


Me despido compartiendo un maravilloso bar que encontré en Bulgaria:


Un buen sitio para un sysadmin y su cerveza.

Listar clientes wifi conectados a un punto de acceso OpenWRT/LEDE

Cuanto tenemos un punto de acceso creado desde un dispositivo con OpenWRT o LEDE en el centro educativo puede suceder que se sature porque hay muchos clientes conectados. Es muy útil saber en cualquier momento cuantos clientes tiene asociados nuestro punto, por si fuera necesario hacer una limpieza.

Esto lo haríamos con el comando:
# iw dev wlan0 station dump | grep Station
o bien con:
# iwinfo wlan0 assoclist
Siendo wlan0 la tarjeta wifi sobre la que se monta el punto de acceso. Una vez averiguadas las MACs podemos hacer limpieza expulsando clientes con:
# ubus call hostapd.wlan0 del_client "{'addr':'00:11:22:33:44:55', 'reason':5, 'deauth':false, 'ban_time':0}"

En el último mes Space X nos ha alegrado con el lanzamiento y aterrizaje exítoso de un Falcon Heavy con carga útil (un satélite Arabsat). El despegue:


El aterrizaje de los dos boosters, siempre me queda estremecido esta imagen:


Y el aterrizaje de la etapa central en la barcaza "Of course, I still love you":


Por desgracia, la etapa central cayó al mar por el fuerte oleaje al volver a tierra, ya que falló el anclaje. No volverá a suceder, seguro.

El alucinante vídeo con todo el aterrizaje:

jueves, 25 de abril de 2019

Monitorizando los puestos del aula con monit (II)

Seguimos desde aquí. Vamos a ampliar añadiendo controles basándonos en esta entrada de mi compañero Esteban:
  • Temperatura de la CPU
  • Temperatura de la placa base
  • Temperatura del disco duro
  • Temperatura de la GPU (tarjeta gráfica)
  • Velocidad ventiladores
  • Estado de las fuentes de alimentación redundantes en el servidor del centro
Todo esto lo haremos usando los comandos sensors, nvidia-smi, hddtemp y hplog.

El comando sensors es el que mas información da, pero el problema es que es muy dependiente del hardware y con él no obtenemos una salida homogénea con los números bien colocaditos, sino distintos formatos de presentación a partir de los cuales extraemos los datos. A eso hay que añadir que no siempre tenemos accesibles todos los valores de temperaturas y/o ventiladores debido a que a veces los comandos sensors y hddtemp no son compatibles con el hardware subyacente.

Con esto así he adaptado los scripts para que sean los mas completos posibles, pero no es descartable irlos ampliando conforme vayamos recibiendo nuevos equipos o actualizaciones que hagan que sensorsse comunique mejor con el hardware.

El fichero de monitorización para todas la máquinas sería (esto se añadiría a la tarea puppet vista en el post anterior):
# cat /etc/monit/conf.d/monitrc.temperatura
check program mbtemperatura with path "/usr/local/bin/mbtemp.sh"
   if status > 60 for 3 cycles then alert
   group temperature

check program cputemperature  with path "/usr/local/bin/cputemp.sh"
   if status > 65 for 3 cycles then alert
   group temperature

check program hddtemperature with path "/usr/local/bin/hddtemp.sh"
   if status > 50 for 3 cycles then alert
   group temperature

check program vgatemperature with path "/usr/local/bin/vgatemp.sh"
   if status > 98 for 3 cycles then alert
   group temperature

check program fanspeed with path "/usr/local/bin/fanspeed.sh"
   if status = 1 for 3 cycles then alert
   group temperature
El script que comprueba la velocidad de los ventiladores (solo funciona en las placas Asus de los servidores LTSP que nos envió Telefónica) sería:
# cat /usr/local/bin/fanspeed.sh
#!/bin/bash
hardware=$(facter hardware)
FANSPEED=0 #
case $hardware in
   "telefonica")
         FANSPEED1=$(sensors |grep "^CPU FAN Speed" | awk '{print $4}')
         FANSPEED2=$(sensors |grep "^CHASSIS2 FAN Speed" | awk '{print $4}')
         test $FANSPEED1 -lt 600 -o $FANSPEED2 -lt 600 && FANSPEED=1       #Si alguno de los ventiladores gira por debajo de los 600RPM se avisa de ello
         ;;
esac
#echo $FANSPEED # for debug only
exit $FANSPEED
Para estos PC, que tienen una placa Asus P5Q DELUXE, la salida de sensors es muy completa:
# sensors
coretemp-isa-0000
Adapter: ISA adapter
Core 0:       +43.0°C  (high = +82.0°C, crit = +100.0°C)
Core 1:       +43.0°C  (high = +82.0°C, crit = +100.0°C)
Core 2:       +43.0°C  (high = +82.0°C, crit = +100.0°C)
Core 3:       +40.0°C  (high = +82.0°C, crit = +100.0°C)

radeon-pci-0100
Adapter: PCI adapter
temp1:        +56.0°C  

atk0110-acpi-0
Adapter: ACPI interface
Vcore Voltage:       +1.13 V  (min =  +0.80 V, max =  +1.60 V)
 +3.3 Voltage:       +3.28 V  (min =  +2.97 V, max =  +3.63 V)
 +5 Voltage:         +5.14 V  (min =  +4.50 V, max =  +5.50 V)
 +12 Voltage:       +12.21 V  (min = +10.20 V, max = +13.80 V)
CPU FAN Speed:      2556 RPM  (min =  600 RPM, max = 7200 RPM)
CHASSIS1 FAN Speed:    0 RPM  (min =  600 RPM, max = 7200 RPM)
CHASSIS2 FAN Speed: 3515 RPM  (min =  600 RPM, max = 7200 RPM)
CHASSIS3 FAN Speed:    0 RPM  (min =  600 RPM, max = 7200 RPM)
POWER FAN Speed:       0 RPM  (min =  600 RPM, max = 7200 RPM)
CPU Temperature:     +27.0°C  (high = +60.0°C, crit = +95.0°C)
MB Temperature:      +45.0°C  (high = +45.0°C, crit = +95.0°C)
Por desgracia, en el resto de máquinas que tengo la información es mucho mas limitada.

El script que comprueba la temperatura de la VGA utiliza varios filtros y comandos para extraer a los datos. Su código es:
# cat /usr/local/bin/vgatemp.sh
#!/bin/bash

#ati radeon y nouveau se comprueban con "sensors"
#nvidia se comprueba con nvidia-smi
#intel no se puede monitorizar, no he encontrado herramienta
 
VGATEMP=0
if sensors | grep -q radeon-pci
then
  VGATEMP=$(sensors | sed -n '/radeon-pci/,/^$/p' | grep "^temp" | tr -d '+°C' | awk '{printf("%d\n",$2 + 0.5)}' | sort -nr | head -1)
else
   if sensors | grep -q nouveau-pci
   then
     VGATEMP=$(sensors | sed -n '/nouveau-pci/,/^$/p' | grep "^temp" | tr -d '+°C' | awk '{printf("%d\n",$2 + 0.5)}' | sort -nr | head -1)
   else
      if test -f /usr/bin/nvidia-smi
      then
        VGATEMP=$(nvidia-smi -q | grep "GPU Current Temp" | awk '{printf("%d\n",$5)}')
      fi
   fi

fi

#echo $VGATEMP # for debug only
exit $VGATEMP
El script que comprueba la temperatura de la placa base, según el hardware que usemos, sería:
# cat /usr/local/bin/mbtemp.sh
#!/bin/bash
hardware=$(facter hardware)
MBTEMP=0
case $hardware in
   "telefonica") MBTEMP=$(sensors |grep "^MB Temperature:"| awk '{printf $3}'  | tr -d '+°C'  | awk '{printf("%d\n",$1 + 0.5)}')
           ;;
   "siatic") MBTEMP=$(sensors | sed -n '/acpitz-virtual-0/,/^$/p' | grep "^temp" | tr -d '+°C' | awk '{printf("%d\n",$2 + 0.5)}' | sort -nr | head -1)
           ;;
   "infolab" ) MBTEMP=$(sensors | sed -n '/pch_skylake-virtual-0/,/^$/p' | grep "^temp" | tr -d '+°C' | awk '{printf("%d\n",$2 + 0.5)}' | sort -nr | head -1)
           ;;

   * ) MBTEMP=$(sensors | sed -n '/acpitz-virtual-0/,/^$/p' | grep "^temp" | tr -d '+°C' | awk '{printf("%d\n",$2 + 0.5)}' | sort -nr | head -1)

        ;;
esac
#echo $MBTEMP # for debug only
exit $MBTEMP
El script que obtiene la temperatura de todos los discos duros y devuelve la mayor entre ellas es:
# cat /usr/local/bin/hddtemp.sh
#!/bin/bash

HDDTEMP=0
DISCOS=$(lsblk  -l | grep disk | cut -f1 -d" ")
for i in $DISCOS
do
  TEMP=$(hddtemp  /dev/$i 2> /dev/null | tr -d "°C " | cut -d":" -f3)
  test -z "$TEMP" && TEMP="0"
  test "$TEMP" -gt "$HDDTEMP" && HDDTEMP="$TEMP"
done

#echo $HDDTEMP # for debug only
exit $HDDTEMP
El script que comprueba la temperatura de la CPU o sus cores y devuelve la mayor:
# cat /usr/local/bin/cputemp.sh
#!/bin/bash
hardware=$(facter hardware)
CPUTEMP=0
case $hardware in
   "telefonica") CPUTEMP=$(sensors |grep "^CPU Temperature"| awk '{printf $3}'  | tr -d '+°C'  | awk '{printf("%d\n",$1 + 0.5)}')
           ;;
   "siatic" | "infolab" ) CPUTEMP=$(sensors |grep "^Package id"| awk '{printf $4}'  | tr -d '+°C' | awk '{printf("%d\n",$1 + 0.5)}')
           ;;
   * )  CPUTEMP=$(sensors |grep "^Core "| tr -d '+°C' |  awk '{printf("%d\n",$3 + 0.5)}'  | sort -nr | head -1) #El mayor de los cores
        ;;
esac
#echo $CPUTEMP # for debug only
exit $CPUTEMP
En el caso del servidor del centro tenemos un HP Proliant que gracias al paquete hp-health nos permite acceder a más valores interesantes, como el estado de las dos fuentes de alimentación redundantes que tiene.
# cat /etc/monit/conf.d/monitrc.temperatura
check program mbtemperatura with path "/usr/local/bin/mbtemp.sh"
   if status > 60 then alert
   group temperature

check program cputemperature  with path "/usr/local/bin/cputemp.sh"
   if status > 60 then alert
   group temperature

check program hddtemperature with path "/usr/local/bin/hddtemp.sh"
   if status > 50 then alert
   group temperature

check program fanspeed with path "/usr/local/bin/fanspeed.sh"
   if status = 1 then alert
   group temperature

check program powersupply with path "/usr/local/bin/powersupply.sh"
   if status = 1 then alert
   group temperature
El script de chequeo de ambas fuentes de alimentación sería:
# cat /usr/local/bin/powersupply.sh
#!/bin/bash
fans=$(hplog -p | grep Normal | wc -l)
if [ $fans -ne 2 ] #Verificamos que ambas fuentes estén en estado "normal"
then
   salida=1
else
   salida=0
fi
#echo $salida # for debug only
exit $salida
El script de chequeo de los ventiladores (para el HP Proliant se usa hplog en lugar de sensors) sería:
# cat /usr/local/bin/fanspeed.sh
#!/bin/bash
fans=$(hplog -f | grep Normal | wc -l)
if [ $fans -ne 2 ] #Verificamos que ambos ventiladores estén en estado "normal"
then
   salida=1
else
   salida=0
fi
#echo $salida # for debug only
exit $salida
Nota: los valores de temperatura en monitrc.temperatura los he ido afinando con diversas pruebas a lo largo de 10 días, ya que no es raro que haya máximos puntuales sobre todo cuando se reproducen vídeos. Cada uno debe ir probando y cambiando valores hasta dar con el equilibrio óptimo que no te fría a mensajes y a la vez te alerte cuando algo empiece a ir mal.

Bueno, pues hasta aquí hemos llegado. Si nos salen nuevas cosas que comprobar haremos una tercera parte.

domingo, 14 de abril de 2019

Monitorizando los puestos del aula con monit (I)


Mi compañero Esteban ha publicado en su blog varios artículos muy interesantes sobre monit. Resumidamente: monit es un servicio que se encarga de monitorizar el sistema y asegurarse de que otros servicios funcionan y/o informarnos ante determinados eventos.

Aparte de usarlo en los servidores del centro también viene bien tenerlo en funcionamiento en los ordenadores de los profesores dentro del aula, ya que se ocupan de varias tareas críticas dentro del contexto de sus funciones y es recomendable tener asegurada y controlada su disponibilidad.

1. Configuración de alertas mediante correo.

Para que monit nos notifique cosas la opción más sencilla es que nos envíe correos electrónicos a través de una cuenta de Gmail. En mi caso ya tengo en el centro un servidor de correo postfix que redirige sus correos a través de la cuenta de Gmail, tal como conté en al apartado 2 de la entrada sobre la Gestión de Avisos del SAI usando nut, por lo que lo mas correcto es que los distintos servicios monit que hay por los pc del centro envíen sus alertas al servidor postfix y este a su vez lo reenvíe a través Gmail.

Para que el servidor postfix admita correos de cualquier PC de nuestra red hay que editar su fichero /etc/postfix/main.cf y añadir:
..
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 172.19.196.0/24
..
smtpd_client_restrictions = permit_mynetworks, reject
Siendo 172.19.196.0 mi red local y no olvidando reiniciar el servicio postfix después.

A continuación, en cada /etc/monit/monitrc añadimos:
.....
set mailserver 172.19.196.X port 25

set alert mi.correo@gmail.com not on {instance}

set mail-format { from: mi.correos@gmail.com
subject: $HOST - $SERVICE $EVENT a $DATE
message: Monit $ACTION $SERVICE a $DATE en $HOST, Descripcion: $DESCRIPTION.
}
Siendo 172.19.196.X el servidor donde está ejecutándose el servicio postfix en mi red y mi.correo@gmail.com la cuenta de correo Gmail usada para notificar las alertas. El "not on {instance}" es un filtro para que no nos envien correos de alerta cada vez que el servicio monit se enciende o se apaga, ya que son bastante molestos.

2. Monitorizando servicios básicos.

En los puestos de los profesores tengo como mínimo 2 servicios críticos: dhcp (para dar IP a los portátiles, thinclients o worskstations de alumnos) y tftp (para la imagen de arranque de thinclients).
# cat /etc/monit/conf.d/monit.dhcp
check process dhcpd matching "dhcpd"
  start program "/etc/init.d/isc-dhcp-server start"
  stop  program "/etc/init.d/isc-dhcp-server stop"
Y:
# cat /etc/monit/conf.d/monit.tftp
check process tftp matching "/usr/sbin/in.tftpd"
  start program "/etc/init.d/tftpd-hpa restart"  # El restart funciona mejor, porque a veces si no se hace stop luego no arranca.
  stop  program "/etc/init.d/tftpd-hpa stop"
De igual manera podemos ir añadiendo ficheros para monitorizar cualquier servicio que juzguemos imprescindible.

3. Monitorizando los puntos wifi.

Otro recurso crítico en las aulas son los puntos wifi para permitir la conexión de portátiles y dispositivos móviles. Por regla general están en la IP 192.168.0.1 de la red interna del aula:
# cat /etc/monit/conf.d/monit.puntowifi
check host punto-wifi  with address 192.168.0.1
      if failed icmp type echo count 5 with timeout 30 seconds then alert
De esta manera si hay algún problema con el punto wifi (bloqueo o desconexión de cables) nos llegará una alerta por correo.

4. Monitorizando la conexión de las pizarras digitales.

Esta es más divertida: las pizarras digitales se conectan por USB y a veces por accidente o por diabluras de los alumnos se desconecta el cable que las une al PC.
# cat /etc/monit/conf.d/monit.pizarra
check program pizarra with path /usr/local/bin/check_pizarra
    if status != 0 then alert
Evidentemente, para este caso no hay orden específica de monit, lo que tenemos es un script que busca la pizarra entre los dispositivos USB y devuelve 1 si no la encuentra.
# cat /usr/local/bin/check_pizarra
#!/bin/bash
# Devuelve 1 para avisar de desconexión, 0 si esá conectada o bien ya se avisó.

pizarra=$(lsusb -d 0b8c: ; lsusb -d 13ff:) # 0b8c:0069  0b8c:0001  13ff:0008 - Pizarras SmartBoard 480/640 y Galneo
if test -z "$pizarra"
then
     if ! test -f /var/cache/no-pizarra
     then
         retorno=1
         touch /var/cache/no-pizarra
     else
         retorno=0 # Ya se avisó, no necesario volver a hacerlo
     fi
else
      retorno=0
      rm -f /var/cache/no-pizarra  # Reconectada, se borra el testigo de aviso.
fi
exit $retorno
De esta manera se avisa de forma inmediata de cualquier desconexión, quedando registrado en el correo el momento en que sucedió por si necesitamos hacer indagaciones posteriores.

5. Monitorizando teclados y ratones.

Al igual que las pizarras digitales, los teclados y ratones en los puestos del profesor son causa de algún que otro problema. Ya traté este tema en otro artículo, pero ahora lo enfocaré para que la detección se haga desde monit:
# cat /etc/monit/conf.d/monit.kbmouse
check program teclado_raton with path /usr/local/bin/check_kb_mouse
    if status != 0 then alert
Siendo el script:
# cat /usr/local/bin/check_kb_mouse
#!/bin/bash

FICHERO=/var/cache/kbvigila

#En teclados Sweex USB, aparece mouse en devices, aun cuando no haya ratón 
#conectado. Con el filtro grep -v kbd eliminamos esas lineas, para que solo
#coja las corresponden a un ratón real.
raton=$(cat /proc/bus/input/devices  | grep -i mouse | grep -v kbd | grep Handlers| wc -l)

#En teclados RML, la cadena es "keykoard" en lugar de "keyboard"
teclado=$(cat /proc/bus/input/devices  | grep -i key[bk]oard | wc -l)

pizarra=$(lsusb -d 13ff:0008) # Pizarra Galneo
if test -n "$pizarra"
then
   #Las pizarras Galneo se identifican como ratón, asi que hay que decrementar el contador
   ((raton--))
fi

test $raton -eq 0  && hayraton="1" ||  hayraton="2"
test $teclado -eq 0 &&  hayteclado="1" || hayteclado="2"

#En hayXXX: Valor "1": no detectado. 
#           Valor "2": detectado. 

#Recupera el estado anterior de teclado y ratón.
if [ -f $FICHERO ]
then
   km_anterior=$(cat $FICHERO)
else
   km_anterior=""
fi
#Estado actual
km_actual="${hayteclado}${hayraton}"

#Si el estado teclado/raton ha cambiado respecto al estado anterior, devuelve 1
#para que haya una alerta
if  [ "$km_anterior" != "$km_actual" ]
then
   retorno=1
   #Guarda el estado actual para la siguiente comprobación.
   echo "${hayteclado}${hayraton}" > $FICHERO   
else
   retorno=0
fi
exit $retorno
Simplemente se comprueba el estado de conexión de teclado/ratón y se compara con el resultado de la comprobación anterior. Si ha variado algo se lanza un aviso.

6. Tarea puppet.

Todo esto lo distribuyo mediante una tarea puppet que aplicaría a las distintos pc de profesor que quiero monitorizar, siendo el init.pp de la tarea:
class  xubuntu18_monit {

        package { "monit": ensure =>installed }

        service { 'monit':
                ensure  => 'running',
                enable  => true,
                require => Package['monit'],
        }

        file { "monitrc":
                path => "/etc/monit/monitrc",
                owner => root, group => root, mode => 600,
                source => "puppet:///modules/xubuntu18_monit/monitrc",
                ensure => file,
                notify  => Service['monit'],  # Reinicia el servicio si el fichero cambia
                require => Package['monit'],
        }

        case $ies_isltsp {
                "si","yes","true" : {  #En los pc con thinclients hay serficio tftp
                        file { "monitrc-tftp":
                                path => "/etc/monit/conf.d/monitrc.tftp",
                                owner => root, group => root, mode => 600,
                                source => "puppet:///modules/xubuntu18_monit/monitrc.tftp",
                                ensure => file, notify  => Service['monit'], require => Package['monit'],
                        }
                }
                default: { 
                }
        }


        file { "monitrc-wifiap":
                path => "/etc/monit/conf.d/monitrc.wifiap",
                owner => root, group => root, mode => 600,
                source => "puppet:///modules/xubuntu18_monit/monitrc.wifiap",
                ensure => file, notify  => Service['monit'], require => Package['monit'],
        }

        file { "monitrc-pizarra":
                path => "/etc/monit/conf.d/monitrc.pizarra",
                owner => root, group => root, mode => 600,
                source => "puppet:///modules/xubuntu18_monit/monitrc.pizarra",
                ensure => file, notify  => Service['monit'], require => Package['monit'],
        }

        file { "pizarra":
                path => "/usr/local/bin/check_pizarra",
                owner => root, group => root, mode => 755,
                source => "puppet:///modules/xubuntu18_monit/check_pizarra",
        }

        file { "kb_mouse":
                path => "/usr/local/bin/check_kb_mouse",
                owner => root, group => root, mode => 755,
                source => "puppet:///modules/xubuntu18_monit/check_kb_mouse",
        }

}
7. Continuará...

Una vez montado el sistema lo seguiré ampliando con más scripts de monitorización de temperaturas de CPU, placa y GPU, espacio en disco, uso de CPU, estado de las fuentes de alimentación, etc. Lo iremos viendo en artículos sucesivos.


Llevamos unas semanas frenéticas para los espaciotrastornados. Podría hablar de:
  • Increíbles fotos de agujeros negros.


  • El éxito completo de la Falcon Heavy de Space con los tres cohetes reutilizados aterrizando suavemente en sus plataformas.


    ¡Eres grande, Elon Musk!

  • Próxima C: otro candidato a planeta rocoso a 4 años luz de nosotros.

Pero no, la imagen es un eclipse de sol desde la superficie Marte, al pasar las lunas Fobos/Deimos delante del astro rey. ¿Quién tomó esta maravillosa imagen? Mi admirada Opportunity:


Impresionante.

jueves, 28 de marzo de 2019

VirtualBoxing Windows (Parte IV)

1. Introducción.

Venimos de aquí:


Voy a darle otra vuelta de tuerca al asunto porque me he encontrado con la tarea de montar un aula con 15 máquinas virtuales con Windows 10.

Podría haber hecho la configuración completa en cada una de las máquinas a mano, pero he preferido escribir una tarea puppet que automatice todo lo posible los pasos descritos en los enlaces anteriores por dos motivos:
  1. Me da pereza repetir lo mismo n veces. Soy administrador de sistemas: pienso que mi tarea consiste en trabajar construyendo cosas divertidas que me evitan trabajar repitiendo cosas aburridas.
  2. Porque en Xubuntu 18 me he propuesto hacer todo lo que pueda desde puppet para facilitar cualquier nueva instalación y la migración futura a Xubuntu 22.

2. Tarea puppet.

La tarea puppet tiene esta estructura:
├── files
│   ├── 15-vbox.conf
│   ├── Oracle_VM_VirtualBox_Extension_Pack-5.2.18.vbox-extpack
│   ├── run_vbox
│   ├── vbox_permisos
│   ├── VirtualBox.xml
│   └── Win10.vbox
└── manifests
    └── init.pp
Siendo el init.pp:
# cat init.pp                                                                           

import "/etc/puppet/defines/*.pp"

class xubuntu18_virtualbox {

        #Deja todo preparado para arrancar una máquina virtual con run_vbox
        #Solo haria falta instalar el fichero con permisos 777 .vdi en la ruta /datos/VirtualBox VMs/VirtualBox/Win10-Choco-Autocad-Office.vdi. Si se cambia hay que editar los ficheros Virtualbox.xml y Win10.box

        package {"virtualbox": ensure => installed}

        package {"virtualbox-guest-additions-iso": ensure => installed }

        line { entorno_virtualbox:
                file => "/etc/environment",
                line => 'export VBOX_USER_HOME="/datos/VirtualBox VMs/VirtualBox"',
                ensure => present
        }

        $dirs = [ "/datos", "/datos/VirtualBox VMs","/datos/VirtualBox VMs/VirtualBox","/datos/VirtualBox VMs/VirtualBox/Win10","/datos/VirtualBox VMs/VirtualBox/Win10/Logs" ]

        file {$dirs:
                ensure => 'directory',
                owner  => 'root',
                group  => 'root',
                mode   => '0777',
                before => [File ["/datos/VirtualBox VMs/VirtualBox/VirtualBox.xml"], File ["/datos/VirtualBox VMs/VirtualBox/Win10/Win10.vbox"], File ["extpack"] ]
        }

        file { "/datos/VirtualBox VMs/VirtualBox/VirtualBox.xml":
                owner => root , group => root , mode => 644 ,
                source => "puppet:///modules/xubuntu18_virtualbox/VirtualBox.xml",
        }

        file { "/datos/VirtualBox VMs/VirtualBox/Win10/Win10.vbox":
                owner => root , group => root , mode => 644 ,
                source => "puppet:///modules/xubuntu18_virtualbox/Win10.vbox",
        }

        file { "extpack":
                path =>"/datos/VirtualBox VMs/VirtualBox/Oracle_VM_VirtualBox_Extension_Pack-5.2.18.vbox-extpack",
                owner => root , group => root , mode => 644 ,
                source => "puppet:///modules/xubuntu18_virtualbox/Oracle_VM_VirtualBox_Extension_Pack-5.2.18.vbox-extpack",
                notify => Exec ["install_extpack"],
                }

        #El accept-license del extpack para instalacion desatendida se consigue instalando una vez a mano y cogiendo el código que nos muestra
        exec { "install_extpack":
                path => "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                command => 'vboxmanage extpack install --replace --accept-license=56be48f923303c8cababb0bb4c478284b688ed23f16d775d729b89a2e8e5f9eb "/datos/VirtualBox VMs/VirtualBox/Oracle_VM_VirtualBox_Extension_Pack-5.2.18.vbox-extpack"',              
                refreshonly => true,
        }


        #El fichero win.desktop para ir a /usr/share/applications se mete desde la tarea pupet xubuntu18_xfce4, junto con el icono. Aqui no lo haremos.

        file {"/usr/bin/run_vbox":
                owner => root , group => root , mode => 777 ,
                source => "puppet:///modules/xubuntu18_virtualbox/run_vbox"
        }

        file {"/usr/bin/vbox_permisos":
                owner => root , group => root , mode => 777 ,
                source => "puppet:///modules/xubuntu18_virtualbox/vbox_permisos"
        }


        case $uso {
                "infolab" : {
                        file {"/etc/lightdm/lightdm.conf.d/15-vbox.conf":
                                owner => root , group => root , mode => 644 ,
                                source => "puppet:///modules/xubuntu18_virtualbox/15-vbox.conf"
                        }
                }
                "siatic"  : {
                        line { permisos:
                                file => "/usr/lib/siatic/poweron.sh",
                                line => "/usr/bin/vbox_permisos",
                                ensure => present
                        }
                        #En las siatic el directorio /datos se monta sobre el disco duro secundario. En los infolabs va en el raiz, ya que hay espacio de sobra en él.
                        line { disco_secundario:
                                file => "/etc/fstab",
                                line => "/dev/sdb1 /datos ext4 rw,relatime,data=ordered 0 0",
                                ensure => present
                        }
                }
                default: { }
        }

}
Básicamente:
  • Instala los paquetes de virtualbox y su "extension pack" (en este caso la 5.2.18, habría que cambiarlo en función del tu Virtualbox).
  • Crea el árbol de directorios /datos/VirtualBox VMs/VirtualBox/Win10, se configura el entorno para que virtualbox trabaje con esos directorios y pone en ellos los ficheros que definen la máquina virtual de Windows 10. Estos 2 ficheros son VirtualBox.xml y Win10.vbox, extraídos de una configuración manual de un virtualbox donde se prepara todo. Aquí cada cual pondrá lo que necesite según su caso.
  • Se instalan los scripts run_vbox, que abrirá la máquina virtual, y vbox_permisos, que en el inicio de sesión configurará los permisos del usuario para hacer funcionar todo.
  • Si es necesario y en función de la máquina, configuramos en fstab la ruta /datos para que se monte sobre la partición de mayor tamaño.

Aquí está el enlace a la tarea puppet completa, con todos los ficheros excepto el .vdi, evidentemente.

La carpeta /datos tiene este contenido (en negrita los ficheros significativos, el resto son creados de forma automática):
datos
└── VirtualBox VMs
        └── VirtualBox
                ├── compreg.dat
                ├── Oracle_VM_VirtualBox_Extension_Pack-5.2.18.vbox-extpack
                ├── selectorwindow.log
                ├── selectorwindow.log.1
                ├── VBoxSVC.log
                ├── VBoxSVC.log.1
                ├── VBoxSVC.log.2
                ├── VBoxSVC.log.3
                ├── VBoxSVC.log.4
                ├── VBoxSVC.log.5
                ├── VBoxSVC.log.6
                ├── VBoxSVC.log.7
                ├── VirtualBox.xml
                ├── VirtualBox.xml-prev
                ├── Win10
                │   ├── Logs
                │   │   ├── VBox.log
                │   │   ├── VBox.log.1
                │   │   └── VBox.log.2
                │   ├── Win10.vbox
                │   └── Win10.vbox-prev
                ├── Win10-Original.vdi
                ├── Win10.vdi
                └── xpti.dat


El fichero Wind10.vdi es la imagen de disco .vdi con el sistema operativo, enlazada desde dentro de Win10.vbox. El fichero Win10-Original.vdi es una copia que hago cada vez que actualizo Win10.vdi, que queda como un fichero de backup por si se estropease la máquina original tener una copia funcional en poco tiempo.

3. Distribución rápida de imágenes vdi.

Los ficheros .vdi son basante pesados (en mi caso una imagen de 27Gb) y distribuirlos por la red entre diferentes máquinas cuando se añade algo y hay que actualizar en todos los puestos se hace interminable.

Para evitarlo lo mejor es que, si tenemos la opción, hagamos esta distribución usando udpcast, que nos permite copiar por multicast una imagen en 15, 20 o más puestos a casi la misma velocidad que si fuese a un único puesto.

La única condición es que todas las máquinas estén conectadas al mismo switch y esté esté configurado para permitir multicast (con IGM Snooping activado y con ciertos controles -dependientes del modelo del switch- para evitar tormentas de red desactivados). Si todo está bien, la transferencia se realizará hacia todas la máquinas receptoras a unos 80-90Mbps, lo cual nos permitirá distribuir la imagen completa en todo el aula en menos de una hora.

La forma de hacerlo es instalar el paquete udpcast en todas las máquinas y en la máquina emisora (que puede ser cualquier PC del aula) hacer:
# udp-sender --file "/datos/VirtualBox VMs/VirtualBox/Win10.vdi" --interface eno1 --min-receivers 15
Mandamos por la tarjeta de red "eno1" hacia 15 receptores.

En los receptores hacemos:
# udp-receiver --file "/datos/VirtualBox VMs/VirtualBox/Win10.vdi" --interface eno1
Como teclear este comando en todos y cada uno de los receptores es bastante aburrido, aconsejo fervientemente usar tmux-cssh recomendado por mi compañero Esteban para abrir una sesión ssh en todos los receptores y escribir/ejecutar en paralelo las órdenes en los 15 puestos. Una pequeña maravilla.

Una vez hecha la copia de la imagen .vdi no hay que olvidar hacer una copia de seguridad en cada máquina y dar permisos 777 a "Win10.vdi" para permitir su acceso desde cualquier usuario que inicie sesión.

Nota: en mi caso he tenido un problema con la transmisión multicast que hacia que la velocidad de copia se redujese a 2-3Mbps. El problema es que en el aula donde estaba trabajando tenía un punto wifi Dlink DIR-860L configurado además como enlace de red entre el emisor y los receptores. El punto wifi limitaba el tráfico sin que yo cayese en ello, y nos ha hecho perder tiempo a mí y a mi compañero David pensando que el problema estaba en el switch del aula. Ojo por tanto con cualquier dispositivo adicional de electrónica de red que pudiera haber el aula, ya que el tráfico multicast puede ser penalizado al pasar por él.

martes, 19 de marzo de 2019

Gestión remota de wifi en un router OpenWRT/LEDE

Tanto en el centro como para usos domésticos tengo varios router con OpenWRT o LEDE donados o recogidos literalmente de la basura. Aunque a veces es dificultoso poner el firmware OpenWRT en los router de las operadoras telefónicas el resultado merece la pena, ya que nos queda un aparatejo con un Linux empotrado y un abanico increíble de posibles usos, una pequeña parte de los cuales ya he tratado aquí. El DD-WRT (primo del OpenWRT) que traen nuestros puntos de acceso D-Link DIR-860L no está mal, pero el OpenwRT es mucho mas versátil, tanto en facilidad de uso como en repositorio de paquetes instalables.

Uno de estos usos es hacerlos funcionar como Puntos de Acceso wifi neutros (Dumb AP) ideales para crear redes wifi por diferentes puntos del edificio.

Al ser un Linux lo que corre por sus entrañas, es sencillo manejar el punto de acceso wifi remotamente desde una aplicación, script y/o consola remota. Ejecutar un comando sobre el router desde otra máquina es tan sencillo como:
# sshpass -p contraseña ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@ip "comando"
Ahora voy a describir 4 secuencias de comandos específicas para manejar la wifi:
  • Encender la wifi:
    wifi up
  • Apagar la wifi:
    wifi down
  • Cambiar la clave de la wifi:
    uci set wireless.@wifi-iface[0].key=clave1234; uci commit wireless;  wifi reload
  • Obtener estado de la wifi (on/off), clave, SSID:
    valor=$(iwinfo | head -1 | wc -l );key=$(uci get wireless.@wifi-iface[0].key);ssid=$(uci get wireless.@wifi-iface[0].ssid);echo $valor:$key:$ssid
Por tanto, para cambiar la clave de la wifi de un punto de acceso desde nuestro PC se haría tecleando:
# sshpass -p contraseña ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@ip "uci set wireless.@wifi-iface[0].key=clave1234; uci commit wireless;  wifi reload"
Con esto queda expuesta la facilidad de manejar estos puntos de acceso remotamente desde cualquier otro entorno con simples comandos. Ahora el límite es nuestra imaginación.



Ya lo sé, tengo debilidad por la Opportunity. Es uno de los aparatos mas condenadamente perfectos que ha hecho nuestra especie.

Su última foto panorámica (hay corrección de color para resaltar los detalles, el tono real es mas rojizo):


Su última foto antes de interrumpir la comunicación (nube de polvo y corte a mitad de la transmisión):


Su próxima foto cuando despierte:

viernes, 15 de marzo de 2019

Clonando por comandos

Normalmente hacemos la clonación de sistemas operativos usando clonezilla, pero me he encontrado con un disco duro con arranque dual en el que la partición de Windows 8 se mostraba especialmente rebelde: hacía la imagen, pero luego al restaurar fallaba con errores de checksum y otros más esotéricos. No es frecuente, pero a veces pasa. Tras intentarlo varias veces con diferentes versiones de clonezilla he cambiado de estrategia para hacer algo que nunca había probado: clonar y restaurar la partición mediante comandos, sin usar clonezilla. Es decir: haré mediante línea de comandos lo que clonezilla hace internamente.

Para ello basta con arrancar la partición de Linux (recordemos que es un sistema dual) o bien arrancar con una distribución live y hacer:
# apt-get install partclone
# partclone.ntfs -c -d -s /dev/sda2  -o /ruta/sda2.img
Esto crea una imagen de la partición sda2 (que es la partición con Windows que me estaba dando la lata) en la ruta indicada. Si es una distribución live deberíamos guardarlo en un dispositivo de memoria externo (o carpeta de red) con capacidad suficiente.

Una vez hecha la imagen en el fichero sda2.img, lo llevamos a la maquina destino, arrancamos y hacemos el proceso inverso:
# apt-get install partclone
# partclone.ntfs -r -d  -s /ruta/sda2.img -o /dev/sda2 
A diferencia de con el clonezilla... esta restauración funcionó a la primera. Y el arranque posterior del sistema también, sin que haya encontrado explicación al fallo previo. Decía Arthur C. Clarke que "cualquier tecnología lo suficientemente avanzada es totalmente indistinguible de la magia". En el caso de la informática yo diría que adicionalmente es indistinguible del vudú.

Lo que me queda pendiente de probar es ahorrarme guardar la imagen en una unidad de almacenamiento, sino que conforme la imagen se va haciendo irla enviado por la red con la utilidad netcat hacia la otra máquina, realizando la clonación al vuelo. En el ordenador original se haría:
# partclone.ntfs -c -s /dev/sda2 | nc 192.168.1.33 8000 
Y en el que recibe la imagen (suponemos que tiene la IP 192.168.33):
# nc -l -p 8000 | partclone.ntfs -r -o /dev/sda2
Bueno, pues este método es bastante casero pero nos puede resolver alguna papeleta.

No tan sonado, pero igualmente importante: la Dragon se ha soltado de la EEI y ha vuelto a casa, amerizando sin problema.


Estos son los valientes que entraron en la cápsula una vez acoplada a ver si todo iba bien:


Según comentaron, había un sospechoso olor a "alcohol isopropílico" dentro. Yo me inclino a pensar que llevaba vodka o coñac armenio de contrabando entre los 204Kg de carga útil. Es un clásico subir bebidas espirituosas allá arriba.