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

jueves, 1 de diciembre de 2022

Interruptor casero USB.

Vamos a ver como construir un interruptor casero que se conecta por USB y que al pulsarse permite lanzar un evento en el ordenador, ejecutando un script.

Lo primero es construir el interruptor: ¿que usar si no tenemos ni idea de electrónica?. Pues no hace falta nada especial ya que con un ratón de ordenador es suficiente. Todos tenemos ratones USB rotos o antiguos que podemos reciclar. La idea es desmontar el ratón, sacar la placa, arrancar la luz led y verificar que el botón central (el asociado al click de la rueda) funciona y manda señal por el cable USB. Da igual el estado del resto de mecanismos.

Cogemos el ratón, lo metemos dentro de una cajita del tamaño adecuado y lo pegamos usando la pistola térmica de silicona que tenemos todos para las manualidades. En mi caso tenía una cajita que venía perfecta:
Nótese como buscamos que el interruptor del botón quede justo en el centro (marcado con el círculo amarillo). Luego he puesto una tapa de plástico agujereada para permitir llegar al interruptor y forrada con goma eva. Por último hago un interruptor externo con un tapón y un poco de espuma de embalaje. La idea es que el interruptor externo presione al interruptor interno del ratón.
Una vez pegado y montado todo:
Creo que es resultón para lo que yo quiero, pero si queremos hacerlo mas formal siempre podemos usar la impresora 3D para generar una cajita y botón con aspecto mas profesional.

Ya tenemos el hardware, vamos al software. Pinchamos el cable en un puerto USB y el Linux lo detecta como un ratón, pero como esta casi todo inutilizado tan solo recibirá eventos del botón central. Lo primero es encontrar el generador de eventos asociado al nuevo ratón:
# ls -l /dev/input/by-id
total 0
lrwxrwxrwx 1 root root  9 oct 27 09:34 usb-0461_USB_Optical_Mouse-event-mouse -> ../event2
lrwxrwxrwx 1 root root  9 oct 27 09:34 usb-0461_USB_Optical_Mouse-mouse -> ../mouse0
lrwxrwxrwx 1 root root  9 oct 27 09:34 usb-CHICONY_HP_Basic_USB_Keyboard-event-kbd -> ../event3
lrwxrwxrwx 1 root root 10 nov 29 13:32 usb-Logitech_USB-PS_2_Optical_Mouse-event-mouse -> ../event14
lrwxrwxrwx 1 root root  9 nov 29 13:32 usb-Logitech_USB-PS_2_Optical_Mouse-mouse -> ../mouse1
En nuestro caso sería /dev/input/event14. El paso siguiente es verificar que se detectan los eventos de pulsación. Para ello usamos triggerhappy:
# apt-get install triggerhappy
# thd --dump /dev/input/event14
Y pulsamos varias veces el interruptor para ver si se detecta. En consola debería mostrarse:
EV_KEY	BTN_MIDDLE	1	/dev/input/event14
# BTN_MIDDLE	1	command
EV_KEY	BTN_MIDDLE	0	/dev/input/event14
# BTN_MIDDLE	0	command
EV_KEY	BTN_MIDDLE	1	/dev/input/event14
# BTN_MIDDLE	1	command
thd --dump /dev/input/event14
EV_KEY	BTN_MIDDLE	0	/dev/input/event14
# BTN_MIDDLE	0	command
Perfecto: el evento generado por la pulsación del botón es "BTN_MIDDLE 1". Conviene recalcar en este momento que la pulsación del botón central del ratón puede ser también interceptado por nuestro entorno de escritorio Linux y provocar algún efecto asociado (por ejemplo, pegar el texto que hay en el portapapeles). Para evitar efectos colaterales recomendamos desactivar ese ratón en la configuración del entorno de escritorio:

Una vez tenemos el evento localizado, creamos la configuración que asocia dicho evento al lanzamiento de un script:
# cat /etc/triggerhappy/triggers.d/redbutton.conf
BTN_MIDDLE    1       /root/scripts/redbutton.sh
Después de este cambio de configuración se debe reiniciar el servicio triggerhappy, pero antes debemos configurarlo para que se ejecute como root (normalmente lo hace como nobody) y escuche solo los eventos que vengan de /dev/input/event14.

Inocente de mi, probé a modificar tanto /etc/default/triggerhappy como /etc/init.d/triggerhappy sin éxito. Seguia ejecutándose con el usario nobody y escuchando en /dev/input/event*. Esto lo podemos verificar haciendo:
# ps aux | grep thd
nobody   12523  0.1  0.0  43844  2852 ?        Ss   21:32   0:00 /usr/sbin/thd --triggers /etc/triggerhappy/triggers.d/ --socket /run/thd.socket --user nobody --deviceglob /dev/input/event*
La causa de esto es que en Ubuntu 18 el demonio triggerhappy se lanza realmente desde /lib/systemd/system/triggerhappy.service. Los otros dos ficheros están de adorno. No entiendo esta manía de tener servicios que están init.d y en systemd a la vez, es como si hubiesen quedado el trabajo a medias y se hubiesen ido de cañas.

