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

miércoles, 29 de mayo de 2019

Conectando por ssh a un Clonezilla Live

A veces nos vendría bien conectarnos a la la sesión clonezilla que está ejecutando un compañero o nosotros mismos en otra ubicación, para así poder hacer la clonación desde nuestro puesto de trabajo o ver y depurar las causas de algún error.

Esto no es tan trivial como en un Linux corriente ya que clonezilla arranca como una distribución live con el servicio ssh apagado. Vamos a ver como habilitar el sshd y conectar a la red, permitiendo así la conexión remota desde otra ubicación.

Una vez arrancado clonezilla en el equipo, nos vamos a la shell (ya sea desde el menú o con CTRL-ALT-Fx) y activamos el servicio ssh con:
# sudo service ssh start
A continuación hay que conectar a la red el equipo, para ello nos aseguramos de que tiene un cable ethernet conectado y hacemos:
# sudo ocs-live-netcfg
Que mostrará el asistente de conexión a red. Lo habitual es elegir "dhcp" y apuntar la IP que se recibe.

Una vez hecho esto, el pc con el clonezilla queda a la espera, y desde la otra ubicación podemos conectarnos con:
# ssh user@ip.del.clonezilla
La contraseña por defecto es "live". Una vez conectados en remoto tenemos una shell desde donde realizar las tareas que deseemos sobre la máquina remota, incluyendo lanzar el asistente de clonezilla:
# sudo clonezilla
Si además estamos conectando a una ubicación remota donde hay un compañero, puedes sernos usar el comando "screen" para compartir la sesión y que ambos podamos ver a la vez lo que se hace en una pantalla común. Estos dos enlaces nos muestran como hacerlo:



Este es el tren de 60 satélites Starlink de Elon Musk surcando el cielo. Se pueden observar con unos prismáticos si estamos en una zona de baja contaminación lumínica.

Con este enlace podemos ver en tiempo real por donde va el tren de satélites y nos permite saber cuando pasará por nuestra vertical.

miércoles, 22 de mayo de 2019

TVHeadend: configuración y uso (II)

Seguimos con el Tvheadend. Después de instalarlo, configurarlo y conectarlo a varios streams de IPTV para jugar con ellos, en este post vamos a ver como configurarlo con una tarjeta de TV física.

1. Hardware.

Para ello usaremos una tarjeta TDT PCI. En su día ya estuvimos lidiando con otra parecida. Identifiquemos la tarjeta:
# lspci -nnvv

04:01.0 Multimedia controller [0480]: Philips Semiconductors SAA7134/SAA7135HL Video Broadcast Decoder [1131:7134] (rev 01)
 Subsystem: Creatix Polymedia GmbH Medion 7134 [16be:0003]
 Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
 Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
 Latency: 64 (21000ns min, 8000ns max)
 Interrupt: pin A routed to IRQ 16
 Region 0: Memory at febffc00 (32-bit, non-prefetchable) [size=1K]
 Capabilities: [40] Power Management version 1
  Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
  Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=1 PME-
 Kernel driver in use: saa7134
 Kernel modules: saa7134
