Recreando nuestro propio wpdirectory.net

El proyecto wpdirectory.net es fantástico, es un proyecto de Peter Booker para buscar mediante expresiones regulares cadenas en el código y el texto de todos los archivos de los repositorios de plugins y temas de WordPress.

Este proyecto es una herramienta esencial para el equipo de plugins, nos permite buscar copias de plugins, posibles violaciones de las normas del repositorio, problemas de seguridad, y analizar el código de todo el repositorio para mejorar nuestras herramientas internas.

Hace tiempo me planteé que, por resiliencia, el equipo de plugins necesita tener su propia versión de esta herramienta.

Las alternativas

Tal como viene indicado en el handbook, hay herramientas para descargar el repositorio. También hay herramientas como WPDS para además buscar en él.

Desgraciadamente, a día de hoy, esto es poco funcional porque el repositorio es enorme y, aunque se use ag para buscar (que es extremadamente rápido), una búsqueda tarda del orden de 4 minutos.

Esta no era una alternativa, de modo que intenté hacer uso directamente del proyecto wpdir, que está abierto en Github y que, desgraciadamente, no llegué a hacer funcionar en mi entorno, pero si que pude ver cómo funciona.

wpdir usa:

  • wpds para descargar y actualizar el repositorio.
  • hound , que a su vez usa codesearch, para indexar el código y permitir hacer búsquedas rápidas mediante expresiones regulares.

Gracias a todas las personas que han contribuido con estos proyectos de código abierto tenemos estas herramientas disponibles y puedo seguir avanzando en este artículo.

Nuestro propio buscador

Preparando el entorno

Necesitamos un servidor que sea lo suficientemente potente, con suficiente almacenamiento y memoria. Para este caso he usado un servidor con 8 cores compartidos AMD EPYC™ 7002, 16Gb de RAM y 240Gb de almacenamiento SSD NvME.

El servidor corre sobre Ubuntu y tiene los siguientes paquetes adicionales instalados:

sudo apt install subversion make npm golang-go silversearcher-ag

Además, hay que hacer algunos ajustes adicionales al sistema operativo, dado que va a trabajar con un número enorme de archivos y va a hacer un uso de recursos fuera de lo habitual.

Para esto, dado que no soy sysadmin, simplemente he puesto valores grandes, no sé realmente qué estoy haciendo ni qué implicaciones tiene, si eres un sysadmin puedes ayudarme a establecer mejor estos valores.

Añadir estas líneas a /etc/sysctl.conf

fs.inotify.max_user_instances = 1024
vm.max_map_count = 262144

Edita estos dos archivos:
/etc/systemd/system.conf
/etc/systemd/user.conf

En ambos casos busca la propiedad DefaultLimitNOFILE, descomenta y déjala así:

DefaultLimitNOFILE=262144:5242880

Tendrás que reiniciar después de aplicar estos cambios, y comprobar con ulimit -n que se han aplicado.

Descargar los plugins

Lo primero que necesitamos es wpds, que descarga todo el repositorio actual de WordPress y permite sincronizar los cambios más recientes.

Para ello simplemente hay que ejecutar ./wpds update plugins que creará una carpeta ./plugins/ dónde se introducirá cada plugin en una carpeta nueva.

Actualmente descargará más de 60.000 plugins que ocuparán unos 95Gb de espacio. El proceso tarda alrededor de 4 horas.

Configurar el buscador

La instalación es tan simple como indican

git clone https://github.com/hound-search/hound.git
cd hound
make

La configuración se hace a través de un fichero JSON en el que se puede indicar de qué repositorios leerá la información. He creado un JSON de este tipo.

{
	"max-concurrent-indexers":2,
	"max-connections":50,
	"dbpath":"db",
	"title":"Plugins search",
	"health-check-uri":"/healthz",
	"repos":{
		"woocommerce":{
			"url":"file:///mnt/plugins/plugins/woocommerce",
			"url-pattern": {
				"base-url":"https://plugins.trac.wordpress.org/browser/woocommerce/trunk/{path}{anchor}", 
				"anchor":"#L{line}"
			},
			"vcs":"local"
		}
	}
}