Editamos /lib/systemd/system/triggerhappy.service y lo quedamos:
[Unit]
Description=triggerhappy global hotkey daemon
After=local-fs.target

[Service]
Type=notify
ExecStart=/usr/sbin/thd --triggers /etc/triggerhappy/triggers.d/ --socket /run/thd.socket --user root --deviceglob /dev/input/event14

[Install]
WantedBy=multi-user.target
Luego reiniciamos el servicio:
# service triggerhappy restart
Y bueno ahora nos falta escribir el script. Aqui podemos poner cualquier cosa, yo simplemente voy a hacer que se oiga un audio (descargado de Internet o generado con pico2wave) en el escritorio:
# cat /root/scripts/redbutton.sh 
#!/bin/bash

#Subimos el volumen al máximo en el alsamixer
amixer set Master unmute
amixer set Master 100%

#Si hay un usuario logado, conectamos con su pulseaudio para subir el volumen al máximo
user=$(who | grep "(:0)" | head -1 | cut -f1 -d" "); 
if  [ -n "$user" ]
then
  su $user -c "DISPLAY=:0 pactl set-sink-volume 0 150%"
  su $user -c "DISPLAY=:0 pactl set-sink-mute 0 0"
  cp -f /root/scripts/no.wav /tmp/no.wav
  su $user -c  "DISPLAY=:0 aplay /tmp/no.wav"
else
  cp -f /root/scripts/no.wav /tmp/no.wav
  DISPLAY=:0 aplay /tmp/no.wav
fi

exit 0
Con esto ya tenemos todo funcionando. Bien, y ahora la pregunta: ¿Para qué carajos quiero esto?. Bueno, pues aparte de para enredar, para conectarlo a una Raspberry Pi o un OpenWRT sin teclado/ratón y poder lanzar eventos sobre ellos: apagar/encender la wifi, hacer una foto con la webcam, reiniciar un servicio o una aplicación, etc.

En mi caso tengo una Rasbperry Pi mostrando una página web en modo kiosko con información en tiempo real. A veces el navegador se bloquea y hay que cerrarlo y abrirlo de nuevo, teniendo que conectarme por VNC y hacer el proceso a mano. Con un botón de este tipo puedo lanzar un script que permite a cualquiera reiniciar el navegador en todo momento.

Out!

Directorio home de usuarios + nfs4: lentitud en el escritorio.

Una de las cosas que mas me gustan de Linux en un entorno de red es la capacidad de que los homes de los usuarios estén centralizados en un servidor de red común, de tal forma que siempre tenemos el mismo escritorio independientemente de la máquina usada. Esto facilita al usuario trabajar sin tener que andar subiendo ficheros a una nube o carpeta concreta de red, y a nosotros hacer copias de seguridad de sus datos y no preocuparnos de recuperar datos del usuario cuando falle físicamente el disco del equipo donde ha estado trabajando.

En nuestro caso siempre hemos usado NFS para montar estos homes, aunque hay mas alternativas. Nunca había habido problema pero cuando cambiamos hace unos años a usar Ubuntu 18 empezaron a aparecer problemas aleatorios de lentitud extrema en los escritorios/navegadores web. Una explicación común es que el aumento de complejidad de los navegadores en los últimos años (y eso es algo de lo que habrá que hablar algún día martillo en mano) los ha convertido en unos artefactos que con sus operaciones de entrada/salida acaban saturando el servidor NFS. Una pista en contra de esta hipótesis es que la lentitud va y viene sin correlación aparente con el número de usuarios instantáneos en la red del centro y que cuando una máquina va lenta, la de al lado no tiene por qué hacer lo mismo. Tenía que haber alguna explicación adicional.

Después de muchas pruebas hemos establecido que cambiar el sistema de montaje de los homes de los clientes de nfs4 a nfs3 mejora enormemente el problema, haciéndolo desaparecer en muchos casos. Vamos a ver las pruebas a realizar cuando tenemos un escritorio/navegador ralentizado para determinar si este cambio en el nfs solucionaría el problema.