La carga del driver la he configurado así:
# cat /etc/modprobe.d/saa7134.conf 
options saa7134 card=12 alsa=1
install saa7134 /sbin/modprobe --ignore-install saa7134; /sbin/modprobe saa7134-dvb ; /sbin/modprobe tuner ; /sbin/modprobe tda9887
En el arranque, el syslog recoge estos mensajes de detección:
# dmesg |grep saa
[   13.906748] saa7134: saa7130/34: v4l2 driver version 0, 2, 17 loaded
[   13.906963] saa7134: saa7134[0]: found at 0000:04:01.0, rev: 1, irq: 16, latency: 64, mmio: 0xfebffc00
[   13.906971] saa7134: saa7134[0]: subsystem: 16be:0003, board: Medion 7134 [card=12,insmod option]
[   13.906999] saa7134: saa7134[0]: board init: gpio is 0
[   14.076684] saa7134: i2c eeprom 00: be 16 03 00 54 20 1c 00 43 43 a9 1c 55 d2 b2 92
[   14.076688] saa7134: i2c eeprom 10: 00 ff 86 0f ff 20 ff 00 01 50 32 79 01 3c ca 50
[   14.076690] saa7134: i2c eeprom 20: 01 40 01 02 02 03 01 00 06 ff 00 1f 02 51 96 2b
[   14.076692] saa7134: i2c eeprom 30: a7 58 7a 1f 03 8e 84 5e da 7a 04 b3 05 87 b2 3c
[   14.076694] saa7134: i2c eeprom 40: ff 1d 00 c2 86 10 01 01 00 00 fd 79 44 9f c2 8f
[   14.076696] saa7134: i2c eeprom 50: ff ff ff ff ff ff 06 06 0f 00 0f 00 0f 00 0f 00
[   14.076698] saa7134: i2c eeprom 60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[   14.076701] saa7134: i2c eeprom 70: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[   14.076703] saa7134: i2c eeprom 80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[   14.076705] saa7134: i2c eeprom 90: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[   14.076707] saa7134: i2c eeprom a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[   14.076709] saa7134: i2c eeprom b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[   14.076711] saa7134: i2c eeprom c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[   14.076714] saa7134: i2c eeprom d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[   14.076716] saa7134: i2c eeprom e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[   14.076718] saa7134: i2c eeprom f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[   14.106696] saa7134: saa7134[0] Board has DVB-T
[   14.106700] saa7134: saa7134[0] Tuner type is 63
[   14.513476] saa7134: saa7134[0]: registered device video0 [v4l2]
[   14.513564] saa7134: saa7134[0]: registered device vbi0
[   14.513639] saa7134: saa7134[0]: registered device radio0
[   14.609062] saa7134_dvb: dvb_init() allocating 1 frontend
[   14.706705] DVB: registering new adapter (saa7134[0])
[   14.706713] saa7134 0000:04:01.0: DVB: registering adapter 0 frontend 0 (Philips TDA10046H DVB-T)...
[   17.115786] saa7134_alsa: saa7134 ALSA driver for DMA sound loaded
[   17.115822] saa7134_alsa: saa7134[0]/alsa: saa7134[0] at 0xfebffc00 irq 16 registered as card -1
[   30.560105] saa7134 0000:04:01.0: DVB: adapter 0 frontend 0 frequency 0 out of range (51000000..858000000)
Y puesto que el driver está bien configurado, crea los dispositivos adecuados en /dev:
# ls -l /dev/dvb/adapter0/*
crw-rw----+ 1 root video 212, 4 may 15 16:49 /dev/dvb/adapter0/demux0
crw-rw----+ 1 root video 212, 5 may 15 16:49 /dev/dvb/adapter0/dvr0
crw-rw----+ 1 root video 212, 3 may 15 16:49 /dev/dvb/adapter0/frontend0
crw-rw----+ 1 root video 212, 7 may 15 16:49 /dev/dvb/adapter0/net0

2. Canales TDT.

Cada zona de España tiene sus propios canales TDT en función del repetidor. Por tanto, según sea nuestra ubicación geográfica debemos conocer que frecuencias se utilizan y qué canales hay disponibles dentro de cada frecuencia. Esto se puede consultar en la página http://www.tdt1.com, donde aparece la información tal que así:


Para no tener que meter las frecuencias a mano, todos los programas de manejo de la TDT (vlc, kaffeine, Tvheadend, ...) cuentan con algún script o fichero de configuración donde vienen las frecuencias de nuestra zona. En el caso de Tvheadend la ubicación de estos ficheros es:
# ls /usr/share/tvheadend/data/dvb-scan/dvb-t/es-*
/usr/share/tvheadend/data/dvb-scan/dvb-t/es-Alava
/usr/share/tvheadend/data/dvb-scan/dvb-t/es-Albacete
/usr/share/tvheadend/data/dvb-scan/dvb-t/es-Alfabia
/usr/share/tvheadend/data/dvb-scan/dvb-t/es-Alicante
...
Como a veces el gobierno reubica las frecuencias con el fin de hacer sitio para la telefonía móvil puede suceder que estos ficheros anteriores estén obsoletos. Afortunadamente hay gente que pone en github un repositorio con ficheros actualizados. Por tanto no está mal comparar el fichero correspondiente a nuestra zona con el del repositorio y actualizarlo si fuese necesario.

3. Configuración de Tvheadend.

Una vez pinchada la tarjeta y arrancado el PC, esta aparece en la configuración de Tvheadend al entrar por su interface web:


