Cómo ver los detalles de la CPU en Illumos (por ejemplo, SmartOS)

En una máquina con sistema operativo basado en Illumos, como un SmartOS, podemos ver los detalles de su CPU con el siguiente comando:

[root@X ~]# kstat -p cpu_info:0:cpu_info0:brand
cpu_info:0:cpu_info0:brand      Intel(r) Core(tm) i7-6700 CPU @ 3.40GHz

Una vez que conocemos el modelo, podemos investigar sus características en infinidad de páginas online. Si lo que queremos es saber cuántos núcleos tiene esa CPU, sin andar buscando online, podemos ir probando valores de núcleo:

[root@X ~]# kstat -p cpu_info:0:cpu_info0:brand
cpu_info:0:cpu_info0:brand      Intel(r) Core(tm) i7-6700 CPU @ 3.40GHz
[...]
[root@X ~]# kstat -p cpu_info:7:cpu_info7:brand
cpu_info:7:cpu_info7:brand      Intel(r) Core(tm) i7-6700 CPU @ 3.40GHz
[root@X ~]# kstat -p cpu_info:8:cpu_info8:brand
[root@X ~]#

La CPU de esta máquina tiene ocho núcleos. Recuerda que se empieza a contar desde cero.

Este comando es útil, por ejemplo, en máquinas en hospedaje en centros de datos ajenos, a las que no tenemos acceso físico.

Problema actualizando mis servicios WSGI a Python 3.13

Acaba de salir Python 3.13 y, como siempre, actualizo mi código y servicios a esta nueva versión. Actualizo rápido para aprovechar las mejoras de la nueva versión de Python y porque acumular actualizaciones pendientes supone que el coste de migrar va creciendo cada año.

Normalmente los cambios necesarios son mínimos, pero en esta ocasión tengo problemas con mis servicios WSGI a través del módulo mod_wsgi.

Los servicios en sí parecen funcionar correctamente, pero los logs se saturan de cientos de líneas por segundo con el siguiente error:

Exception ignored in: <_io.TextIOWrapper name='<wsgi.errors>' encoding='utf-8'>
RuntimeError: log object has expired

Viendo el código fuente de mod_wsgi y del propio intérprete de Python, esto ocurre cuando se escribe en el log (o se hace flush) una vez que ya se ha llamado a close. La parte de Exception ignored está dentro del intérprete de Python, cuando se intenta escribir en un fichero que no puede dar una excepción. Por ejemplo, cuando un destructor levanta una excepción o durante la recogida de basuras.

Aunque todo parece ir bien, de momento seguiré con Python 3.12, mientras investigo el problema en detalle. Ahora mismo estoy bastante ocupado...

20241015: Alguien se me ha adelantado informando del problema: RuntimeError: log object has expired in mod_wsgi 5.0.1 with Django 5.0.9 python 3.13.0 #912.

20241122: Se publica la versión 5.0.2 de mod_wsgi que, aparentemente, soluciona este problema.

20250125: Encuentro un rato para actualizar mis servicios WSGI a la nueva versión de mod_wsgi y confirmo que el problema se ha solucionado.

IPv6 en OSMC

Se puede activar IPv6 en una instalación OSMC moderna de forma simple, aunque hay que hacerlo interfaz de red a interfaz de red (tanto por cable ethernet como por wifi):

$ connmanctl
> services
[...]
> config ethernet_XXXXXXXXXX_cable --ipv6 auto
> quit

Esto es un problema porque, al aparecer la dirección MAC en la configuración, si metemos esta tarjeta en otra Raspberry PI el servicio IPv6 dejará de estar disponible hasta que lo volvamos a configurar.