Las pruebas que podemos realizar son las siguientes:
  • Entrar por ssh como root a un puesto donde el escritorio vaya lento y hacer el comando "time su <usuario>", siendo "usuario" un usuario que monta su home por NFS, claro está. Hacer lo mismo en un equipo no afectado por el problema. Si en el primero tarda 5 o mas veces que el segundo es un síntoma de que está afectado.
  • Entrar por ssh como root a un puesto donde el escritorio vaya lento y hacer "wget https://speed.hetzner.de/1GB.bin". Hacer lo mismo en un equipo no afectado por el problema. Es un fichero de prueba de 1Gb para hacer tests de velocidad desde consola. Si la velocidad es similar en ambos puestos podemos descartar que sea un problema de red (bucles de red, problemas de cableado, de switchs, de salida a Internet) y centrarnos en que es un problema de NFS.
  • Entrar por ssh como root a un puesto donde el escritorio vaya lento y mirar en el syslog buscando errores como:
    NFS: nfs4_reclaim_open_state: Lock reclaim failed!
    NFS: nfs4_reclaim_open_state: unhandled error -10026
    nfs4_reclaim_open_state: 3 callbacks suppressed
        
    Estos errores son síntomas de bloqueos y otros problemas en el montaje NFS.
  • Entrar en el servidor NFS y testear la carga con los comandos:
    # atop
    # iotop
    # nfsstat
      
    Buscando sobrecargas en el disco, red o en los procesos nfs.
  • Entrar por ssh como root a un puesto donde el escritorio vaya lento y hacer
    # nfsiostat
      
    Comparar el resultado con un equipo no afectado por el problema.
Después de todas estas pruebas, si sospechamos que las causas de la lentitud están relacionadas con el servidor NFS, el siguiente paso es verificar que tipo de montaje usamos en nuestros puestos. Para ello entramos por ssh como root en un equipo de usario y hacemos:
# automount -m

global options: none configured

  Mount point: /home

  source(s):

   type: ldap
   map: ldap:ou=auto.home,ou=Automount,dc=instituto,dc=extremadura,dc=es
   ....
   ....
   * | -fstype=nfs4,rw,hard,intr,nodev,nosuid,nolock,rsize=16384,wsize=16384 servidor:/&
La última línea nos dice que el montaje del home esta siendo realizado mediante nfs4. No tiene porque ser igual a la indicada, pero el "nfs4" es revelador. La idea es cambiarla por:
   * | -fstype=nfs,rw,fg,hard,intr,nodev,nosuid,async,ac,vers=3,fsc servidor:/home/&
que cambia el montaje del home para que se haga usando nfs3. Esta línea si que debemos ponerla de forma literal, tal cual aparece aquí.

El lugar donde se hace este cambio dependerá de donde configuremos el montaje en nuestro entorno. Para el caso de nuestros centros esto se hace en el directorio ldap, al que accedemos mediante phpldapadmin en el nodo:
cn=/,ou=auto.home,ou=Automount,dc=instituto,dc=extremadura,dc=es
Una vez allí localizamos el atributo "automountInformation", hacemos una copia de su contenido por si las moscas y lo sustitumos por:
* | -fstype=nfs,rw,fg,hard,intr,nodev,nosuid,async,ac,vers=3,fsc servidor:/home/&
Después de esto recargamos el servicio nfs en el servidor principal:
/etc/init.d/nfs-kernel-server reload
Y por último reiniciamos los clientes, dejando que trabajen durante varios días a ver si desaparecen los problemas. En bastantes casos con este sencillo cambio ha sido suficiente.

viernes, 11 de noviembre de 2022

Log histórico de portátiles encendidos cada día

Por una necesidad concreta he escrito un script que va rellenando un log de los portátiles de alumnas que se encienden cada día en el instituto. La finalidad es generar un listado tabulado como el siguiente:
...
2022/11/11-08:37:10	portinves-o11	10.192.55.97
2022/11/11-08:37:10	portinves-o12	10.192.54.74
2022/11/11-08:37:23	portinves-o04	10.192.54.91
2022/11/11-08:37:30	portlenovo-o02	10.192.55.106
2022/11/11-08:37:38	portinves-o01	10.192.54.115
2022/11/11-08:37:45	portinves-o09	10.192.54.114
2022/11/11-08:37:46	portinves-o10	10.192.54.159
2022/11/11-08:37:51	portinves-o15	10.192.54.110
2022/11/11-08:38:09	portinves-o05	10.192.54.78
2022/11/11-08:38:26	portinves-o02	10.192.54.116
...
Aunque esa información puede encontrarse en la herramienta "controlies", quería tenerla centralizada en un fichero de texto plano fácilmente procesable para hacer estadísticas. Para saber que portátiles se han encendido puedo consultar el fichero /var/log/syslog del servidor, filtrando por "DHCPACK" y por el nombre "port":
# grep DHCPACK /var/log/syslog | grep -i port
...
Nov 11 10:37:21 servidor dhcpd: DHCPACK on 10.192.54.196 to 28:e3:47:32:7e:0e (portinves-o16) via 10.192.54.1
Nov 11 10:58:53 servidor dhcpd: DHCPACK on 10.192.55.111 to 6c:62:6d:14:e4:36 (portmsi-o13) via 10.192.54.1
Nov 11 11:10:29 servidor dhcpd: DHCPACK on 10.192.55.112 to 6c:62:6d:15:14:b6 (portmsi-o02) via 10.192.54.1
...
En mi caso esto es sencillo porque todos los portátiles de alumnos se llaman "portXXX-oXX". Otro filtro que se puede usar es la MAC, ya que la mayoría de portátiles del mismo lote tiene un prefijo de MAC idéntico.