A partir de aquí, la secuencia de pasos es bastante parecida a lo hecho en el post anterior:

  • Creamos una red para la TDT: Configuration->DVB Inputs->Networks->Add Network->DVB-T Network (el nombre técnico real de la TDT es "DVB-T"):


    En el formulario seleccionamos "Enabled", damos nombre a la red ("TDT"), y en "Pre-defined muxes" elegimos el fichero de configuración de frecuencias TDT correspondiente a nuestra zona (la que vimos en el apartado previo - en mi caso es "es-Carceres". No es un error: hace años alguien lo escribió mal y la errata se ha perpetuado):


    Al dar a "Create" se crea la red y los muxes asociados a las frecuencias definidas en el fichero de configuración asociado.
  • Ahora hay que vincular la tarjeta de TV y la red, ya que si no Tvheadend no sabe dónde sintonizar las frecuencias definidas para los muxes recién creados. Para ello vamos a Configuration->DVB Inputs->TV Adapters y pinchamos sobre la tarjeta de TV. Aparecerá un formulario para la configuración de la misma. Allí nos aseguramos de que "Enabled" y "Over-the-air EPG" estén activados. En el desplegable "Networks" seleccionamos "TDT", que es la red creada en el paso anterior. Al dar al botón "Save" se guardan y aplican los cambios.

  • Muxes y servicios: ahora los muxes encuentran un "origen" de señal y empiezan a sintonizar los canales. En Configuration->DVB Inputs->Muxes nos aparece la lista de muxes, uno asociado a cada frecuencia (expresada en MHz):


    Dentro de cada mux/frecuencia hay varios canales multiplexados. Esos canales deberían aparecer en la pestaña Configuration->DVB Inputs->Services:


    Nota: en el caso de que no aparezcan los servicios de forma automática podemos volver a la pestaña Muxes y darle al reproductor de cada mux (botón de la columna más a la izquierda que muestra la etiqueta "Play this stream"), eso descarga un fichero con un stream que se abrirá en vlc y mostrará uno de los canales del mux. Al hacer esto se fuerza la detección de los canales y la creación de los servicios correspondientes.

  • Mapeo de los servicios en canales de Tvheadend: una vez tenemos cada uno de los canales de TDT sintonizados metido como servicio en Tvheadend es el momento de decidir que canal queremos que se converta en un canal de Tvheadend.

    Recordemos que Tvheadend distingue entre servicio (un stream de vídeo entrante) y canal (canal de Tvheadend que aparecerá en el interface web, las aplicaciones cliente android y sobre el que podremos programar grabaciones). De esta manera podemos ignorar los canales entrantes que no nos interesen y configurar solo unos cuantos de ellos de cara al usuario final.

    Esto lo hacemos en Configuration->DVB Inputs->Services->Map Selected, que permite mapear los servicios que queramos en canales:


    Una vez mapeado, si nos vamos a Channel EPG->Channel podremos ver el canal recién creado:

    Con esto dicho canal ya estará disponible en los clientes Tvheadend y sobre el podremos programar grabaciones y timeshifts. A partir de aquí sólo tendremos que repetir esto con todos los canales que nos interese tener.

4. Enlaces.

Para escribir este post he tenido que buscar la información en varias fuentes muy interesantes donde se hablan tanto de sintonización TDT como satélite, así que pongo los enlaces usados por si quisieramos ampliar:

Veamos esta foto:


La sonda lunar del Estado Nación Judío de Israel se hace un selfie un ratito antes de estrellarse violentamente contra la Luna, en lugar de aterrizar suavemente. Quizá lo confundió con la franja de Gaza.

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.


Addenda 22/mayo/2019:

Hemos tenido otro problema con el touchpad, que de manera aleatoria deja de funcionar cuando llevamos un rato trabajando, obligándonos a conectar un ratón USB. Se detecta como un dispositivo SYNA3602:00 0911:5288 Touchpad (podemos verlo con "cat /proc/bus/input/devices") y es manejado por el módulo i2c_hid. Si buscamos en Internet vemos que tiene un pequeño historial de problemas.

La solución propuesta por nuestros compañeros de servicios centrales es actualizar el kernel y sus módulos a la versión 5.0.0-15, lo cual podemos hacer con unas reglas puppet:
package { 'linux-image-5.0.0-15-generic' :
    ensure => "installed" ,
}
package { 'linux-modules-5.0.0-15-generic' :
    ensure => "installed" ,
}
package { 'linux-modules-extra-5.0.0-15-generic' :
    ensure => "installed" ,
}
Y después de esto no vuelve a aparecer el problema del touchpad.


Addenda 23/mayo/2019:

Seguimos con cosas para corregir o mejorar que van descubriendo los compañeros.

En el escritorio de los portátiles parece el disco "sda2" accesible. Esta partición es donde se guarda clonezilla y lo mas adecuado es ocultarla con este fichero de configuración:
# cat /etc/udev/rules.d/99-hide-disks.rules
KERNEL=="sda2", ENV{UDISKS_IGNORE}="1"
Si queremos acceder desde los portátiles a la carpeta compartida /home/instituto hay un pequeño problema con los permisos, que se corrige:
file { "/etc/auto.instituto":
    ensure => file,
    owner => root, group => root, mode => 644,
}

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.