También se pueden activar las privacy extensions de IPv6 en /var/lib/connman/*/settings, editando la línea IPv6.privacy. Los valores son: disabled, enabled (activado pero prefiere la IP pública) o preferred/prefered (activado y prefiere las privadas).

Para configurar la duración de las IPs privadas en IPv6, se configura en el directorio /proc/sys/net/ipv6/conf/INTERFAZ/, los ficheros temp_prefered_lft y temp_valid_lft. En las Raspberry PI que estoy modificando los valores son 24 horas y 7 días.

Espero que IPv6 esté mejor integrado en futuras versiones de OSMC, pero de momento podemos ir tirando.

Problema activando una característica opcional de ZFS y actualización urgente del módulo ZFS de este servidor Linux

Nota

Estas son notas rápidas durante la investigación y solución de un problema, no un artículo depurado y organizado.

He activado algunas características opcionales de uno de mis servidores con OpenZFS (una máquina con Linux) y me encuentro que la actividad del disco duro es muy baja y me salen errores de este estilo en dmesg:

[19937.978681] INFO: task z_upgrade:720856 blocked for more than 483 seconds.
[19938.004576]       Tainted: P           O      5.4.0-181-generic #201-Ubuntu
[19938.030512] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
[19938.081727] z_upgrade       D    0 720856      2 0x80004000
[19938.081730] Call Trace:
[19938.081739]  __schedule+0x2e3/0x740
[19938.081744]  ? __wake_up_common_lock+0x8a/0xc0
[19938.081746]  schedule+0x42/0xb0
[19938.081747]  io_schedule+0x16/0x40
[19938.081757]  cv_wait_common+0xdc/0x180 [spl]
[19938.081759]  ? __wake_up_pollfree+0x40/0x40
[19938.081763]  __cv_wait_io+0x18/0x20 [spl]
[19938.081845]  txg_wait_synced_impl+0xd7/0x120 [zfs]
[19938.081903]  txg_wait_synced+0x10/0x40 [zfs]
[19938.081945]  dmu_objset_id_quota_upgrade_cb+0xba/0x170 [zfs]
[19938.081986]  dmu_objset_upgrade_task_cb+0xdf/0x100 [zfs]
[19938.081992]  taskq_thread+0x245/0x430 [spl]
[19938.081994]  ? wake_up_q+0xa0/0xa0
[19938.081998]  kthread+0x104/0x140
[19938.082003]  ? task_done+0x90/0x90 [spl]
[19938.082005]  ? kthread_park+0x90/0x90
[19938.082007]  ret_from_fork+0x35/0x40

Un top muestra una carga muy elevada en arc_prune, 99.4 de sys time.

El smartctl o leer el disco duro entero con ddrescue, no muestran ningún error. Esto parece un bug de OpenZFS.

Si importo el zpool en read only, funciona. Esto me permitiría recuperar los datos en caso necesario. No estoy en situación catastrófica aún, aunque no puedo hacer más copias de seguridad en este disco duro [1].

[1] Este servidor Linux es mi servidor de copias de seguridad. Si se perdiese ese zpool, se perdería la copia de los datos, no los datos originales. Además, ese zpool es un espejo y su otra mitad está desconectada y en otro domicilio, como procedimiento de seguridad. A las malas, tendría esa mitad actualizada hasta unas semanas antes.

Intento compilar OpenZFS 2.2.4, pero falla en construir los paquetes Debian.

Pruebo con OpenZFS 2.1.12. Toco configure para que use el Python3.8 del sistema operativo en vez del moderno 3.12.

Opto por usar el repositorio https://launchpad.net/~jonathonf/+archive/ubuntu/zfs?field.series_filter=focal , que me instalará OpenZFS 2.1.6.

Con esta versión, la cosa tiene buena pinta. Al importar el zpool, se empieza a actualizar, pero es un proceso que no se va de madre. Supongo que la actualización costosa es debido a la activación de project_quota.

La cuestión es no hacer más upgrades con esta versión de OpenZFS, de momento, para poder volver atrás si es necesario.

SmartOS: Stock "mkvtoolnix" crashes on 2023.4.0 with locale error

This post transcribes some emails I sent to the SmartOS mailing list some time ago. You can check the original thread:

Message-ID: <15dec164-940e-17d7-a7db-dcdf19f9ec2d@jcea.es>
Date: Tue, 12 Mar 2024 14:07:13 +0100
To: smartos-discuss <smartos-discuss@lists.smartos.org>
From: Jesus Cea <jcea@jcea.es>
List-Id: "smartos-discuss" <smartos-discuss.lists.smartos.org>
Subject: [smartos-discuss] Stock "mkvtoolnix" crashes on 2023.4.0 with locale
  error

Hi, there.

I install "pkgin install mkvtoolnix" with no issues (but a huge number
of dependencies, 1.6 Gigabytes total!).

Then, I run "mkvmerge" and it crashes:

"""
[jcea@test ~]$ mkvmerge
terminate called after throwing an instance of 'std::runtime_error'
what():  locale::facet::_S_create_c_locale name not valid
Abort (core dumped)
"""

This worked fine in 2022.4.0.

My environment variables are:

"""
MANPATH=/opt/local/man:/usr/share/man:/opt/local/lib/perl5/man:/opt/local/lib/perl5/vendor_perl/man
LC_MONETARY=es_ES.UTF-8
TERM=xterm
SHELL=/usr/bin/bash
SSH_CLIENT=***
LC_NUMERIC=es_ES.UTF-8
SSH_TTY=/dev/pts/26
USER=root
COLUMNS=80
PAGER=less
MAIL=/var/mail/root
PATH=/usr/local/sbin:/usr/local/bin:/opt/local/sbin:/opt/local/bin:/usr/sbin:/usr/bin:/sbin
LC_COLLATE=es_ES.UTF-8
PWD=/home/jcea
LANG=en_US.UTF-8
TZ=Europe/Madrid
LINES=25
SHLVL=1
HOME=/home/jcea
TERMINFO=/opt/local/share/lib/terminfo
LOGNAME=jcea
SSH_CONNECTION=****
LC_TIME=es_ES.UTF-8
FTPMODE=auto
_=/opt/local/bin/env
"""

Jonathan Perkin replied:

Leer más…

Feed Slashdot: Modo "verboso" y peticiones HTTP incondicionales

Artículos previos sobre este proyecto para enviar por email las novedades diarias de un feed RSS:

Aunque el código va necesitando una refactorización y limpieza, sigo haciendo pequeñas modificaciones y mejoras:

  • Modo verboso: Normalmente cuando se invoca el programa hace su trabajo sin más. Pero a veces nos interesa saber qué ha hecho, si ha enviado un correo electrónico o no, por ejemplo, cuántas entradas nuevas hay en el feed RSS, etc.

  • Peticiones HTTP incondicionales: De vez en cuando el feed RSS de Slashdot da un error HTTP 50x, indicando un error interno. Cuando esto ocurre, el Sistema Operativo de mi servidor me envía un email indicando que el proceso ha fallado. Ejecutándolo manualmente compruebo que cuando ocurren esos errores el feed RSS de Slashdot no ha cambiado desde la petición anterior y que, de hecho, el problema se resuelve solo cuando aparece una entrada nueva.

    Esto tiene toda la pinta de ser un bug en el código de Slashdot y en realidad solo me afecta de forma cosmética (los correos electrónicos de errores que me llegan por ser administrador de la máquina que ejecuta este servicio), pero durante las pruebas comprobé que hacer una petición HTTP incondicional [1] no produce un error, así que añadí esa funcionalidad al programa.

    [1]

    Cuando mi programa detecta una actualización del feed RSS se queda con sus entradas y las siguientes peticiones no vuelven a pedir el feed RSS sin más, sino que envía al servidor HTTP de Slashdot lo que se llama una petición condicional que básicamente dice: "envíame el feed RSS solo si ha habido algún cambio desde la versión anterior. Si no no me mandes nada". Esto es ventajoso para todo el mundo, pero parece que Slashdot falla de vez en cuando cuando en realidad no ha habido un cambio en el feed RSS y simplemente tendría que haberme respondido con un código HTTP 304. Es así cómo debería ser y, de hecho, es lo que hace el 99.99% del tiempo. Pero falla ese 0.01%...

El parche es largo, pero fácil de entender:

Leer más…

"Nullmailer", "Return-Path" y GMail

En Generar un email diario a partir de un feed RSS (Slashdot), Mejoras a la hora de generar un email diario a partir de un feed RSS (Slashdot) y Los peligros de volcar a "pickle" cualquier cosa describo un programa para enviar por email las novedades diarias de un feed RSS.

Hace un tiempo modifiqué el programa para enviar los emails a varias direcciones de correo electrónico, no solo a mi cuenta. Todo ha ido bien hasta recientemente que añadí una dirección de GMail a la lista de destinatarios. GMail me rechazaba los mensajes por spam, sin un motivo claro a solucionar.

Tras dedicar unos ratos de diagnóstico y experimentos, he llegado a las siguientes conclusiones:

  • El remitente de mis emails era root@P2Ppriv.jcea.es. Ese dominio no existe. No es sorprendente que GMail no aceptase mis mensajes de las novedades diarias del feed RSS.

    No había tenido problemas hasta ese momento porque todos los destinatarios de las novedades diarias del feed RSS de Slashdot eran usuarios locales de mi propio servidor de correo electrónico.

  • Incluso poniendo un dominio remitente que exista en la cabecera From, nullmailer estaba usando un envelope SMTP con el mismo dominio inválido. Leyendo la documentación de nullmailer, en concreto el componente nullmailer-inject, podemos leer lo siguiente:

    -f sender

    Set the envelope sender address to sender.

    Esto es esperanzador, pero no estamos usando nullmailer directamente para inyectar los mensajes en el sistema de correo, sino el comando estándar mail, que no tiene un parámetro para controlar el envelope SMTP.

    Revisando otra vez el manual de nullmailer-inject, vemos algo interesante:

    If the Return-Path header field is present and contains a single address, its contents will be used to set the envelope sender address.

    Vaya, podemos utilizar la cabecera Return-Path para controlar el envelope SMTP utilizado por nullmailer.

Por tanto el parche es sencillo:

             msg = MIMEText(html, 'html')
             msg['Subject'] = f'Feed Slashdot {time.strftime("%Y-%m-%d", ts_max)}'
+            msg['From'] = 'slashdot-sender@jcea.es'
             msg['To'] = addr
             msg['Date'] = email.utils.formatdate()
             msg['List-Id'] = 'Notificaciones Slashdot'
             msg['Message-Id'] = email.utils.make_msgid(domain='P2Ppriv')
+            # Esto es para controlar el "sender" del envelope que pone "nullmailer".
+            # Ver "man nullmailer-inject".
+            msg['Return-Path'] = 'slashdot-sender@jcea.es'
+
             msg = msg.as_bytes()

Esta modificacion utiliza una cabecera From para indicar una dirección de correo electrónico que sí exista (en concreto, su dominio) y una cabecera Return-Path para controlar el envelope SMTP y que salga también con un dominio correcto.

Con esto GMail está satisfecho aceptando mis mensajes y tengo amigos felices con su dosis diaria de noticias curadas.

How to pin a "pkgin" package, what is the right way to deploy my own packages?

This post transcribes some emails I sent to SmartOS mailing list:

My initial email:

Message-ID: <d50150d8-b863-3886-89d7-f2ae156610a2@jcea.es>
Date: Mon, 4 Mar 2024 03:02:31 +0100
To: smartos-discuss <smartos-discuss@lists.smartos.org>
From: Jesus Cea <jcea@jcea.es>
Subject: [smartos-discuss] How to pin a "pkgin" package, what
   is the right way to deploy my own packages?

I compiled an Apache server package myself because I need some
special compilations. I used the pkgsrc-tls zone image. In
order to avoid automatic updates, I modified the package
version from "2.4.58" to "2.4.589" (I added a 9 at the end). I
naively considered that since my version is higher, it would
override system package.

I did that change in the Makefile.

I manually installed the package with "pkg_add". So good so
far.

Then, I installed stock pkgsrc package
"py312-ap24-mod_wsgi-4.9.4". The dependencies of that package
are:

"""
[root@TEST ~]# pkgin show-deps py312-ap24-mod_wsgi-4.9.4
direct dependencies for py312-ap24-mod_wsgi-4.9.4
         py312-setuptools-[0-9]*
         apache>=2.4.58nb1<2.5
         gcc13-libs>=13.2.0
         python312>=3.12.0
"""

Since dependencies list "apache>=2.4.58nb1<2.5", I would
guess that my "apache-2.4.589" would fit the bill. But pkgin
"refreshes" package system "apache-2.4.58nb1" (not actually
installed!), replacing my package "apache-2.4.589".

So my questions are:

* What would be the right way to compile/install my own
packages shadowing "pkgin" packages, in order to avoid SmartOS
to mess with them when "pkgin install" some other package or,
worse "pkgin upgrade". Yes, I know that this have security
implications, I deal with them myself for my packages.

* Sometimes installing a package does a "refresh" of an
already installed package. Apparently, this uninstall and
reinstall the package. In this particular case, that "refresh"
uninstall my package and install the system package. What is
the point of this "refresh"? What are the conditions that
trigger that action?.

Any advice? Best practices?

Thanks!

PS: My packages are not signed (yet), I disabled (temporary)
signature verification, if that is something important.

After a few hours, Jonathan Perkin <jperkin@mnx.io> provided this useful reply:

Date: Mon, 4 Mar 2024 09:18:21 +0000
From: Jonathan Perkin <jperkin@mnx.io>
To: smartos-discuss <smartos-discuss@lists.smartos.org>
Subject: Re: [smartos-discuss] How to pin a "pkgin" package,
   what is the right way to deploy my own packages?
Message-ID: <ZeWR3Y9NO-ggG_Yu@mnx.io>
References: <d50150d8-b863-3886-89d7-f2ae156610a2@jcea.es>

* On 2024-03-04 at 02:04 GMT, Jesus Cea wrote:

>* What would be the right way to compile/install my own
>packages shadowing "pkgin" packages, in order to avoid
>SmartOS to mess with them when "pkgin install" some other
>package or, worse "pkgin upgrade". Yes, I know that this have
>security implications, I deal with them myself for my
>packages.

pkgin keys packages based on their PKGPATH, i.e. in the case
of apache it'll be www/apache24.  If your custom package is
built in that same directory, then regardless of the version,
pkgin will treat it as being the same.

In order to stop that happening, create a separate directory
in pkgsrc for your custom packages and copy the apache24
directory there, for example local/apache24.  You can also
then revert any version numbering changes and just use the
same as the www/apache24 package.

Ideally have your own git repository for custom packages, for
example the packages under pkgsrc/extra in our tree come from
https://github.com/TritonDataCenter/pkgsrc-extra which is
added as a git submodule.

>* Sometimes installing a package does a "refresh" of an
>already installed package. Apparently, this uninstall and
>reinstall the package. In this particular case, that
>"refresh" uninstall my package and install the system
>package. What is the point of this "refresh"? What are the
>conditions that trigger that action?.

Refresh happens if the remote package BUILD_DATE is newer than
what is installed.  This happens quite frequently, as pkgsrc
will rebuild a package if any of its dependencies have
changed, but this avoids many classes of severely unpleasant
bugs.

One thing to note is that this will happen regardless of
version, as there are some occasions where the version will go
backwards (e.g. we found a critical bug in the newer software
and had to revert back to a previous release), which is why
your modification of the version didn't really do anything.

Cheers,

Refrescar el certificado X.509 de una entidad de certificación para OpenVPN, manteniendo sus firmas previas como válidas

Tengo un servicio OpenVPN privado desde hace diez años. Todos los certificados X.509 de acceso y el certificado X.509 del servidor OpenVPN están firmados por una autoridad de certificación privada.

El problema es que esa autoridad de certificación tiene una validez de diez años, caducando en unos meses. En ese momento OpenVPN dejará de funcionar si no hago nada.

La solución evidente es crear un nuevo certificado para la autoridad de certificación privada, con una validez de otros diez años (por ejemplo). El problema es que eso requiere emitir nuevos certificados X.509 para el servidor OpenVPN y para todos los clientes. Todo el cambio tiene que estar coordinado, porque los certificados X.509 previos dejarían de ser válidos en cuanto se active la nueva clave de la autoridad de certificación.

¿Cómo refrescar una autoridad de certificación para extender su fecha de caducidad manteniendo la validez de los certificados X.509 firmados previamente?

Los certificados X.509 tienen un número de serie y una fecha de mínima y otra máxima de validez. ¿Es posible modificar dichas fechas del certificado X.509 de la autoridad de certificación y que sigan funcionando las firmas antiguas?

Leer más…

Los peligros de volcar a "pickle" cualquier cosa

En Generar un email diario a partir de un feed RSS (Slashdot) y Mejoras a la hora de generar un email diario a partir de un feed RSS (Slashdot) describo un programa para enviar por email las novedades diarias de un feed RSS.

Aunque al programa le vendría bien una reescritura, todo fue bien hasta hace unos días, cuando el programa falló con un error indicando que no se podía recuperar el estado volcado con pickle debido a una dependencia (inesperada e inadvertida) con beautifulsoup4.

El error en sí era críptico y poco claro, pero ocurrió tras haber actualizado la biblioteca beautifulsoup4. Esto fue una pista crucial. Obviamente todo volvió a la normalidad tras instalar una versión previa y así siguió cumpliendo con su trabajo unos días hasta que encontré tiempo para echarle un vistazo. La actualización de beautifulsoup4 no era urgente y pude aplazar la investigación hasta que me vino bien.

Una vez metido en faena quedó claro que el problema era que la estructura interna de beautifulsoup4 había cambiado y los objetos serializados de la versión anterior de beautifulsoup4 no podían cargarse en la versión actual de la biblioteca. Esto no es ninguna sorpresa, es lo normal. La sorpresa es que estuviera serializando objetos beautifulsoup4 de forma inadvertida.

Leer más…