Una vez obtenido el listado lo manipulo uno poco con utilidades bash para extraer la marca de tiempo, nombre e IP. Luego se ordena y eliminan líneas duplicadas, llevando todo a /var/log/portatiles.log. El script queda:
#!/bin/bash

dhcp_hoy=$(mktemp)
log_portatiles_hoy=$(mktemp)
log_portatiles="/var/log/portatiles.log"

grep DHCPACK /var/log/syslog | grep -i port  > $dhcp_hoy

while read -r line
do
  fecha=$(echo $line | head -c 15)
  fecha=$(date -d"$fecha" +%Y/%m/%d-%H:%M:%S)
  ip=$(echo $line | cut -d" " -f8)
  mac=$(echo $line | cut -d" " -f10)
  nombre=$(echo $line | cut -d" " -f11 | tr -d "()")

  echo -e "${fecha}\t${nombre}\t${ip}" >> $log_portatiles
done < $dhcp_hoy

cat $log_portatiles_hoy >> $log_portatiles

sort -u  -o $log_portatiles $log_portatiles

exit 0
Todo esto se pone en un script del servidor que es invocado un par de veces al día usando crontab. Con eso tendremos el log preparado para consultar y disponer de esa información por si nos la requieren.


Los 同志 chinos han acabado de ensamblar en órbita su Estación Espacial:
Han tenido que montarse su propia estación debido a las reticencias de USA. Cuando no se quiere colaborar no queda otra que competir... y competir contra China es cada vez más complicado. No creo que hayamos aprendido la lección.

Zabbix (IV): creación de plantilla con items y triggers para agentes Linux.

En la primera entrada dedicada a Zabbix vimos templates para monitorizar impresoras Brother color. De todas las impresoras que tengo de esta marca he notado que la Broher DCP-9020CDW cada varios días se bloqueaba y me obligaba a reiniciarla. Si desactivaba la monitorización de Zabbix de esa impresora el problema desaparecía.

He deducido que alguno de los ítems que interrogaban a la impresora acababan finalmente provocando su cuelgue. Durante varios días he ido habilitando e inhabilitando ítems de la plantilla por grupos, mediante un divide y vencerás, hasta dar con el culpable: el "JetDirect Check".
Como es un ítem intrascendente que venía en la plantilla por defecto, lo he dejado desactivado (casilla "Enabled" desmarcada) y ya no ha vuelto a bloquearse:
¡Asunto solucionado!

viernes, 30 de septiembre de 2022

Filtrando publicidad con powerdns (III)

Nuestro filtro de publicidad basado en PowerDNS funciona bastante bien limpiando anuncios indeseados de las páginas y agilizando la navegación dentro de nuestra red.

El problema es que a veces filtra demasiado y nos quedamos sin ver cosas que pueden interesarnos (o no, como ATRESplayer). Esta semana me comunicaron que no se cargaban los contenidos de RTVE Play. Tras analizar el tráfico web con las opciones de desarrollador del navegador veo que se están cortando peticiones web a una serie de sitios con el nombre "gigya" y esto acababa repercutiendo en que no se cargaban los vídeos de RTVE.

La solución es no filtrar esos sitios, pero recordeoms que el script que construye la lista negra recopila los datos de varias ubicaciones web y no es sencillo quitar de esa lista uno a uno manualmente los sitios que si deseo permitir. Es el momento de implementar una "lista blanca" con patrones para identificar los sitios permitidos. El script blacklist-powerdns.sh quedaría:
# cat blacklist-powerdns.sh 
#!/bin/bash

#Crea fichero de bloqueos de publicidad y sitios web para powerdns.

#Descargamos listados de sitios web de publicidad a bloquear.
cp /dev/null /tmp/filter-hosts

wget -N -O /tmp/hosts https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
grep "^0.0.0.0" /tmp/hosts |  awk '{print $2}' >> /tmp/filter-hosts
echo "" >> /tmp/filter-hosts

wget -N -O /tmp/hosts http://sysctl.org/cameleon/hosts
grep "^127.0.0.1" /tmp/hosts | awk '{print $2}' >> /tmp/filter-hosts
echo "" >> /tmp/filter-hosts