jueves, 14 de marzo de 2019

Problemas en el inicio de sesión en thinclients LTSP.

Como ya hemos visto otras veces, en muchos centros seguimos usando el modelo de thinclients con Ubuntu LTSP para seguir sacando partido a máquinas que ya van para 15 años de antigüedad.

Por desgracia, da la impresión que el soporte para thinclients está cada vez mas dejado y nos cuesta trabajito tenerlo operativo.

Durante el todo el curso me han venido advirtiendo de un problema recurrente: cuando un thinclient en el que estaba trabajando un alumno quedaba colgado o se apagaba (el hardware sobre el que corren tiene sus achaques), el alumno ya no podía iniciar sesión en ese u otro thinclient con sus credenciales hasta pasado un tiempo, ya que era expulsado de la sesión a cada intento de entrada. Tenía que usar las de otro usuario para entrar. En los últimos tiempos este problema se había convertido en una manera de interrumpir el desarrollo de la clase para un grupito de alumnos graciosetes.

Mirando lo que pasaba advertimos que se habían quedado un montón de procesos a nombre del usuario abiertos y alguno de ellos bloqueaba el nuevo inicio de sesión. Esto se mantenía así hasta que esos procesos morían (pasado un tiempo o con el reinicio del LTSP).

Una manera rápida de liberar esos procesos es matarlos con uno de los varios comandos que hay para ello, por ejemplo:
# killall -9 -u usuario
Pero esto obliga a que lo haga alguien con permisos de root y acceso a la consola, lo cual no es nada cómodo.

Vamos a repasar como se inicia sesión en un thinclient y dilucidar que está fallando.

1. Proceso de inicio de sesión en thinclients.

Los thinclients usan como display manager ldm, que a diferencia de lightdm y similares, establece una conexión ssh con el servidor de aula para iniciar la sesión en él.

Toda la imagen de disco con el que funcionan los thinclients cuelga de la ruta /opt/ltsp/i386 de los servidores de aula. En esa ruta está el fichero /usr/share/ldm/ldm-script, que se ejecuta desde ldm y que lanza los scripts que hay en /usr/share/ldm/rc.d/.

ldm-script recibe un parámetro en $1 que puede tener los valores init/pressh/start/xsession/stop, tal como se ve en este "case", donde se indica en los comentarios a que evento del inicio de sesión está ligado cada valor:
case "${ACTION}" in
    init)
        # From ldm.c: LDM has just started, X is running, the greeter isn't.
        SCRIPTS="I*"
        ;;
    pressh)
        # From ssh.c: a username/password was provided, no connection yet.
        SCRIPTS="P*"
        ;;
    start)
        # From ssh.c: an ssh connection was established.
        SCRIPTS="S*"
        ;;
    xsession)
        # From plugin.c: an xsession was started (maybe even rdp).
        SCRIPTS="X*"
        ;;
    stop)
        # From screen.d/ldm.c: the xsession has ended.
        SCRIPTS="K*"
        ;;
esac
Lo que hace ldm-script es ejecutar en orden los scripts de /usr/share/ldm/rc.d/ que comienzan por la letra de la variable $SCRIPTS del paso anterior. Esto nos permite tener una secuencia de scripts asociados a cada evento de ldm. Los ficheros contenidos en mi rc.d son:
I00-localapps-cleanup
I01-halt-check
I01-nbd-checkupdate
K99-ltsp-cluster
K99_seguimiento_usuario
P00-ltsp-cluster
S01-setup-xauth
S15-userLoginCheck
S20-restrictUser
S99-debug-terminal
S99-ltsp-cluster
S99_seguimiento_usuario
X01-localapps
X01-remoteapps
X02-genmenu
X10-delayed-mounter
X50-dmrc-processing
X50-generate-env
X50-printers
X51-localapps
X51-opengl
X51-remoteapps
X52-xcompmgr
X95-run-x-session
X98-delayed-mounter
X99-ltsp-logout-action
Como se ve, hay un puñado de ficheros ligado a cada tipo de evento.

2. Inicio de sesión de usuario.

Los scripts comenzados por "S" son los que se ejecutan una vez el usuario ha tecleado usuario y contraseña, se ha establecido conexión ssh y se va a iniciar sesión gráfica.

Entre estos script hay uno llamado /usr/share/ldm/rc.d/S15-userLoginCheck cuya función es comprobar si LDM_LIMIT_ONE_SESSION es true y en caso afirmativo, matar todos los procesos previos del usuario. LDM_LIMIT_ONE_SESSION es una variable definida en /etc/lts.conf y tiene como función "Only allow a given user to log into one thin-client at a time", es decir, solo se permite que un usuario haga login en único thinclient al mismo tiempo. Para ello el script S15-userLoginCheck mata todos los procesos y sesiones previas del usuario.