Que carga localmente desde /mnt/plugins/plugins/woocommerce un plugin llamado woocommerce cuyo enlace al código es https://plugins.trac.wordpress.org/browser/woocommerce/trunk/{path}{anchor} .

Se este modo indexará de forma independiente el código de este plugin y luego nos saldrá de forma agrupada, además haciendo esto evitamos el límite técnico de 4Gb para los index que tiene codesearch.

Esto hay que hacerlo para los más de 60.000 plugins que hay.

Venga, comienza a escribir el JSON.

Uno a uno.

Estoy esperando.

Bueno, vale, en verdad hay una alternativa, pero es un script en PHP, no soy perfecto.

<?php
$dir = "/mnt/plugins/plugins";  // Plugins dir
$items = scandir($dir);

var_dump('Number of repositories: '.sizeof($items));

$hound_config = array(
	"max-concurrent-indexers" => 2,
    "dbpath" => "/mnt/plugins/db",
    "title" => "Plugins Search",
    "health-check-uri" => "/healthz",
	"repos" => []
);

foreach($items as $item) {

	// Allows us creating the indexing in batches.
	$limit = 1000000;
	if(sizeof($hound_config["repos"])>$limit){
		var_dump('Repositories limited to: '.$limit);
		break;
	}

	if(is_dir($dir . DIRECTORY_SEPARATOR . $item) && $item != "." && $item != "..") {
		$hound_config["repos"][$item] = [
			"url" => "file://".$dir."/".$item,
            "url-pattern" => [
	            "base-url" => "https://plugins.trac.wordpress.org/browser/".$item."/trunk/{path}{anchor}",
                "anchor" => "#L{line}"
            ],
            "vcs" => "local"
		];
	}
}

$json = json_encode($hound_config, JSON_UNESCAPED_SLASHES);

file_put_contents("config.json", $json);

Esto creará este fichero config.json para todos los repositorios almacenados en /mnt/plugins/plugins . Tiene una pequeña condición para limitar el número de repositorios creados, útil para probar las primeras ejecuciones.

Ejecutar el buscador

Una vez creado el archivo de configuración hay que lanzar hound, con el siguiente comando.

./.build/bin/houndd

Comenzará a indexar el contenido de todos estos repositorios uno por uno y a copiar los contenidos en texto a su directorio. Esto ocupa aproximadamente 33Gb y el proceso tarda alrededor de 5 horas.

Una vez terminado, levantará un servidor web en el puerto 6080 desde el cual podemos realizar nuestras búsquedas.

Mantenerlo en ejecución

Para que se mantenga en ejecución, se vuelva a levantar cuando falla (cosa que ocurre en esta configuración, dado que llega al límite de memoria en búsquedas muy genéricas) y se actualice, hay que hacer varias operaciones adicionales.

Servicio de sistema

Crea el servicio de sistema hound, creando su archivo de servicio nano /etc/systemd/system/hound.service

[Unit]
Description=Hound Daemon
After=network.target
StartLimitIntervalSec=30
[Service]
Type=simple
Restart=on-failure
RestartSec=5
User=hound
ExecStart=/mnt/plugins/hound/.build/bin/houndd -conf /mnt/plugins/config.json

[Install]
WantedBy=multi-user.target

Y actívalo con el comando systemctl enable hound . Si el proceso falla (lo cual es probable que ocurra, se reiniciará automáticamente en unos 5 segundos).

¿Va todo bien? Puedes comprobarlo con systemctl status hound

Actualización

Con todo esto, actualizar ya es algo más sencillo con un pequeño script en BASH.

#!/bin/bash

cd /mnt/plugins
./wpds update plugins
php wpds-to-hound-config.php
systemctl restart hound

Que podemos ejecutar mediante cron, tal vez una vez al día.

crontab -e
0 9 * * * /mnt/plugins/update.sh

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.