wget -N -O /tmp/hosts https://mirror1.malwaredomains.com/files/justdomains
cat /tmp/hosts >> /tmp/filter-hosts
echo "" >> /tmp/filter-hosts

wget -N -O /tmp/hosts https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt
cat /tmp/hosts >> /tmp/filter-hosts
echo "" >> /tmp/filter-hosts

wget -N -O /tmp/hosts https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt
cat /tmp/hosts >> /tmp/filter-hosts
echo "" >> /tmp/filter-hosts

#Este enlace está muerto
#wget -N -O /tmp/hosts https://hosts-file.net/ad_servers.txt
#cat /tmp/hosts >> /tmp/filter-hosts

#Añadimos lista negra de dominios mantenida por nosotros
if [ -f /etc/powerdns/bloqueados.list ]
then
   cat /etc/powerdns/bloqueados.list >> /tmp/filter-hosts
   echo "" >> /tmp/filter-hosts
fi

#Ordenamos y quitamos dominios repetidos. Borramos comentarios.
cp /tmp/filter-hosts /tmp/filter-hosts2
sort -u -o /tmp/filter-hosts /tmp/filter-hosts
sed -i '/^localhost$/d' /tmp/filter-hosts
sed -i '/^#/d' /tmp/filter-hosts

#Quitamos de la lista los que tienen las palabras en /etc/powerdns/permitidos.list
if [ -f /etc/powerdns/permitidos.list ]
then
   for cadena in $(cat /etc/powerdns/permitidos.list)
   do
     sed -i  "/$cadena/d" /tmp/filter-hosts
   done
fi

#Generamos el fichero blocklist.lua compatible con powerdns
echo "return {" > /tmp/blocklist.lua
for i in $(cat /tmp/filter-hosts)
do
   echo \"$i\", >> /tmp/blocklist.lua
done
echo "}" >> /tmp/blocklist.lua

#Copiamos fichero de bloqueo DNS y reiniciamos servicio.
/etc/init.d/pdns-recursor stop
/etc/init.d/pdns stop
cp -f /etc/powerdns/blocklist.lua /etc/powerdns/blocklist.lua.bak
cp -f /tmp/blocklist.lua /etc/powerdns/blocklist.lua
/etc/init.d/pdns start
/etc/init.d/pdns-recursor start

exit 0

En negrita está el código nuevo: una vez hecha la lista de sitios filtrados recorremos el contenido del fichero /etc/powerdns/permitidos.list y eliminamos de la lista los sitios que tienen las palabras/subcadenas encontradas allí. En principio he puesto en permitidos.list solo una línea con la cadena "gigya", pero seguramente en los próximos meses vaya añadiendo mas contrafiltros que hagan menos estricta la lista negra con la que venimos trabajando.


Espectacular petardazo de la NASA para desviar un asteroide con el impacto de la sonda DART. Esperemos que, como las armas nucleares, todo se quede en ensayos y no sea necesario usarlo nunca.

lunes, 26 de septiembre de 2022

Lanzar de forma remota una aplicación dentro de la sesión gráfica del usuario.

En diferentes escenarios puede ser que tengamos que abrir una aplicación gráfica dentro del escritorio del usuario que ha iniciado la sesión sin estar fisicamente presentes en ese puesto. Esto va desde mostrar un mensaje al usuario con "zenity" o "notify-send" a abrir una aplicación concreta de forma automática en su escritorio en un momento dado.

Esto nos permitiría abrir una aplicación "mágicamente" en el escritorio del usuario desde una conexión ssh remota o desde un script lanzado desde crontab.

El truco está en que antes de ejecutar el comando que lanza la aplicación asignamos a las variables XAUTHORITY y DISPLAY los valores adecuados para entrometerse en la sesión abierta por el usuario que ha iniciado sesión físicamente en la máquina.

Una primera aproximación, muy burda, sería ejecutar, con el usuario root, estos comandos desde consola:
# export XAUTHORITY=/run/lightdm/root/:0 
# DISPLAY=:0 zenity --info --text "Ola ke ase"

Esto conecta con la sesión X iniciada con lightdm (el gestor de inicios de sesión) y muestra la ventana. El peligro que tiene esta forma es que el comando (zenity en este caso) se ejecuta como root, con los riegos que esto conlleva. En el caso de zenity en principio no hay mucho peligro, pero un programa como geany o un explorador de archivos abiertos como root en una sesión de usuario raso es bastante mas arriesgado.

La ventaja que tiene esté metodo es que permite mostrar la aplicación incluso si ningún usuario ha iniciado sesión, en la pantalla de login. Por ejemplo, puede ser util para mostrar mensajes en el escritorio haya o no sesión iniciada.