Bien, pues esto que ha venido funcionando durante años, ahora con Ubuntu 18 ha dejado de funcionar. Y como consecuencia de ello tenemos el problema que estamos comentando en esta entrada.

Si miramos en todos los scripts de rc.d vemos que en muchos de ellos se usan las variables LDM_SOCKET, LDM_SERVER y LDM_USERNAME, que deberían contener respectivamente el socket de la conexión ssh entre thinclient y LTSP, la IP del LTSP y el nombre del usuario que está iniciando sesión. Bien, pues aunque antaño estas variables tenían valores correctos, hace ya tiempo que vienen vacías. Esto hace que muchos de los scripts de rc.d no hagan nada.

Podemos solucionar esto dando los valores adecuados a esas variables en cada script, que tras un proceso de investigación averiguamos que consiste en añadir las líneas:
LDM_SOCKET=$(ls -1 /var/run/ldm_socket*  | head -1)
LDM_SERVER=192.168.0.254
LDM_USERNAME=$(ssh -S $LDM_SOCKET $LDM_SERVER "id -un")
pero el hecho de que eso no venga de serie y nadie se ocupe de añadirlo nos da una idea del estado actual de semiabandono del proyecto, pese a lo cual sigue funcionando bastante bien.

Pero es que incluso después de poner las líneas arriba indicadas dentro de S15-userLoginCheck con la esperanza de que volviese a funcionar la matanza de procesos previos del usuario pude comprobar que seguía sin funcionar, y que por desgracia no se podía iniciar sesión por segunda vez. Podría haberme puesto a depurar el código de S15-userLoginCheck, pero antes se me han cruzado un par de asuntos que han solucionado el problema por otra vía.

3. Solución.

Recordé que en /etc/lts.conf había una variable llamada LDM_DIRECTX, que tradicionalmente habíamos tenido con valor False, que es el valor que trae por defecto. Cuando vale False toda la sesión entre thinclient y LTSP se hace cifrada por el túnel ssh, lo cual aporta de seguridad a costa de hacer mas lento el escritorio por sobrecarga de trabajo del thinclient. Un compañero sugirió probar con LDM_DIRECTX = True, que evita el uso de este tunel ssh y lo cierto es que el escritorio de los thinclients iba sensiblemente mas rápido, así que la dejamos con True.

Haciendo caso a un pálpito cambié LDM_DIRECTX = False y regeneré la imagen de thinclients...y ¡voilá!, volvía a funcionar S15-userLoginCheck y un alumno podía iniciar sesión en cualquier lado sin problema, provocando el cierre de la sesión previa. Como contrapartida tenemos que el escritorio de los thinclients quedaba un poco mas lento. ¿Causa de que se arreglase el desaguisado? Je ne sais pas.

No todo queda aquí, en una sincronicidad al poco tiempo otro compañero nos reveló un método para que se liquidasen los procesos de los usuarios que han cerrado sesión, consistente en añadir a /etc/systemd/logind.conf (en nuestro caso, del servidor LTSP) la línea:
KillUserProcesses=yes
con la cual systemd se ocupa de matar procesos de usuarios que han salido del sistema.

No tenía mucha confianza de que funcionase con los thinclients, pero probé a realizar estos pasos:

  1. Añadir KillUserProcesses=yes a logind.conf.
  2. Reiniciar el servicio systemd-logind.
  3. Poner LDM_DIRECTX = True en lts.conf.
  4. Regenerar imagen de thinclients con ltsp-update-image

He podido verificar con alegría que ahora si funcionaba todo bien como antiguamente. Al final el truco para arreglar todo no estaba en nada relacionado con LTSP, sino con logind.conf.

En conclusión: larga vida a los thinclients.


El 22 de febrero pasado la sonda japonesa Hayabusa 2 le dió un piquito al asteoride Ryugu para recoger muestras antes de traerlas a casa:



No es Bruce Willis y su equipo de perforadores de Armageddon, pero la hazaña de llegar hasta un pedrolo de 435 metros, orbitarlo, aterrizar con éxito 2 rovers del tamaño de una Roomba y acercarse a la superficie para chocar suavemente con ella y recoger muestras no es moco de pavo.

En la primera temporada de True Detective el detective Rust observa un grupo de fanáticos religiosos baptistas y sentencia "míralos: estos nunca fisionarán el átomo". Ni aterrizarán en un asteroide.