La otra aproximación, más ortodoxa, pasa por averiguar que usuario ha iniciado sesión en el escritorio y conectarnos con su sesión X en concreto. Los pasos son:
# comando='zenity --info --text "Ola ke ase"' # Programa a ejecutar
# user=$(who | grep "(:0)" | awk '{print $1}')) # Averiguamos que usuario ha iniciado sesión en el ordenador, 
# home_user=$(su usuario -c 'echo $HOME') # Averiguamos cual es su directorio home. Otra forma: home_user=$(getent passwd  usuario | cut -d":" -f6)
# export XAUTHORITY="$home_user/.Xauthority" # Accedemos a su fichero .Xauthority
# DISPLAY=:0 su $user -c $comando # Lanzamos el programa con la identidad del usuario

Todo este código anterior lo podemos meter un script que lancemos desde nuestra conexión ssh o desde un crontab u otro sistema de ejecución en background y con ello lograremos nuestro objetivo, para desconcierto del usuario que verá como se abren cosas de forma inesperada.

viernes, 23 de septiembre de 2022

Cambiar hostname de un equipo de forma automática a partir de los datos de ldap.

Como todo principio de curso, andamos de mundanza moviendo equipos de unas aulas a otras. Eso implica cambiar su nombre según la nomenclatura que sigamos en nuestro centro, para tenerlo localizado ante cualquier alarma o incidencia.

En el árbol ldap de nuestra red tenemos una entrada en la que asociamos la MAC de cada equipo con su hostname. Una vez hemos cambiado el nombre allí luego toca ir fisicamente al propio equipo y cambiar dicho hostname otra vez a mano. Como esta parte es muy aburrida he escrito un script que toma la MAC del equipo, la busca en ldap y si la encuentra cambia el hostname al que allí aparece.
# cat set-hostname-from-mac.sh 

#!/bin/bash

#Busca las MACs en ldap y si tienen un nombre asociado, configura el equipo con dicha mac.

#Sacamos las MACs de las tarjetas de red del equipo
macs=$(cat /sys/class/net/*/address | grep -v "00:00:00:00:00:00")

for mac in $macs
do
   #Buscamos en la MAC en ldap en la rama de configuración DHCP
   name=$(ldapsearch -xLLL -h ldap -b cn=DHCP\ Config,dc=instituto,dc=extremadura,dc=es "(dhcpHWAddress=ethernet $mac)" "cn" | grep "^cn" | cut -d" " -f2)
   if [ -n  "$name" ]
   then
         echo "Nombre nuevo: $name"

         echo $name > /etc/hostname
         hostname -F /etc/hostname
         echo $name > /proc/sys/kernel/hostname
         sed -i "s/127.0.1.1.*/127.0.1.1 $name/g"  /etc/hosts

         exit 0
   fi
done
echo "MAC no encontrada"
exit

Este script podemos ejecutarlo desde una tarea puppet o en paralelo sobre muchos equipos a la vez usando tmux-cssh.


Bonita foto tomada desde la ISS del despegue de la Soyuz MS-22 hace un par de días, con un astronauta estadounidense y dos astronautas rusos. Al menos allí arriba no hay guerras.

Nunca había visto un chemtrail de una Soyuz. Los conspiranoicos correrían en círculos gritando si se enterasen.

miércoles, 29 de junio de 2022

Problema con las firmas de paquetes en Manjaro.

Tras varios años sigo usando Manjaro Linux en muchos de mis PC personales, que llevan todo este tiempo sin una reinstalación ya que al ser una distribución rolling release siempre está a la última. Demasiado a la última algunas veces.

Esto no evita problemas con la paquetería, sobre todo si te quedas varios meses sin actualizar, pero hasta ahora siempre he salido airoso de los pequeños líos que se montan ocasionalmente.

Esta semana me puse a actualizar una máquina y me encontré con este nuevo error:
# pacman -Syyuu
....
....
error: Error de GPGME: No hay datos
error: no se pudo actualizar core (base de datos no válida o dañada (firma PGP))
....
....
Mirando en Internet vi muchos consejos: refresca la lista de mirrors, refresca los países desde dónde descargas, etc. Ninguna funcionaba hasta que encontre esta solución:
# rm -Rf /var/lib/pacman/sync
# rm -Rf /tmp/pamac/dbs/*  
# pacman -Syu
# pamac update
Y listo, funcionó.

Aunque pude actualizar luego me encontré con otro problemilla. La compilación-instalación del paquete:
# pamac build  mjpg-streamer-git 
Me daba de nuevo el error "error: 'mjpg-streamer-git-1:1.0.0.r1.g310b29f-1-x86_64.pkg.tar.zst': paquete sin la firma exigida" cuando iba a instalarlo tras la descarga y compilación. Este tipo de problemas suelen ser cuestiones puntuales con los repositorios pero en este caso tenía prisa. Solución:
# pamac build  -k mjpg-streamer-git 
Esto descarga y compila el paquete, pero además deja una copia del paquete instalable binario en /var/cache/pamac/mjpg-streamer-git-1\:1.0.0.r1.g310b29f-1-x86_64.pkg.tar.zst. Vamos a intentar instalarlo a mano:
# cp /var/cache/pamac/mjpg-streamer-git-1\:1.0.0.r1.g310b29f-1-x86_64.pkg.tar.zst /root
# pacman -U /root/mjpg-streamer-git-1\:1.0.0.r1.g310b29f-1-x86_64.pkg.tar.zst 
error: 'mjpg-streamer-git-1:1.0.0.r1.g310b29f-1-x86_64.pkg.tar.zst': paquete sin la firma exigida
Nada, sigue fallando. Para saltar el problema hay que desactivar la comprobación de firmas para paquetes que se instalen localmente. Editamos el fichero /etc/pacman.conf y cambiamos la línea:
LocalFileSigLevel = Never
Tras esto, ya podemos instalar el paquete sin contratiempos con:
# pacman -U /root/mjpg-streamer-git-1\:1.0.0.r1.g310b29f-1-x86_64.pkg.tar.zst 
Tras esto podemos poner LocalFileSigLevel con su valor anterior o dejarlo a Never, según nos parezca.

Out!

martes, 28 de junio de 2022

Gestión de fechas en fotos.

Voy a recopilar varios comandos y scripts para trabajar con las fechas de las fotos y facilitar su ordenación cuando trabajamos con gran cantidad de ellas. Supongamos un fichero denominado IMG20220414185751.jpg, en cuyo nombre aparece la fecha en que se tomó: 14/04/2022 a las 18:57:51 horas.

Aparte de en el nombre, la fecha se guarda en los metadatos EXIF de la foto, dentro de los metadatos binarios del fichero de imagen. Podemos consultarlo con:
# exiftool IMG20220414185751.jpg | grep "Create Date"
Create Date                     : 2022:04:14 18:57:51
Create Date                     : 2022:04:14 18:57:51.764000
Luego con "ls -l" podemos ver la fecha de modificación del fichero que contiene la foto (llamada ctime en el mundo Unix). Normalmente coincide con la fecha EXIF, pero si lo copiamos de un dispositivo a otro y/o lo modificamos con un editor de imágenes esta fecha puede cambiar, como vemos aquí:
$ ls -l IMG20220414185751.jpg
-rw-r--r-- 1 manjaro manjaro 2499469 jun 27 06:38 IMG20220414185751.jpg
Si queremos que la fecha EXIF se copie a la fecha ctime podemos usar el comando:
$ exiv2 -T rename IMG20220414185751.jpg
$ ls -l IMG20220414185751.jpg
-rw-r--r-- 1 manjaro manjaro 2499469 abr 14 18:57 IMG20220414185751.jpg
Si queremos que la fecha EXIF se copie al nombre del fichero podemos usar un formato como:
# exiv2  -r 'IMG%Y%m%d%H%M%S' rename fichero.jpg
# ls -l IMG20220414185751.jpg
-rw-r--r-- 1 manjaro manjaro 2499469 abr 14 18:57 IMG20220414185751.jpg
Por ultimo, si la fecha EXIF ha sido elminada y queremos cambiar el ctime del fichero extrayendolo de su nombre el comando sería:
# fichero="IMG20220414185751.jpg"
# fecha=$(echo ${fichero:3:8})
# touch -a  -m -t "${fecha}0100" $fichero
# ls -l IMG20220414185751.jpg
-rw-r--r-- 1 manjaro manjaro 2499469 abr 14 01:00 IMG20220414185751.jpg
Y aquí paro porque con estos comandos tenemos suficiente para clasificar cronológicamente la selección de fotos. Por supuesto hay muchas otras combinaciones que me quedo en el tintero, como escribir la fecha EXIF (usando exiftool) y operaciones por el estilo que quizá veamos en otra ocasión.

lunes, 6 de junio de 2022

Zabbix (III): creación de plantilla con items y triggers para agentes Linux.

Después de tener montado el Zabbix, van surgiendo nuevas necesidades para monitorizar nuestros clientes. En esta entrada voy a ver como he creado una plantilla para los Linux del IES, que me permite monitorizar varias cosas no previstas en la plantilla por defecto. Lo que haremos en primer lugar es crear la plantilla "Template IES Linex"
A continuación vamos definir los ítems que extraigan datos del cliente. Estos ítems son pequeños fragmentos de código con comandos de terminal Unix. Lo podemos hacer de dos maneras:
  1. Definir el código en el cliente dentro de /etc/zabbix/zabbix_agentd.conf.d/blablaba.conf y luego referenciarlo en el servidor Zabbix.
  2. Definir el código en el servidor Zabbix, dentro del mismo item usando system.run[...]
En el primer caso vamos a crear, por ejemplo, un ítem llamado "puppetcheck" que nos diga si la última ejecución de puppet ha acabado con éxito. Para ello lo primero es programar las instrucciones que hagan eso. Hay varias maneras de averiguarlo, como por ejemplo esta:
# cat /var/lib/puppet/state/last_run_report.yaml | grep -i -e "failed: true" -e "status: failed" | wc -l 
Esto nos devolverá 0 si no hay ningún error y >0 si hay algun error en la última ejecución de puppet. Esta secuencia de comandos ejecutada como usuario root funciona, pero hay que tener en cuenta que el agente Zabbix se ejecuta con el usuario zabbix y eso nos puede causar problemas. En este caso concreto el problema era el acceso al fichero /var/lib/puppet/state/last_run_report.yaml del cliente.

Para que el agente Zabbix pueda llegar hasta allí tenemos que echar mano de sudoers:
# cat /etc/sudoers.d/puppetcheck
Cmnd_Alias CHECKPUPPET = /bin/cat /var/lib/puppet/state/last_run_report.yaml
zabbix ALL=(ALL) NOPASSWD: CHECKPUPPET
Una vez hecho esto, ya podemos definir el parámetro que usará el ítem en el cliente:
# cat /etc/zabbix/zabbix_agentd.conf.d/checkpuppet.conf
UserParameter=system.puppetcheck,sudo cat /var/lib/puppet/state/last_run_report.yaml | grep -i -e "failed: true" -e "status: failed" | wc -l
. Una vez definido el item en los clientes, lo añadimos a la plantilla en el servidor Zabbix:
Además de crear el ítem, le añadimos una regla de preprocesamiento llamada "Discard unchanged with a heartbeat" que evita que se guarden valores repetidos consecutivos del ítem en el registro histórico. De esta manera solo guardamos el ítem cuando cambia su valor respecto a la actualización anterior (o, en este caso concreto, han pasado 12 horas desde la última actualización). La finalidad de esto es evitar guardar valores repetidos consecutivos de los ítems en toda la base de datos histórica.
Finalmente creamos un trigger para que avise cuando hay un error. En este caso vemos si hay error en puppet durante las 3 últimas actualizaciones del ítem:



Con esto tenemos el pack completo: parámetro defínido en el cliente Zabbix, asociado a un ítem en el servidor Zabbix y con un trigger que nos avisa este tiene un valor determinado.

La otra otra opción consiste en definir en el servidor Zabbix el ítem con el código a ejecutar en el cliente remoto. Por ejemplo, un ítem que muestre en cada momento que usuario ha hecho login en la máquina, definido así:
Parent items: Template Linux IES
Name: LoggedUser
Type: Zabbix agent
Uptdate time: 1m
Key: system.run["who | grep -v root | cut -d' ' -f1"]
El problema de este tipo de ítems es que debemos estar seguros de que el cliente Zabbix permite la ejecución remota de comandos, ya que si no es así el ítem no se actualizará nunca. De igual manera, si el agente se ejecuta en una máquina que está detrás de un firewall o un NAT tampoco podremos llegar a ella para ejecutar el comando desde el servidor Zabbix.

En este ítem LoggedUser tambien añadiremos una regla de preprocesamiento del tipo "Discard unchanged", para evitar guardar de forma repetida el usuario logado cada vez que se actualiza el ítem, y solo guardarlo cuando cambia entre una actualización y la siguiente.

Por último, comentar que una vez hemos definido los ítems tenemos la posibilidad de probarlos desde la línea de comandos para ver que tal funcionan. En el cliente local:
# zabbix_agentd -t system.puppetcheck
O de forma remota:
# zabbix_get -s 172.X.Y.Z -p 10050 -k system.puppetcheck
Bueno, pues con esto ya tenemos el armazón para añadir ítems y triggers a saco en nuestros clientes.
Aquí están los 3 camaradas taikonautas que han subido estos días en la Shenzou 14 para finalizar el montaje de la Estación Espacial China. Recordemos que esta estación existe porque USA se negó a dar acceso a China a la Estación Espacial Internacional, por lo que los chinos decidieron montarse su propia estación mastodóntica (que a diferencia de la de Bender, no tendrá casinos ni furcias (*)) adquiriendo en el proceso una experiencia y know-how que les vendrá de perlas.

Es lo que pasa cuando no se quiere colaborar internacionalmente. Avisados quedamos.

(*)